52 Commits

Author SHA1 Message Date
David
10a400ac28 [maven-release-plugin] prepare release j2html-0.88 2017-01-29 21:32:34 +01:00
David
e0b0425da4 Remove stringutils and add simple escaper (#34) 2017-01-29 17:26:54 +01:00
David
f44d62d93a Change 'unsafeHtml' to 'rawHtml' (#44) 2017-01-29 16:43:50 +01:00
David
652b6921c7 Use assertThat instead of assertEquals 2017-01-29 16:27:19 +01:00
David
d7e56686d1 Add equals method to Tag (#28) 2017-01-29 15:49:36 +01:00
David
cc289b8430 Fix imports in rendertest 2017-01-29 14:46:14 +01:00
David
85d0ab023c Add withStyle method 2017-01-29 14:22:33 +01:00
David
0b3ca28cf3 Sort attributes 2017-01-29 14:16:14 +01:00
David
45a7c32d88 Auto format files 2017-01-29 13:20:18 +01:00
David
733199cd15 Remove closure in favor of a simple JSMin implementation
Closure is a great js-minifier, but js-minification is really
outside the scope of this project.
A simple space/line stripper should be suffcient.
2017-01-29 12:55:30 +01:00
David
df1e4da96d Autoformat CSSMin 2017-01-29 12:07:08 +01:00
David
05dcf6d679 Merge pull request #39 from dellgreen/java8doclintFixs
updated javadoc comments to pass doclint checks in java 8
2017-01-15 20:56:07 +01:00
David
b5d7f5fe18 Merge pull request #38 from dellgreen/renameTestResource
renamed test java resource to match its declared class name
2017-01-15 20:55:07 +01:00
David
872baeeeea Merge pull request #36 from charphi/optional-dep
Set closure-compiler dependency as optional.
2017-01-15 20:54:58 +01:00
David
fcc42cfd8f Merge pull request #35 from tipsy/pr/31
created render(Appendable)-method as a faster alternative to converting to string and writing then.
2017-01-15 20:54:47 +01:00
Dell Green
db8d968f7e updated javadoc comments to pass doclint checks in java 8 2017-01-13 11:42:11 +00:00
Dell Green
673a19faaa renamed test java resource to match its declared class name, otherwise Netbeans flags it as an error 2017-01-13 11:32:09 +00:00
Philippe Charles
96020f8396 Set closure-compiler dependency as optional. 2017-01-09 11:50:53 +01:00
Abius
91c3f42696 created render(Appendable)-method as a faster alternative to converting
to string and writing then.
2017-01-07 16:09:11 +01:00
David
0efd3c6f0c Tell travis to use latest sdk 2017-01-07 16:03:18 +01:00
David
b73c5d0c14 Merge pull request #27 from amaembo/master
Several cosmetic fixes
2016-06-12 10:19:00 +02:00
lan
977c31dad5 Cosmetic fixes:
1. Attr: all public static constants declared final
2. Tag: f-bounded type declaration
3. Tag::renderOpenTag: StringBuilder used
4. ContainerTag::with, condWith: Iterable and PECS arguments used
2016-06-06 15:49:08 +06:00
David
0c1cb2be10 Merge pull request #24 from DevFactory/release/general-code-quality-fix-1
Use isEmpty in TagContainer and collapse some if's in CSSMin
2016-04-26 22:36:27 +02:00
David
d09eb8597c Merge pull request #23 from DevFactory/release/exception-classes-should-be-immutable-fix-1
Code quality fix - Exception classes should be immutable.
2016-04-26 22:33:57 +02:00
David
b8a3882529 Merge pull request #22 from DevFactory/release/utility-classes-should-not-have-public-constructors-fix-1
Code quality fix - Utility classes should not have public constructors.
2016-04-26 22:33:12 +02:00
tipsy
b366207e30 Bump travis jdk version 2016-04-24 16:05:47 +02:00
tipsy
3821671a65 Add 'each' and 'filter' methods 2016-04-24 15:53:58 +02:00
Faisal Hameed
66fff8db69 Fixing squid:S1066, squid:S1155 2016-04-22 12:33:44 +05:00
Faisal Hameed
b11af765fa Fixing squid:S1165 - Exception classes should be immutable. 2016-04-22 12:03:36 +05:00
Faisal Hameed
d331789074 Fixing squid:S1118 - Utility classes should not have public constructors. 2016-04-22 11:55:40 +05:00
David
314de2459a Update README.md 2016-04-16 21:57:25 +02:00
tipsy
2beb4e903e Refactor core classes
- Introduce DomContent class with render method
- Make Tag and Text/UnescapedText extend DomContent (Text/UnescapedText don't extend Tag anymore)
- Use generics to remove duplicate code from ContainerTag and EmptyTag
- Remove setParent method
- Make setAttribute private
2016-04-02 18:08:37 +02:00
tipsy
d29da958e1 Auto format / organize imports 2016-04-01 22:45:01 +02:00
tipsy
595d658a15 Clean up CSSMin slightly 2016-04-01 22:44:42 +02:00
tipsy
dd4a025ad0 Add missing tests 2016-04-01 22:43:55 +02:00
David
3c42c7d4f4 Merge pull request #15 from arnzel/patch-1
Add Attribute "role"
2016-04-01 14:22:36 +02:00
Arne Zelasko
871405c414 Update EmptyTag.java 2016-04-01 10:54:22 +02:00
David
e7588aeb6a Merge pull request #16 from snaketl/master
Adjusted junit dependency to use only on scope test
2016-04-01 08:31:26 +02:00
Luiz Henrique Feltes
074aae4609 Adjusted junit dependency to use only on scope test 2016-03-31 21:10:17 -03:00
Arne Zelasko
66479f52c5 Update ContainerTag.java 2016-03-31 12:54:47 +02:00
Arne Zelasko
a5e79b536d Update Attr.java 2016-03-31 12:52:50 +02:00
tipsy
79e062355e Bump closure 2015-12-18 12:44:10 +01:00
David
947f12d5a1 Update README.md 2015-11-22 17:03:17 +01:00
tipsy
a46ba46bda Dat newline again 2015-11-22 16:39:41 +01:00
tipsy
41da131bbc Dat newline 2015-11-22 16:38:22 +01:00
tipsy
9428bf7397 Dat travis 2015-11-22 16:37:41 +01:00
tipsy
67e1c887b8 Formatting 2015-11-07 01:02:55 +01:00
David
bdd8dcbd2c Merge pull request #9 from ronanlg/master
Enable developpment under Linux and with Eclipse
2015-11-07 00:59:47 +01:00
RaG
b9d1f3a74d make end of line in test more independent from the OS 2015-11-06 20:56:00 +01:00
RaG
530565c9df add ignore rules specific to eclipse 2015-11-06 20:55:15 +01:00
David
30d1331c28 Update README.md 2015-10-25 11:45:11 +01:00
tipsy
58b2444ed4 [maven-release-plugin] prepare for next development iteration 2015-10-24 14:36:58 +02:00
24 changed files with 1169 additions and 675 deletions

5
.gitignore vendored
View File

@@ -93,4 +93,9 @@ pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
### Eclipse ###
.classpath
.project
.settings/
buildNumber.properties

8
.travis.yml Normal file
View File

@@ -0,0 +1,8 @@
language: java
jdk:
- oraclejdk8
sudo: false
addons:
apt:
packages:
- oracle-java8-installer

View File

@@ -1,7 +1,11 @@
![](https://img.shields.io/travis/tipsy/j2html.svg)
![](https://img.shields.io/github/license/tipsy/j2html.svg)
![](https://img.shields.io/maven-central/v/com.j2html/j2html.svg)
# j2html
Java to HTML generator. Enjoy typesafe HTML generation.
The project webpage is [j2html.com](http://j2html.com)
The project webpage is [j2html.com](http://j2html.com).
##Getting started
###Add the maven dependency
@@ -9,7 +13,7 @@ The project webpage is [j2html.com](http://j2html.com)
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.5.0</version>
<version>0.7</version>
</dependency>
```

22
pom.xml
View File

@@ -10,7 +10,7 @@
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.7</version>
<version>0.88</version>
<name>j2html</name>
<description>Java to HTML builder with a fluent API</description>
@@ -44,16 +44,13 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.google.javascript</groupId>
<artifactId>closure-compiler</artifactId>
<version>r2388</version>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -66,8 +63,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<source>1.8</source>
<target>1.8</target>
<optimize>true</optimize>
</configuration>
</plugin>
@@ -84,7 +81,7 @@
<configuration>
<rules>
<requireJavaVersion>
<version>[1.7,)</version>
<version>[1.8,)</version>
</requireJavaVersion>
</rules>
</configuration>
@@ -99,7 +96,6 @@
</configuration>
</plugin>
</plugins>
</build>
<profiles>

View File

@@ -1,24 +1,79 @@
package j2html;
import j2html.tags.*;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import j2html.tags.ContainerTag;
import j2html.tags.DomContent;
import j2html.tags.EmptyTag;
import j2html.tags.InlineStaticResource;
import j2html.tags.Text;
import j2html.tags.UnescapedText;
public class TagCreator {
private TagCreator() {}
/**
* Creates a DomContent object containing HTML using a mapping function on a collection
* Intended usage: {@literal each(numbers, n -> li(n.toString()))}
*
* @param <T> The derived generic parameter type
* @param collection the collection to iterate over, ex: a list of values "1, 2, 3"
* @param mapper the mapping function, ex: {@literal "n -> li(n.toString())"}
* @return rawHtml containing mapped data {@literal (ex. docs: <li>1</li><li>2</li><li>3</li>)}
*/
public static <T> DomContent each(Collection<T> collection, Function<? super T, DomContent> mapper) {
return rawHtml(collection.stream().map(mapper.andThen(DomContent::render)).collect(Collectors.joining()));
}
/**
* Filters a collection to a list, to be used with {@link j2html.TagCreator#each}
* Intended usage: {@literal each(filter(numbers, n -> n % 2 == 0), n -> li(n.toString()))}
*
* @param <T> The derived generic parameter type
* @param collection the collection to filter, ex: a list of values "1, 2, 3"
* @param filter the filter predicate, {@literal ex: "n -> n % 2 == 0"}
* @return the filtered collection as a list (ex. docs: 2)
*/
public static <T> List<T> filter(Collection<T> collection, Predicate<? super T> filter) {
return collection.stream().filter(filter).collect(Collectors.toList());
}
/**
* Wraps a String in an UnescapedText element
*
* @param html the input html
* @return the input html wrapped in an UnescapedText element
*/
public static UnescapedText rawHtml(String html) {
return new UnescapedText(html);
}
/**
* Wraps a String in a Text element (does html-escaping)
*
* @param text the input string
* @return the input string, html-escaped
*/
public static Text text(String text) {
return new Text(text);
}
//Special tags
public static ContainerTag tag(String tagName) { return new ContainerTag(tagName); }
public static EmptyTag emptyTag(String tagName) { return new EmptyTag(tagName); }
public static Text text(String text) { return new Text(text); }
public static UnescapedText unsafeHtml(String html) { return new UnescapedText(html); }
public static Tag styleWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS); }
public static Tag scriptWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS); }
public static Tag styleWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS_MIN); }
public static Tag scriptWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS_MIN); }
public static UnescapedText fileAsString(String path) { return new UnescapedText(InlineStaticResource.getFileAsString(path)); }
public static Text fileAsEscapedString(String path) { return new Text(InlineStaticResource.getFileAsString(path)); }
public static Text fileAsEscapedString(String path) { return text(InlineStaticResource.getFileAsString(path)); }
public static UnescapedText fileAsString(String path) { return rawHtml(InlineStaticResource.getFileAsString(path)); }
public static ContainerTag styleWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS); }
public static ContainerTag scriptWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS); }
public static ContainerTag styleWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS_MIN); }
public static ContainerTag scriptWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS_MIN); }
//EmptyTags
public static EmptyTag area() { return new EmptyTag("area"); }

View File

@@ -1,114 +1,119 @@
package j2html.attributes;
public class Attr {
public static String HIDDEN = "hidden";
public static String HIGH = "high";
public static String HREF = "href";
public static String HREFLANG = "hreflang";
public static String HTTP_EQUIV = "http-equiv";
public static String ICON = "icon";
public static String ID = "id";
public static String ISMAP = "ismap";
public static String ITEMPROP = "itemprop";
public static String KEYTYPE = "keytype";
public static String KIND = "kind";
public static String LABEL = "label";
public static String LANG = "lang";
public static String LANGUAGE = "language";
public static String LIST = "list";
public static String LOOP = "loop";
public static String LOW = "low";
public static String MANIFEST = "manifest";
public static String MAX = "max";
public static String MAXLENGTH = "maxlength";
public static String MEDIA = "media";
public static String METHOD = "method";
public static String MIN = "min";
public static String MULTIPLE = "multiple";
public static String NAME = "name";
public static String NOVALIDATE = "novalidate";
public static String OPEN = "open";
public static String OPTIMUM = "optimum";
public static String PATTERN = "pattern";
public static String PING = "ping";
public static String PLACEHOLDER = "placeholder";
public static String POSTER = "poster";
public static String PRELOAD = "preload";
public static String PUBDATE = "pubdate";
public static String RADIOGROUP = "radiogroup";
public static String READONLY = "readonly";
public static String REL = "rel";
public static String REQUIRED = "required";
public static String REVERSED = "reversed";
public static String ROWS = "rows";
public static String ROWSPAN = "rowspan";
public static String SANDBOX = "sandbox";
public static String SPELLCHECK = "spellcheck";
public static String SCOPE = "scope";
public static String SCOPED = "scoped";
public static String SEAMLESS = "seamless";
public static String SELECTED = "selected";
public static String SHAPE = "shape";
public static String SIZE = "size";
public static String SIZES = "sizes";
public static String SPAN = "span";
public static String SRC = "src";
public static String SRCDOC = "srcdoc";
public static String SRCLANG = "srclang";
public static String SRCSET = "srcset";
public static String START = "start";
public static String STEP = "step";
public static String STYLE = "style";
public static String SUMMARY = "summary";
public static String TABINDEX = "tabindex";
public static String TARGET = "target";
public static String TITLE = "title";
public static String TYPE = "type";
public static String USEMAP = "usemap";
public static String VALUE = "value";
public static String WIDTH = "width";
public static String WRAP = "wrap";
public static String BORDER = "border";
public static String BUFFERED = "buffered";
public static String CHALLENGE = "challenge";
public static String CHARSET = "charset";
public static String CHECKED = "checked";
public static String CITE = "cite";
public static String CLASS = "class";
public static String COLOR = "color";
public static String COLS = "cols";
public static String COLSPAN = "colspan";
public static String CONTENT = "content";
public static String CONTENTEDITABLE = "contenteditable";
public static String CONTEXTMENU = "contextmenu";
public static String CONTROLS = "controls";
public static String COORDS = "coords";
public static String DATA = "data";
public static String DATETIME = "datetime";
public static String DEFAULT = "default";
public static String DEFER = "defer";
public static String DIR = "dir";
public static String DIRNAME = "dirname";
public static String DISABLED = "disabled";
public static String DOWNLOAD = "download";
public static String DRAGGABLE = "draggable";
public static String DROPZONE = "dropzone";
public static String ENCTYPE = "enctype";
public static String FOR = "for";
public static String FORM = "form";
public static String FORMACTION = "formaction";
public static String HEADERS = "headers";
public static String HEIGHT = "height";
public static String ACCEPT = "accept";
public static String ACCEPT_CHARSET = "accept-charset";
public static String ACCESSKEY = "accesskey";
public static String ACTION = "action";
public static String ALIGN = "align";
public static String ALT = "alt";
public static String ASYNC = "async";
public static String AUTOCOMPLETE = "autocomplete";
public static String AUTOFOCUS = "autofocus";
public static String AUTOPLAY = "autoplay";
public static String AUTOSAVE = "autosave";
private Attr() {
}
public static final String ACCEPT = "accept";
public static final String ACCEPT_CHARSET = "accept-charset";
public static final String ACCESSKEY = "accesskey";
public static final String ACTION = "action";
public static final String ALIGN = "align";
public static final String ALT = "alt";
public static final String ASYNC = "async";
public static final String AUTOCOMPLETE = "autocomplete";
public static final String AUTOFOCUS = "autofocus";
public static final String AUTOPLAY = "autoplay";
public static final String AUTOSAVE = "autosave";
public static final String BORDER = "border";
public static final String BUFFERED = "buffered";
public static final String CHALLENGE = "challenge";
public static final String CHARSET = "charset";
public static final String CHECKED = "checked";
public static final String CITE = "cite";
public static final String CLASS = "class";
public static final String COLOR = "color";
public static final String COLS = "cols";
public static final String COLSPAN = "colspan";
public static final String CONTENT = "content";
public static final String CONTENTEDITABLE = "contenteditable";
public static final String CONTEXTMENU = "contextmenu";
public static final String CONTROLS = "controls";
public static final String COORDS = "coords";
public static final String DATA = "data";
public static final String DATETIME = "datetime";
public static final String DEFAULT = "default";
public static final String DEFER = "defer";
public static final String DIR = "dir";
public static final String DIRNAME = "dirname";
public static final String DISABLED = "disabled";
public static final String DOWNLOAD = "download";
public static final String DRAGGABLE = "draggable";
public static final String DROPZONE = "dropzone";
public static final String ENCTYPE = "enctype";
public static final String FOR = "for";
public static final String FORM = "form";
public static final String FORMACTION = "formaction";
public static final String HEADERS = "headers";
public static final String HEIGHT = "height";
public static final String HIDDEN = "hidden";
public static final String HIGH = "high";
public static final String HREF = "href";
public static final String HREFLANG = "hreflang";
public static final String HTTP_EQUIV = "http-equiv";
public static final String ICON = "icon";
public static final String ID = "id";
public static final String ISMAP = "ismap";
public static final String ITEMPROP = "itemprop";
public static final String KEYTYPE = "keytype";
public static final String KIND = "kind";
public static final String LABEL = "label";
public static final String LANG = "lang";
public static final String LANGUAGE = "language";
public static final String LIST = "list";
public static final String LOOP = "loop";
public static final String LOW = "low";
public static final String MANIFEST = "manifest";
public static final String MAX = "max";
public static final String MAXLENGTH = "maxlength";
public static final String MEDIA = "media";
public static final String METHOD = "method";
public static final String MIN = "min";
public static final String MULTIPLE = "multiple";
public static final String NAME = "name";
public static final String NOVALIDATE = "novalidate";
public static final String OPEN = "open";
public static final String OPTIMUM = "optimum";
public static final String PATTERN = "pattern";
public static final String PING = "ping";
public static final String PLACEHOLDER = "placeholder";
public static final String POSTER = "poster";
public static final String PRELOAD = "preload";
public static final String PUBDATE = "pubdate";
public static final String RADIOGROUP = "radiogroup";
public static final String READONLY = "readonly";
public static final String REL = "rel";
public static final String REQUIRED = "required";
public static final String REVERSED = "reversed";
public static final String ROLE = "role";
public static final String ROWS = "rows";
public static final String ROWSPAN = "rowspan";
public static final String SANDBOX = "sandbox";
public static final String SCOPE = "scope";
public static final String SCOPED = "scoped";
public static final String SEAMLESS = "seamless";
public static final String SELECTED = "selected";
public static final String SHAPE = "shape";
public static final String SIZE = "size";
public static final String SIZES = "sizes";
public static final String SPAN = "span";
public static final String SPELLCHECK = "spellcheck";
public static final String SRC = "src";
public static final String SRCDOC = "srcdoc";
public static final String SRCLANG = "srclang";
public static final String SRCSET = "srcset";
public static final String START = "start";
public static final String STEP = "step";
public static final String STYLE = "style";
public static final String SUMMARY = "summary";
public static final String TABINDEX = "tabindex";
public static final String TARGET = "target";
public static final String TITLE = "title";
public static final String TYPE = "type";
public static final String USEMAP = "usemap";
public static final String VALUE = "value";
public static final String WIDTH = "width";
public static final String WRAP = "wrap";
}

View File

@@ -1,6 +1,7 @@
package j2html.attributes;
import static org.apache.commons.lang3.StringEscapeUtils.*;
import j2html.utils.SimpleEscaper;
public class Attribute {
private String name;
@@ -8,7 +9,7 @@ public class Attribute {
public Attribute(String name, String value) {
this.name = name;
this.value = escapeHtml4(value);
this.value = SimpleEscaper.escape(value);
}
public Attribute(String name) {
@@ -17,8 +18,12 @@ public class Attribute {
}
public String render() {
if (name == null) { return ""; }
if (value == null) { return " "+name; }
if (name == null) {
return "";
}
if (value == null) {
return " " + name;
}
return (" " + name + "=\"" + value + "\"");
}

View File

@@ -1,88 +1,105 @@
package j2html.tags;
import j2html.attributes.Attr;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ContainerTag extends Tag {
public class ContainerTag extends Tag<ContainerTag> {
public List<Tag> children;
private List<DomContent> children;
public ContainerTag(String tagType) {
super(tagType);
public ContainerTag(String tagName) {
super(tagName);
this.children = new ArrayList<>();
}
/**
* Appends a tag to the end of this element
* Appends a DomContent-object to the end of this element
*
* @param child tag to be appended
* @param child DomContent-object to be appended
* @return itself for easy chaining
*/
public ContainerTag with(Tag child) {
public ContainerTag with(DomContent child) {
if (this == child) {
throw new Error("Cannot append a tag to itself.");
}
child.setParent(this);
children.add(child);
return this;
}
/**
* Call with-method based on condition
* {@link #with(Tag child)}
* {@link #with(DomContent child)}
*
* @param condition the condition to use
* @param child DomContent-object to be appended if condition met
* @return itself for easy chaining
*/
public ContainerTag condWith(boolean condition, Tag child) {
public ContainerTag condWith(boolean condition, DomContent child) {
return condition ? this.with(child) : this;
}
/**
* Appends a list of tags to the end of this element
* Appends a list of DomContent-objects to the end of this element
*
* @param children tags to be appended
* @param children DomContent-objects to be appended
* @return itself for easy chaining
*/
public ContainerTag with(List<Tag> children) {
public ContainerTag with(Iterable<? extends DomContent> children) {
if (children != null) {
for (Tag child : children) {
for (DomContent child : children) {
this.with(child);
}
}
return this;
}
/**
* Call with-method based on condition
* {@link #with(List children)}
* {@link #with(java.lang.Iterable)}
*
* @param condition the condition to use
* @param children DomContent-objects to be appended if condition met
* @return itself for easy chaining
*/
public ContainerTag condWith(boolean condition, List<Tag> children) {
public ContainerTag condWith(boolean condition, Iterable<? extends DomContent> children) {
return condition ? this.with(children) : this;
}
/**
* Appends the tags to the end of this element
* Appends the DomContent-objects to the end of this element
*
* @param children tags to be appended
* @param children DomContent-objects to be appended
* @return itself for easy chaining
*/
public ContainerTag with(Tag... children) {
for (Tag aChildren : children) {
with(aChildren);
public ContainerTag with(DomContent... children) {
for (DomContent child : children) {
with(child);
}
return this;
}
/**
* Call with-method based on condition
* {@link #with(Tag... children)}
* {@link #with(DomContent... children)}
*
* @param condition the condition to use
* @param children DomContent-objects to be appended if condition met
* @return itself for easy chaining
*/
public ContainerTag condWith(boolean condition, Tag... children) {
public ContainerTag condWith(boolean condition, DomContent... children) {
return condition ? this.with(children) : this;
}
/**
* Appends a text tag to this element
* Appends a Text-object to this element
*
* @param text the text to be appended
* @return itself for easy chaining
@@ -91,34 +108,17 @@ public class ContainerTag extends Tag {
return with(new Text(text));
}
/**
* Sets a custom attribute
* Render the ContainerTag and its children
*
* @param attribute the attribute name
* @param value the attribute value
* @return itself for easy chaining
*/
public ContainerTag attr(String attribute, String value) {
setAttribute(attribute, value);
return this;
}
/**
* Call attr-method based on condition
* {@link #attr(String attribute, String value)}
*/
public ContainerTag condAttr(boolean condition, String attribute, String value) {
return condition ? attr(attribute, value) : this;
}
/**
* Render the tag and its children
* @return the rendered string
*/
@Override
public String render() {
StringBuilder rendered = new StringBuilder(renderOpenTag());
if (children != null && children.size() > 0) {
for (Tag child : children) {
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
rendered.append(child.render());
}
}
@@ -127,56 +127,14 @@ public class ContainerTag extends Tag {
}
@Override
public String toString() {
return this.render();
public void render(Appendable writer) throws IOException {
writer.append(renderOpenTag());
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
child.render(writer);
}
}
writer.append(renderCloseTag());
}
/**
* Methods below this point are convenience methods
* that call attr with a predefined attribute.
*/
//TODO: TEST ?
public ContainerTag isAutoComplete() { return attr(Attr.AUTOCOMPLETE, null); }
public ContainerTag isAutoFocus() { return attr(Attr.AUTOFOCUS, null); }
public ContainerTag isHidden() { return attr(Attr.HIDDEN, null); }
public ContainerTag isRequired() { return attr(Attr.REQUIRED, null); }
public ContainerTag withAlt(String alt) { return attr(Attr.ALT, alt); }
public ContainerTag withAction(String action) { return attr(Attr.ACTION, action); }
public ContainerTag withCharset(String charset) { return attr(Attr.CHARSET, charset); }
public ContainerTag withClass(String className) { return attr(Attr.CLASS, className); }
public ContainerTag withContent(String content) { return attr(Attr.CONTENT, content); }
public ContainerTag withHref(String href) { return attr(Attr.HREF, href); }
public ContainerTag withId(String id) { return attr(Attr.ID, id); }
public ContainerTag withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
public ContainerTag withMethod(String method) { return attr(Attr.METHOD, method); }
public ContainerTag withName(String name) { return attr(Attr.NAME, name); }
public ContainerTag withPlaceholder(String placeholder) { return attr(Attr.PLACEHOLDER, placeholder); }
public ContainerTag withTarget(String target) { return attr(Attr.TARGET, target); }
public ContainerTag withType(String type) { return attr(Attr.TYPE, type); }
public ContainerTag withRel(String rel) { return attr(Attr.REL, rel); }
public ContainerTag withSrc(String src) { return attr(Attr.SRC, src); }
public ContainerTag withValue(String value) { return attr(Attr.VALUE, value); }
public ContainerTag withCondAutoComplete(boolean condition) { return condAttr(condition, Attr.AUTOCOMPLETE, null); }
public ContainerTag withCondAutoFocus(boolean condition) { return condAttr(condition, Attr.AUTOFOCUS, null); }
public ContainerTag withCondHidden(boolean condition) { return condAttr(condition, Attr.HIDDEN, null); }
public ContainerTag withCondRequired(boolean condition) { return condAttr(condition, Attr.REQUIRED, null); }
public ContainerTag withCondAlt(boolean condition, String alt) { return condAttr(condition, Attr.ALT, alt); }
public ContainerTag withCondAction(boolean condition, String action) { return condAttr(condition, Attr.ACTION, action); }
public ContainerTag withCharset(boolean condition, String charset) { return condAttr(condition, Attr.CHARSET, charset); }
public ContainerTag withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
public ContainerTag withCondContent(boolean condition, String content) { return condAttr(condition, Attr.CONTENT, content); }
public ContainerTag withCondHref(boolean condition, String href) { return condAttr(condition, Attr.HREF, href); }
public ContainerTag withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
public ContainerTag withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
public ContainerTag withCondMethod(boolean condition, String method) { return condAttr(condition, Attr.METHOD, method); }
public ContainerTag withCondName(boolean condition, String name) { return condAttr(condition, Attr.NAME, name); }
public ContainerTag withCondPlaceholder(boolean condition, String placeholder) { return condAttr(condition, Attr.PLACEHOLDER, placeholder); }
public ContainerTag withCondTarget(boolean condition, String target) { return condAttr(condition, Attr.TARGET, target); }
public ContainerTag withCondType(boolean condition, String type) { return condAttr(condition, Attr.TYPE, type); }
public ContainerTag withCondRel(boolean condition, String rel) { return condAttr(condition, Attr.REL, rel); }
public ContainerTag withCondSrc(boolean condition, String src) { return condAttr(condition, Attr.SRC, src); }
public ContainerTag withCondValue(boolean condition, String value) { return condAttr(condition, Attr.VALUE, value); }
}

View File

@@ -0,0 +1,18 @@
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();
}
}

View File

@@ -1,94 +1,14 @@
package j2html.tags;
import j2html.attributes.Attr;
import j2html.attributes.Attribute;
public class EmptyTag extends Tag<EmptyTag> {
public class EmptyTag extends Tag {
public EmptyTag(String tagType) {
super(tagType);
}
/**
* Sets a custom attribute
*
* @param attribute the attribute name
* @param value the attribute value
* @return itself for easy chaining
*/
public EmptyTag attr(String attribute, String value) {
setAttribute(attribute, value);
return this;
}
/**
* Call attr-method based on condition
* {@link #attr(String attribute, String value)}
*/
public EmptyTag condAttr(boolean condition, String attribute, String value) {
return condition ? attr(attribute, value) : this;
}
public String render() {
String tagAttributes = "";
for (Attribute attribute : attributes) {
tagAttributes += attribute;
}
return "<" + tag + tagAttributes + ">";
public EmptyTag(String tagName) {
super(tagName);
}
@Override
public String toString() {
return this.render();
public String render() {
return renderOpenTag();
}
/**
* Methods below this point are convenience methods
* that call attr with a predefined attribute.
*/
//TODO: TEST ?
public EmptyTag isAutoComplete() { return attr(Attr.AUTOCOMPLETE, null); }
public EmptyTag isAutoFocus() { return attr(Attr.AUTOFOCUS, null); }
public EmptyTag isHidden() { return attr(Attr.HIDDEN, null); }
public EmptyTag isRequired() { return attr(Attr.REQUIRED, null); }
public EmptyTag withAlt(String alt) { return attr(Attr.ALT, alt); }
public EmptyTag withAction(String action) { return attr(Attr.ACTION, action); }
public EmptyTag withCharset(String charset) { return attr(Attr.CHARSET, charset); }
public EmptyTag withClass(String className) { return attr(Attr.CLASS, className); }
public EmptyTag withContent(String content) { return attr(Attr.CONTENT, content); }
public EmptyTag withHref(String href) { return attr(Attr.HREF, href); }
public EmptyTag withId(String id) { return attr(Attr.ID, id); }
public EmptyTag withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
public EmptyTag withMethod(String method) { return attr(Attr.METHOD, method); }
public EmptyTag withName(String name) { return attr(Attr.NAME, name); }
public EmptyTag withPlaceholder(String placeholder) { return attr(Attr.PLACEHOLDER, placeholder); }
public EmptyTag withTarget(String target) { return attr(Attr.TARGET, target); }
public EmptyTag withType(String type) { return attr(Attr.TYPE, type); }
public EmptyTag withRel(String rel) { return attr(Attr.REL, rel); }
public EmptyTag withSrc(String src) { return attr(Attr.SRC, src); }
public EmptyTag withValue(String value) { return attr(Attr.VALUE, value); }
public EmptyTag withCondAutoComplete(boolean condition) { return condAttr(condition, Attr.AUTOCOMPLETE, null); }
public EmptyTag withCondAutoFocus(boolean condition) { return condAttr(condition, Attr.AUTOFOCUS, null); }
public EmptyTag withCondHidden(boolean condition) { return condAttr(condition, Attr.HIDDEN, null); }
public EmptyTag withCondRequired(boolean condition) { return condAttr(condition, Attr.REQUIRED, null); }
public EmptyTag withCondAlt(boolean condition, String alt) { return condAttr(condition, Attr.ALT, alt); }
public EmptyTag withCondAction(boolean condition, String action) { return condAttr(condition, Attr.ACTION, action); }
public EmptyTag withCharset(boolean condition, String charset) { return condAttr(condition, Attr.CHARSET, charset); }
public EmptyTag withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
public EmptyTag withCondContent(boolean condition, String content) { return condAttr(condition, Attr.CONTENT, content); }
public EmptyTag withCondHref(boolean condition, String href) { return condAttr(condition, Attr.HREF, href); }
public EmptyTag withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
public EmptyTag withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
public EmptyTag withCondMethod(boolean condition, String method) { return condAttr(condition, Attr.METHOD, method); }
public EmptyTag withCondName(boolean condition, String name) { return condAttr(condition, Attr.NAME, name); }
public EmptyTag withCondPlaceholder(boolean condition, String placeholder) { return condAttr(condition, Attr.PLACEHOLDER, placeholder); }
public EmptyTag withCondTarget(boolean condition, String target) { return condAttr(condition, Attr.TARGET, target); }
public EmptyTag withCondType(boolean condition, String type) { return condAttr(condition, Attr.TYPE, type); }
public EmptyTag withCondRel(boolean condition, String rel) { return condAttr(condition, Attr.REL, rel); }
public EmptyTag withCondSrc(boolean condition, String src) { return condAttr(condition, Attr.SRC, src); }
public EmptyTag withCondValue(boolean condition, String value) { return condAttr(condition, Attr.VALUE, value); }
}

View File

@@ -1,22 +1,28 @@
package j2html.tags;
import j2html.utils.*;
import java.nio.file.*;
import static j2html.TagCreator.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import j2html.utils.CSSMin;
import j2html.utils.JSMin;
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(unsafeHtml("alert('Unable to read file. File: \"" + path + "\", Type: \"" + 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(unsafeHtml(compressCss(fileString)));
case JS_MIN : return script().with(unsafeHtml(compressJs(fileString, path)));
case CSS : return style().with(unsafeHtml(fileString));
case JS : return script().with(unsafeHtml(fileString));
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;
}
}
@@ -35,8 +41,8 @@ public class InlineStaticResource {
return CSSMin.compress(code);
}
private static String compressJs(String code, String debugPath) {
return JSMin.compressJs(code, debugPath);
private static String compressJs(String code) {
return JSMin.compressJs(code);
}
}

View File

@@ -1,23 +1,35 @@
package j2html.tags;
import j2html.attributes.Attribute;
import java.util.ArrayList;
public abstract class Tag {
import j2html.attributes.Attr;
import j2html.attributes.Attribute;
protected String tag;
protected ArrayList<Attribute> attributes;
protected Tag parent;
public abstract class Tag<T extends Tag<T>> extends DomContent {
protected Tag(String tagType) {
this.tag = tagType;
protected String tagName;
private ArrayList<Attribute> attributes;
protected Tag(String tagName) {
this.tagName = tagName;
this.attributes = new ArrayList<>();
}
public void setParent(Tag parent) {
this.parent = parent;
String renderOpenTag() {
StringBuilder sb = new StringBuilder("<").append(tagName);
for (Attribute attribute : attributes) {
sb.append(attribute.render());
}
sb.append(">");
return sb.toString();
}
String renderCloseTag() {
return "</" + tagName + ">";
}
/**
* Sets an attribute on an element
@@ -25,7 +37,7 @@ public abstract class Tag {
* @param name the attribute
* @param value the attribute value
*/
public boolean setAttribute(String name, String value) {
boolean setAttribute(String name, String value) {
if (value == null) {
return attributes.add(new Attribute(name));
}
@@ -38,25 +50,90 @@ public abstract class Tag {
return attributes.add(new Attribute(name, value));
}
public String render() {
return renderOpenTag() + renderCloseTag();
/**
* Sets a custom attribute
*
* @param attribute the attribute name
* @param value the attribute value
* @return itself for easy chaining
*/
public T attr(String attribute, String value) {
setAttribute(attribute, value);
return (T) this;
}
/**
* Call attr-method based on condition
* {@link #attr(String attribute, String value)}
*
* @param condition the condition
* @param attribute the attribute name
* @param value the attribute value
* @return itself for easy chaining
*/
public T condAttr(boolean condition, String attribute, String value) {
return (condition ? attr(attribute, value) : (T) this);
}
@Override
public String toString() {
return this.render();
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Tag)) {
return false;
}
return ((Tag) obj).render().equals(this.render());
}
public String renderOpenTag() {
String tagAttributes = "";
for (Attribute attribute : attributes) {
tagAttributes += attribute.render();
}
return "<" + tag + tagAttributes + ">";
}
public String renderCloseTag() {
return "</" + tag + ">";
}
/**
* 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 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); }
}

View File

@@ -1,21 +1,18 @@
package j2html.tags;
import static org.apache.commons.lang3.StringEscapeUtils.*;
import j2html.utils.SimpleEscaper;
public class Text extends Tag {
public class Text extends DomContent {
private String text;
public Text(String text) {
super(text);
this.text = text;
}
@Override
public String render() {
return escapeHtml4(tag);
}
@Override
public String toString() {
return this.render();
return SimpleEscaper.escape(text);
}
}

View File

@@ -1,19 +1,16 @@
package j2html.tags;
public class UnescapedText extends Tag {
public class UnescapedText extends DomContent {
private String text;
public UnescapedText(String text) {
super(text);
this.text = text;
}
@Override
public String render() {
return tag;
}
@Override
public String toString() {
return this.render();
return text;
}
}

View File

@@ -1,27 +1,27 @@
/**
* * CSSMin Copyright License Agreement (BSD License)
*
* <p>
* Copyright (c) 2011-2014, Barry van Oudtshoorn
* All rights reserved.
*
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* <p>
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* <p>
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* <p>
* - Neither the name of Barryvan nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission.
*
* <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -33,11 +33,11 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* <p>
* CSSMin takes in well-formed, human-readable CSS and reduces its size substantially.
* It removes unnecessary whitespace and comments, and orders the contents of CSS
* selectors alphabetically to enhance GZIP compression.
*
* <p>
* Originally by Barry van Oudtshoorn, with bug reports, fixes, and contributions by
* <ul>
* <li>Kevin de Groote</li>
@@ -53,21 +53,31 @@
package j2html.utils;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import java.util.regex.*;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class CSSMin {
private CSSMin() {
}
private static final Logger LOG = Logger.getLogger(CSSMin.class.getName());
protected static boolean debugLogging = false;
static boolean debugLogging = false;
/**
* Minify CSS from a reader to a printstream.
* Minify supplied CSS.
*
* @param input Where to read the CSS from
* @param input the CSS
* @return the compressed version
*/
public static String compress(String input) {
try {
@@ -84,7 +94,9 @@ public class CSSMin {
}
String s;
while ((s = br.readLine()) != null) {
if (s.trim().equals("")) continue;
if (s.trim().equals("")) {
continue;
}
sb.append(s);
}
@@ -178,7 +190,7 @@ class Selector {
* @param selector The selector; for example, "div { border: solid 1px red; color: blue; }"
* @throws IncompleteSelectorException, UnterminatedSelectorException, EmptySelectorBodyException If the selector is incomplete and cannot be parsed.
*/
public Selector(String selector) throws IncompleteSelectorException, UnterminatedSelectorException, EmptySelectorBodyException {
Selector(String selector) throws IncompleteSelectorException, UnterminatedSelectorException, EmptySelectorBodyException {
String[] parts = selector.split("\\{"); // We have to escape the { with a \ for the regex, which itself requires escaping for the string. Sigh.
if (parts.length < 2) {
throw new IncompleteSelectorException(selector);
@@ -189,7 +201,6 @@ class Selector {
// Simplify combinators
this.selector = this.selector.replaceAll("\\s?(\\+|~|,|=|~=|\\^=|\\$=|\\*=|\\|=|>)\\s?", "$1");
// We're dealing with a nested property, eg @-webkit-keyframes
if (parts.length > 2) {
this.subSelectors = new Vector<>();
@@ -266,15 +277,21 @@ class Selector {
} else if (contents.charAt(i) == '"') {
bInsideString = true;
} else if (contents.charAt(i) == '(') {
if ((i - 3) > 0 && "url".equals(contents.substring(i - 3, i))) bInsideURL = true;
if ((i - 3) > 0 && "url".equals(contents.substring(i - 3, i))) {
bInsideURL = true;
}
} else if (contents.charAt(i) == ';') {
substr = contents.substring(j, i);
if (!(substr.trim().equals(""))) parts.add(substr);
if (!(substr.trim().equals(""))) {
parts.add(substr);
}
j = i + 1;
}
}
substr = contents.substring(j, contents.length());
if (!(substr.trim().equals(""))) parts.add(substr);
if (!(substr.trim().equals(""))) {
parts.add(substr);
}
ArrayList<Property> results = new ArrayList<>();
for (String part : parts) {
@@ -302,8 +319,8 @@ class Property implements Comparable<Property> {
private static final Logger LOG = Logger.getLogger(Property.class.getName());
protected String property;
protected Part[] parts;
private String property;
private Part[] parts;
/**
* Creates a new Property using the supplied strings. Parses out the values of the property selector.
@@ -311,7 +328,7 @@ class Property implements Comparable<Property> {
* @param property The property; for example, "border: solid 1px red;" or "-moz-box-shadow: 3px 3px 3px rgba(255, 255, 0, 0.5);".
* @throws IncompletePropertyException If the property is incomplete and cannot be parsed.
*/
public Property(String property) throws IncompletePropertyException {
Property(String property) throws IncompletePropertyException {
try {
// Parse the property.
ArrayList<String> parts = new ArrayList<>();
@@ -326,14 +343,18 @@ class Property implements Comparable<Property> {
bCanSplit = (property.charAt(i) == '"');
} else if (property.charAt(i) == '"') {
bCanSplit = false;
} else if (property.charAt(i) == ':' && parts.size() < 1) {
} else if (property.charAt(i) == ':' && parts.isEmpty()) {
substr = property.substring(j, i);
if (!(substr.trim().equals(""))) parts.add(substr);
if (!(substr.trim().equals(""))) {
parts.add(substr);
}
j = i + 1;
}
}
substr = property.substring(j, property.length());
if (!(substr.trim().equals(""))) parts.add(substr);
if (!(substr.trim().equals(""))) {
parts.add(substr);
}
if (parts.size() < 2) {
throw new IncompletePropertyException(property);
}
@@ -375,24 +396,17 @@ class Property implements Comparable<Property> {
*/
public int compareTo(Property other) {
// We can't just use String.compareTo(), because we need to sort properties that have hack prefixes last -- eg, *display should come after display.
String thisProp = this.property;
String thatProp = other.property;
return sort(this.property).compareTo(sort(other.property));
}
private String sort(String thisProp) {
if (thisProp.charAt(0) == '-') {
thisProp = thisProp.substring(1);
thisProp = thisProp.substring(thisProp.indexOf('-') + 1);
} else if (thisProp.charAt(0) < 65) {
thisProp = thisProp.substring(1);
}
if (thatProp.charAt(0) == '-') {
thatProp = thatProp.substring(1);
thatProp = thatProp.substring(thatProp.indexOf('-') + 1);
} else if (thatProp.charAt(0) < 65) {
thatProp = thatProp.substring(1);
}
return thisProp.compareTo(thatProp);
return thisProp;
}
/**
@@ -456,8 +470,8 @@ class Property implements Comparable<Property> {
}
class Part {
String contents;
String property;
private String contents;
private String property;
/**
* Create a new property by parsing the given string.
@@ -465,7 +479,7 @@ class Part {
* @param contents The string to parse.
* @throws Exception If the part cannot be parsed.
*/
public Part(String contents, String property) throws Exception {
Part(String contents, String property) throws Exception {
// Many of these regular expressions are adapted from those used in the YUI CSS Compressor.
// For simpler regexes.
@@ -486,9 +500,15 @@ class Part {
this.contents = this.contents.trim();
// Simplify multiple zeroes
if (this.contents.equals("0 0 0 0")) this.contents = "0";
if (this.contents.equals("0 0 0")) this.contents = "0";
if (this.contents.equals("0 0")) this.contents = "0";
if (this.contents.equals("0 0 0 0")) {
this.contents = "0";
}
if (this.contents.equals("0 0 0")) {
this.contents = "0";
}
if (this.contents.equals("0 0")) {
this.contents = "0";
}
// Simplify multiple-parameter properties
simplifyParameters();
@@ -505,32 +525,28 @@ class Part {
}
private void simplifyParameters() {
if (this.property.equals("background-size")) return;
if (this.property.equals("background-size")) {
return;
}
StringBuilder newContents = new StringBuilder();
String[] params = this.contents.split(" ");
if (params.length == 4) {
if (params.length == 4 && params[1].equalsIgnoreCase(params[3])) {
// We can drop off the fourth item if the second and fourth items match
// ie turn 3px 0 3px 0 into 3px 0 3px
if (params[1].equalsIgnoreCase(params[3])) {
params = Arrays.copyOf(params, 3);
}
}
if (params.length == 3) {
if (params.length == 3 && params[0].equalsIgnoreCase(params[2])) {
// We can drop off the third item if the first and third items match
// ie turn 3px 0 3px into 3px 0
if (params[0].equalsIgnoreCase(params[2])) {
params = Arrays.copyOf(params, 2);
}
}
if (params.length == 2) {
if (params.length == 2 && params[0].equalsIgnoreCase(params[1])) {
// We can drop off the second item if the first and second items match
// ie turn 3px 3px into 3px
if (params[0].equalsIgnoreCase(params[1])) {
params = Arrays.copyOf(params, 1);
}
}
for (String param : params) {
newContents.append(param).append(" ");
@@ -541,7 +557,9 @@ class Part {
}
private void simplifyFontWeights() {
if (!this.property.equals("font-weight")) return;
if (!this.property.equals("font-weight")) {
return;
}
String lcContents = this.contents.toLowerCase();
@@ -615,14 +633,16 @@ class Part {
}
}
class UnterminatedCommentException extends Exception {}
class UnterminatedCommentException extends Exception {
}
class UnbalancedBracesException extends Exception {}
class UnbalancedBracesException extends Exception {
}
class IncompletePropertyException extends Exception {
String message = null;
private final String message;
public IncompletePropertyException(String message) {
IncompletePropertyException(String message) {
this.message = message;
}
@@ -632,9 +652,9 @@ class IncompletePropertyException extends Exception {
}
class EmptySelectorBodyException extends Exception {
String message = null;
private final String message;
public EmptySelectorBodyException(String message) {
EmptySelectorBodyException(String message) {
this.message = message;
}
@@ -644,9 +664,9 @@ class EmptySelectorBodyException extends Exception {
}
class UnterminatedSelectorException extends Exception {
String message = null;
private final String message;
public UnterminatedSelectorException(String message) {
UnterminatedSelectorException(String message) {
this.message = message;
}
@@ -656,9 +676,9 @@ class UnterminatedSelectorException extends Exception {
}
class IncompleteSelectorException extends Exception {
String message = null;
private final String message;
public IncompleteSelectorException(String message) {
IncompleteSelectorException(String message) {
this.message = message;
}

View File

@@ -1,18 +1,305 @@
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;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import com.google.javascript.jscomp.*;
import com.google.javascript.jscomp.Compiler;
public class JSMin {
public static String compressJs(String code, String sourcePath) {
com.google.javascript.jscomp.Compiler compiler = new Compiler();
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
SourceFile extern = SourceFile.fromCode("externs.js", "");
SourceFile input = SourceFile.fromCode(sourcePath, code);
compiler.compile(extern, input, options);
return compiler.toSource();
/**
* Compress a JS-string
*
* @param code the js-code you want to compress
* @return the compressed code
*/
public static String compressJs(String code) {
InputStream inStream = new ByteArrayInputStream(code.getBytes());
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
JSMin jsmin = new JSMin(inStream, outStream);
try {
jsmin.jsmin();
return outStream.toString().trim();
} catch (IOException | UnterminatedRegExpLiteralException | UnterminatedCommentException | UnterminatedStringLiteralException e) {
e.printStackTrace();
return "";
}
}
private static final int EOF = -1;
private PushbackInputStream in;
private OutputStream out;
private int theA;
private int theB;
private JSMin(InputStream in, OutputStream out) {
this.in = new PushbackInputStream(in);
this.out = out;
}
/**
* isAlphanum -- return true if the character is a letter, digit,
* underscore, dollar sign, or non-ASCII character.
*/
private static boolean isAlphanum(int c) {
return ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
c == '_' ||
c == '$' ||
c == '\\' ||
c > 126);
}
/**
* get -- return the next character from stdin. Watch out for lookahead. If
* the character is a control character, translate it to a space or
* linefeed.
*/
private int get() throws IOException {
int c = in.read();
if (c >= ' ' || c == '\n' || c == EOF) {
return c;
}
if (c == '\r') {
return '\n';
}
return ' ';
}
/**
* Get the next character without getting it.
*/
private int peek() throws IOException {
int lookaheadChar = in.read();
in.unread(lookaheadChar);
return lookaheadChar;
}
/**
* next -- get the next character, excluding comments. peek() is used to see
* if a '/' is followed by a '/' or '*'.
*/
private int next() throws IOException, UnterminatedCommentException {
int c = get();
if (c == '/') {
switch (peek()) {
case '/':
for (; ; ) {
c = get();
if (c <= '\n') {
return c;
}
}
case '*':
get();
for (; ; ) {
switch (get()) {
case '*':
if (peek() == '/') {
get();
return ' ';
}
break;
case EOF:
throw new UnterminatedCommentException();
}
}
default:
return c;
}
}
return c;
}
/**
* action -- do something! What you do is determined by the argument: 1
* Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
* (Delete A). 3 Get the next B. (Delete B). action treats a string as a
* single character. Wow! action recognizes a regular expression if it is
* preceded by ( or , or =.
*/
private void action(int d) throws IOException, UnterminatedRegExpLiteralException,
UnterminatedCommentException, UnterminatedStringLiteralException {
switch (d) {
case 1:
out.write(theA);
case 2:
theA = theB;
if (theA == '\'' || theA == '"') {
for (; ; ) {
out.write(theA);
theA = get();
if (theA == theB) {
break;
}
if (theA <= '\n') {
throw new UnterminatedStringLiteralException();
}
if (theA == '\\') {
out.write(theA);
theA = get();
}
}
}
case 3:
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=')) {
out.write(theA);
out.write(theB);
for (; ; ) {
theA = get();
if (theA == '/') {
break;
} else if (theA == '\\') {
out.write(theA);
theA = get();
} else if (theA <= '\n') {
throw new UnterminatedRegExpLiteralException();
}
out.write(theA);
}
theB = next();
}
}
}
/**
* jsmin -- Copy the input to the output, deleting the characters which are
* insignificant to JavaScript. Comments will be removed. Tabs will be
* replaced with spaces. Carriage returns will be replaced with linefeeds.
* Most spaces and linefeeds will be removed.
*/
public void jsmin() throws IOException, UnterminatedRegExpLiteralException, UnterminatedCommentException, UnterminatedStringLiteralException {
theA = '\n';
action(3);
while (theA != EOF) {
switch (theA) {
case ' ':
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
break;
case '\n':
switch (theB) {
case '{':
case '[':
case '(':
case '+':
case '-':
action(1);
break;
case ' ':
action(3);
break;
default:
if (isAlphanum(theB)) {
action(1);
} else {
action(2);
}
}
break;
default:
switch (theB) {
case ' ':
if (isAlphanum(theA)) {
action(1);
break;
}
action(3);
break;
case '\n':
switch (theA) {
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
action(1);
break;
default:
if (isAlphanum(theA)) {
action(1);
} else {
action(3);
}
}
break;
default:
action(1);
break;
}
}
}
out.flush();
}
private class UnterminatedCommentException extends Exception {
}
private class UnterminatedStringLiteralException extends Exception {
}
private class UnterminatedRegExpLiteralException extends Exception {
}
}

View File

@@ -0,0 +1,28 @@
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

@@ -1,30 +1,32 @@
package j2html.attributes;
import j2html.tags.ContainerTag;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import j2html.tags.ContainerTag;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class AttributeTest {
@Test
public void testRender() throws Exception {
Attribute attributeWithValue = new Attribute("href", "http://example.com");
assertEquals(attributeWithValue.render(), " href=\"http://example.com\"");
assertThat(attributeWithValue.render(), is(" href=\"http://example.com\""));
Attribute attribute = new Attribute("required", null);
assertEquals(attribute.render(), " required");
assertThat(attribute.render(), is(" required"));
Attribute nullAttribute = new Attribute(null, null);
assertEquals(nullAttribute.render(), "");
assertThat(nullAttribute.render(), is(""));
}
@Test
public void testSetAttribute() throws Exception {
ContainerTag testTag = new ContainerTag("a");
testTag.setAttribute("href", "http://example.com");
testTag.setAttribute("href", "http://example.org");
assertEquals(testTag.render(), "<a href=\"http://example.org\"></a>");
testTag.attr("href", "http://example.com");
testTag.attr("href", "http://example.org");
assertThat(testTag.render(), is("<a href=\"http://example.org\"></a>"));
}
}

View File

@@ -2,8 +2,26 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.junit.Assert.assertEquals;
import j2html.attributes.Attr;
import static j2html.TagCreator.a;
import static j2html.TagCreator.body;
import static j2html.TagCreator.button;
import static j2html.TagCreator.div;
import static j2html.TagCreator.document;
import static j2html.TagCreator.footer;
import static j2html.TagCreator.h1;
import static j2html.TagCreator.h2;
import static j2html.TagCreator.head;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.input;
import static j2html.TagCreator.main;
import static j2html.TagCreator.script;
import static j2html.TagCreator.text;
import static j2html.TagCreator.title;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class ComplexRenderTest {
@@ -17,20 +35,21 @@ public class ComplexRenderTest {
),
body().with(
header().with(
h1("Test Header")
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")
)
).condWith(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")
).condWith(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
),
footer().withText("Test Footer"),
footer().attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id").withText("Test Footer"),
script().withSrc("/testScript.js")
)
).render();
@@ -38,7 +57,7 @@ public class ComplexRenderTest {
@Test
public void testComplexRender() {
String expectedResult = "<!DOCTYPE html><html><head><title>Test</title></head><body><header><h1>Test Header</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>Test Footer</footer><script src=\"/testScript.js\"></script></body></html>";
assertEquals(renderTest(), expectedResult);
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));
}
}

View File

@@ -2,32 +2,41 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.junit.Assert.assertEquals;
import static j2html.TagCreator.a;
import static j2html.TagCreator.div;
import static j2html.TagCreator.form;
import static j2html.TagCreator.img;
import static j2html.TagCreator.input;
import static j2html.TagCreator.link;
import static j2html.TagCreator.meta;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class ConvenienceMethodTest {
@Test
public void testAllConvenienceMethods() throws Exception {
assertEquals(input().isAutoComplete().render(), "<input autocomplete>");
assertEquals(input().isAutoFocus().render(), "<input autofocus>");
assertEquals(input().isHidden().render(), "<input hidden>");
assertEquals(input().isRequired().render(), "<input required>");
assertEquals(img().withAlt("An image").render(), "<img alt=\"An image\">");
assertEquals(form().withAction("post").render(), "<form action=\"post\"></form>");
assertEquals(meta().withCharset("UTF-8").render(), "<meta charset=\"UTF-8\">");
assertEquals(div().withClass("test-class").render(), "<div class=\"test-class\"></div>");
assertEquals(meta().withContent("Test Content").render(), "<meta content=\"Test Content\">");
assertEquals(a().withHref("http://example.com").render(), "<a href=\"http://example.com\"></a>");
assertEquals(div().withId("test-id").render(), "<div id=\"test-id\"></div>");
assertEquals(div().withData("testdata", "test").render(), "<div data-testdata=\"test\"></div>");
assertEquals(form().withMethod("get").render(), "<form method=\"get\"></form>");
assertEquals(input().withName("test-name").render(), "<input name=\"test-name\">");
assertEquals(input().withPlaceholder("test-placeholder").render(), "<input placeholder=\"test-placeholder\">");
assertEquals(a().withTarget("_blank").render(), "<a target=\"_blank\"></a>");
assertEquals(input().withType("email").render(), "<input type=\"email\">");
assertEquals(link().withRel("stylesheet").render(), "<link rel=\"stylesheet\">");
assertEquals(img().withSrc("/img/test.png").render(), "<img src=\"/img/test.png\">");
assertEquals(input().withValue("test-value").render(), "<input value=\"test-value\">");
assertThat(input().isAutoComplete().render(), is("<input autocomplete>"));
assertThat(input().isAutoFocus().render(), is("<input autofocus>"));
assertThat(input().isHidden().render(), is("<input hidden>"));
assertThat(input().isRequired().render(), is("<input required>"));
assertThat(img().withAlt("An image").render(), is("<img alt=\"An image\">"));
assertThat(form().withAction("post").render(), is("<form action=\"post\"></form>"));
assertThat(meta().withCharset("UTF-8").render(), is("<meta charset=\"UTF-8\">"));
assertThat(div().withClass("test-class").render(), is("<div class=\"test-class\"></div>"));
assertThat(meta().withContent("Test Content").render(), is("<meta content=\"Test Content\">"));
assertThat(a().withHref("http://example.com").render(), is("<a href=\"http://example.com\"></a>"));
assertThat(div().withId("test-id").render(), is("<div id=\"test-id\"></div>"));
assertThat(div().withData("testdata", "test").render(), is("<div data-testdata=\"test\"></div>"));
assertThat(form().withMethod("get").render(), is("<form method=\"get\"></form>"));
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(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\">"));
assertThat(img().withSrc("/img/test.png").render(), is("<img src=\"/img/test.png\">"));
assertThat(div().withStyle("background:red;").render(), is("<div style=\"background:red;\"></div>"));
assertThat(input().withValue("test-value").render(), is("<input value=\"test-value\">"));
}
}

View File

@@ -1,178 +1,229 @@
package j2html.tags;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.junit.Assert.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class TagCreatorTest {
private static final String EOL = System.getProperty("line.separator"); // System independent End Of Line
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 testEach() throws Exception {
String j2htmlMap = ul().with(
li("Begin list"),
each(employees, employee -> li().with(
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()))
).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
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)
))
).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()))
).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>"));
}
@Test
public void testAllTags() throws Exception {
//Special Tags
assertEquals(tag("tagname").render(), "<tagname></tagname>");
assertEquals(emptyTag("tagname").render(), "<tagname>");
assertEquals(text("text").render(), "text");
assertEquals(text("<script> and \"</script>\"").render(), "&lt;script&gt; and &quot;&lt;/script&gt;&quot;");
assertEquals(unsafeHtml("<script>").render(), "<script>");
assertEquals(styleWithInlineFile_min("/test.css").render(), "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>");
assertEquals(scriptWithInlineFile_min("/test.js").render(), "<script>(function(){console.log(15)})();</script>");
assertEquals(fileAsString("/test.html").render(), "<body>\r\n"+" Any content\r\n"+"</body>\r\n");
assertEquals(fileAsEscapedString("/test.html").render(), "&lt;body&gt;\r\n"+" Any content\r\n"+"&lt;/body&gt;\r\n");
assertEquals(fileAsString("/test.java").render(), "public class AnyContent{}\r\n");
assertThat(tag("tagname").render(), is("<tagname></tagname>"));
assertThat(emptyTag("tagname").render(), is("<tagname>"));
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
assertEquals(document().render(), "<!DOCTYPE html>");
assertEquals(area().render(), "<area>");
assertEquals(base().render(), "<base>");
assertEquals(br().render(), "<br>");
assertEquals(col().render(), "<col>");
assertEquals(embed().render(), "<embed>");
assertEquals(hr().render(), "<hr>");
assertEquals(img().render(), "<img>");
assertEquals(input().render(), "<input>");
assertEquals(keygen().render(), "<keygen>");
assertEquals(link().render(), "<link>");
assertEquals(meta().render(), "<meta>");
assertEquals(param().render(), "<param>");
assertEquals(source().render(), "<source>");
assertEquals(track().render(), "<track>");
assertEquals(wbr().render(), "<wbr>");
assertThat(document().render(), is("<!DOCTYPE html>"));
assertThat(area().render(), is("<area>"));
assertThat(base().render(), is("<base>"));
assertThat(br().render(), is("<br>"));
assertThat(col().render(), is("<col>"));
assertThat(embed().render(), is("<embed>"));
assertThat(hr().render(), is("<hr>"));
assertThat(img().render(), is("<img>"));
assertThat(input().render(), is("<input>"));
assertThat(keygen().render(), is("<keygen>"));
assertThat(link().render(), is("<link>"));
assertThat(meta().render(), is("<meta>"));
assertThat(param().render(), is("<param>"));
assertThat(source().render(), is("<source>"));
assertThat(track().render(), is("<track>"));
assertThat(wbr().render(), is("<wbr>"));
//ContainerTags
assertEquals(a().render(), "<a></a>");
assertEquals(a("Text").render(), "<a>Text</a>");
assertEquals(abbr().render(), "<abbr></abbr>");
assertEquals(address().render(), "<address></address>");
assertEquals(article().render(), "<article></article>");
assertEquals(aside().render(), "<aside></aside>");
assertEquals(audio().render(), "<audio></audio>");
assertEquals(b().render(), "<b></b>");
assertEquals(b("Text").render(), "<b>Text</b>");
assertEquals(bdi().render(), "<bdi></bdi>");
assertEquals(bdi("Text").render(), "<bdi>Text</bdi>");
assertEquals(bdo().render(), "<bdo></bdo>");
assertEquals(bdo("Text").render(), "<bdo>Text</bdo>");
assertEquals(blockquote().render(), "<blockquote></blockquote>");
assertEquals(blockquote("Text").render(), "<blockquote>Text</blockquote>");
assertEquals(body().render(), "<body></body>");
assertEquals(button().render(), "<button></button>");
assertEquals(button("Text").render(), "<button>Text</button>");
assertEquals(canvas().render(), "<canvas></canvas>");
assertEquals(caption().render(), "<caption></caption>");
assertEquals(caption("Text").render(), "<caption>Text</caption>");
assertEquals(cite().render(), "<cite></cite>");
assertEquals(cite("Text").render(), "<cite>Text</cite>");
assertEquals(code().render(), "<code></code>");
assertEquals(colgroup().render(), "<colgroup></colgroup>");
assertEquals(datalist().render(), "<datalist></datalist>");
assertEquals(dd().render(), "<dd></dd>");
assertEquals(dd("Text").render(), "<dd>Text</dd>");
assertEquals(del().render(), "<del></del>");
assertEquals(del("Text").render(), "<del>Text</del>");
assertEquals(details().render(), "<details></details>");
assertEquals(dfn().render(), "<dfn></dfn>");
assertEquals(dfn("Text").render(), "<dfn>Text</dfn>");
assertEquals(dialog().render(), "<dialog></dialog>");
assertEquals(dialog("Text").render(), "<dialog>Text</dialog>");
assertEquals(div().render(), "<div></div>");
assertEquals(dl().render(), "<dl></dl>");
assertEquals(dt().render(), "<dt></dt>");
assertEquals(dt("Text").render(), "<dt>Text</dt>");
assertEquals(em().render(), "<em></em>");
assertEquals(em("Text").render(), "<em>Text</em>");
assertEquals(fieldset().render(), "<fieldset></fieldset>");
assertEquals(figcaption().render(), "<figcaption></figcaption>");
assertEquals(figcaption("Text").render(), "<figcaption>Text</figcaption>");
assertEquals(figure().render(), "<figure></figure>");
assertEquals(footer().render(), "<footer></footer>");
assertEquals(form().render(), "<form></form>");
assertEquals(h1().render(), "<h1></h1>");
assertEquals(h1("Text").render(), "<h1>Text</h1>");
assertEquals(h2().render(), "<h2></h2>");
assertEquals(h2("Text").render(), "<h2>Text</h2>");
assertEquals(h3().render(), "<h3></h3>");
assertEquals(h3("Text").render(), "<h3>Text</h3>");
assertEquals(h4().render(), "<h4></h4>");
assertEquals(h4("Text").render(), "<h4>Text</h4>");
assertEquals(h5().render(), "<h5></h5>");
assertEquals(h5("Text").render(), "<h5>Text</h5>");
assertEquals(h6().render(), "<h6></h6>");
assertEquals(h6("Text").render(), "<h6>Text</h6>");
assertEquals(head().render(), "<head></head>");
assertEquals(header().render(), "<header></header>");
assertEquals(html().render(), "<html></html>");
assertEquals(i().render(), "<i></i>");
assertEquals(i("Text").render(), "<i>Text</i>");
assertEquals(iframe().render(), "<iframe></iframe>");
assertEquals(ins().render(), "<ins></ins>");
assertEquals(ins("Text").render(), "<ins>Text</ins>");
assertEquals(kbd().render(), "<kbd></kbd>");
assertEquals(label().render(), "<label></label>");
assertEquals(label("Text").render(), "<label>Text</label>");
assertEquals(legend().render(), "<legend></legend>");
assertEquals(legend("Text").render(), "<legend>Text</legend>");
assertEquals(li().render(), "<li></li>");
assertEquals(li("Text").render(), "<li>Text</li>");
assertEquals(main().render(), "<main></main>");
assertEquals(map().render(), "<map></map>");
assertEquals(mark().render(), "<mark></mark>");
assertEquals(menu().render(), "<menu></menu>");
assertEquals(menuitem().render(), "<menuitem></menuitem>");
assertEquals(meter().render(), "<meter></meter>");
assertEquals(nav().render(), "<nav></nav>");
assertEquals(noscript().render(), "<noscript></noscript>");
assertEquals(object().render(), "<object></object>");
assertEquals(ol().render(), "<ol></ol>");
assertEquals(optgroup().render(), "<optgroup></optgroup>");
assertEquals(option().render(), "<option></option>");
assertEquals(option("Text").render(), "<option>Text</option>");
assertEquals(output().render(), "<output></output>");
assertEquals(p().render(), "<p></p>");
assertEquals(p("Text").render(), "<p>Text</p>");
assertEquals(pre().render(), "<pre></pre>");
assertEquals(progress().render(), "<progress></progress>");
assertEquals(q().render(), "<q></q>");
assertEquals(q("Text").render(), "<q>Text</q>");
assertEquals(rp().render(), "<rp></rp>");
assertEquals(rt().render(), "<rt></rt>");
assertEquals(ruby().render(), "<ruby></ruby>");
assertEquals(s().render(), "<s></s>");
assertEquals(samp().render(), "<samp></samp>");
assertEquals(script().render(), "<script></script>");
assertEquals(section().render(), "<section></section>");
assertEquals(select().render(), "<select></select>");
assertEquals(small().render(), "<small></small>");
assertEquals(small("Text").render(), "<small>Text</small>");
assertEquals(span().render(), "<span></span>");
assertEquals(span("Text").render(), "<span>Text</span>");
assertEquals(strong().render(), "<strong></strong>");
assertEquals(strong("Text").render(), "<strong>Text</strong>");
assertEquals(style().render(), "<style></style>");
assertEquals(sub().render(), "<sub></sub>");
assertEquals(sub("Text").render(), "<sub>Text</sub>");
assertEquals(summary().render(), "<summary></summary>");
assertEquals(summary("Text").render(), "<summary>Text</summary>");
assertEquals(sup().render(), "<sup></sup>");
assertEquals(sup("Text").render(), "<sup>Text</sup>");
assertEquals(table().render(), "<table></table>");
assertEquals(tbody().render(), "<tbody></tbody>");
assertEquals(td().render(), "<td></td>");
assertEquals(td("Text").render(), "<td>Text</td>");
assertEquals(textarea().render(), "<textarea></textarea>");
assertEquals(tfoot().render(), "<tfoot></tfoot>");
assertEquals(th().render(), "<th></th>");
assertEquals(th("Text").render(), "<th>Text</th>");
assertEquals(thead().render(), "<thead></thead>");
assertEquals(time().render(), "<time></time>");
assertEquals(title().render(), "<title></title>");
assertEquals(tr().render(), "<tr></tr>");
assertEquals(u().render(), "<u></u>");
assertEquals(u("Text").render(), "<u>Text</u>");
assertEquals(ul().render(), "<ul></ul>");
assertEquals(var().render(), "<var></var>");
assertEquals(video().render(), "<video></video>");
assertThat(a().render(), is("<a></a>"));
assertThat(a("Text").render(), is("<a>Text</a>"));
assertThat(abbr().render(), is("<abbr></abbr>"));
assertThat(address().render(), is("<address></address>"));
assertThat(article().render(), is("<article></article>"));
assertThat(aside().render(), is("<aside></aside>"));
assertThat(audio().render(), is("<audio></audio>"));
assertThat(b().render(), is("<b></b>"));
assertThat(b("Text").render(), is("<b>Text</b>"));
assertThat(bdi().render(), is("<bdi></bdi>"));
assertThat(bdi("Text").render(), is("<bdi>Text</bdi>"));
assertThat(bdo().render(), is("<bdo></bdo>"));
assertThat(bdo("Text").render(), is("<bdo>Text</bdo>"));
assertThat(blockquote().render(), is("<blockquote></blockquote>"));
assertThat(blockquote("Text").render(), is("<blockquote>Text</blockquote>"));
assertThat(body().render(), is("<body></body>"));
assertThat(button().render(), is("<button></button>"));
assertThat(button("Text").render(), is("<button>Text</button>"));
assertThat(canvas().render(), is("<canvas></canvas>"));
assertThat(caption().render(), is("<caption></caption>"));
assertThat(caption("Text").render(), is("<caption>Text</caption>"));
assertThat(cite().render(), is("<cite></cite>"));
assertThat(cite("Text").render(), is("<cite>Text</cite>"));
assertThat(code().render(), is("<code></code>"));
assertThat(colgroup().render(), is("<colgroup></colgroup>"));
assertThat(datalist().render(), is("<datalist></datalist>"));
assertThat(dd().render(), is("<dd></dd>"));
assertThat(dd("Text").render(), is("<dd>Text</dd>"));
assertThat(del().render(), is("<del></del>"));
assertThat(del("Text").render(), is("<del>Text</del>"));
assertThat(details().render(), is("<details></details>"));
assertThat(dfn().render(), is("<dfn></dfn>"));
assertThat(dfn("Text").render(), is("<dfn>Text</dfn>"));
assertThat(dialog().render(), is("<dialog></dialog>"));
assertThat(dialog("Text").render(), is("<dialog>Text</dialog>"));
assertThat(div().render(), is("<div></div>"));
assertThat(dl().render(), is("<dl></dl>"));
assertThat(dt().render(), is("<dt></dt>"));
assertThat(dt("Text").render(), is("<dt>Text</dt>"));
assertThat(em().render(), is("<em></em>"));
assertThat(em("Text").render(), is("<em>Text</em>"));
assertThat(fieldset().render(), is("<fieldset></fieldset>"));
assertThat(figcaption().render(), is("<figcaption></figcaption>"));
assertThat(figcaption("Text").render(), is("<figcaption>Text</figcaption>"));
assertThat(figure().render(), is("<figure></figure>"));
assertThat(footer().render(), is("<footer></footer>"));
assertThat(form().render(), is("<form></form>"));
assertThat(h1().render(), is("<h1></h1>"));
assertThat(h1("Text").render(), is("<h1>Text</h1>"));
assertThat(h2().render(), is("<h2></h2>"));
assertThat(h2("Text").render(), is("<h2>Text</h2>"));
assertThat(h3().render(), is("<h3></h3>"));
assertThat(h3("Text").render(), is("<h3>Text</h3>"));
assertThat(h4().render(), is("<h4></h4>"));
assertThat(h4("Text").render(), is("<h4>Text</h4>"));
assertThat(h5().render(), is("<h5></h5>"));
assertThat(h5("Text").render(), is("<h5>Text</h5>"));
assertThat(h6().render(), is("<h6></h6>"));
assertThat(h6("Text").render(), is("<h6>Text</h6>"));
assertThat(head().render(), is("<head></head>"));
assertThat(header().render(), is("<header></header>"));
assertThat(html().render(), is("<html></html>"));
assertThat(i().render(), is("<i></i>"));
assertThat(i("Text").render(), is("<i>Text</i>"));
assertThat(iframe().render(), is("<iframe></iframe>"));
assertThat(ins().render(), is("<ins></ins>"));
assertThat(ins("Text").render(), is("<ins>Text</ins>"));
assertThat(kbd().render(), is("<kbd></kbd>"));
assertThat(label().render(), is("<label></label>"));
assertThat(label("Text").render(), is("<label>Text</label>"));
assertThat(legend().render(), is("<legend></legend>"));
assertThat(legend("Text").render(), is("<legend>Text</legend>"));
assertThat(li().render(), is("<li></li>"));
assertThat(li("Text").render(), is("<li>Text</li>"));
assertThat(main().render(), is("<main></main>"));
assertThat(map().render(), is("<map></map>"));
assertThat(mark().render(), is("<mark></mark>"));
assertThat(menu().render(), is("<menu></menu>"));
assertThat(menuitem().render(), is("<menuitem></menuitem>"));
assertThat(meter().render(), is("<meter></meter>"));
assertThat(nav().render(), is("<nav></nav>"));
assertThat(noscript().render(), is("<noscript></noscript>"));
assertThat(object().render(), is("<object></object>"));
assertThat(ol().render(), is("<ol></ol>"));
assertThat(optgroup().render(), is("<optgroup></optgroup>"));
assertThat(option().render(), is("<option></option>"));
assertThat(option("Text").render(), is("<option>Text</option>"));
assertThat(output().render(), is("<output></output>"));
assertThat(p().render(), is("<p></p>"));
assertThat(p("Text").render(), is("<p>Text</p>"));
assertThat(pre().render(), is("<pre></pre>"));
assertThat(progress().render(), is("<progress></progress>"));
assertThat(q().render(), is("<q></q>"));
assertThat(q("Text").render(), is("<q>Text</q>"));
assertThat(rp().render(), is("<rp></rp>"));
assertThat(rt().render(), is("<rt></rt>"));
assertThat(ruby().render(), is("<ruby></ruby>"));
assertThat(s().render(), is("<s></s>"));
assertThat(s("Text").render(), is("<s>Text</s>"));
assertThat(samp().render(), is("<samp></samp>"));
assertThat(script().render(), is("<script></script>"));
assertThat(section().render(), is("<section></section>"));
assertThat(select().render(), is("<select></select>"));
assertThat(small().render(), is("<small></small>"));
assertThat(small("Text").render(), is("<small>Text</small>"));
assertThat(span().render(), is("<span></span>"));
assertThat(span("Text").render(), is("<span>Text</span>"));
assertThat(strong().render(), is("<strong></strong>"));
assertThat(strong("Text").render(), is("<strong>Text</strong>"));
assertThat(style().render(), is("<style></style>"));
assertThat(sub().render(), is("<sub></sub>"));
assertThat(sub("Text").render(), is("<sub>Text</sub>"));
assertThat(summary().render(), is("<summary></summary>"));
assertThat(summary("Text").render(), is("<summary>Text</summary>"));
assertThat(sup().render(), is("<sup></sup>"));
assertThat(sup("Text").render(), is("<sup>Text</sup>"));
assertThat(table().render(), is("<table></table>"));
assertThat(tbody().render(), is("<tbody></tbody>"));
assertThat(td().render(), is("<td></td>"));
assertThat(td("Text").render(), is("<td>Text</td>"));
assertThat(textarea().render(), is("<textarea></textarea>"));
assertThat(tfoot().render(), is("<tfoot></tfoot>"));
assertThat(th().render(), is("<th></th>"));
assertThat(th("Text").render(), is("<th>Text</th>"));
assertThat(thead().render(), is("<thead></thead>"));
assertThat(time().render(), is("<time></time>"));
assertThat(title().render(), is("<title></title>"));
assertThat(title("Text").render(), is("<title>Text</title>"));
assertThat(tr().render(), is("<tr></tr>"));
assertThat(u().render(), is("<u></u>"));
assertThat(u("Text").render(), is("<u>Text</u>"));
assertThat(ul().render(), is("<ul></ul>"));
assertThat(var().render(), is("<var></var>"));
assertThat(video().render(), is("<video></video>"));
}
}

View File

@@ -2,8 +2,15 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.junit.Assert.assertEquals;
import static j2html.TagCreator.body;
import static j2html.TagCreator.footer;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.main;
import static j2html.TagCreator.p;
import static j2html.TagCreator.tag;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class TagTest {
@@ -11,28 +18,35 @@ public class TagTest {
public void testRender() throws Exception {
ContainerTag testTag = new ContainerTag("a");
testTag.setAttribute("href", "http://example.com");
assertEquals(testTag.render(), "<a href=\"http://example.com\"></a>");
assertThat(testTag.render(), is("<a href=\"http://example.com\"></a>"));
ContainerTag complexTestTag = html().with(body().with(header(), main().with(p("Main stuff...")), footer().condWith(1 == 1, p("Conditional with!"))));
String expectedResult = "<html><body><header></header><main><p>Main stuff...</p></main><footer><p>Conditional with!</p></footer></body></html>";
assertEquals(complexTestTag.render(), (expectedResult));
assertThat(complexTestTag.render(), is((expectedResult)));
}
@Test
public void testOpenTag() throws Exception {
ContainerTag testTag = new ContainerTag("a");
assertEquals(testTag.renderOpenTag(), "<a>");
assertThat(testTag.renderOpenTag(), is("<a>"));
ContainerTag complexTestTag = new ContainerTag("input");
complexTestTag.withType("password").withId("password").withName("password").withPlaceholder("Password").isRequired();
String expectedResult = "<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\" required>";
assertEquals(complexTestTag.renderOpenTag(), expectedResult);
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
}
@Test
public void testCloseTag() throws Exception {
ContainerTag testTag = new ContainerTag("a");
assertEquals(testTag.renderCloseTag(), "</a>");
assertThat(testTag.renderCloseTag(), is("</a>"));
}
@Test
public void testEquals() throws Exception {
Tag tagOne = tag("p").withClass("class").withText("Test");
Tag tagTwo = p("Test").withClass("class");
assertThat(tagOne.equals(tagTwo), is(true));
}
}

View File

@@ -0,0 +1,13 @@
package j2html.tags;
class Employee {
final int id;
final String name;
final String title;
Employee(int id, String name, String title) {
this.id = id;
this.name = name;
this.title = title;
}
}