├── .gitignore
├── LICENSE
├── README.md
├── doc
└── components.jpg
├── pom.xml
└── src
├── main
├── java
│ └── io
│ │ └── github
│ │ └── thymeleaf
│ │ └── ui
│ │ ├── Attrs.java
│ │ ├── Component.java
│ │ ├── Components.java
│ │ ├── Element.java
│ │ ├── HasHtmlAttributes.java
│ │ ├── HasStatus.java
│ │ ├── Renderable.java
│ │ ├── components
│ │ ├── Alert.java
│ │ ├── Badge.java
│ │ ├── Breadcrumb.java
│ │ ├── Button.java
│ │ ├── ButtonGroup.java
│ │ ├── Card.java
│ │ ├── Carousel.java
│ │ ├── Dropdown.java
│ │ ├── ElementCollection.java
│ │ ├── Figure.java
│ │ ├── Nav.java
│ │ ├── Navigation.java
│ │ ├── NavigationHeader.java
│ │ └── Sidebar.java
│ │ ├── dialect
│ │ ├── ComponentTemplateResolver.java
│ │ ├── IsThemeConfigured.java
│ │ ├── UiDialect.java
│ │ ├── UiDialectAutoconfiguration.java
│ │ ├── UiExpressionObjectFactory.java
│ │ └── tags
│ │ │ ├── AbstractTagProcessor.java
│ │ │ ├── AlertAttributeTagProcessor.java
│ │ │ ├── BadgeAttributeTagProcessor.java
│ │ │ ├── BreadcrumbAttributeTagProcessor.java
│ │ │ ├── ButtonAttributeTagProcessor.java
│ │ │ ├── ButtonGroupAttributeTagProcessor.java
│ │ │ ├── CardAttributeTagProcessor.java
│ │ │ ├── CarouselAttributeTagProcessor.java
│ │ │ ├── CopyTagAttributesTagProcessor.java
│ │ │ ├── DropdownAttributeTagProcessor.java
│ │ │ ├── FigureAttributeTagProcessor.java
│ │ │ ├── NavigationAttributeTagProcessor.java
│ │ │ ├── NavigationHeaderAttributeTagProcessor.java
│ │ │ ├── RenderAttributeTagProcessor.java
│ │ │ └── SidebarAttributeTagProcessor.java
│ │ ├── elements
│ │ ├── Image.java
│ │ └── Link.java
│ │ └── internal
│ │ ├── Checks.java
│ │ ├── Reflection.java
│ │ ├── Strings.java
│ │ ├── Urls.java
│ │ └── package.java
└── resources
│ ├── META-INF
│ └── spring.factories
│ └── templates
│ └── ui
│ └── themes
│ ├── Readme
│ └── default
│ ├── alert-component.html
│ ├── badge-component.html
│ ├── breadcrumb-component.html
│ ├── button-component.html
│ ├── button-group-component.html
│ ├── card-component.html
│ ├── carousel-component.html
│ ├── dropdown-component.html
│ ├── figure-component.html
│ ├── navigation-component.html
│ ├── navigation-header-component.html
│ └── sidebar-component.html
└── test
├── java
└── io
│ └── github
│ └── thymeleaf
│ └── ui
│ ├── ComponentsTest.java
│ └── dialect
│ └── DialectBenchmarkTest.java
└── resources
└── test.html
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 | .settings
4 | .classpath
5 | .project
6 |
7 | .DS_Store
8 | # Log file
9 | *.log
10 |
11 | # BlueJ files
12 | *.ctxt
13 |
14 | # Mobile Tools for Java (J2ME)
15 | .mtj.tmp/
16 |
17 | # Package Files #
18 | *.jar
19 | *.war
20 | *.nar
21 | *.ear
22 | *.zip
23 | *.tar.gz
24 | *.rar
25 |
26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
27 | hs_err_pid*
28 | /target/
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Thymeleaf UI Dialect
2 | Thymeleaf dialect to create interface components, provides a simple way to define reusable components and some html attributes to render user interface (html) components.
3 |
4 | See demo project: https://github.com/jpenren/thymeleaf-ui-dialect-demo
5 |
6 | Usage
7 | -----
8 |
9 | Add the Maven dependency to your project:
10 | ```xml
11 |
12 | io.github.jpenren
13 | thymeleaf-ui-dialect
14 | 1.1.0
15 |
16 | ```
17 |
18 | This library uses Spring Boot autoconfiguration feature, if required you can define this dialect manually:
19 | ```java
20 | templateEngine.addDialect(new UiDialect());
21 | String theme = "default";
22 | templateEngine.addTemplateResolver(new ComponentTemplateResolver(theme));
23 | ```
24 |
25 | Components
26 | -----
27 |
28 | Enabling this dialect will introduce the `ui` namespace and a new set of attribute processors for available components:
29 |
30 | **Alert**
31 |
32 | Template:
33 | ```html
34 |
35 | ```
36 | Output:
37 | ```html
38 |
39 | Alert message
40 |
41 | ×
42 |
43 |
44 | ```
45 |
46 | **Badge**
47 |
48 | Template:
49 | ```html
50 |
51 | ```
52 | Output:
53 | ```html
54 | value
55 | ```
56 | Template:
57 | ```html
58 |
59 | ```
60 | Output:
61 | ```html
62 | value
63 | ```
64 |
65 | **Breadcrumb**
66 |
67 | Template:
68 | ```html
69 |
70 | ```
71 | Output:
72 | ```html
73 |
74 |
75 |
76 | Home
77 |
78 |
79 | Current page
80 |
81 |
82 |
83 | ```
84 |
85 | **Button**
86 |
87 | Template:
88 | ```html
89 |
90 | ```
91 | Output:
92 | ```html
93 |
94 | ```
95 |
96 | **Card**
97 |
98 | Template:
99 | ```html
100 |
101 | ```
102 | Output:
103 | ```html
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | ```
112 |
113 | **Carousel**
114 |
115 | Template:
116 | ```html
117 |
118 | ```
119 | Output:
120 | ```html
121 |
144 | ```
145 |
146 | **Dropdown**
147 |
148 | Template:
149 | ```html
150 |
151 | ```
152 | Output:
153 | ```html
154 |
155 | Toggle
156 |
162 |
163 | ```
164 |
165 | **Figure**
166 |
167 | Template:
168 | ```html
169 |
170 | ```
171 | Output:
172 | ```html
173 |
174 |
175 | Caption text
176 |
177 | ```
178 |
179 | **Navigation**
180 |
181 | Template:
182 | ```html
183 |
184 | ```
185 | Output:
186 | ```html
187 |
188 |
189 | Text
190 |
191 |
192 | Text
193 |
194 |
195 | ```
196 |
197 | **Navigation header**
198 |
199 | Template:
200 | ```html
201 |
202 | ```
203 | Output:
204 | ```html
205 |
206 | Text
207 |
208 |
209 |
210 |
211 |
212 |
213 | Text
214 |
215 |
216 |
217 |
218 | ```
219 |
220 | Example with Java code:
221 | ```Java
222 | import static io.github.thymeleaf.ui.Components.*;
223 | ...
224 | @ControllerAdvice
225 | public class UiControllerAdvice {
226 |
227 | @ModelAttribute
228 | public NavigationHeader addNavigationHeader() {
229 | NavigationHeader header = navigationHeader("#", "navheader", link("#", "text"));
230 | Dropdown dropdown = dropdown("toggle", "t1");
231 | dropdown.add(link("#", "text"));
232 | dropdown.add(link("#", "text"));
233 | dropdown.divider();
234 | dropdown.add(link("#", "text"));
235 | header.add(dropdown);
236 |
237 | return header;
238 | }
239 | }
240 | ```
241 | Template:
242 | ```html
243 |
244 | ```
245 | Output:
246 | ```html
247 |
248 | Text
249 |
250 |
251 |
252 |
253 |
254 |
255 | Text
256 |
257 |
258 | Toogle
259 |
265 |
266 |
267 | Text
268 |
269 |
270 |
271 |
272 | ```
273 |
274 | **Sidebar**
275 |
276 | Template:
277 | ```html
278 |
279 | ```
280 | Output:
281 | ```html
282 |
293 | ```
294 |
295 | Exmple with Java code:
296 | ```Java
297 | import static io.github.thymeleaf.ui.Components.*;
298 | ...
299 | @ControllerAdvice
300 | public class UiControllerAdvice {
301 |
302 | @ModelAttribute
303 | public Sidebar addSidebar() {
304 | Sidebar sidebar = sidebar("Header", link("#", "text"), link("#", "text"));
305 | sidebar.add(submenu("Menu", link("#", "text"), link("#", "text")));
306 |
307 | return sidebar;
308 | }
309 | }
310 | ```
311 | Template
312 | ```html
313 |
314 | ```
315 | Output:
316 | ```html
317 |
339 | ```
340 |
341 |
342 | Create UI components in Java
343 | --------
344 |
345 | Spring MVC @Controller:
346 |
347 | ```java
348 | import static io.github.thymeleaf.ui.Components.*;
349 | ...
350 |
351 | @GetMapping("/index")
352 | public String index(ModelMap model){
353 |
354 | // Alert
355 | model.addAttribute("alert", alert("This is an alert"));
356 |
357 | //Badge
358 | model.addAttribute("badge", badge("4"));
359 | model.addAttribute("badge2", badge("5"));
360 |
361 | //Breadcrumb
362 | Breadcrumb breadcrumb = breadcrumb(location("/", "home"), location("/", "admin"), location("current-page"));
363 | model.addAttribute(breadcrumb);
364 |
365 | //Card
366 | Card card = card("http://[image-location]", "Image alt");
367 | card.setHeader("Card header");
368 | card.setTitle("Card title");
369 | card.setText("Some quick example text");
370 | card.addLink("#", "Launch");
371 | model.addAttribute(card);
372 |
373 | //Carousel
374 | Carousel carousel = carousel("demoCarousel", slide("http://[img-location]"), slide("http://img-location"));
375 | carousel.setShowControls(true);
376 | carousel.setShowIndicators(true);
377 | model.addAttribute(carousel);
378 |
379 | //Dropdown
380 | Dropdown dropdown = dropdown("Toggle");
381 | dropdown.add(link("#", "First Link"));
382 | dropdown.setHeader("My header");
383 | model.addAttribute(dropdown);
384 |
385 | return "index";
386 | }
387 | ```
388 |
389 | Application html template:
390 |
391 | ```html
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 | ```
405 |
406 | Note: the ui:render
tag is able to render any Renderable object. Using ui:render="${alert}"
produces the same output as ui:alert="${alert}"
407 |
408 |
409 |
410 |
411 | Themes
412 | --------
413 |
414 | Any component has an html template with some Thymeleaf logic, these templates are located under `templates/ui/themes/[theme]/[class-name]-component.html`.
415 |
416 | The default theme is `default` based on Bootstrap 4.
417 |
418 |
419 | Custom components
420 | -------
421 |
422 | Define your custom components just extending `io.github.thymeleaf.ui.Component` and create the html template, an example of a new component:
423 |
424 | ```java
425 | public class CustomComponent extends Component {
426 | private final String message;
427 |
428 | public CustomComponent(String message) {
429 | this.message = message;
430 | }
431 |
432 | public String getMessage() {
433 | return message;
434 | }
435 | }
436 | ```
437 |
438 | Template file for this component `src/main/resources/templates/ui/themes/[theme]/custom-component-component.html`:
439 | ```html
440 |
441 |
442 |
443 | ```
444 |
445 | Spring MVC @Controller
446 |
447 | ```java
448 | @GetMapping("/index")
449 | public String index(ModelMap model) {
450 | model.addAttribute(new CustomComponent("Hello world!"));
451 |
452 | return "index";
453 | }
454 | ```
455 |
456 | Application html template:
457 |
458 | ```html
459 |
460 |
461 |
462 |
463 |
464 |
465 | ```
466 |
--------------------------------------------------------------------------------
/doc/components.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpenren/thymeleaf-ui-dialect/10edac115bcf21b754975f729c955f43044ed7a8/doc/components.jpg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 | io.github.jpenren
6 | thymeleaf-ui-dialect
7 | 1.1.0
8 |
9 | Thymeleaf UI Dialect
10 | Thymeleaf dialect for reusable interface components
11 | https://github.com/jpenren/thymeleaf-ui-dialect
12 | 2019
13 |
14 |
15 |
16 | Apache License, Version 2.0
17 | https://www.apache.org/licenses/LICENSE-2.0.txt
18 |
19 |
20 |
21 |
22 |
23 | Javier Pena
24 | javiprendo@gmail.com
25 | https://github.com/jpenren
26 |
27 |
28 |
29 |
30 | scm:git:git://github.com/jpenren/thymeleaf-ui-dialect.git
31 | scm:git:git@github.com:jpenren/thymeleaf-ui-dialect.git
32 | git@github.com:jpenren/thymeleaf-ui-dialect.git
33 |
34 |
35 |
36 | UTF-8
37 | UTF-8
38 | 1.7
39 | 1.7
40 |
41 |
42 |
43 |
44 |
45 | org.apache.maven.plugins
46 | maven-source-plugin
47 | 3.0.1
48 |
49 |
50 | attach-sources
51 |
52 | jar
53 |
54 |
55 |
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-javadoc-plugin
60 | 3.0.1
61 |
62 |
63 | attach-javadocs
64 |
65 | jar
66 |
67 |
68 |
69 |
70 |
71 | org.apache.maven.plugins
72 | maven-gpg-plugin
73 | 1.6
74 |
75 |
76 | sign-artifacts
77 | verify
78 |
79 | sign
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | org.springframework
90 | spring-context
91 | 4.0.0.RELEASE
92 |
93 |
94 |
95 | org.thymeleaf
96 | thymeleaf
97 | 3.0.0.RELEASE
98 |
99 |
100 |
101 | org.slf4j
102 | slf4j-api
103 | 1.7.25
104 |
105 |
106 |
107 | org.projectlombok
108 | lombok
109 | 1.18.4
110 | provided
111 | true
112 |
113 |
114 |
115 | javax.servlet
116 | javax.servlet-api
117 | 3.0.1
118 | provided
119 |
120 |
121 |
122 | junit
123 | junit
124 | 4.12
125 | test
126 |
127 |
128 | org.slf4j
129 | slf4j-simple
130 | 1.7.25
131 | test
132 |
133 |
134 | org.thymeleaf
135 | thymeleaf-spring4
136 | 3.0.0.RELEASE
137 | test
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/Attrs.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | public final class Attrs {
20 |
21 | public static final String ID = "id";
22 | public static final String CLASS ="class";
23 |
24 | private Attrs() {
25 | // utilities
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/Component.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | import io.github.thymeleaf.ui.internal.Strings;
20 | import lombok.Getter;
21 | import lombok.Setter;
22 |
23 | /**
24 | * Any HTML element with template
25 | */
26 | @Getter
27 | @Setter
28 | public abstract class Component extends Element implements Renderable {
29 | private static final String SUFFIX = "-component";
30 | private String template = defaultTemplate();
31 |
32 | // Default template name: ClassName to dash + '-component'
33 | private String defaultTemplate() {
34 | final String simpleName = getClass().getSimpleName();
35 | final boolean isAnonimous = Strings.isEmpty(simpleName);
36 | final String className = isAnonimous ? getClass().getSuperclass().getSimpleName() : simpleName;
37 |
38 | return Strings.dash(className) + SUFFIX;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/Components.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | import io.github.thymeleaf.ui.components.Alert;
20 | import io.github.thymeleaf.ui.components.Badge;
21 | import io.github.thymeleaf.ui.components.Breadcrumb;
22 | import io.github.thymeleaf.ui.components.Button;
23 | import io.github.thymeleaf.ui.components.ButtonGroup;
24 | import io.github.thymeleaf.ui.components.Card;
25 | import io.github.thymeleaf.ui.components.Carousel;
26 | import io.github.thymeleaf.ui.components.Dropdown;
27 | import io.github.thymeleaf.ui.components.Figure;
28 | import io.github.thymeleaf.ui.components.Navigation;
29 | import io.github.thymeleaf.ui.components.NavigationHeader;
30 | import io.github.thymeleaf.ui.components.Sidebar;
31 | import io.github.thymeleaf.ui.components.Breadcrumb.Location;
32 | import io.github.thymeleaf.ui.components.Carousel.Slide;
33 | import io.github.thymeleaf.ui.components.Dropdown.Toggle;
34 | import io.github.thymeleaf.ui.components.Sidebar.Submenu;
35 | import io.github.thymeleaf.ui.elements.Image;
36 | import io.github.thymeleaf.ui.elements.Link;
37 | import io.github.thymeleaf.ui.internal.Strings;
38 |
39 | /**
40 | * A set of methods useful for create components. These methods can be used directly:
41 | * Components.alert(...)
, however, they read better if they
42 | * are referenced through static import:
43 | *
44 | *
45 | * import static io.github.thymeleaf.ui.Components.*;
46 | * ...
47 | * alert(...);
48 | *
49 | *
50 | * @author jpenren
51 | *
52 | */
53 | public final class Components {
54 |
55 | private Components() {
56 | // Utility
57 | }
58 |
59 | public static Alert alert(String message) {
60 | return new Alert(message);
61 | }
62 |
63 | public static Alert alertDismissible(String message) {
64 | Alert alert = new Alert(message);
65 | alert.setDismissible(true);
66 | return alert;
67 | }
68 |
69 | public static Badge badge(String text) {
70 | return new Badge(text);
71 | }
72 |
73 | public static Badge badge(String href, String text) {
74 | Badge badge = new Badge(text);
75 | badge.setHref(href);
76 | return badge;
77 | }
78 |
79 | public static Breadcrumb breadcrumb() {
80 | return new Breadcrumb();
81 | }
82 |
83 | public static Breadcrumb breadcrumb(Location... locations) {
84 | Breadcrumb breadcrumb = new Breadcrumb();
85 | breadcrumb.add(locations);
86 | return breadcrumb;
87 | }
88 |
89 | public static Location location(String text) {
90 | return new Location(text);
91 | }
92 |
93 | public static Location location(String href, String text) {
94 | return new Location(href, text);
95 | }
96 |
97 | public static Button button(String text) {
98 | return new Button(text);
99 | }
100 |
101 | public static Button button(String text, String type) {
102 | Button button = new Button(text);
103 | button.setType(type);
104 | return button;
105 | }
106 |
107 | public static Button buttonToggle(String text) {
108 | Button button = new Button(text);
109 | button.setToggle(true);
110 | return button;
111 | }
112 |
113 | public static Button buttonLink(String href, String text) {
114 | Button button = new Button(text);
115 | button.setHref(href);
116 | return button;
117 | }
118 |
119 | public static ButtonGroup buttonGroup() {
120 | return new ButtonGroup();
121 | }
122 |
123 | public static ButtonGroup buttonGroup(String label) {
124 | ButtonGroup buttonGroup = new ButtonGroup();
125 | buttonGroup.setLabel(label);
126 | return buttonGroup;
127 | }
128 |
129 | public static ButtonGroup buttonGroup(Button ... buttons) {
130 | return buttonGroup(Strings.EMPTY, buttons);
131 | }
132 |
133 | public static ButtonGroup buttonGroup(String label, Button ... buttons) {
134 | ButtonGroup buttonGroup = new ButtonGroup();
135 | buttonGroup.setLabel(label);
136 | buttonGroup.add(buttons);
137 | return buttonGroup;
138 | }
139 |
140 | public static Card card() {
141 | return new Card();
142 | }
143 |
144 | public static Card card(String src) {
145 | return card(src, null);
146 | }
147 |
148 | public static Card card(String src, String alt) {
149 | return new Card(image(src, alt));
150 | }
151 |
152 | public static Carousel carousel() {
153 | return new Carousel();
154 | }
155 |
156 | public static Carousel carousel(String id) {
157 | Carousel carousel = new Carousel();
158 | carousel.setId(id);
159 | return carousel;
160 | }
161 |
162 | public static Carousel carousel(Slide ... slides) {
163 | return carousel(null, slides);
164 | }
165 |
166 | public static Carousel carousel(String id, Slide ... slides) {
167 | Carousel carousel = new Carousel();
168 | carousel.setId(id);
169 | for (Slide slide : slides) {
170 | carousel.add(slide);
171 | }
172 |
173 | return carousel;
174 | }
175 |
176 | public static Slide slide(String src) {
177 | return new Slide(new Image(src));
178 | }
179 |
180 | public static Slide slide(String src, String caption) {
181 | Slide slide = new Slide(new Image(src));
182 | slide.setCaption(caption);
183 | return slide;
184 | }
185 |
186 | public static Dropdown dropdown(String text) {
187 | return dropdown(text, null);
188 | }
189 |
190 | public static Dropdown dropdown(String text, String toggleId) {
191 | Toggle toggle = new Toggle(text);
192 | toggle.setId(toggleId);
193 | return new Dropdown(toggle);
194 | }
195 |
196 | public static Figure figure(Image image) {
197 | return new Figure(image);
198 | }
199 |
200 | public static Figure figure(String src) {
201 | return new Figure(image(src));
202 | }
203 |
204 | public static Figure figure(String src, String alt) {
205 | return new Figure(image(src, alt));
206 | }
207 |
208 | public static Figure figure(String src, String alt, String title) {
209 | return new Figure(image(src, alt, title));
210 | }
211 |
212 | public static Navigation navigation() {
213 | return new Navigation();
214 | }
215 |
216 | public static Navigation navigation(Link...links) {
217 | Navigation navigation = new Navigation();
218 | navigation.add(links);
219 | return navigation;
220 | }
221 |
222 | public static NavigationHeader navigationHeader() {
223 | return new NavigationHeader();
224 | }
225 |
226 | public static NavigationHeader navigationHeader(String href, String text) {
227 | return navigationHeader(href, text, new Link[0]);
228 | }
229 |
230 | public static NavigationHeader navigationHeader(Link... links) {
231 | NavigationHeader header = new NavigationHeader();
232 | header.add(links);
233 | return header;
234 | }
235 |
236 | public static NavigationHeader navigationHeader(String href, String text, Link...links) {
237 | NavigationHeader navigationHeader = new NavigationHeader();
238 | navigationHeader.setBrand(link(href, text));
239 | if( links!=null ) {
240 | navigationHeader.add(links);
241 | }
242 |
243 | return navigationHeader;
244 | }
245 |
246 | public static Sidebar sidebar() {
247 | return new Sidebar();
248 | }
249 |
250 | public static Sidebar sidebar(String header) {
251 | return sidebar(header, new Link[0]);
252 | }
253 |
254 | public static Sidebar sidebar(Link... links) {
255 | return sidebar(null, links);
256 | }
257 |
258 | public static Sidebar sidebar(String header, Link... links) {
259 | Sidebar sidebar = sidebar();
260 | sidebar.setHeader(header);
261 | if(links!=null) {
262 | sidebar.add(links);
263 | }
264 |
265 | return sidebar;
266 | }
267 |
268 | public static Submenu submenu(String text, Link... links) {
269 | return submenu(text, "menu_"+System.currentTimeMillis(), null, links);
270 | }
271 |
272 | public static Submenu submenu(String text, String id, Link... links) {
273 | return submenu(text, id, null, links);
274 | }
275 |
276 | public static Submenu submenu(String text, String id, String className, Link... links) {
277 | Submenu submenu = new Submenu(text, id, links);
278 | submenu.setClassName(className);
279 | return submenu;
280 | }
281 |
282 | public static Link link(String href, String text) {
283 | return new Link(href, text);
284 | }
285 |
286 | public static Link link(String href, String text, String title) {
287 | Link link = new Link(href, text);
288 | link.setTitle(title);
289 | return link;
290 | }
291 |
292 | public static Link link(String href, String text, String title, String target) {
293 | return link(href, text, title, target, null);
294 | }
295 |
296 | public static Link link(String href, String text, String title, String target, String rel) {
297 | Link link = new Link(href, text);
298 | link.setTitle(title);
299 | link.setTarget(target);
300 | link.setRel(rel);
301 | return link;
302 | }
303 |
304 | public static Image image(String src) {
305 | return new Image(src);
306 | }
307 |
308 | public static Image image(String src, String alt) {
309 | return new Image(src, alt, null);
310 | }
311 |
312 | public static Image image(String src, String alt, String title) {
313 | return new Image(src, alt, title);
314 | }
315 |
316 | }
317 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/Element.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | import io.github.thymeleaf.ui.internal.Strings;
22 | import lombok.Getter;
23 | import lombok.Setter;
24 |
25 | /**
26 | * Base HTML element
27 | */
28 | @Setter
29 | public abstract class Element implements HasHtmlAttributes, HasStatus {
30 | private @Getter String id;
31 | private @Getter String className; // html class attribute
32 | private boolean active;
33 | private boolean disabled;
34 | private boolean visible = true;
35 |
36 | public String getName() {
37 | final String simpleName = getClass().getSimpleName();
38 | return Strings.isNotEmpty(simpleName) ? simpleName : getClass().getSuperclass().getSimpleName();
39 | }
40 |
41 | @Override
42 | public boolean isActive(HttpServletRequest request) {
43 | return active;
44 | }
45 |
46 | @Override
47 | public boolean isDisabled(HttpServletRequest request) {
48 | return disabled;
49 | }
50 |
51 | @Override
52 | public boolean isVisible(HttpServletRequest request) {
53 | return visible;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/HasHtmlAttributes.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | /**
20 | * Elements that can handle id attribute
21 | */
22 | public interface HasHtmlAttributes {
23 |
24 | String getId();
25 |
26 | void setId(String id);
27 |
28 | String getClassName();
29 |
30 | void setClassName(String className);
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/HasStatus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | public interface HasStatus {
22 |
23 | boolean isActive(HttpServletRequest request);
24 |
25 | boolean isDisabled(HttpServletRequest request);
26 |
27 | boolean isVisible(HttpServletRequest request);
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/Renderable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | public interface Renderable {
20 |
21 | String getTemplate();
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Alert.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import io.github.thymeleaf.ui.Component;
20 | import lombok.Getter;
21 | import lombok.NoArgsConstructor;
22 | import lombok.Setter;
23 |
24 | @Getter
25 | @Setter
26 | @NoArgsConstructor
27 | public class Alert extends Component {
28 | private String message;
29 | private boolean dismissible;
30 |
31 | public Alert(String message) {
32 | this.message = message;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Badge.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | import io.github.thymeleaf.ui.Component;
22 | import io.github.thymeleaf.ui.internal.Strings;
23 | import io.github.thymeleaf.ui.internal.Urls;
24 | import lombok.Getter;
25 | import lombok.NoArgsConstructor;
26 | import lombok.Setter;
27 |
28 | @Setter
29 | @NoArgsConstructor
30 | public class Badge extends Component {
31 | private @Getter String text;
32 | private String href;
33 |
34 | public Badge(String text) {
35 | this.text = text;
36 | }
37 |
38 | public String getHref(HttpServletRequest request) {
39 | return Urls.resolve(href, request);
40 | }
41 |
42 | public boolean hasLink() {
43 | return Strings.isNotEmpty(href);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Breadcrumb.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.List;
22 |
23 | import javax.servlet.http.HttpServletRequest;
24 |
25 | import io.github.thymeleaf.ui.Component;
26 | import io.github.thymeleaf.ui.Element;
27 | import io.github.thymeleaf.ui.internal.Checks;
28 | import io.github.thymeleaf.ui.internal.Strings;
29 | import io.github.thymeleaf.ui.internal.Urls;
30 | import lombok.Getter;
31 | import lombok.RequiredArgsConstructor;
32 |
33 | public class Breadcrumb extends Component {
34 | private final List locations = new ArrayList<>();
35 |
36 | public void add(Location... locations) {
37 | Checks.checkNotNullArgument(locations);
38 | for (Location location : locations) {
39 | this.locations.add(location);
40 | }
41 | }
42 |
43 | public void setLocations(List locations) {
44 | this.locations.addAll(locations);
45 | }
46 |
47 | public List getLocations() {
48 | return Collections.unmodifiableList(locations);
49 | }
50 |
51 | @RequiredArgsConstructor
52 | public static class Location extends Element {
53 | private final String href;
54 | private final @Getter String text;
55 |
56 | public Location(String text) {
57 | this.href = Strings.EMPTY;
58 | this.text = text;
59 | }
60 |
61 | public boolean hasLink() {
62 | return Strings.isNotEmpty(href);
63 | }
64 |
65 | public String getHref(HttpServletRequest request) {
66 | return Urls.resolve(href, request);
67 | }
68 |
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Button.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | import io.github.thymeleaf.ui.Component;
22 | import io.github.thymeleaf.ui.internal.Strings;
23 | import io.github.thymeleaf.ui.internal.Urls;
24 | import lombok.Getter;
25 | import lombok.NoArgsConstructor;
26 | import lombok.Setter;
27 |
28 | @Setter
29 | @NoArgsConstructor
30 | public class Button extends Component {
31 | public static final String DEFAULT_TYPE = "button";
32 | private @Getter String text;
33 | private @Getter String type = DEFAULT_TYPE; // button, input, reset
34 | private @Getter boolean toggle;
35 | private String href;
36 |
37 | public Button(String text) {
38 | this.text = text;
39 | }
40 |
41 | public String getHref(HttpServletRequest request) {
42 | return Urls.resolve(href, request);
43 | }
44 |
45 | public boolean hasLink() {
46 | return Strings.isNotEmpty(href);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/ButtonGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.List;
22 |
23 | import io.github.thymeleaf.ui.Component;
24 | import io.github.thymeleaf.ui.internal.Checks;
25 | import lombok.Getter;
26 | import lombok.Setter;
27 |
28 | @Getter
29 | @Setter
30 | public class ButtonGroup extends Component {
31 | private final List buttons = new ArrayList<>();
32 | private String label;
33 |
34 | public void add(Button...buttons) {
35 | Checks.checkNotNullArgument(buttons);
36 | for (Button button : buttons) {
37 | this.buttons.add(button);
38 | }
39 | }
40 |
41 | public List getButtons(){
42 | return Collections.unmodifiableList(buttons);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Card.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | import io.github.thymeleaf.ui.Component;
23 | import io.github.thymeleaf.ui.elements.Image;
24 | import io.github.thymeleaf.ui.elements.Link;
25 | import lombok.Getter;
26 | import lombok.NoArgsConstructor;
27 | import lombok.Setter;
28 |
29 | @Getter
30 | @Setter
31 | @NoArgsConstructor
32 | public class Card extends Component {
33 | private final List links = new ArrayList<>();
34 | private Image image;
35 | private String header;
36 | private String title;
37 | private String subtitle;
38 | private String text;
39 | private String footer;
40 |
41 | public Card(Image image) {
42 | this.image = image;
43 | }
44 |
45 | public void addLink(String href, String text) {
46 | add(new Link(href, text));
47 | }
48 |
49 | public void add(Link link) {
50 | links.add(link);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Carousel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.List;
22 |
23 | import io.github.thymeleaf.ui.Component;
24 | import io.github.thymeleaf.ui.Element;
25 | import io.github.thymeleaf.ui.elements.Image;
26 | import io.github.thymeleaf.ui.internal.Strings;
27 | import lombok.Data;
28 | import lombok.EqualsAndHashCode;
29 | import lombok.Getter;
30 | import lombok.RequiredArgsConstructor;
31 | import lombok.Setter;
32 |
33 | @Getter
34 | @Setter
35 | @RequiredArgsConstructor
36 | public class Carousel extends Component {
37 | private final List slides = new ArrayList<>();
38 | private boolean showIndicators;
39 | private boolean showControls;
40 |
41 | public void add(Slide slide) {
42 | slides.add(slide);
43 | }
44 |
45 | public void setSlides(List slides) {
46 | this.slides.addAll(slides);
47 | }
48 |
49 | public List getSlides() {
50 | return Collections.unmodifiableList(slides);
51 | }
52 |
53 | @Data
54 | @EqualsAndHashCode(callSuper=false)
55 | public static class Slide extends Element {
56 | private final Image image;
57 | private String caption;
58 |
59 | public boolean hasCaption() {
60 | return Strings.isNotEmpty(caption);
61 | }
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Dropdown.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | import io.github.thymeleaf.ui.Component;
23 | import io.github.thymeleaf.ui.Element;
24 | import io.github.thymeleaf.ui.elements.Link;
25 | import lombok.Getter;
26 | import lombok.RequiredArgsConstructor;
27 | import lombok.Setter;
28 |
29 | @Getter
30 | @Setter
31 | @RequiredArgsConstructor
32 | public class Dropdown extends Component {
33 |
34 | public enum Direction {
35 | DROPUP, DROPRIGHT, DROPLEFT, DROPDOWN;
36 | }
37 |
38 | private final ElementCollection items = new ElementCollection();
39 | private final Toggle toggle;
40 | private Direction direction = Direction.DROPDOWN;
41 | private Header header;
42 |
43 | public void setHeader(String header) {
44 | this.header = new Header(header);
45 | }
46 |
47 | public void setDirection(String direction) {
48 | this.direction = Direction.valueOf(direction.toUpperCase());
49 | }
50 |
51 | public void add(Link ... links) {
52 | this.items.addAll(links);
53 | }
54 |
55 | public void setItems(List items) {
56 | this.items.addAll(items);
57 | }
58 |
59 | public void add(int index, Link ... links) {
60 | this.items.addAll(index, links);
61 | }
62 |
63 | public void divider() {
64 | items.add(Divider.INSTANCE);
65 | }
66 |
67 | public List getItems() {
68 | return Collections.unmodifiableList(items);
69 | }
70 |
71 | @Getter
72 | @RequiredArgsConstructor
73 | public static class Toggle extends Element {
74 | private final String text;
75 |
76 | public static Toggle toggle(String text) {
77 | return new Toggle(text);
78 | }
79 |
80 | public static Toggle toggle(String text, String id) {
81 | return toggle(text, id, null);
82 | }
83 |
84 | public static Toggle toggle(String text, String id, String className) {
85 | Toggle toggle = new Toggle(text);
86 | toggle.setId(id);
87 | toggle.setClassName(className);
88 | return toggle;
89 | }
90 | }
91 |
92 | @Getter
93 | @RequiredArgsConstructor
94 | public static class Header extends Element {
95 | private final String text;
96 |
97 | public static Header with(String text) {
98 | return new Header(text);
99 | }
100 | }
101 |
102 | public static class Divider extends Element {
103 | public static final Divider INSTANCE = new Divider();
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/ElementCollection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collection;
21 |
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 |
25 | import io.github.thymeleaf.ui.Element;
26 | import io.github.thymeleaf.ui.internal.Checks;
27 |
28 | class ElementCollection extends ArrayList implements Collection {
29 | private static final Logger LOGGER = LoggerFactory.getLogger(ElementCollection.class);
30 | private static final long serialVersionUID = 1L;
31 |
32 | public void addAll(Element ... elements) {
33 | Checks.checkNotNullArgument(elements);
34 | for (Element element : elements) {
35 | add(element);
36 | }
37 | }
38 |
39 | public void addAll(int index, Element ... elements) {
40 | Checks.checkNotNullArgument(elements);
41 | //prevent out of bounds
42 | if(index<0||index>size()) {
43 | LOGGER.warn("Array index out of bounds [index:{}, size:{}]", index, size());
44 | addAll(elements);
45 | }
46 |
47 | for (Element element : elements) {
48 | add(index, element);
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Figure.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import io.github.thymeleaf.ui.Component;
20 | import io.github.thymeleaf.ui.elements.Image;
21 | import io.github.thymeleaf.ui.internal.Strings;
22 | import lombok.Getter;
23 | import lombok.NoArgsConstructor;
24 | import lombok.Setter;
25 |
26 | @Getter
27 | @Setter
28 | @NoArgsConstructor
29 | public class Figure extends Component {
30 | private Image image;
31 | private String caption;
32 |
33 | public Figure(Image image) {
34 | this.image = image;
35 | }
36 |
37 | public boolean hasCaption() {
38 | return Strings.isNotEmpty(caption);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Nav.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | import io.github.thymeleaf.ui.Component;
23 | import io.github.thymeleaf.ui.Element;
24 | import io.github.thymeleaf.ui.elements.Link;
25 |
26 | abstract class Nav extends Component {
27 | private final ElementCollection items = new ElementCollection();
28 |
29 | public void setItems(List items) {
30 | this.items.addAll(items);
31 | }
32 |
33 | public void add(Link ... links) {
34 | items.addAll(links);
35 | }
36 |
37 | public void add(int index, Link ... links) {
38 | items.addAll(index, links);
39 | }
40 |
41 | public void add(Dropdown dropdown) {
42 | items.add(dropdown);
43 | }
44 |
45 | public void add(int index, Dropdown dropdown) {
46 | items.add(index, dropdown);
47 | }
48 |
49 | public List getItems() {
50 | return Collections.unmodifiableList(items);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Navigation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | public class Navigation extends Nav {
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/NavigationHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import io.github.thymeleaf.ui.elements.Link;
20 | import lombok.Getter;
21 | import lombok.Setter;
22 |
23 | @Getter
24 | @Setter
25 | public class NavigationHeader extends Nav {
26 | private Link brand;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/components/Sidebar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.components;
18 |
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 |
24 | import io.github.thymeleaf.ui.Component;
25 | import io.github.thymeleaf.ui.Element;
26 | import io.github.thymeleaf.ui.elements.Link;
27 | import lombok.Getter;
28 | import lombok.RequiredArgsConstructor;
29 | import lombok.Setter;
30 |
31 | @Getter
32 | @Setter
33 | public class Sidebar extends Component {
34 | private final ElementCollection items = new ElementCollection();
35 | private String header;
36 |
37 | public void setItems(List items) {
38 | this.items.addAll(items);
39 | }
40 |
41 | public void add(Link... links) {
42 | items.addAll(links);
43 | }
44 |
45 | public void add(int index, Link... links) {
46 | items.addAll(index, links);
47 | }
48 |
49 | public void add(Submenu... submenus) {
50 | items.addAll(submenus);
51 | }
52 |
53 | public void add(int index, Submenu... submenus) {
54 | items.addAll(index, submenus);
55 | }
56 |
57 | public List getItems() {
58 | return Collections.unmodifiableList(items);
59 | }
60 |
61 | @RequiredArgsConstructor
62 | public static class Submenu extends Element {
63 | private final ElementCollection items = new ElementCollection();
64 | private final @Getter String text;
65 |
66 | public Submenu(String text, String id) {
67 | this(text);
68 | this.setId(id);
69 | }
70 |
71 | public Submenu(String text, String id, Link ...links) {
72 | this(text, id);
73 | this.add(links);
74 | }
75 |
76 | public Submenu add(Link... links) {
77 | items.addAll(links);
78 | return this;
79 | }
80 |
81 | public Submenu add(int index, Link... links) {
82 | items.addAll(index, links);
83 | return this;
84 | }
85 |
86 | public List getItems() {
87 | return Collections.unmodifiableList(items);
88 | }
89 |
90 | public boolean isExpanded(HttpServletRequest request) {
91 | return false;
92 | }
93 |
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/ComponentTemplateResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect;
18 |
19 | import java.util.Collections;
20 |
21 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
22 |
23 | final class ComponentTemplateResolver extends ClassLoaderTemplateResolver {
24 |
25 | public ComponentTemplateResolver(String theme) {
26 | setPrefix("/templates/ui/themes/"+theme+"/");
27 | setSuffix(".html");
28 |
29 | // Template name must match '[template-name]-component'
30 | setResolvablePatterns(Collections.singleton("*-component"));
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/IsThemeConfigured.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect;
18 |
19 | import org.springframework.context.annotation.Condition;
20 | import org.springframework.context.annotation.ConditionContext;
21 | import org.springframework.core.type.AnnotatedTypeMetadata;
22 |
23 | public class IsThemeConfigured implements Condition {
24 |
25 | @Override
26 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
27 | return context.getEnvironment().getProperty("thymeleaf.ui.theme") != null;
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/UiDialect.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect;
18 |
19 | import java.util.HashSet;
20 | import java.util.Set;
21 |
22 | import org.thymeleaf.dialect.AbstractProcessorDialect;
23 | import org.thymeleaf.dialect.IExpressionObjectDialect;
24 | import org.thymeleaf.expression.IExpressionObjectFactory;
25 | import org.thymeleaf.processor.IProcessor;
26 | import org.thymeleaf.standard.processor.StandardXmlNsTagProcessor;
27 | import org.thymeleaf.templatemode.TemplateMode;
28 |
29 | import io.github.thymeleaf.ui.dialect.tags.AlertAttributeTagProcessor;
30 | import io.github.thymeleaf.ui.dialect.tags.BadgeAttributeTagProcessor;
31 | import io.github.thymeleaf.ui.dialect.tags.BreadcrumbAttributeTagProcessor;
32 | import io.github.thymeleaf.ui.dialect.tags.ButtonAttributeTagProcessor;
33 | import io.github.thymeleaf.ui.dialect.tags.ButtonGroupAttributeTagProcessor;
34 | import io.github.thymeleaf.ui.dialect.tags.CardAttributeTagProcessor;
35 | import io.github.thymeleaf.ui.dialect.tags.CarouselAttributeTagProcessor;
36 | import io.github.thymeleaf.ui.dialect.tags.CopyTagAttributesTagProcessor;
37 | import io.github.thymeleaf.ui.dialect.tags.DropdownAttributeTagProcessor;
38 | import io.github.thymeleaf.ui.dialect.tags.FigureAttributeTagProcessor;
39 | import io.github.thymeleaf.ui.dialect.tags.NavigationAttributeTagProcessor;
40 | import io.github.thymeleaf.ui.dialect.tags.NavigationHeaderAttributeTagProcessor;
41 | import io.github.thymeleaf.ui.dialect.tags.RenderAttributeTagProcessor;
42 | import io.github.thymeleaf.ui.dialect.tags.SidebarAttributeTagProcessor;
43 |
44 | public final class UiDialect extends AbstractProcessorDialect implements IExpressionObjectDialect {
45 |
46 | private static final UiExpressionObjectFactory UI_FACTORY = new UiExpressionObjectFactory();
47 | private static final String PREFIX = "ui";
48 |
49 | public UiDialect() {
50 | super("User Interface Components Dialect", PREFIX, 1000);
51 | }
52 |
53 | public Set getProcessors(final String dialectPrefix) {
54 | final Set processors = new HashSet<>();
55 | processors.add(new StandardXmlNsTagProcessor(TemplateMode.HTML, PREFIX));
56 | processors.add(new CopyTagAttributesTagProcessor(dialectPrefix));
57 | processors.add(new RenderAttributeTagProcessor(dialectPrefix));
58 | processors.add(new AlertAttributeTagProcessor(dialectPrefix));
59 | processors.add(new BadgeAttributeTagProcessor(dialectPrefix));
60 | processors.add(new BreadcrumbAttributeTagProcessor(dialectPrefix));
61 | processors.add(new ButtonAttributeTagProcessor(dialectPrefix));
62 | processors.add(new ButtonGroupAttributeTagProcessor(dialectPrefix));
63 | processors.add(new CardAttributeTagProcessor(dialectPrefix));
64 | processors.add(new CarouselAttributeTagProcessor(dialectPrefix));
65 | processors.add(new DropdownAttributeTagProcessor(dialectPrefix));
66 | processors.add(new FigureAttributeTagProcessor(dialectPrefix));
67 | processors.add(new NavigationAttributeTagProcessor(dialectPrefix));
68 | processors.add(new NavigationHeaderAttributeTagProcessor(dialectPrefix));
69 | processors.add(new SidebarAttributeTagProcessor(dialectPrefix));
70 |
71 | return processors;
72 | }
73 |
74 | @Override
75 | public IExpressionObjectFactory getExpressionObjectFactory() {
76 | return UI_FACTORY;
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/UiDialectAutoconfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect;
18 |
19 | import org.springframework.beans.factory.annotation.Value;
20 | import org.springframework.context.annotation.Bean;
21 | import org.springframework.context.annotation.Conditional;
22 | import org.springframework.context.annotation.Configuration;
23 | import org.thymeleaf.templateresolver.ITemplateResolver;
24 |
25 | @Configuration
26 | public class UiDialectAutoconfiguration {
27 |
28 | @Value("${thymeleaf.ui.theme:}")
29 | private String theme;
30 | @Value("${spring.thymeleaf.cache:true}")
31 | private boolean cacheable;
32 |
33 | @Bean
34 | public UiDialect uiDialect() {
35 | return new UiDialect();
36 | }
37 |
38 | @Bean
39 | @Conditional(IsThemeConfigured.class)
40 | public ITemplateResolver componentTemplateResolver() {
41 | final ComponentTemplateResolver templateResolver = new ComponentTemplateResolver(theme);
42 | templateResolver.setOrder(Integer.MAX_VALUE-1); // allow override templates from default theme
43 | templateResolver.setCacheable(cacheable);
44 | templateResolver.setCheckExistence(true);
45 |
46 | return templateResolver;
47 | }
48 |
49 | @Bean
50 | public ITemplateResolver fallbackTemplateResolver() {
51 | final ComponentTemplateResolver templateResolver = new ComponentTemplateResolver("default");
52 | templateResolver.setOrder(Integer.MAX_VALUE);
53 | templateResolver.setCacheable(cacheable);
54 | templateResolver.setCheckExistence(true);
55 |
56 | return templateResolver;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/UiExpressionObjectFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect;
18 |
19 | import java.util.Collections;
20 | import java.util.Set;
21 |
22 | import org.thymeleaf.context.IExpressionContext;
23 | import org.thymeleaf.context.ITemplateContext;
24 | import org.thymeleaf.expression.IExpressionObjectFactory;
25 |
26 | import io.github.thymeleaf.ui.components.Breadcrumb.Location;
27 | import io.github.thymeleaf.ui.components.Carousel.Slide;
28 | import io.github.thymeleaf.ui.components.Dropdown.Divider;
29 | import io.github.thymeleaf.ui.components.Dropdown.Toggle;
30 | import io.github.thymeleaf.ui.elements.Image;
31 | import io.github.thymeleaf.ui.elements.Link;
32 | import io.github.thymeleaf.ui.internal.Strings;
33 |
34 | class UiExpressionObjectFactory implements IExpressionObjectFactory {
35 |
36 | @Override
37 | public Set getAllExpressionObjectNames() {
38 | return Collections.singleton("ui");
39 | }
40 |
41 | @Override
42 | public Object buildObject(IExpressionContext context, String expressionObjectName) {
43 | return new UiExpressions(context);
44 | }
45 |
46 | @Override
47 | public boolean isCacheable(String expressionObjectName) {
48 | return false;
49 | }
50 |
51 | public static final class UiExpressions {
52 | private final IExpressionContext context;
53 | public final Divider divider = Divider.INSTANCE;
54 |
55 | public UiExpressions(IExpressionContext context) {
56 | this.context = context;
57 | }
58 |
59 | public Image image(String src, String alt, String title) {
60 | return new Image(src, i18n(alt), i18n(title));
61 | }
62 |
63 | public Image image(String src, String alt) {
64 | return new Image(src, i18n(alt), Strings.EMPTY);
65 | }
66 |
67 | public Image image(String src) {
68 | return new Image(src, Strings.EMPTY, Strings.EMPTY);
69 | }
70 |
71 | public Link link(String href, String text) {
72 | return new Link(href, i18n(text));
73 | }
74 |
75 | public Slide slide(String src) {
76 | return new Slide(new Image(src));
77 | }
78 |
79 | public Slide slide(String src, String caption) {
80 | Slide slide = new Slide(new Image(src));
81 | slide.setCaption(i18n(caption));
82 | return slide;
83 | }
84 |
85 | public Location location(String href, String text) {
86 | return new Location(href, i18n(text));
87 | }
88 |
89 | public Location location(String text) {
90 | return new Location(i18n(text));
91 | }
92 |
93 | public Divider divider() {
94 | return Divider.INSTANCE;
95 | }
96 |
97 | public Toggle toggle(String text) {
98 | return toggle(text, null, null);
99 | }
100 |
101 | public Toggle toggle(String text, String id) {
102 | return toggle(text, id, null);
103 | }
104 |
105 | public Toggle toggle(String text, String id, String className) {
106 | return Toggle.toggle(i18n(text), id, className);
107 | }
108 |
109 | private String i18n(String str) {
110 | if(context instanceof ITemplateContext) {
111 | final ITemplateContext templateContext = (ITemplateContext)context;
112 | String msg = templateContext.getMessage(null, str, null, true);
113 | return msg==null ? str : msg;
114 | }
115 |
116 | return str;
117 | }
118 |
119 | }
120 |
121 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/AbstractTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import static io.github.thymeleaf.ui.dialect.tags.CopyTagAttributesTagProcessor.PARENT_ATTRIBUTES_VAR;
20 | import static org.thymeleaf.standard.expression.StandardExpressions.getExpressionParser;
21 |
22 | import java.io.StringWriter;
23 | import java.util.Collections;
24 | import java.util.regex.Pattern;
25 |
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 | import org.thymeleaf.TemplateSpec;
29 | import org.thymeleaf.context.IEngineContext;
30 | import org.thymeleaf.context.IExpressionContext;
31 | import org.thymeleaf.context.ITemplateContext;
32 | import org.thymeleaf.engine.AttributeName;
33 | import org.thymeleaf.engine.TemplateManager;
34 | import org.thymeleaf.model.IAttribute;
35 | import org.thymeleaf.model.IProcessableElementTag;
36 | import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
37 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
38 | import org.thymeleaf.standard.expression.IStandardExpression;
39 | import org.thymeleaf.standard.expression.IStandardExpressionParser;
40 | import org.thymeleaf.templatemode.TemplateMode;
41 |
42 | import io.github.thymeleaf.ui.Renderable;
43 | import io.github.thymeleaf.ui.internal.Reflection;
44 | import io.github.thymeleaf.ui.internal.Strings;
45 |
46 | abstract class AbstractTagProcessor extends AbstractAttributeTagProcessor {
47 |
48 | private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTagProcessor.class);
49 | private static final Pattern CLEANER = Pattern.compile("(?m)^[ \t]*\r?\n");
50 | private static final int PRECEDENCE = 10000;
51 |
52 | protected AbstractTagProcessor(String dialectPrefix, String attributeName) {
53 | super(TemplateMode.HTML, dialectPrefix, null, false, attributeName, true, PRECEDENCE, true);
54 | }
55 |
56 | protected Object evaluate(String attributeValue, IExpressionContext context) {
57 | final String value = String.valueOf(attributeValue);
58 | final IStandardExpressionParser expressionParser = getExpressionParser(context.getConfiguration());
59 | final IStandardExpression expression = expressionParser.parseExpression(context, value);
60 |
61 | return expression.execute(context);
62 | }
63 |
64 | protected void render(Renderable renderable, ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structureHandler, AttributeName attributeName) {
65 | // IEngineContext should not be used but
66 | // structureHandler.setSelectionTarget(target); do not process variable until
67 | // the next execution
68 | if (!(context instanceof IEngineContext)) {
69 | throw new IllegalStateException("IEngineContext expected at this point!");
70 | }
71 |
72 | // Available data on template
73 | final IEngineContext engineContext = (IEngineContext) context;
74 | engineContext.setVariable(PARENT_ATTRIBUTES_VAR, tag.getAllAttributes());
75 | final Object previousSelectionTarget = engineContext.getSelectionTarget();
76 | assignProperties(renderable, tag, engineContext, attributeName);
77 | engineContext.setSelectionTarget(renderable);
78 |
79 | // Process template
80 | final String template = renderable.getTemplate();
81 | final TemplateManager templateManager = context.getConfiguration().getTemplateManager();
82 | final TemplateSpec templateSpec = new TemplateSpec(template, Collections.emptyMap());
83 | final StringWriter writer = new StringWriter();
84 | templateManager.parseAndProcess(templateSpec, context, writer);
85 | final String content = writer.toString();
86 | final String adjusted = CLEANER.matcher(content).replaceAll(Strings.EMPTY);
87 |
88 | structureHandler.replaceWith(adjusted, false);
89 | engineContext.removeVariable(PARENT_ATTRIBUTES_VAR);
90 | engineContext.setSelectionTarget(previousSelectionTarget);
91 | }
92 |
93 | protected void assignProperties(Renderable renderable, IProcessableElementTag tag, ITemplateContext context, AttributeName skipAttribute) {
94 | final IAttribute[] allAttributes = tag.getAllAttributes();
95 | for (IAttribute attribute : allAttributes) {
96 | final AttributeName attr = attribute.getAttributeDefinition().getAttributeName();
97 | final boolean skip = attr.equals(skipAttribute);
98 | if(getDialectPrefix().equals(attr.getPrefix()) && !skip) {
99 | final Object value = evaluate(attribute.getValue(), context);
100 | try {
101 | Reflection.set(renderable, attr.getAttributeName(), value);
102 | } catch (Exception e) {
103 | LOGGER.error("Unable to set value", e);
104 | }
105 | }
106 | }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/AlertAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Alert;
25 | import io.github.thymeleaf.ui.internal.Strings;
26 |
27 | public class AlertAttributeTagProcessor extends AbstractTagProcessor {
28 |
29 | public AlertAttributeTagProcessor(String dialectPrefix) {
30 | super(dialectPrefix, "alert");
31 | }
32 |
33 | @Override
34 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
35 | String attributeValue, IElementTagStructureHandler structureHandler) {
36 | Object target = evaluate(attributeValue, context);
37 | boolean isAnAlert = target instanceof Alert;
38 | Alert alert = isAnAlert ? (Alert) target : new Alert(Strings.asString(target));
39 | render(alert, context, tag, structureHandler, attributeName);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/BadgeAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Badge;
25 | import io.github.thymeleaf.ui.internal.Strings;
26 |
27 | public class BadgeAttributeTagProcessor extends AbstractTagProcessor {
28 |
29 | public BadgeAttributeTagProcessor(String dialectPrefix) {
30 | super(dialectPrefix, "badge");
31 | }
32 |
33 | @Override
34 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
35 | String attributeValue, IElementTagStructureHandler structureHandler) {
36 | Object target = evaluate(attributeValue, context);
37 | boolean isRenderable = target instanceof Badge;
38 | Badge badge = isRenderable ? (Badge) target : new Badge(Strings.asString(target));
39 | render(badge, context, tag, structureHandler, attributeName);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/BreadcrumbAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Breadcrumb;
25 |
26 | public class BreadcrumbAttributeTagProcessor extends AbstractTagProcessor {
27 |
28 | public BreadcrumbAttributeTagProcessor(String dialectPrefix) {
29 | super(dialectPrefix, "breadcrumb");
30 | }
31 |
32 | @Override
33 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
34 | String attributeValue, IElementTagStructureHandler structureHandler) {
35 | Object target = evaluate(attributeValue, context);
36 | boolean isRenderable = target instanceof Breadcrumb;
37 | Breadcrumb breadcrumb = isRenderable ? (Breadcrumb) target : new Breadcrumb();
38 | render(breadcrumb, context, tag, structureHandler, attributeName);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/ButtonAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Button;
25 |
26 | public class ButtonAttributeTagProcessor extends AbstractTagProcessor {
27 |
28 | public ButtonAttributeTagProcessor(String dialectPrefix) {
29 | super(dialectPrefix, "button");
30 | }
31 |
32 | @Override
33 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
34 | String attributeValue, IElementTagStructureHandler structureHandler) {
35 | Object target = evaluate(attributeValue, context);
36 | boolean isRenderable = target instanceof Button;
37 | Button button = isRenderable ? (Button) target : new Button();
38 | render(button, context, tag, structureHandler, attributeName);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/ButtonGroupAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.ButtonGroup;
25 |
26 | public class ButtonGroupAttributeTagProcessor extends AbstractTagProcessor {
27 |
28 | public ButtonGroupAttributeTagProcessor(String dialectPrefix) {
29 | super(dialectPrefix, "button-group");
30 | }
31 |
32 | @Override
33 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
34 | String attributeValue, IElementTagStructureHandler structureHandler) {
35 | Object target = evaluate(attributeValue, context);
36 | boolean isRenderable = target instanceof ButtonGroup;
37 | ButtonGroup button = isRenderable ? (ButtonGroup) target : new ButtonGroup();
38 | render(button, context, tag, structureHandler, attributeName);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/CardAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Card;
25 |
26 | public class CardAttributeTagProcessor extends AbstractTagProcessor {
27 |
28 | public CardAttributeTagProcessor(String dialectPrefix) {
29 | super(dialectPrefix, "card");
30 | }
31 |
32 | @Override
33 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
34 | String attributeValue, IElementTagStructureHandler structureHandler) {
35 | Object target = evaluate(attributeValue, context);
36 | boolean isRenderable = target instanceof Card;
37 | Card card = isRenderable ? (Card) target : new Card();
38 | render(card, context, tag, structureHandler, attributeName);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/CarouselAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IAttribute;
22 | import org.thymeleaf.model.IProcessableElementTag;
23 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
24 |
25 | import io.github.thymeleaf.ui.Attrs;
26 | import io.github.thymeleaf.ui.components.Carousel;
27 |
28 | public class CarouselAttributeTagProcessor extends AbstractTagProcessor {
29 |
30 | public CarouselAttributeTagProcessor(String dialectPrefix) {
31 | super(dialectPrefix, "carousel");
32 | }
33 |
34 | @Override
35 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
36 | String attributeValue, IElementTagStructureHandler structureHandler) {
37 | Object target = evaluate(attributeValue, context);
38 | boolean isRenderable = target instanceof Carousel;
39 | Carousel carousel = isRenderable ? (Carousel) target : new Carousel();
40 |
41 | //Carousel needs an id for indicator links
42 | if(target instanceof String) {
43 | carousel.setId((String) target);
44 | }
45 |
46 | if(tag.hasAttribute(Attrs.ID)) {
47 | IAttribute attribute = tag.getAttribute(Attrs.ID);
48 | carousel.setId(attribute.getValue());
49 | }
50 |
51 | if(carousel.getId()==null) {
52 | carousel.setId("car_"+System.currentTimeMillis());
53 | }
54 |
55 | render(carousel, context, tag, structureHandler, attributeName);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/CopyTagAttributesTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import java.util.Collections;
20 |
21 | import org.thymeleaf.context.ITemplateContext;
22 | import org.thymeleaf.engine.AttributeName;
23 | import org.thymeleaf.model.IAttribute;
24 | import org.thymeleaf.model.IProcessableElementTag;
25 | import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
26 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
27 | import org.thymeleaf.templatemode.TemplateMode;
28 |
29 | import io.github.thymeleaf.ui.Attrs;
30 | import io.github.thymeleaf.ui.HasHtmlAttributes;
31 | import io.github.thymeleaf.ui.internal.Strings;
32 |
33 | public class CopyTagAttributesTagProcessor extends AbstractAttributeTagProcessor {
34 |
35 | private static final int PRECEDENCE = Integer.MAX_VALUE;
36 | private static final String ATTR_NAME = "copy-tag-attributes";
37 | public static final String PARENT_ATTRIBUTES_VAR = "_tag_node_attributes";
38 |
39 | public CopyTagAttributesTagProcessor(final String dialectPrefix) {
40 | super(TemplateMode.HTML, dialectPrefix, null, false, ATTR_NAME, true, PRECEDENCE, true);
41 | }
42 |
43 | @Override
44 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
45 | String attributeValue, IElementTagStructureHandler structureHandler) {
46 |
47 | IAttribute[] parentAttributes = getTagAttributes(context);
48 | for (IAttribute iAttribute : parentAttributes) {
49 | AttributeName attribute = iAttribute.getAttributeDefinition().getAttributeName();
50 | if(isStandardAttribute(attribute)) {
51 | String value = iAttribute.getValue();
52 | String name = iAttribute.getAttributeCompleteName();
53 | structureHandler.setAttribute(name, value);
54 | }
55 | }
56 |
57 | // Overrides id and class attributes from target object
58 | Object selectionTarget = context.getSelectionTarget();
59 | if(selectionTarget instanceof HasHtmlAttributes) {
60 | HasHtmlAttributes target = (HasHtmlAttributes) selectionTarget;
61 | if(Strings.isNotNull(target.getId())) {
62 | structureHandler.setAttribute(Attrs.ID, target.getId());
63 | }
64 |
65 | if(Strings.isNotNull(target.getClassName())) {
66 | structureHandler.setAttribute(Attrs.CLASS, target.getClassName());
67 | }
68 | }
69 | }
70 |
71 | private IAttribute[] getTagAttributes(ITemplateContext context) {
72 | Object variable = context.getVariable(PARENT_ATTRIBUTES_VAR);
73 | return (IAttribute[]) (variable==null ? Collections.emptyList() : variable);
74 | }
75 |
76 | private boolean isStandardAttribute(AttributeName attributeName) {
77 | return !getDialectPrefix().equals(attributeName.getPrefix());
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/DropdownAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Dropdown;
25 | import io.github.thymeleaf.ui.components.Dropdown.Toggle;
26 | import io.github.thymeleaf.ui.internal.Strings;
27 |
28 | public class DropdownAttributeTagProcessor extends AbstractTagProcessor {
29 |
30 | public DropdownAttributeTagProcessor(String dialectPrefix) {
31 | super(dialectPrefix, "dropdown");
32 | }
33 |
34 | @Override
35 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
36 | String attributeValue, IElementTagStructureHandler structureHandler) {
37 | Object target = evaluate(attributeValue, context);
38 | boolean isToggle = target instanceof Toggle;
39 | Toggle toggle = isToggle ? (Toggle)target : Toggle.toggle(Strings.asString(target));
40 | Dropdown dropdown = new Dropdown(toggle);
41 | render(dropdown, context, tag, structureHandler, attributeName);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/FigureAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Figure;
25 | import io.github.thymeleaf.ui.elements.Image;
26 |
27 | public class FigureAttributeTagProcessor extends AbstractTagProcessor {
28 |
29 | public FigureAttributeTagProcessor(String dialectPrefix) {
30 | super(dialectPrefix, "figure");
31 | }
32 |
33 | @Override
34 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
35 | String attributeValue, IElementTagStructureHandler structureHandler) {
36 | Object target = evaluate(attributeValue, context);
37 | boolean isRenderable = target instanceof Figure;
38 | Figure figure = isRenderable ? (Figure) target : new Figure();
39 |
40 | boolean isImage = target instanceof Image;
41 | if(isImage) {
42 | figure.setImage((Image) target);
43 | }
44 |
45 | render(figure, context, tag, structureHandler, attributeName);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/NavigationAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.ITemplateContext;
20 | import org.thymeleaf.engine.AttributeName;
21 | import org.thymeleaf.model.IProcessableElementTag;
22 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
23 |
24 | import io.github.thymeleaf.ui.components.Navigation;
25 |
26 | public class NavigationAttributeTagProcessor extends AbstractTagProcessor {
27 |
28 | public NavigationAttributeTagProcessor(String dialectPrefix) {
29 | super(dialectPrefix, "nav");
30 | }
31 |
32 | @Override
33 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
34 | String attributeValue, IElementTagStructureHandler structureHandler) {
35 | Object target = evaluate(attributeValue, context);
36 | boolean isRenderable = target instanceof Navigation;
37 | Navigation nav = isRenderable ? (Navigation) target : new Navigation();
38 | render(nav, context, tag, structureHandler, attributeName);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/NavigationHeaderAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.IEngineContext;
20 | import org.thymeleaf.context.ITemplateContext;
21 | import org.thymeleaf.engine.AttributeName;
22 | import org.thymeleaf.model.IProcessableElementTag;
23 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
24 |
25 | import io.github.thymeleaf.ui.components.NavigationHeader;
26 |
27 | public class NavigationHeaderAttributeTagProcessor extends AbstractTagProcessor {
28 |
29 | private static final String ATTRIBUTE_NAME = "nav-header";
30 |
31 | public NavigationHeaderAttributeTagProcessor(String dialectPrefix) {
32 | super(dialectPrefix, ATTRIBUTE_NAME);
33 | }
34 |
35 | @Override
36 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
37 | String attributeValue, IElementTagStructureHandler structureHandler) {
38 | NavigationHeader nav = resolve(attributeValue, context);
39 | render(nav, context, tag, structureHandler, attributeName);
40 | }
41 |
42 | private NavigationHeader resolve(String attributeValue, ITemplateContext context) {
43 | if(attributeValue==null) {
44 | Object variable = context.getVariable("navigationHeader");
45 | return variable instanceof NavigationHeader ? (NavigationHeader) variable : new NavigationHeader();
46 | }
47 |
48 | Object target = evaluate(attributeValue, context);
49 | boolean isRenderable = target instanceof NavigationHeader;
50 | if(isRenderable) {
51 | return (NavigationHeader) target;
52 | }
53 |
54 | NavigationHeader navHeader = new NavigationHeader();
55 | if(target instanceof String) {
56 | ((IEngineContext)context).setVariable((String)target, navHeader);
57 | }
58 |
59 | return navHeader;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/RenderAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import org.thymeleaf.context.ITemplateContext;
22 | import org.thymeleaf.engine.AttributeName;
23 | import org.thymeleaf.model.IProcessableElementTag;
24 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
25 |
26 | import io.github.thymeleaf.ui.Renderable;
27 |
28 | public final class RenderAttributeTagProcessor extends AbstractTagProcessor {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(RenderAttributeTagProcessor.class);
31 | private static final String ATTR_NAME = "render";
32 |
33 | public RenderAttributeTagProcessor(final String dialectPrefix) {
34 | super(dialectPrefix, ATTR_NAME);
35 | }
36 |
37 | protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag,
38 | final AttributeName attributeName, final String attributeValue,
39 | final IElementTagStructureHandler structureHandler) {
40 |
41 | final Object target = evaluate(attributeValue, context);
42 | if (target instanceof Renderable) {
43 | render((Renderable)target, context, tag, structureHandler, attributeName);
44 | } else {
45 | LOGGER.debug("Target object '{}' is not Renderable", attributeValue);
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/dialect/tags/SidebarAttributeTagProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.dialect.tags;
18 |
19 | import org.thymeleaf.context.IEngineContext;
20 | import org.thymeleaf.context.ITemplateContext;
21 | import org.thymeleaf.engine.AttributeName;
22 | import org.thymeleaf.model.IProcessableElementTag;
23 | import org.thymeleaf.processor.element.IElementTagStructureHandler;
24 |
25 | import io.github.thymeleaf.ui.components.Sidebar;
26 |
27 | public class SidebarAttributeTagProcessor extends AbstractTagProcessor {
28 |
29 | private static final String ATTRIBUTE_NAME = "sidebar";
30 |
31 | public SidebarAttributeTagProcessor(String dialectPrefix) {
32 | super(dialectPrefix, ATTRIBUTE_NAME);
33 | }
34 |
35 | @Override
36 | protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName,
37 | String attributeValue, IElementTagStructureHandler structureHandler) {
38 | Sidebar sidebar = resolve(attributeValue, context);
39 | render(sidebar, context, tag, structureHandler, attributeName);
40 | }
41 |
42 | private Sidebar resolve(String attributeValue, ITemplateContext context) {
43 | if(attributeValue==null) {
44 | Object variable = context.getVariable(ATTRIBUTE_NAME);
45 | return variable instanceof Sidebar ? (Sidebar) variable : new Sidebar();
46 | }
47 |
48 | Object target = evaluate(attributeValue, context);
49 | boolean isRenderable = target instanceof Sidebar;
50 | if(isRenderable) {
51 | return (Sidebar) target;
52 | }
53 |
54 | Sidebar sidebar = new Sidebar();
55 | if(target instanceof String) {
56 | ((IEngineContext)context).setVariable((String)target, sidebar);
57 | }
58 |
59 | return sidebar;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/elements/Image.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.elements;
18 |
19 | import io.github.thymeleaf.ui.Element;
20 | import lombok.AllArgsConstructor;
21 | import lombok.Getter;
22 | import lombok.RequiredArgsConstructor;
23 |
24 | @Getter
25 | @AllArgsConstructor
26 | @RequiredArgsConstructor
27 | public class Image extends Element {
28 | private final String src;
29 | private String alt;
30 | private String title;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/elements/Link.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.elements;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | import io.github.thymeleaf.ui.Element;
22 | import io.github.thymeleaf.ui.internal.Checks;
23 | import io.github.thymeleaf.ui.internal.Urls;
24 | import lombok.AccessLevel;
25 | import lombok.Getter;
26 | import lombok.Setter;
27 |
28 | @Getter
29 | @Setter
30 | public class Link extends Element {
31 | private final @Getter(value = AccessLevel.NONE) String href;
32 | private final String text;
33 | private String title;
34 | private String target;
35 | private String rel;
36 |
37 | public Link(String href, String text) {
38 | Checks.checkIsNotEmpty(href);
39 | Checks.checkIsNotEmpty(text);
40 | this.href = href;
41 | this.text = text;
42 | }
43 |
44 | public String getHref(HttpServletRequest request) {
45 | return Urls.resolve(href, request);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/internal/Checks.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.internal;
18 |
19 | public final class Checks {
20 |
21 | private Checks() {
22 | }
23 |
24 | public static void checkNotNullArgument(Object param) {
25 | if(param==null) {
26 | throw new IllegalArgumentException("Argument can not be null");
27 | }
28 | }
29 |
30 | public static void checkIsNotEmpty(String param) {
31 | if(param==null) {
32 | throw new IllegalArgumentException("Argument can not be null");
33 | }
34 |
35 | if(param.length()==0) {
36 | throw new IllegalArgumentException("Argument can not be empty");
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/internal/Reflection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.internal;
18 |
19 | import java.lang.reflect.Method;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | public final class Reflection {
24 |
25 | private Reflection() {
26 | // Utility
27 | }
28 |
29 | public static void set(Object obj, String propertyName, Object value) {
30 | if(value!=null) {
31 | final Method method = getMethod(obj, propertyName, value);
32 | try {
33 | method.invoke(obj, value);
34 | } catch (Exception e) {
35 | throw new IllegalStateException("Unable to set value for property "+propertyName, e);
36 | }
37 | }
38 | }
39 |
40 | private static Method getMethod(Object obj, String propertyName, Object value) {
41 | final String methodName = "set" + Strings.capitalize(propertyName);
42 | try {
43 | // try as primitive
44 | Class> t = resolvePrimitive(value);
45 | return obj.getClass().getMethod(methodName, t);
46 | } catch (Exception e) {
47 | try {
48 | return obj.getClass().getMethod(methodName, value.getClass());
49 | } catch (Exception e1) {
50 | String m = obj.getClass().getName() +"."+ methodName;
51 | String arg = value==null ? "null" : String.valueOf(value.getClass());
52 | throw new IllegalStateException("Unable to found method: '"+m+"("+arg+")'", e1);
53 | }
54 | }
55 | }
56 |
57 | private static Class> resolvePrimitive(Object value) {
58 | if(value instanceof ArrayList) {
59 | return List.class;
60 | }
61 |
62 | if(value instanceof Boolean) {
63 | return Boolean.TYPE;
64 | }
65 |
66 | if(value instanceof Integer) {
67 | return Integer.TYPE;
68 | }
69 |
70 | throw new IllegalStateException("No primitive alternative");
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/internal/Strings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.internal;
18 |
19 | public final class Strings {
20 |
21 | public static final String EMPTY = "";
22 |
23 | private Strings() {
24 | }
25 |
26 | public static boolean isEmpty(String text) {
27 | return text == null || text.length() == 0;
28 | }
29 |
30 | public static boolean isNotEmpty(String text) {
31 | return !isEmpty(text);
32 | }
33 |
34 | public static boolean isNotNull(Object obj) {
35 | return obj != null;
36 | }
37 |
38 | public static String dash(String str) {
39 | return str == null ? EMPTY : str.replaceAll("([a-z])([A-Z]+)", "$1-$2").toLowerCase();
40 | }
41 |
42 | public static String capitalize(String str) {
43 | if (str == null || str.length() == 0) {
44 | return str;
45 | }
46 |
47 | final StringBuilder sb = new StringBuilder(str.length());
48 | final String[] strings = str.split("-");
49 | for (String string : strings) {
50 | sb.append(Character.toUpperCase(string.charAt(0)));
51 | sb.append(string.substring(1));
52 | }
53 |
54 | return sb.toString();
55 | }
56 |
57 | public static String asString(Object obj) {
58 | return obj instanceof String ? (String) obj : EMPTY;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/internal/Urls.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui.internal;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 |
21 | public final class Urls {
22 | // Match absolute uri (http://www.google.com | //www.google.com)
23 | private static final String ABSOLUTE_URI_REGEX = ".*//.*";
24 |
25 | private Urls() {
26 | }
27 |
28 | public static String resolve(String href, HttpServletRequest request) {
29 | if("#".equals(href)) {
30 | return href;
31 | }
32 | String contextPath = request==null ? Strings.EMPTY : request.getContextPath();
33 |
34 | return href.matches(ABSOLUTE_URI_REGEX) ? href : contextPath + href;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/github/thymeleaf/ui/internal/package.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * Classes under this package are implementation-dependent and subject to change
19 | * without warning or backwards compatibility.
20 | */
21 | package io.github.thymeleaf.ui.internal;
--------------------------------------------------------------------------------
/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.github.thymeleaf.ui.dialect.UiDialectAutoconfiguration
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/Readme:
--------------------------------------------------------------------------------
1 | Themes folder.
2 |
3 | default theme: Bootstrap v4
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/alert-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ×
5 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/badge-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/breadcrumb-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/button-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/button-group-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/card-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
[[*{title}]]
6 |
[[*{subtitle}]]
7 |
[[*{text}]]
8 |
[[${link.text}]]
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/carousel-component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/dropdown-component.html:
--------------------------------------------------------------------------------
1 |
2 | [[*{toggle.text}]]
3 |
10 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/figure-component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | [[*{caption}]]
4 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/navigation-component.html:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/navigation-header-component.html:
--------------------------------------------------------------------------------
1 |
2 | Navbar
3 |
4 |
5 |
6 |
7 |
26 |
--------------------------------------------------------------------------------
/src/main/resources/templates/ui/themes/default/sidebar-component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/test/java/io/github/thymeleaf/ui/ComponentsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002-2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.github.thymeleaf.ui;
18 |
19 | import static io.github.thymeleaf.ui.Components.alert;
20 | import static io.github.thymeleaf.ui.Components.alertDismissible;
21 | import static io.github.thymeleaf.ui.Components.badge;
22 | import static io.github.thymeleaf.ui.Components.breadcrumb;
23 | import static io.github.thymeleaf.ui.Components.button;
24 | import static io.github.thymeleaf.ui.Components.buttonGroup;
25 | import static io.github.thymeleaf.ui.Components.buttonToggle;
26 | import static io.github.thymeleaf.ui.Components.card;
27 | import static io.github.thymeleaf.ui.Components.carousel;
28 | import static io.github.thymeleaf.ui.Components.dropdown;
29 | import static io.github.thymeleaf.ui.Components.figure;
30 | import static io.github.thymeleaf.ui.Components.image;
31 | import static io.github.thymeleaf.ui.Components.link;
32 | import static io.github.thymeleaf.ui.Components.location;
33 | import static io.github.thymeleaf.ui.Components.navigation;
34 | import static io.github.thymeleaf.ui.Components.navigationHeader;
35 | import static io.github.thymeleaf.ui.Components.sidebar;
36 | import static io.github.thymeleaf.ui.Components.slide;
37 |
38 | import javax.servlet.http.HttpServletRequest;
39 |
40 | import org.junit.Test;
41 |
42 | import io.github.thymeleaf.ui.components.Alert;
43 | import io.github.thymeleaf.ui.components.Badge;
44 | import io.github.thymeleaf.ui.components.Breadcrumb;
45 | import io.github.thymeleaf.ui.components.Breadcrumb.Location;
46 | import io.github.thymeleaf.ui.components.Button;
47 | import io.github.thymeleaf.ui.components.ButtonGroup;
48 | import io.github.thymeleaf.ui.components.Card;
49 | import io.github.thymeleaf.ui.components.Carousel;
50 | import io.github.thymeleaf.ui.components.Dropdown;
51 | import io.github.thymeleaf.ui.components.Dropdown.Toggle;
52 | import io.github.thymeleaf.ui.components.Figure;
53 | import io.github.thymeleaf.ui.components.Navigation;
54 | import io.github.thymeleaf.ui.components.NavigationHeader;
55 | import io.github.thymeleaf.ui.components.Sidebar;
56 | import io.github.thymeleaf.ui.elements.Image;
57 | import io.github.thymeleaf.ui.elements.Link;
58 |
59 | public class ComponentsTest {
60 |
61 | @Test
62 | public void componentsApiTest() throws Exception {
63 | new Alert("text");
64 | new Alert("Alert text").setDismissible(true);
65 |
66 | alert("");
67 | alertDismissible("");
68 |
69 | new Badge("3");
70 | badge("3");
71 | badge("#", "text");
72 |
73 | Breadcrumb breadcrumb = new Breadcrumb();
74 | breadcrumb.add(new Location("#", "text"));
75 | breadcrumb(location("text"));
76 | breadcrumb().add(location("#","text"));
77 |
78 | Button button = new Button("text");
79 | button.setHref("#");
80 |
81 | button("text");
82 | button("text", "type");
83 | buttonToggle("text");
84 |
85 | new ButtonGroup();
86 | new ButtonGroup().add(button("text"));
87 | new ButtonGroup().add(button("text"), button("text"));
88 | buttonGroup(); //.empty();
89 | buttonGroup().add(button("text"));
90 | buttonGroup().add(button("text"), button("text"));
91 | buttonGroup(button("text"));
92 | buttonGroup(button("text"), button("text"));
93 |
94 | new Card(new Image("src"));
95 | card("src");
96 | card("src", "alt");
97 | Card card = card("src");
98 | card.setHeader("h");
99 | card.setTitle("t");
100 | card.setSubtitle("s");
101 | card.setText("t");
102 | card.setFooter("f");
103 | card.addLink("#", "text");
104 |
105 | new Carousel();
106 | carousel("id");
107 | carousel(slide("src"));
108 | carousel(slide("src"), slide("src"));
109 | carousel("id", slide("src"));
110 | carousel("id").setShowControls(true);
111 | carousel("id").setShowIndicators(true);
112 |
113 | new Dropdown(new Toggle(""));
114 | dropdown("toggle");
115 | dropdown("text");
116 | dropdown("text", "id");
117 | dropdown("text", "id").add(link("#", "text"), link("#", "text"));
118 |
119 | new Dropdown.Toggle("text");
120 | Dropdown.Toggle.toggle("text");
121 | Dropdown.Toggle.toggle("id", "text");
122 | Dropdown.Toggle.toggle("id", "text", "className");
123 |
124 |
125 | new Figure(new Image("src"));
126 | figure("src");
127 | figure("src", "alt");
128 | figure("src", "alt", "title");
129 |
130 | new Navigation();
131 | navigation();
132 | navigation(link("#", "text"));
133 |
134 | new NavigationHeader();
135 | new NavigationHeader().add(link("#", "text"));
136 | navigationHeader();
137 | navigationHeader(link("#", "text"));
138 | navigationHeader("#", "text");
139 | navigationHeader("#", "text", link("#", "text"));
140 |
141 | new Sidebar();
142 | sidebar();
143 | sidebar("header");
144 | sidebar("header", link("#", "text"));
145 | sidebar(link("#", "text"));
146 | }
147 |
148 | @Test
149 | public void elementsApiTest() throws Exception {
150 | new Link("#", "Link");
151 | link("#", "text", "title");
152 | Link link = new Link("#", "Link");
153 | link.setRel("rel");
154 | link.setTarget("target");
155 | new Link("#","Link") {
156 | @Override
157 | public boolean isActive(HttpServletRequest request) {
158 | return false;
159 | }
160 | @Override
161 | public boolean isDisabled(HttpServletRequest request) {
162 | return false;
163 | }
164 | @Override
165 | public boolean isVisible(HttpServletRequest request) {
166 | return true;
167 | }
168 | };
169 |
170 | link("#", "Link");
171 | link("#", "link", "title");
172 | link("#", "Link", "Title", "target");
173 | link("#", "Link", "Title", "target", "rel");
174 |
175 | new Image("src");
176 | image("src");
177 | image("src", "alt");
178 | image("src", "alt", "title");
179 | }
180 |
181 | }
182 |
--------------------------------------------------------------------------------
/src/test/java/io/github/thymeleaf/ui/dialect/DialectBenchmarkTest.java:
--------------------------------------------------------------------------------
1 | package io.github.thymeleaf.ui.dialect;
2 |
3 | import static io.github.thymeleaf.ui.Components.carousel;
4 | import static io.github.thymeleaf.ui.Components.dropdown;
5 | import static io.github.thymeleaf.ui.Components.link;
6 | import static io.github.thymeleaf.ui.Components.navigationHeader;
7 | import static io.github.thymeleaf.ui.Components.sidebar;
8 | import static io.github.thymeleaf.ui.Components.slide;
9 | import static io.github.thymeleaf.ui.Components.submenu;
10 |
11 | import org.junit.Test;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.thymeleaf.context.Context;
15 | import org.thymeleaf.spring4.SpringTemplateEngine;
16 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
17 |
18 | import io.github.thymeleaf.ui.components.Alert;
19 | import io.github.thymeleaf.ui.components.Breadcrumb;
20 | import io.github.thymeleaf.ui.components.Card;
21 | import io.github.thymeleaf.ui.components.Dropdown;
22 | import io.github.thymeleaf.ui.components.Navigation;
23 | import io.github.thymeleaf.ui.components.NavigationHeader;
24 | import io.github.thymeleaf.ui.components.Sidebar;
25 | import io.github.thymeleaf.ui.elements.Link;
26 | import io.github.thymeleaf.ui.components.Breadcrumb.Location;
27 |
28 | public class DialectBenchmarkTest {
29 |
30 | private static final Logger LOGGER = LoggerFactory.getLogger(DialectBenchmarkTest.class);
31 |
32 | @Test
33 | // @Ignore
34 | public void benchmark() throws Exception {
35 | ClassLoaderTemplateResolver res = new ClassLoaderTemplateResolver();
36 | res.setCacheable(false);
37 | SpringTemplateEngine engine = new SpringTemplateEngine();
38 | engine.addTemplateResolver(res);
39 |
40 | UiDialect uiDialect = new UiDialect();
41 | engine.addDialect(uiDialect);
42 | ComponentTemplateResolver uiTemplateResolver = new ComponentTemplateResolver("default");
43 | uiTemplateResolver.setOrder(1);
44 | uiTemplateResolver.setCacheable(false);
45 | engine.addTemplateResolver(uiTemplateResolver);
46 |
47 | long startup = System.currentTimeMillis();
48 |
49 | String html = null;
50 | for (int i = 0; i < 1; i++) {
51 | Context context = new Context();
52 |
53 | Alert alert = new Alert("From java");
54 | alert.setId("theid");
55 | alert.setDismissible(true);
56 | context.setVariable("theAlert", alert);
57 |
58 | Card card = new Card();
59 | card.setId("cardId");
60 | card.setHeader("my header");
61 | context.setVariable("theCard", card);
62 |
63 | Breadcrumb breadcrumb = new Breadcrumb();
64 | breadcrumb.add(new Location("href","text"));
65 | context.setVariable("breadcrumb", breadcrumb);
66 |
67 | Navigation nav = new Navigation();
68 | nav.add(new Link("href","alt"));
69 | nav.add(new Link("href","alt"));
70 | context.setVariable("nav", nav);
71 |
72 | NavigationHeader header = navigationHeader("#", "navheader", link("#", "link"));
73 | Dropdown dropdown = dropdown("tog", "t1");
74 | dropdown.add(link("#", "Link"));
75 | dropdown.add(link("#", "Link2"));
76 | dropdown.divider();
77 | dropdown.add(link("#", "Link"));
78 | header.add(dropdown);
79 | context.setVariable("navigationHeader", header);
80 |
81 | Sidebar sidebar = sidebar("Header", link("#", "link"), link("#", "link"));
82 | sidebar.add(submenu("Menu", link("#", "link"), link("#", "Link")));
83 | context.setVariable("sidebar", sidebar);
84 |
85 | context.setVariable("msg", "Mensaje molón");
86 | context.setVariable("carousel", carousel(slide("src", "caption text"), slide("src", "caption text")));
87 | html = engine.process("/test.html", context);
88 | }
89 |
90 | LOGGER.info(html);
91 |
92 | LOGGER.info("time: " + (System.currentTimeMillis() - startup) + "ms");
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/test/resources/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------