84 Commits

Author SHA1 Message Date
David
7d9ad230c1 [maven-release-plugin] prepare release j2html-1.2.2 2017-12-06 17:03:56 +01:00
David
7ebf4792b4 auto format 2017-12-06 14:08:24 +01:00
Janning Vygen
889fd2a3ac Add renderModel(writer, model) to Renderable (#93) 2017-12-06 14:04:13 +01:00
David
4acda0c6bb auto format project 2017-12-05 19:46:47 +01:00
Janning Vygen
17dac2871e Pass StringBuilder around instead of returning/concating strings (#88)
- Also remove retrolambda
2017-12-05 19:40:14 +01:00
David
1bfceaa62c Auto-format project (#92) 2017-12-02 12:17:32 +01:00
Janning Vygen
13134d042a Add Eclipse formatting config (#91) 2017-12-02 11:57:32 +01:00
Janning Vygen
b808d70a0d Addin root=true to .editorconfig (#90) 2017-12-02 11:47:24 +01:00
David
b068024070 Rewrite escaper-performance-test 2017-12-02 00:37:38 +01:00
David
5448c41887 Add basic editorconfig 2017-12-02 00:26:11 +01:00
Janning Vygen
d853c9cb1e Adding a performance test for https://github.com/tipsy/j2html/issues/86 (#87)
* Fix for https://github.com/tipsy/j2html/issues/79

* Adding PerformanceTest to measure execution time of rendering and GC

Signed-off-by: Janning Vygen <vygen@kicktipp.de>
2017-12-01 19:55:17 +01:00
David
eff53e073f Update README.md 2017-11-28 00:14:12 +01:00
David
98d7a6e912 [maven-release-plugin] prepare for next development iteration 2017-11-28 00:05:42 +01:00
David
eb3f28a09f [maven-release-plugin] prepare release j2html-1.2.1 2017-11-28 00:05:25 +01:00
David
368241313d Allow reading static resources from jars 2017-11-27 19:41:20 +01:00
David
4288924f8f Fix greedy semi-colon stripper bug in CSSMin
If CSSMin encounters a CSS-rule without a semi-colon at the end,
it will strip one char too many from that rule. This commit fixes that.
2017-11-27 12:54:07 +01:00
Janning Vygen
9948095c08 Fix for https://github.com/tipsy/j2html/issues/80 (#82)
* Fix for https://github.com/tipsy/j2html/issues/79

* Fix for https://github.com/tipsy/j2html/issues/80
2017-11-10 16:11:58 +01:00
Janning Vygen
56090046b5 Fix for https://github.com/tipsy/j2html/issues/79 (#81) 2017-11-10 16:07:20 +01:00
Thomas Tanon
d45af42650 Adds Tag.withLang and Tag.withDir (#76)
* Adds Tag.withLang and Tag.withDir

Allows easiest addition of mixed languages

* Add withCond(Lang|Dir)
2017-10-23 14:21:29 +02:00
David
7d65f91f44 Fix javadoc bug 2017-09-03 11:30:05 +02:00
David
aecf5e71d6 Update README.md 2017-09-03 11:26:10 +02:00
David
cf47772c89 [maven-release-plugin] prepare for next development iteration 2017-09-03 11:16:05 +02:00
David
897c53d830 [maven-release-plugin] prepare release j2html-1.2.0 2017-09-03 11:15:46 +02:00
David
1e29d81107 Fix another javadoc violation 2017-09-03 11:14:41 +02:00
David
dee3efb8e7 Remove javadoc violation 2017-09-03 11:08:36 +02:00
David
ee82201dfb Misc cleanup
- Add javadoc to Config
- Make CSSMin/JSMin configurable (add Minifier interface)
- Change SimpleEscaper back to a util
2017-09-02 19:41:37 +02:00
David
691680ea51 Add simple formatter (fixed #65)
* Add simple formatter
* Create Indenter interface
* Shorten variable-names in renderFormatted
* Fix javadoc
2017-09-02 19:05:48 +02:00
David
0853692e80 Use diamond operator 2017-09-01 20:50:20 +02:00
David
c2bc4b3209 Add @FunctionalInterface annotation to TextEscaper 2017-09-01 20:40:57 +02:00
David
ff9d138f63 Add option to close empty tags (fixes #52) 2017-09-01 20:39:23 +02:00
David
f778f4df3c Add convenience method for title (fixes #71) 2017-09-01 20:12:47 +02:00
David
a0b060ac42 Let attr() take object value (fixes #57) 2017-09-01 20:09:10 +02:00
David
4161be67bb Fix escaper-test 2017-09-01 20:07:48 +02:00
David
863527f684 Update README.md 2017-08-14 17:58:37 +02:00
David
5ef2dd3ec5 [maven-release-plugin] prepare for next development iteration 2017-08-14 17:45:23 +02:00
David
fc3bb29b6a [maven-release-plugin] prepare release j2html-1.1.0 2017-08-14 17:45:02 +02:00
Sergey Bezkostnyi
ef5777e54a Add ability to change text escaper implementation (#70) 2017-08-14 17:10:02 +02:00
David
cfc1489399 Merge pull request #63 from maztan/master
Add method to get number of children of ContainerTag
2017-07-29 19:19:08 +02:00
Ed Savailonei
8112dad1bb Add methd to get number of children of ContainerTag 2017-07-03 12:41:10 +02:00
David
235dec78ed Merge pull request #62 from kiru/patch-1
Updaate Gradle Version
2017-05-19 23:05:12 +02:00
Kiru
6316dd2262 Updaate Gradle Version 2017-05-19 21:57:04 +02:00
David
5667d7c68d Update README.md 2017-05-16 18:49:27 +02:00
David
13911d5f57 [maven-release-plugin] prepare for next development iteration 2017-05-16 18:00:33 +02:00
David
0bc6e274db [maven-release-plugin] prepare release j2html-1.0.0 2017-05-16 18:00:10 +02:00
David
325afd463c Fix version 2017-05-16 17:58:03 +02:00
David
f331eb9eb3 Merge pull request #61 from EthanDRaymond/DomContentJoiner-Does-Not-Use-Delimiter
Fixed a bug (maybe) where a delimiter was not being used
2017-05-12 22:45:10 +02:00
Ethan Raymond
d37dc1cac6 Fixed a bug (maybe) where a delimiter was not being used. 2017-05-12 15:39:23 -04:00
David
dab61bd662 [maven-release-plugin] prepare for next development iteration 2017-05-03 19:57:56 +02:00
David
d559f05903 [maven-release-plugin] prepare release j2html-1.0.0-RC 2017-05-03 19:57:31 +02:00
David
97a8f34572 Make filereader java6 compatible, because why not 2017-05-02 22:39:59 +02:00
David
6305e364ca Experimental Java6/Java7 support 2017-05-02 03:12:17 +02:00
David
28ba518b12 Fix name collision + minor cleanup 2017-05-01 19:10:42 +02:00
David
5f04cde97c Merge pull request #56 from tipsy/id-class-shorthand
Add shorthand notation for id/class
2017-05-01 18:59:11 +02:00
David
b00ba50133 Add attrs method to tagcreator 2017-05-01 18:51:04 +02:00
David
e09918da12 Add missing test-case to attr.shortform 2017-05-01 18:06:10 +02:00
David
55b74e81aa Improve generics in Attr.addTo 2017-05-01 16:54:05 +02:00
David
75deeff13d Remove unwanted import 2017-05-01 16:29:22 +02:00
David
3aa05aa540 Merge branch 'master' into id-class-shorthand 2017-05-01 16:15:01 +02:00
David
fb24d1eabf Merge pull request #55 from chmuche/empty-attribute
Empty attribute
2017-05-01 15:50:07 +02:00
David
458f3baf98 Merge pull request #54 from chmuche/gradle-dependency
Add Gradle dependency in README.md
2017-05-01 15:48:25 +02:00
David
a661f37575 Add document() method that renders a html() child 2017-05-01 15:45:02 +02:00
David
26796cd30d Add shorthand notation for id/class 2017-05-01 15:22:48 +02:00
chmuche
75dc60c415 Add Test 2017-05-01 15:19:27 +02:00
chmuche
99b98f9b09 Create a method attr without value to create empty attribute inside the tag 2017-05-01 15:12:41 +02:00
chmuche
8d4756bab0 Add Gradle dependency in README.md 2017-05-01 15:07:50 +02:00
David
2c1f337348 Update README.md 2017-04-30 20:37:27 +02:00
David
d437e1affd Add a domcontentjoiner 2017-04-29 16:44:48 +02:00
David
4fdcc3c213 Remove need for with() 2017-04-29 12:15:51 +02:00
David
ba3261b210 Update README.md 2017-04-25 23:34:26 +02:00
David
ee0100d1a7 Set snapshot to 1.0.0 2017-04-20 23:17:07 +02:00
David
9ec3088d82 [maven-release-plugin] prepare for next development iteration 2017-04-20 23:13:36 +02:00
David
8052cdaff1 [maven-release-plugin] prepare release j2html-0.99 2017-04-20 23:13:16 +02:00
David
34b2410830 Add withClasses(String... classes) method 2017-04-20 23:08:12 +02:00
David
75d361fa20 Merge pull request #51 from tipsy/iff-else
Add generic iff-method to use in method calls
2017-04-20 21:34:07 +02:00
David
3e91da0640 Add generic iff-method to use in method calls 2017-04-17 16:20:12 +02:00
David
d1613b0570 Change Error to RuntimeException 2017-04-17 15:35:06 +02:00
David
a841271ba4 Merge pull request #50 from tipsy/inline-static-fix
Fix #14 (Unable to read files from directories other that /src/main/r…
2017-04-16 10:37:09 +02:00
David
9272438940 Simplify resource handling and throw exception 2017-04-13 21:21:01 +02:00
David
3d43eb159f Fix #14 (Unable to read files from directories other that /src/main/resources) 2017-04-13 01:25:16 +02:00
David
30bfe4ea7f Small formatting fix 2017-04-12 19:40:26 +02:00
David
7409772c20 Update README.md 2017-04-12 19:30:26 +02:00
David
29e16df057 Improve escaper performance 2017-03-28 22:23:33 +02:00
David
6903bcbe4d Update README.md 2017-01-30 00:28:58 +01:00
David
56b830782f [maven-release-plugin] prepare for next development iteration 2017-01-29 21:32:54 +01:00
46 changed files with 4329 additions and 458 deletions

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
root=true
[*]
charset=utf-8
end_of_line=crlf
insert_final_newline=true
indent_style=space
indent_size=4

View File

@@ -7,25 +7,29 @@ Java to HTML generator. Enjoy typesafe HTML generation.
The project webpage is [j2html.com](http://j2html.com).
##Getting started
###Add the maven dependency
## Getting started
### Add the maven dependency
```xml
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.7</version>
<version>1.2.1</version>
</dependency>
```
### OR the gradle dependency
```
compile 'com.j2html:j2html:1.2.1'
```
###Import TagCreator and start building HTML
### Import TagCreator and start building HTML
```java
import static j2html.TagCreator.*;
public class Main {
public static void main(String[] args) {
body().with(
h1("Heading!").withClass("example"),
img().withSrc("img/hello.png")
h1("Heading!").withClass("example"),
img().withSrc("img/hello.png")
).render();
}
}

View File

@@ -0,0 +1,313 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="j2html" version="12">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="52"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

14
pom.xml
View File

@@ -10,7 +10,7 @@
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.88</version>
<version>1.2.2</version>
<name>j2html</name>
<description>Java to HTML builder with a fluent API</description>
@@ -52,6 +52,18 @@
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.carrotsearch</groupId>
<artifactId>junit-benchmarks</artifactId>
<version>0.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<packaging>jar</packaging>

View File

@@ -0,0 +1,49 @@
package j2html;
import j2html.utils.CSSMin;
import j2html.utils.EscapeUtil;
import j2html.utils.Indenter;
import j2html.utils.JSMin;
import j2html.utils.Minifier;
import j2html.utils.TextEscaper;
import java.util.Collections;
public class Config {
private static String FOUR_SPACES = " ";
private Config() {
}
/**
* Change this to configure text-escaping
* For example, to disable escaping, do <code>{@code Config.textEscaper = text -> text;}</code>
*/
public static TextEscaper textEscaper = EscapeUtil::escape;
/**
* Change this to configure css-minification.
* The default minifier is https://github.com/barryvan/CSSMin
*/
public static Minifier cssMinifier = CSSMin::compressCss;
/**
* Change this to configure js-minification.
* The default minifier is a simple whitespace/newline stripper
*/
public static Minifier jsMinifier = JSMin::compressJs;
/**
* Change this to configure indentation when rendering formatted html
* The default is four spaces
*/
public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;
/**
* Change this to configure enable/disable closing empty tags
* The default is to NOT close them
*/
public static boolean closeEmptyTags = false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,62 @@
package j2html.attributes;
import j2html.tags.Tag;
public class Attr {
public static class ShortForm {
String id;
String classes;
private ShortForm(String id, String classes) {
this.id = id;
this.classes = classes;
}
boolean hasId() {
return id != null && !"".equals(id);
}
boolean hasClasses() {
return classes != null && !"".equals(classes);
}
}
public static ShortForm shortFormFromAttrsString(String attrs) {
if (!attrs.contains(".") && !attrs.contains(("#"))) {
throw new IllegalArgumentException("String must contain either id (#) or class (.)");
}
if (attrs.split("#").length > 2) {
throw new IllegalArgumentException("Only one id (#) allowed");
}
String id = "";
StringBuilder classes = new StringBuilder();
for (String attr : attrs.split("\\.")) {
if (attr.contains("#")) {
if (!attr.startsWith("#")) {
throw new IllegalArgumentException("# cannot be in the middle of string");
}
id = attr.replace("#", "");
} else {
classes.append(attr).append(" ");
}
}
return new ShortForm(id.trim(), classes.toString().trim());
}
public static <T extends Tag<T>> T addTo(T tag, ShortForm shortForm) {
if (shortForm.hasId() && shortForm.hasClasses()) {
return tag.withId(shortForm.id).withClass(shortForm.classes);
}
if (shortForm.hasId()) {
return tag.withId(shortForm.id);
}
if (shortForm.hasClasses()) {
return tag.withClass(shortForm.classes);
}
return tag;
}
private Attr() {
}

View File

@@ -1,15 +1,16 @@
package j2html.attributes;
import j2html.Config;
import j2html.tags.Renderable;
import java.io.IOException;
import j2html.utils.SimpleEscaper;
public class Attribute {
public class Attribute implements Renderable {
private String name;
private String value;
public Attribute(String name, String value) {
this.name = name;
this.value = SimpleEscaper.escape(value);
this.value = Config.textEscaper.escape(value);
}
public Attribute(String name) {
@@ -17,19 +18,18 @@ public class Attribute {
this.value = null;
}
public String render() {
if (name == null) {
return "";
}
if (value == null) {
return " " + name;
}
return (" " + name + "=\"" + value + "\"");
}
@Override
public String toString() {
return this.render();
public void renderModel(Appendable writer, Object model) throws IOException {
if (name == null) {
return;
}
writer.append(" ");
writer.append(name);
if (value != null) {
writer.append("=\"");
writer.append(value);
writer.append("\"");
}
}
public String getName() {

View File

@@ -1,5 +1,6 @@
package j2html.tags;
import j2html.Config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -22,7 +23,10 @@ public class ContainerTag extends Tag<ContainerTag> {
*/
public ContainerTag with(DomContent child) {
if (this == child) {
throw new Error("Cannot append a tag to itself.");
throw new RuntimeException("Cannot append a tag to itself.");
}
if (child == null) {
return this; // in some cases, like when using iff(), we ignore null children
}
children.add(child);
return this;
@@ -108,33 +112,58 @@ public class ContainerTag extends Tag<ContainerTag> {
return with(new Text(text));
}
/**
* Gets number of child nodes this tag element contains
*/
public int getNumChildren() {
return children.size();
}
/**
* Render the ContainerTag and its children
* Render the ContainerTag and its children, adding newlines before each
* child and using Config.indenter to indent child based on how deep
* in the tree it is
*
* @return the rendered string
* @return the rendered and formatted string
*/
@Override
public String render() {
StringBuilder rendered = new StringBuilder(renderOpenTag());
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
rendered.append(child.render());
public String renderFormatted() {
try {
return renderFormatted(0);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private String renderFormatted(int lvl) throws IOException {
StringBuilder sb = new StringBuilder();
renderOpenTag(sb, null);
sb.append("\n");
if (!children.isEmpty()) {
for (DomContent c : children) {
lvl++;
if (c instanceof ContainerTag) {
sb.append(Config.indenter.indent(lvl, ((ContainerTag) c).renderFormatted(lvl)));
} else {
sb.append(Config.indenter.indent(lvl, c.render())).append("\n");
}
lvl--;
}
}
rendered.append(renderCloseTag());
return rendered.toString();
sb.append(Config.indenter.indent(lvl, ""));
renderCloseTag(sb);
sb.append("\n");
return sb.toString();
}
@Override
public void render(Appendable writer) throws IOException {
writer.append(renderOpenTag());
public void renderModel(Appendable writer, Object model) throws IOException {
renderOpenTag(writer, model);
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
child.render(writer);
child.renderModel(writer, model);
}
}
writer.append(renderCloseTag());
renderCloseTag(writer);
}
}

View File

@@ -1,18 +1,4 @@
package j2html.tags;
import java.io.IOException;
public abstract class DomContent {
public abstract String render();
public void render(Appendable writer) throws IOException {
writer.append(render());
}
@Override
public String toString() {
return render();
}
public abstract class DomContent implements Renderable {
}

View File

@@ -0,0 +1,24 @@
package j2html.tags;
public class DomContentJoiner {
public static UnescapedText join(CharSequence delimiter, boolean fixPeriodAndCommaSpacing, Object... stringOrDomObjects) {
StringBuilder sb = new StringBuilder();
for (Object o : stringOrDomObjects) {
if (o instanceof String) {
sb.append(((String) o).trim()).append(delimiter);
} else if (o instanceof DomContent) {
sb.append(((DomContent) o).render().trim()).append(delimiter);
} else {
throw new RuntimeException("You can only join DomContent and String objects");
}
}
String joined = sb.toString().trim();
if (fixPeriodAndCommaSpacing) {
joined = joined.replaceAll("\\s\\.", ".");
joined = joined.replaceAll("\\s\\,", ",");
}
return new UnescapedText(joined);
}
}

View File

@@ -1,5 +1,9 @@
package j2html.tags;
import j2html.Config;
import j2html.attributes.Attribute;
import java.io.IOException;
public class EmptyTag extends Tag<EmptyTag> {
public EmptyTag(String tagName) {
@@ -7,8 +11,19 @@ public class EmptyTag extends Tag<EmptyTag> {
}
@Override
public String render() {
return renderOpenTag();
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append("<").append(tagName);
for (Attribute attribute : getAttributes()) {
attribute.renderModel(writer, model);
}
if (Config.closeEmptyTags) {
writer.append("/");
}
writer.append(">");
}
}

View File

@@ -1,48 +1,48 @@
package j2html.tags;
import java.nio.file.Files;
import java.nio.file.Paths;
import j2html.utils.CSSMin;
import j2html.utils.JSMin;
import j2html.Config;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Scanner;
import static j2html.TagCreator.rawHtml;
import static j2html.TagCreator.script;
import static j2html.TagCreator.style;
import static j2html.TagCreator.rawHtml;
public class InlineStaticResource {
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
public static ContainerTag get(String path, TargetFormat format) {
ContainerTag errorAlert = script().with(rawHtml("alert('Unable to read file. File: \"" + path + "\", Type: \"" + format + "\"')"));
String fileString = getFileAsString(path);
if(fileString != null) {
switch(format) {
case CSS_MIN : return style().with(rawHtml(compressCss(fileString)));
case JS_MIN : return script().with(rawHtml(compressJs(fileString)));
case CSS : return style().with(rawHtml(fileString));
case JS : return script().with(rawHtml(fileString));
default : return errorAlert;
}
switch (format) {
case CSS_MIN:
return style().with(rawHtml(Config.cssMinifier.minify(fileString)));
case JS_MIN:
return script().with(rawHtml(Config.jsMinifier.minify((fileString))));
case CSS:
return style().with(rawHtml(fileString));
case JS:
return script().with(rawHtml(fileString));
default:
throw new RuntimeException("Invalid target format");
}
return errorAlert;
}
public static String getFileAsString(String path) {
try {
return new String(Files.readAllBytes(Paths.get(InlineStaticResource.class.getResource(path).toURI())), "UTF-8");
} catch (Exception e) {
return null;
return streamToString(InlineStaticResource.class.getResourceAsStream(path));
} catch (Exception expected) { // we don't ask users to specify classpath or file-system
try {
return streamToString(new FileInputStream(path));
} catch (Exception exception) {
throw new RuntimeException("Couldn't find file with path='" + path + "'");
}
}
}
private static String compressCss(String code) {
return CSSMin.compress(code);
}
private static String compressJs(String code) {
return JSMin.compressJs(code);
private static String streamToString(InputStream inputStream) {
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}

View File

@@ -0,0 +1,37 @@
package j2html.tags;
import java.io.IOException;
public interface Renderable {
/**
* Create a StringBuilder and use it to render the Renderable and it's
* children
*/
default String render() {
StringBuilder stringBuilder = new StringBuilder();
try {
render(stringBuilder);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
return stringBuilder.toString();
}
/**
* Render the Renderable and it's children using the supplied writer
*
* @param writer the current writer
*/
default void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
/**
* Render the Renderable and it's children using the supplied writer and a model.
*
* @param writer the current writer
* @param model a model object to provide data for children to render
*/
void renderModel(Appendable writer, Object model) throws IOException;
}

View File

@@ -1,12 +1,11 @@
package j2html.tags;
import java.util.ArrayList;
import j2html.attributes.Attr;
import j2html.attributes.Attribute;
import java.io.IOException;
import java.util.ArrayList;
public abstract class Tag<T extends Tag<T>> extends DomContent {
protected String tagName;
private ArrayList<Attribute> attributes;
@@ -15,21 +14,39 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
this.attributes = new ArrayList<>();
}
public String getTagName() {
return this.tagName;
}
String renderOpenTag() {
StringBuilder sb = new StringBuilder("<").append(tagName);
String renderOpenTag() throws IOException {
StringBuilder stringBuilder = new StringBuilder();
renderOpenTag(stringBuilder, null);
return stringBuilder.toString();
}
String renderCloseTag() throws IOException {
StringBuilder stringBuilder = new StringBuilder();
renderCloseTag(stringBuilder);
return stringBuilder.toString();
}
void renderOpenTag(Appendable writer, Object model) throws IOException {
writer.append("<").append(tagName);
for (Attribute attribute : attributes) {
sb.append(attribute.render());
attribute.renderModel(writer, model);
}
sb.append(">");
return sb.toString();
writer.append(">");
}
String renderCloseTag() {
return "</" + tagName + ">";
void renderCloseTag(Appendable writer) throws IOException {
writer.append("</");
writer.append(tagName);
writer.append(">");
}
ArrayList<Attribute> getAttributes() {
return attributes;
}
/**
* Sets an attribute on an element
@@ -43,14 +60,13 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
}
for (Attribute attribute : attributes) {
if (attribute.getName().equals(name)) {
attribute.setValue(value); //update with new value
attribute.setValue(value); // update with new value
return true;
}
}
return attributes.add(new Attribute(name, value));
}
/**
* Sets a custom attribute
*
@@ -58,15 +74,25 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
* @param value the attribute value
* @return itself for easy chaining
*/
public T attr(String attribute, String value) {
setAttribute(attribute, value);
public T attr(String attribute, Object value) {
setAttribute(attribute, value == null ? null : String.valueOf(value));
return (T) this;
}
/**
* Sets a custom attribute without value
*
* @param attribute the attribute name
* @return itself for easy chaining
* @see Tag#attr(String, Object)
*/
public T attr(String attribute) {
return attr(attribute, null);
}
/**
* Call attr-method based on condition
* {@link #attr(String attribute, String value)}
* {@link #attr(String attribute, Object value)}
*
* @param condition the condition
* @param attribute the attribute name
@@ -77,7 +103,6 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
return (condition ? attr(attribute, value) : (T) this);
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Tag)) {
@@ -86,54 +111,212 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
return ((Tag) obj).render().equals(this.render());
}
/**
* Convenience methods that call attr with predefined attributes
*
* @return itself for easy chaining
*/
public T isAutoComplete() { return attr(Attr.AUTOCOMPLETE, null); }
public T isAutoFocus() { return attr(Attr.AUTOFOCUS, null); }
public T isHidden() { return attr(Attr.HIDDEN, null); }
public T isRequired() { return attr(Attr.REQUIRED, null); }
public T withAlt(String alt) { return attr(Attr.ALT, alt); }
public T withAction(String action) { return attr(Attr.ACTION, action); }
public T withCharset(String charset) { return attr(Attr.CHARSET, charset); }
public T withClass(String className) { return attr(Attr.CLASS, className); }
public T withContent(String content) { return attr(Attr.CONTENT, content); }
public T withHref(String href) { return attr(Attr.HREF, href); }
public T withId(String id) { return attr(Attr.ID, id); }
public T withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
public T withMethod(String method) { return attr(Attr.METHOD, method); }
public T withName(String name) { return attr(Attr.NAME, name); }
public T withPlaceholder(String placeholder) { return attr(Attr.PLACEHOLDER, placeholder); }
public T withTarget(String target) { return attr(Attr.TARGET, target); }
public T withType(String type) { return attr(Attr.TYPE, type); }
public T withRel(String rel) { return attr(Attr.REL, rel); }
public T withRole(String role) { return attr(Attr.ROLE, role); }
public T withSrc(String src) { return attr(Attr.SRC, src); }
public T withStyle(String style) { return attr(Attr.STYLE, style); }
public T withValue(String value) { return attr(Attr.VALUE, value); }
public T withClasses(String... classes) {
StringBuilder sb = new StringBuilder();
for (String s : classes) {
sb.append(s != null ? s : "").append(" ");
}
return attr(Attr.CLASS, sb.toString().trim());
}
public T withCondAutoComplete(boolean condition) { return condAttr(condition, Attr.AUTOCOMPLETE, null); }
public T withCondAutoFocus(boolean condition) { return condAttr(condition, Attr.AUTOFOCUS, null); }
public T withCondHidden(boolean condition) { return condAttr(condition, Attr.HIDDEN, null); }
public T withCondRequired(boolean condition) { return condAttr(condition, Attr.REQUIRED, null); }
public T withCondAlt(boolean condition, String alt) { return condAttr(condition, Attr.ALT, alt); }
public T withCondAction(boolean condition, String action) { return condAttr(condition, Attr.ACTION, action); }
public T withCharset(boolean condition, String charset) { return condAttr(condition, Attr.CHARSET, charset); }
public T withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
public T withCondContent(boolean condition, String content) { return condAttr(condition, Attr.CONTENT, content); }
public T withCondHref(boolean condition, String href) { return condAttr(condition, Attr.HREF, href); }
public T withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
public T withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
public T withCondMethod(boolean condition, String method) { return condAttr(condition, Attr.METHOD, method); }
public T withCondName(boolean condition, String name) { return condAttr(condition, Attr.NAME, name); }
public T withCondPlaceholder(boolean condition, String placeholder) { return condAttr(condition, Attr.PLACEHOLDER, placeholder); }
public T withCondTarget(boolean condition, String target) { return condAttr(condition, Attr.TARGET, target); }
public T withCondType(boolean condition, String type) { return condAttr(condition, Attr.TYPE, type); }
public T withCondRel(boolean condition, String rel) { return condAttr(condition, Attr.REL, rel); }
public T withCondSrc(boolean condition, String src) { return condAttr(condition, Attr.SRC, src); }
public T withCondStyle(boolean condition, String style) { return condAttr(condition, Attr.STYLE, style); }
public T withCondValue(boolean condition, String value) { return condAttr(condition, Attr.VALUE, value); }
public T isAutoComplete() {
return attr(Attr.AUTOCOMPLETE, null);
}
public T isAutoFocus() {
return attr(Attr.AUTOFOCUS, null);
}
public T isHidden() {
return attr(Attr.HIDDEN, null);
}
public T isRequired() {
return attr(Attr.REQUIRED, null);
}
public T withAlt(String alt) {
return attr(Attr.ALT, alt);
}
public T withAction(String action) {
return attr(Attr.ACTION, action);
}
public T withCharset(String charset) {
return attr(Attr.CHARSET, charset);
}
public T withClass(String className) {
return attr(Attr.CLASS, className);
}
public T withContent(String content) {
return attr(Attr.CONTENT, content);
}
public T withDir(String dir) {
return attr(Attr.DIR, dir);
}
public T withHref(String href) {
return attr(Attr.HREF, href);
}
public T withId(String id) {
return attr(Attr.ID, id);
}
public T withData(String dataAttr, String value) {
return attr(Attr.DATA + "-" + dataAttr, value);
}
public T withLang(String lang) {
return attr(Attr.LANG, lang);
}
public T withMethod(String method) {
return attr(Attr.METHOD, method);
}
public T withName(String name) {
return attr(Attr.NAME, name);
}
public T withPlaceholder(String placeholder) {
return attr(Attr.PLACEHOLDER, placeholder);
}
public T withTarget(String target) {
return attr(Attr.TARGET, target);
}
public T withTitle(String title) {
return attr(Attr.TITLE, title);
}
public T withType(String type) {
return attr(Attr.TYPE, type);
}
public T withRel(String rel) {
return attr(Attr.REL, rel);
}
public T withRole(String role) {
return attr(Attr.ROLE, role);
}
public T withSrc(String src) {
return attr(Attr.SRC, src);
}
public T withStyle(String style) {
return attr(Attr.STYLE, style);
}
public T withValue(String value) {
return attr(Attr.VALUE, value);
}
public T withCondAutoComplete(boolean condition) {
return condAttr(condition, Attr.AUTOCOMPLETE, null);
}
public T withCondAutoFocus(boolean condition) {
return condAttr(condition, Attr.AUTOFOCUS, null);
}
public T withCondHidden(boolean condition) {
return condAttr(condition, Attr.HIDDEN, null);
}
public T withCondRequired(boolean condition) {
return condAttr(condition, Attr.REQUIRED, null);
}
public T withCondAlt(boolean condition, String alt) {
return condAttr(condition, Attr.ALT, alt);
}
public T withCondAction(boolean condition, String action) {
return condAttr(condition, Attr.ACTION, action);
}
public T withCharset(boolean condition, String charset) {
return condAttr(condition, Attr.CHARSET, charset);
}
public T withCondClass(boolean condition, String className) {
return condAttr(condition, Attr.CLASS, className);
}
public T withCondContent(boolean condition, String content) {
return condAttr(condition, Attr.CONTENT, content);
}
public T withCondDir(boolean condition, String dir) {
return condAttr(condition, Attr.DIR, dir);
}
public T withCondHref(boolean condition, String href) {
return condAttr(condition, Attr.HREF, href);
}
public T withCondId(boolean condition, String id) {
return condAttr(condition, Attr.ID, id);
}
public T withCondData(boolean condition, String dataAttr, String value) {
return condAttr(condition, Attr.DATA + "-" + dataAttr, value);
}
public T withCondLang(boolean condition, String lang) {
return condAttr(condition, Attr.LANG, lang);
}
public T withCondMethod(boolean condition, String method) {
return condAttr(condition, Attr.METHOD, method);
}
public T withCondName(boolean condition, String name) {
return condAttr(condition, Attr.NAME, name);
}
public T withCondPlaceholder(boolean condition, String placeholder) {
return condAttr(condition, Attr.PLACEHOLDER, placeholder);
}
public T withCondTarget(boolean condition, String target) {
return condAttr(condition, Attr.TARGET, target);
}
public T withCondTitle(boolean condition, String title) {
return condAttr(condition, Attr.TITLE, title);
}
public T withCondType(boolean condition, String type) {
return condAttr(condition, Attr.TYPE, type);
}
public T withCondRel(boolean condition, String rel) {
return condAttr(condition, Attr.REL, rel);
}
public T withCondSrc(boolean condition, String src) {
return condAttr(condition, Attr.SRC, src);
}
public T withCondStyle(boolean condition, String style) {
return condAttr(condition, Attr.STYLE, style);
}
public T withCondValue(boolean condition, String value) {
return condAttr(condition, Attr.VALUE, value);
}
}

View File

@@ -0,0 +1,167 @@
package j2html.tags;
import java.util.Arrays;
import java.util.List;
class TagCreatorCodeGenerator {
public static void main(String[] args) {
System.out.println("// EmptyTags, generated in " + TagCreatorCodeGenerator.class);
for (String tag : emptyTags()) {
String emptyA1 = "public static EmptyTag " + tag + "()";
String emptyA2 = "{ return new EmptyTag(\"" + tag + "\"); }";
// Attr shorthands
String emptyB1 = "public static EmptyTag " + tag + "(Attr.ShortForm shortAttr)";
String emptyB2 = "{ return Attr.addTo(new EmptyTag(\"" + tag + "\"), shortAttr); }";
// Print
System.out.println(String.format("%-80s%1s", emptyA1, emptyA2));
System.out.println(String.format("%-80s%1s", emptyB1, emptyB2));
System.out.println("");
}
System.out.println("// ContainerTags, generated in " + TagCreatorCodeGenerator.class);
for (String tag : containerTags()) {
String containerA1 = "public static ContainerTag " + tag + "()";
String containerA2 = "{ return new ContainerTag(\"" + tag + "\"); }";
String containerB1 = "public static ContainerTag " + tag + "(String text)";
String containerB2 = "{ return new ContainerTag(\"" + tag + "\").withText(text); }";
String containerC1 = "public static ContainerTag " + tag + "(DomContent... dc)";
String containerC2 = "{ return new ContainerTag(\"" + tag + "\").with(dc); }";
// Attr shorthands
String containerD1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr)";
String containerD2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\"), shortAttr); }";
String containerE1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr, String text)";
String containerE2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\").withText(text), shortAttr); }";
String containerF1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr, DomContent... dc)";
String containerF2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\").with(dc), shortAttr); }";
// Print
System.out.println(String.format("%-80s%1s", containerA1, containerA2));
System.out.println(String.format("%-80s%1s", containerB1, containerB2));
System.out.println(String.format("%-80s%1s", containerC1, containerC2));
System.out.println(String.format("%-80s%1s", containerD1, containerD2));
System.out.println(String.format("%-80s%1s", containerE1, containerE2));
System.out.println(String.format("%-80s%1s", containerF1, containerF2));
System.out.println("");
}
}
// This is a method that contains all ContainerTags, there is nothing below it
private static List<String> emptyTags() {
return Arrays.asList(
"area",
"base",
"br",
"col",
//"!DOCTYPE html",
"embed",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr"
);
}
private static List<String> containerTags() {
return Arrays.asList(
"a",
"abbr",
"address",
"article",
"aside",
"audio",
"b",
"bdi",
"bdo",
"blockquote",
"body",
"button",
"canvas",
"caption",
"cite",
"code",
"colgroup",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"html",
"i",
"iframe",
"ins",
"kbd",
"label",
"legend",
"li",
"main",
"map",
"mark",
"menu",
"menuitem",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"small",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"u",
"ul",
"var",
"video"
);
}
}

View File

@@ -1,6 +1,7 @@
package j2html.tags;
import j2html.utils.SimpleEscaper;
import j2html.Config;
import java.io.IOException;
public class Text extends DomContent {
@@ -11,8 +12,13 @@ public class Text extends DomContent {
}
@Override
public String render() {
return SimpleEscaper.escape(text);
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append(Config.textEscaper.escape(text));
}
}

View File

@@ -1,5 +1,7 @@
package j2html.tags;
import java.io.IOException;
public class UnescapedText extends DomContent {
private String text;
@@ -9,8 +11,13 @@ public class UnescapedText extends DomContent {
}
@Override
public String render() {
return text;
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append(text);
}
}

View File

@@ -1,4 +1,4 @@
/**
/*
* * CSSMin Copyright License Agreement (BSD License)
* <p>
* Copyright (c) 2011-2014, Barry van Oudtshoorn
@@ -79,11 +79,11 @@ public class CSSMin {
* @param input the CSS
* @return the compressed version
*/
public static String compress(String input) {
public static String compressCss(String input) {
try {
int k,
j, // Number of open braces
n; // Current position in stream
j, // Number of open braces
n; // Current position in stream
char curr;
BufferedReader br = new BufferedReader(new StringReader(input));
@@ -224,7 +224,8 @@ class Selector {
if (contents.length() == 1) {
throw new EmptySelectorBodyException(selector);
}
contents = contents.substring(0, contents.length() - 2);
int endIndex = contents.endsWith(";}") ? 2 : 1;
contents = contents.substring(0, contents.length() - endIndex);
this.properties = new Property[0];
this.properties = parseProperties(contents).toArray(this.properties);
@@ -266,7 +267,7 @@ class Selector {
private ArrayList<Property> parseProperties(String contents) {
ArrayList<String> parts = new ArrayList<>();
boolean bInsideString = false,
bInsideURL = false;
bInsideURL = false;
int j = 0;
String substr;
for (int i = 0; i < contents.length(); i++) {

View File

@@ -0,0 +1,36 @@
package j2html.utils;
public class EscapeUtil {
public static String escape(String s) {
if (s == null) {
return null;
}
StringBuilder escapedText = new StringBuilder();
char currentChar;
for (int i = 0; i < s.length(); i++) {
currentChar = s.charAt(i);
switch (currentChar) {
case '<':
escapedText.append("&lt;");
break;
case '>':
escapedText.append("&gt;");
break;
case '&':
escapedText.append("&amp;");
break;
case '"':
escapedText.append("&quot;");
break;
case '\'':
escapedText.append("&#x27;");
break;
default:
escapedText.append(currentChar);
}
}
return escapedText.toString();
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface Indenter {
String indent(int level, String text);
}

View File

@@ -1,43 +1,42 @@
package j2html.utils;
/*
* JSMin.java 2006-02-13
*
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
*
* This work is a translation from C to Java of jsmin.c published by
* Douglas Crockford. Permission is hereby granted to use the Java
* version under the same conditions as the jsmin.c on which it is
* based.
*
*
*
*
* jsmin.c 2003-04-21
*
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// package org.inconspicuous.jsmin;
/*
* JSMin.java 2006-02-13
*
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
*
* This work is a translation from C to Java of jsmin.c published by
* Douglas Crockford. Permission is hereby granted to use the Java
* version under the same conditions as the jsmin.c on which it is
* based.
*
*
*
*
* jsmin.c 2003-04-21
*
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -46,7 +45,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
public class JSMin {
/**
@@ -62,7 +60,7 @@ public class JSMin {
try {
jsmin.jsmin();
return outStream.toString().trim();
} catch (IOException | UnterminatedRegExpLiteralException | UnterminatedCommentException | UnterminatedStringLiteralException e) {
} catch (Exception e) {
e.printStackTrace();
return "";
}
@@ -87,12 +85,12 @@ public class JSMin {
*/
private static boolean isAlphanum(int c) {
return ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
c == '_' ||
c == '$' ||
c == '\\' ||
c > 126);
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
c == '_' ||
c == '$' ||
c == '\\' ||
c > 126);
}
/**
@@ -172,7 +170,7 @@ public class JSMin {
*/
private void action(int d) throws IOException, UnterminatedRegExpLiteralException,
UnterminatedCommentException, UnterminatedStringLiteralException {
UnterminatedCommentException, UnterminatedStringLiteralException {
switch (d) {
case 1:
out.write(theA);
@@ -302,4 +300,4 @@ public class JSMin {
private class UnterminatedRegExpLiteralException extends Exception {
}
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface Minifier {
String minify(String s);
}

View File

@@ -1,28 +0,0 @@
package j2html.utils;
import java.util.HashMap;
import java.util.Map;
public class SimpleEscaper {
private static Map<Character, String> map = new HashMap<Character, String>() {{
put('&', "&amp;");
put('<', "&lt;");
put('>', "&gt;");
put('"', "&quot;");
put('\'', "&#x27;");
}};
public static String escape(String s) {
if(s == null) {
return null;
}
String escapedString = "";
for(char c : s.toCharArray()) {
String escaped = map.get(c);
escapedString += escaped != null ? escaped : c;
}
return escapedString;
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface TextEscaper {
String escape(String text);
}

View File

@@ -0,0 +1 @@
public class AnyContent{}

7
src/test/files/test.css Normal file
View File

@@ -0,0 +1,7 @@
body {
background: goldenrod;
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
}

3
src/test/files/test.html Normal file
View File

@@ -0,0 +1,3 @@
<body>
Any content
</body>

6
src/test/files/test.js Normal file
View File

@@ -0,0 +1,6 @@
(function () {
var test = 5;
var tast = 10;
var testTast = test + tast;
console.log(testTast);
})();

View File

@@ -0,0 +1,59 @@
package j2html;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
import com.carrotsearch.junitbenchmarks.Clock;
import j2html.utils.EscapeUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@BenchmarkOptions(callgc = false, benchmarkRounds = 10000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
public class PerformanceTest {
@Rule
public TestRule benchmarkRun = new BenchmarkRule();
private String shortTestString = "<body>\n"
+ " <h1 class=\"example\">Heading!</h1>\n"
+ " <img src=\"img/hello.png\">\n"
+ "</body>";
// syntax-highlighted getting started example from j2html.com:
private String longTestString =
"<pre class=\" language-java\"><code class=\" language-java\"><span class=\"token keyword\">import</span> <span class=\"token keyword\">static</span> j2html<span class=\"token punctuation\">.</span>TagCreator<span class=\"token punctuation\">.</span>*<span class=\"token punctuation\">;</span>\n"
+ "\n"
+ "<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Main</span> <span class=\"token punctuation\">{</span>\n"
+ " <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">void</span> <span class=\"token function\">main<span class=\"token punctuation\">(</span></span>String<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> args<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n"
+ " <span class=\"token function\">body<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">with<span class=\"token punctuation\">(</span></span>\n"
+ " <span class=\"token function\">h1<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"Heading!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">withClass<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"example\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n"
+ " <span class=\"token function\">img<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">withSrc<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"img/hello.png\"</span><span class=\"token punctuation\">)</span>\n"
+ " <span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n"
+ " <span class=\"token punctuation\">}</span>\n"
+ "<span class=\"token punctuation\">}</span>\n"
+ "</code></pre>";
@Test
public void testSimpleEscaperShort() throws Exception {
EscapeUtil.escape(shortTestString);
}
@Test
public void testSimpleEscaperLong() throws Exception {
EscapeUtil.escape(longTestString);
}
@Test
public void testApacheEscaperShort() throws Exception {
StringEscapeUtils.escapeHtml4(shortTestString);
}
@Test
public void testApacheEscaperLong() throws Exception {
StringEscapeUtils.escapeHtml4(longTestString);
}
}

View File

@@ -0,0 +1,124 @@
package j2html;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.h1;
import static j2html.TagCreator.h2;
import static j2html.TagCreator.head;
import static j2html.TagCreator.html;
import static j2html.TagCreator.p;
import static j2html.TagCreator.title;
import static org.junit.Assert.assertEquals;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
import com.carrotsearch.junitbenchmarks.Clock;
import j2html.model.BrowserTitle;
import j2html.model.Button;
import j2html.model.ButtonModel;
import j2html.model.PageModel;
import j2html.model.TextTemplate;
import j2html.tags.DomContent;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@BenchmarkOptions(callgc = false, benchmarkRounds = 50000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
public class RenderPerformanceTest {
String expected = "<html><head><title>Browsertitle</title></head><body><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div class=\"button\"><div class=\"button-text\">Action!</div></div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></body></html>";
@Rule
public TestRule benchmarkRun = new BenchmarkRule();
private DomContent template;
public RenderPerformanceTest() {
this.template =
// @formatter:off
html(
head(
title(new BrowserTitle())
),
body(
h1(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),new TextTemplate()),
new Button(),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h1(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate())))))))))))))))))))))))))))
)
);
// @formatter:on
}
private DomContent getDomContent(PageModel pageModel) throws Exception {
return
// @formatter:off
html(
head(
title(pageModel.getTitle())
),
body(
h1(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"), pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),pageModel.getText()),
div()
.withClass("button")
.with(
div()
.withClass("button-text")
.withText(pageModel.getButtonModel().getText())
),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h1(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText())))))))))))))))))))))))))))
)
);
// @formatter:on
}
@Test
public void templatePerfomanceTest() throws Exception {
PageModel pageModel = new PageModel("Browsertitle", "Hello World!", new ButtonModel("Action!"));
StringBuilder stringBuilder = new StringBuilder();
template.renderModel(stringBuilder, pageModel);
assertEquals(expected, stringBuilder.toString());
}
@Test
public void staticPerfomanceTest() throws Exception {
PageModel pageModel = new PageModel("Browsertitle", "Hello World!", new ButtonModel("Action!"));
String result = getDomContent(pageModel).render();
assertEquals(expected, result);
}
}

View File

@@ -0,0 +1,37 @@
package j2html;
import j2html.utils.EscapeUtil;
import j2html.utils.TextEscaper;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class TextEscaperTest {
@Test
public void testTextEscaper() throws Exception {
String expected = "&lt;div&gt;&lt;/div&gt;";
assertThat("default text escaper works",
Config.textEscaper.escape("<div></div>"), is(expected));
Config.textEscaper = new NoOpEscaper();
assertThat("user can change text escaper implementation",
Config.textEscaper, is(instanceOf(NoOpEscaper.class)));
expected = "<div></div>";
assertThat("user provided text escaper actually works",
Config.textEscaper.escape("<div></div>"), is(expected));
Config.textEscaper = EscapeUtil::escape; // reset escaper
}
private static class NoOpEscaper implements TextEscaper {
@Override
public String escape(String text) {
return text;
}
}
}

View File

@@ -0,0 +1,62 @@
package j2html.attributes;
import org.junit.Test;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.div;
import static j2html.TagCreator.input;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class AttrShortFormTest {
@Test
public void addTo_emptyTag() throws Exception {
String expected = "<input id=\"some-id\" class=\"some-class\">";
String actual = input(attrs("#some-id.some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_containerTag() throws Exception {
String expected = "<div id=\"some-id\" class=\"some-class\"></div>";
String actual = div(attrs("#some-id.some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_justId() throws Exception {
String expected = "<div id=\"some-id\"></div>";
String actual = div(attrs("#some-id")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_justClass() throws Exception {
String expected = "<div class=\"some-class\"></div>";
String actual = div(attrs(".some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_addTwoClasses() throws Exception {
String expected = "<div class=\"some-class some-other-class\"></div>";
String actual = div(attrs(".some-class.some-other-class")).render();
assertThat(actual, is(expected));
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithoutIdOrClass() throws Exception {
div(attrs("some-class")).render();
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithTwoIds() throws Exception {
div(attrs("#id1#id2")).render();
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithStupidlyPlacedId() throws Exception {
div(attrs("id1#id2")).render();
}
}

View File

@@ -1,9 +1,7 @@
package j2html.attributes;
import org.junit.Test;
import j2html.tags.ContainerTag;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

View File

@@ -0,0 +1,11 @@
package j2html.model;
import java.io.IOException;
public class BrowserTitle extends Template<PageModel> {
@Override
public void renderTemplate(Appendable writer, PageModel pageModel) throws IOException {
writer.append(pageModel.getTitle());
}
}

View File

@@ -0,0 +1,40 @@
package j2html.model;
import static j2html.TagCreator.div;
import java.io.IOException;
import j2html.tags.ContainerTag;
public class Button extends Template<PageModel> {
private ContainerTag template;
public Button() {
// @formatter:off
template =
div()
.withClass("button")
.with(
div()
.withClass("button-text")
.with(
new ButtonText()
)
);
// @formatter:on
}
@Override
public void renderTemplate(Appendable writer, PageModel model) throws IOException {
template.renderModel(writer, model.getButtonModel().getText());
}
}
class ButtonText extends Template<String> {
@Override
public void renderTemplate(Appendable writer, String model) throws IOException {
writer.append(model);
}
}

View File

@@ -0,0 +1,12 @@
package j2html.model;
public class ButtonModel {
private String text;
public ButtonModel(String text) {
this.text = text;
}
public String getText() {
return text;
}
}

View File

@@ -0,0 +1,26 @@
package j2html.model;
public class PageModel {
private String title;
private String text;
private ButtonModel buttonModel;
public PageModel(String title, String text, ButtonModel buttonModel) {
this.title = title;
this.text = text;
this.buttonModel = buttonModel;
}
public ButtonModel getButtonModel() {
return buttonModel;
}
public String getTitle() {
return title;
}
public String getText() {
return text;
}
}

View File

@@ -0,0 +1,16 @@
package j2html.model;
import java.io.IOException;
import j2html.tags.DomContent;
public abstract class Template<T> extends DomContent {
@Override
@SuppressWarnings("unchecked")
public final void renderModel(Appendable writer, Object model) throws IOException {
renderTemplate(writer, (T) model);
}
public abstract void renderTemplate(Appendable writer, T model) throws IOException;
}

View File

@@ -0,0 +1,11 @@
package j2html.model;
import java.io.IOException;
public class TextTemplate extends Template<PageModel> {
@Override
public void renderTemplate(Appendable writer, PageModel pageModel) throws IOException {
writer.append(pageModel.getText());
}
}

View File

@@ -1,9 +1,7 @@
package j2html.tags;
import org.junit.Test;
import j2html.attributes.Attr;
import org.junit.Test;
import static j2html.TagCreator.a;
import static j2html.TagCreator.body;
import static j2html.TagCreator.button;
@@ -15,6 +13,7 @@ import static j2html.TagCreator.h2;
import static j2html.TagCreator.head;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.iff;
import static j2html.TagCreator.input;
import static j2html.TagCreator.main;
import static j2html.TagCreator.script;
@@ -29,35 +28,139 @@ public class ComplexRenderTest {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() +
html().with(
head().with(
title().withText("Test")
),
body().with(
header().with(
h1().with(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main().with(
h2("Test Form"),
div().with(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password")
).condWith(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")
).condWith(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
),
footer().attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id").withText("Test Footer"),
script().withSrc("/testScript.js")
html().with(
head().with(
title().withText("Test")
),
body().with(
header().with(
h1().with(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
).render();
),
main().with(
h2("Test Form"),
div().with(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password")
).condWith(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")
).condWith(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
),
footer().attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id").withText("Test Footer"),
script().withSrc("/testScript.js")
)
).render();
}
private String renderTest2() {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() +
html(
head(
title("Test")
),
body(
header(
h1(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main(
h2("Test Form"),
div(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password"),
iff(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")),
iff(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
)
),
footer("Test Footer").attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id"),
script().withSrc("/testScript.js")
)
).render();
}
private String renderTest3() {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() + "\n" +
html(
head(
title("Test")
),
body(
header(
h1(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main(
h2("Test Form"),
div(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password"),
iff(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")),
iff(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
)
),
footer("Test Footer").attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id"),
script().withSrc("/testScript.js")
)
).renderFormatted();
}
@Test
public void testComplexRender() {
String expectedResult = "<!DOCTYPE html><html><head><title>Test</title></head><body><header><h1>Test Header <a href=\"http://example.com\">with link</a>.</h1></header><main><h2>Test Form</h2><div><input type=\"email\" name=\"email\" placeholder=\"Email\"><input type=\"password\" name=\"password\" placeholder=\"Password\"><button type=\"submit\">Login</button></div></main><footer class=\"footer\" id=\"id\">Test Footer</footer><script src=\"/testScript.js\"></script></body></html>";
assertThat(renderTest(), is(expectedResult));
assertThat(renderTest2(), is(expectedResult));
}
@Test
public void testComplexRender_formatted() {
assertThat(renderTest3(),
is("<!DOCTYPE html>\n"
+ "<html>\n"
+ " <head>\n"
+ " <title>\n"
+ " Test\n"
+ " </title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <header>\n"
+ " <h1>\n"
+ " Test Header \n"
+ " <a href=\"http://example.com\">\n"
+ " with link\n"
+ " </a>\n"
+ " .\n"
+ " </h1>\n"
+ " </header>\n"
+ " <main>\n"
+ " <h2>\n"
+ " Test Form\n"
+ " </h2>\n"
+ " <div>\n"
+ " <input type=\"email\" name=\"email\" placeholder=\"Email\">\n"
+ " <input type=\"password\" name=\"password\" placeholder=\"Password\">\n"
+ " <button type=\"submit\">\n"
+ " Login\n"
+ " </button>\n"
+ " </div>\n"
+ " </main>\n"
+ " <footer class=\"footer\" id=\"id\">\n"
+ " Test Footer\n"
+ " </footer>\n"
+ " <script src=\"/testScript.js\">\n"
+ " </script>\n"
+ " </body>\n"
+ "</html>\n"));
}
}

View File

@@ -1,7 +1,6 @@
package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.a;
import static j2html.TagCreator.div;
import static j2html.TagCreator.form;
@@ -32,6 +31,7 @@ public class ConvenienceMethodTest {
assertThat(input().withName("test-name").render(), is("<input name=\"test-name\">"));
assertThat(input().withPlaceholder("test-placeholder").render(), is("<input placeholder=\"test-placeholder\">"));
assertThat(a().withTarget("_blank").render(), is("<a target=\"_blank\"></a>"));
assertThat(a().withTitle("Title").render(), is("<a title=\"Title\"></a>"));
assertThat(input().withType("email").render(), is("<input type=\"email\">"));
assertThat(link().withRel("stylesheet").render(), is("<link rel=\"stylesheet\">"));
assertThat(link().withRole("role").render(), is("<link role=\"role\">"));

View File

@@ -0,0 +1,45 @@
package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.fileAsEscapedString;
import static j2html.TagCreator.fileAsString;
import static j2html.TagCreator.scriptWithInlineFile_min;
import static j2html.TagCreator.styleWithInlineFile_min;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class InlineStaticResourceTest {
private static final String EOL = System.getProperty("line.separator"); // System independent End Of Line
@Test
public void testAllTags() throws Exception {
String expectedCss = "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>";
String expectedJs = "<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>";
String expectedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
String expectedEscapedHtml = "&lt;body&gt;" + EOL + " Any content" + EOL + "&lt;/body&gt;" + EOL;
String expectedAnyContent = "public class AnyContent{}" + EOL;
// classpath files
assertThat(styleWithInlineFile_min("/test.css").render(), is(expectedCss));
assertThat(styleWithInlineFile_min("/test-without-trailing-semis.css").render(), is(expectedCss));
assertThat(scriptWithInlineFile_min("/test.js").render(), is(expectedJs));
assertThat(fileAsString("/test.html").render(), is(expectedHtml));
assertThat(fileAsEscapedString("/test.html").render(), is(expectedEscapedHtml));
assertThat(fileAsString("/AnyContent.java").render(), is(expectedAnyContent));
// files outside classpath
assertThat(styleWithInlineFile_min("src/test/files/test.css").render(), is(expectedCss));
assertThat(scriptWithInlineFile_min("src/test/files/test.js").render(), is(expectedJs));
assertThat(fileAsString("src/test/files/test.html").render(), is(expectedHtml));
assertThat(fileAsEscapedString("src/test/files/test.html").render(), is(expectedEscapedHtml));
assertThat(fileAsString("src/test/files/AnyContent.java").render(), is(expectedAnyContent));
}
@Test(expected = RuntimeException.class)
public void testExceptionForBadPath() throws Exception {
styleWithInlineFile_min("NOT A FILE");
}
}

View File

@@ -1,14 +1,15 @@
package j2html.tags;
import j2html.Config;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Ignore;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
public class TagCreatorTest {
@@ -16,41 +17,79 @@ public class TagCreatorTest {
List<Employee> employees = Arrays.asList(new Employee(1, "Name 1", "Title 1"), new Employee(2, "Name 2", "Title 2"), new Employee(3, "Name 3", "Title 3"));
@Test
public void testDocument() throws Exception {
Config.closeEmptyTags = true;
assertEquals("<!DOCTYPE html>", document().render());
assertEquals("<!DOCTYPE html><html></html>", document(html()));
Config.closeEmptyTags = false;
assertEquals("<!DOCTYPE html>", document().render());
assertEquals("<!DOCTYPE html><html></html>", document(html()));
}
@Test
public void testIff() throws Exception {
String expected = "<div><p>Test</p><a href=\"#\">Test</a></div>";
String actual = div(
p("Test"),
iff(1 == 1, a("Test").withHref("#")),
iff(1 == 2, a("Tast").withHref("#"))
).render();
assertThat(actual, is(expected));
}
@Test
public void testIffElse() throws Exception {
String expected = "<div><p>Tast</p></div>";
String actual = div(iffElse(1 == 2, p("Test"), p("Tast"))).render();
assertThat(actual, is(expected));
}
@Test
public void testJoin() throws Exception {
String expected = "This is my joined string. It has a <a href=\"#\">link in the middle</a> and <code>code at the end</code>.";
String actual = join("This is my joined string. It has a", a("link in the middle").withHref("#"), "and", code("code at the end"), ".").render();
assertThat(actual, is(expected));
}
@Test
@Ignore // Having some trouble with RetroLambda setup
public void testEach() throws Exception {
String j2htmlMap = ul().with(
li("Begin list"),
each(employees, employee -> li().with(
h2(employee.name),
p(employee.title)
))
li("Begin list"),
each(employees, employee -> li(
h2(employee.name),
p(employee.title)
))
).render();
String javaMap = ul().with(
li("Begin list"),
rawHtml(employees.stream().map(employee -> li().with(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
li("Begin list"),
rawHtml(employees.stream().map(employee -> li(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
).render();
assertThat(j2htmlMap.equals(javaMap), is(true));
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li><h2>Name 1</h2><p>Title 1</p></li><li><h2>Name 2</h2><p>Title 2</p></li><li><h2>Name 3</h2><p>Title 3</p></li></ul>"));
}
@Test
@Ignore // Having some trouble with RetroLambda setup
public void testFilter() throws Exception {
String j2htmlFilter = ul().with(
li("Begin list"),
each(filter(employees, e -> e.id % 2 == 1), employee -> li().with(
h2(employee.name),
p(employee.title)
))
li("Begin list"),
each(filter(employees, e -> e.id % 2 == 1), employee -> li(
h2(employee.name),
p(employee.title)
))
).render();
String javaFilter = ul().with(
li("Begin list"),
rawHtml(employees.stream().filter(e -> e.id % 2 == 1).map(employee -> li().with(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
li("Begin list"),
rawHtml(employees.stream().filter(e -> e.id % 2 == 1).map(employee -> li(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
).render();
assertThat(j2htmlFilter.equals(javaFilter), is(true));
assertThat(j2htmlFilter, is("<ul><li>Begin list</li><li><h2>Name 1</h2><p>Title 1</p></li><li><h2>Name 3</h2><p>Title 3</p></li></ul>"));
@@ -65,11 +104,6 @@ public class TagCreatorTest {
assertThat(text("text").render(), is("text"));
assertThat(text("<script> and \"</script>\"").render(), is("&lt;script&gt; and &quot;&lt;/script&gt;&quot;"));
assertThat(rawHtml("<script>").render(), is("<script>"));
assertThat(styleWithInlineFile_min("/test.css").render(), is("<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>"));
assertThat(scriptWithInlineFile_min("/test.js").render(), is("<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>"));
assertThat(fileAsString("/test.html").render(), is("<body>" + EOL + " Any content" + EOL + "</body>" + EOL));
assertThat(fileAsEscapedString("/test.html").render(), is("&lt;body&gt;" + EOL + " Any content" + EOL + "&lt;/body&gt;" + EOL));
assertThat(fileAsString("/AnyContent.java").render(), is("public class AnyContent{}" + EOL));
//EmptyTags
assertThat(document().render(), is("<!DOCTYPE html>"));

View File

@@ -1,11 +1,15 @@
package j2html.tags;
import j2html.Config;
import org.junit.Test;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.footer;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.iff;
import static j2html.TagCreator.img;
import static j2html.TagCreator.input;
import static j2html.TagCreator.main;
import static j2html.TagCreator.p;
import static j2html.TagCreator.tag;
@@ -42,6 +46,19 @@ public class TagTest {
assertThat(testTag.renderCloseTag(), is("</a>"));
}
@Test
public void testSelfClosingTags() throws Exception {
Config.closeEmptyTags = true;
assertThat(img().withSrc("/test.png").render(), is("<img src=\"/test.png\"/>"));
assertThat(input().withType("text").render(), is("<input type=\"text\"/>"));
Config.closeEmptyTags = false;
}
@Test
public void testFormattedTags() throws Exception { // better test in ComplexRenderTest.java
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
}
@Test
public void testEquals() throws Exception {
Tag tagOne = tag("p").withClass("class").withText("Test");
@@ -49,4 +66,31 @@ public class TagTest {
assertThat(tagOne.equals(tagTwo), is(true));
}
@Test
public void testAcceptObjectValueAttribute() throws Exception {
ContainerTag complexTestTag = new ContainerTag("input")
.attr("attr1", "value1")
.attr("attr2", 2)
.attr("attr3", null);
String expectedResult = "<input attr1=\"value1\" attr2=\"2\" attr3>";
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
}
@Test
public void testWithClasses() throws Exception {
String expected = "<div class=\"c1 c2\"></div>";
String actual = div().withClasses("c1", iff(1 == 1, "c2"), iff(1 == 2, "c3")).render();
assertThat(actual, is(expected));
}
@Test
public void testEmptyAttribute() throws Exception {
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr("attribute", null);
assertThat(testTagWithAttrValueNull.render(), is("<a attribute></a>"));
ContainerTag testTagAttrWithoutAttr = new ContainerTag("a").attr("attribute");
assertThat(testTagAttrWithoutAttr.render(), is("<a attribute></a>"));
}
}

View File

@@ -0,0 +1,7 @@
body {
background: goldenrod;
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px
}