Compare commits
21 Commits
j2html-1.2
...
j2html-1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
023922a7db | ||
|
|
00c0461669 | ||
|
|
cd6e0084ef | ||
|
|
764b5d7759 | ||
|
|
d9c4963ff0 | ||
|
|
3ec15d28a5 | ||
|
|
f1680464d1 | ||
|
|
f497b5c8b5 | ||
|
|
f212895eb2 | ||
|
|
62cafb9b31 | ||
|
|
af7c986dd6 | ||
|
|
3aaab8b0fe | ||
|
|
cf9558b6ab | ||
|
|
f87f9d8647 | ||
|
|
b42ba41697 | ||
|
|
0c7f75f5b8 | ||
|
|
754003ebf6 | ||
|
|
6968478894 | ||
|
|
0b92a963e9 | ||
|
|
ac92facca7 | ||
|
|
4cf16320ad |
16
README.md
16
README.md
@@ -13,12 +13,12 @@ The project webpage is [j2html.com](http://j2html.com).
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.j2html</groupId>
|
<groupId>com.j2html</groupId>
|
||||||
<artifactId>j2html</artifactId>
|
<artifactId>j2html</artifactId>
|
||||||
<version>1.2.1</version>
|
<version>1.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
### OR the gradle dependency
|
### Or the gradle dependency
|
||||||
```
|
```
|
||||||
compile 'com.j2html:j2html:1.2.1'
|
compile 'com.j2html:j2html:1.3.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Import TagCreator and start building HTML
|
### Import TagCreator and start building HTML
|
||||||
@@ -27,9 +27,9 @@ import static j2html.TagCreator.*;
|
|||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
body().with(
|
body(
|
||||||
h1("Heading!").withClass("example"),
|
h1("Hello, World!"),
|
||||||
img().withSrc("img/hello.png")
|
img().withSrc("/img/hello.png")
|
||||||
).render();
|
).render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,8 +37,8 @@ public class Main {
|
|||||||
The above Java will result in the following HTML:
|
The above Java will result in the following HTML:
|
||||||
```html
|
```html
|
||||||
<body>
|
<body>
|
||||||
<h1 class="example">Heading!</h1>
|
<h1>Hello, World!</h1>
|
||||||
<img src="img/hello.png">
|
<img src="/img/hello.png">
|
||||||
</body>
|
</body>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
46
pom.xml
46
pom.xml
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<groupId>com.j2html</groupId>
|
<groupId>com.j2html</groupId>
|
||||||
<artifactId>j2html</artifactId>
|
<artifactId>j2html</artifactId>
|
||||||
<version>1.2.2</version>
|
<version>1.4.0</version>
|
||||||
|
|
||||||
<name>j2html</name>
|
<name>j2html</name>
|
||||||
<description>Java to HTML builder with a fluent API</description>
|
<description>Java to HTML builder with a fluent API</description>
|
||||||
@@ -63,7 +63,22 @@
|
|||||||
<artifactId>junit-benchmarks</artifactId>
|
<artifactId>junit-benchmarks</artifactId>
|
||||||
<version>0.7.2</version>
|
<version>0.7.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- performance test dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.velocity</groupId>
|
||||||
|
<artifactId>velocity</artifactId>
|
||||||
|
<version>1.7</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.16.18</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
@@ -107,6 +122,33 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>bundle-manifest</id>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>manifest</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -10,29 +10,27 @@ import java.util.Collections;
|
|||||||
|
|
||||||
public class Config {
|
public class Config {
|
||||||
|
|
||||||
private static String FOUR_SPACES = " ";
|
|
||||||
|
|
||||||
private Config() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change this to configure text-escaping
|
* Change this to configure text-escaping
|
||||||
* For example, to disable escaping, do <code>{@code Config.textEscaper = text -> text;}</code>
|
* For example, to disable escaping, do <code>{@code Config.textEscaper = text -> text;}</code>
|
||||||
*/
|
*/
|
||||||
public static TextEscaper textEscaper = EscapeUtil::escape;
|
public static TextEscaper textEscaper = EscapeUtil::escape;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change this to configure css-minification.
|
* Change this to configure css-minification.
|
||||||
* The default minifier is https://github.com/barryvan/CSSMin
|
* The default minifier is https://github.com/barryvan/CSSMin
|
||||||
*/
|
*/
|
||||||
public static Minifier cssMinifier = CSSMin::compressCss;
|
public static Minifier cssMinifier = CSSMin::compressCss;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change this to configure js-minification.
|
* Change this to configure js-minification.
|
||||||
* The default minifier is a simple whitespace/newline stripper
|
* The default minifier is a simple whitespace/newline stripper
|
||||||
*/
|
*/
|
||||||
public static Minifier jsMinifier = JSMin::compressJs;
|
public static Minifier jsMinifier = JSMin::compressJs;
|
||||||
|
/**
|
||||||
|
* Change this to configure enable/disable closing empty tags
|
||||||
|
* The default is to NOT close them
|
||||||
|
*/
|
||||||
|
public static boolean closeEmptyTags = false;
|
||||||
|
private static String FOUR_SPACES = " ";
|
||||||
/**
|
/**
|
||||||
* Change this to configure indentation when rendering formatted html
|
* Change this to configure indentation when rendering formatted html
|
||||||
* The default is four spaces
|
* The default is four spaces
|
||||||
@@ -40,10 +38,7 @@ public class Config {
|
|||||||
public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;
|
public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;
|
||||||
|
|
||||||
|
|
||||||
/**
|
private Config() {
|
||||||
* Change this to configure enable/disable closing empty tags
|
}
|
||||||
* The default is to NOT close them
|
|
||||||
*/
|
|
||||||
public static boolean closeEmptyTags = false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,15 @@ import j2html.tags.Text;
|
|||||||
import j2html.tags.UnescapedText;
|
import j2html.tags.UnescapedText;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class TagCreator {
|
public class TagCreator {
|
||||||
|
|
||||||
@@ -31,6 +37,23 @@ public class TagCreator {
|
|||||||
return condition ? ifValue : null;
|
return condition ? ifValue : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic if-expression to if'ing inside method calls
|
||||||
|
*
|
||||||
|
* @param optional The item that may be present
|
||||||
|
* @param ifFunction The function that will be called if that optional is present
|
||||||
|
* @param <T> The derived generic parameter type
|
||||||
|
* @param <U> The supplying generic parameter type
|
||||||
|
* @return transformed value if condition is true, null otherwise
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||||
|
public static <T, U> T iff(Optional<U> optional, Function<U, T> ifFunction) {
|
||||||
|
if (Objects.nonNull(optional) && optional.isPresent()) {
|
||||||
|
return optional.map(ifFunction).orElse(null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link j2html.TagCreator#iff}, but returns else-value instead of null
|
* Like {@link j2html.TagCreator#iff}, but returns else-value instead of null
|
||||||
*/
|
*/
|
||||||
@@ -61,6 +84,17 @@ public class TagCreator {
|
|||||||
return DomContentJoiner.join(" ", true, stringOrDomObjects);
|
return DomContentJoiner.join(" ", true, stringOrDomObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DomContent object containing HTML elements from a stream.
|
||||||
|
* Intended usage: {@literal each(numbers.stream().map(n -> li(n.toString())))}
|
||||||
|
*
|
||||||
|
* @param stream the stream of DomContent elements
|
||||||
|
* @return DomContent containing elements from the stream
|
||||||
|
*/
|
||||||
|
public static DomContent each(Stream<DomContent> stream) {
|
||||||
|
return new ContainerTag(null).with(stream);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a DomContent object containing HTML using a mapping function on a collection
|
* Creates a DomContent object containing HTML using a mapping function on a collection
|
||||||
* Intended usage: {@literal each(numbers, n -> li(n.toString()))}
|
* Intended usage: {@literal each(numbers, n -> li(n.toString()))}
|
||||||
@@ -68,10 +102,28 @@ public class TagCreator {
|
|||||||
* @param <T> The derived generic parameter type
|
* @param <T> The derived generic parameter type
|
||||||
* @param collection the collection to iterate over, ex: a list of values "1, 2, 3"
|
* @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())"}
|
* @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>)}
|
* @return DomContent containing mapped data {@literal (ex. docs: [li(1), li(2), li(3)])}
|
||||||
*/
|
*/
|
||||||
public static <T> DomContent each(Collection<T> collection, Function<? super T, DomContent> mapper) {
|
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()));
|
return tag(null).with(collection.stream().map(mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <I, T> DomContent each(final Map<I, T> map, final Function<Entry<I, T>, DomContent> mapper) {
|
||||||
|
return rawHtml(map.entrySet().stream().map(mapper.andThen(DomContent::render)).collect(Collectors.joining()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DomContent object containing HTML using a mapping function on a map
|
||||||
|
* Intended usage: {@literal each(idsToNames, (id, name) -> li(id + " " + name))}
|
||||||
|
*
|
||||||
|
* @param <I> The type of the keys
|
||||||
|
* @param <T> The type of the values
|
||||||
|
* @param map the map to iterate over, ex: a map of values { 1: "Tom", 2: "Dick", 3: "Harry" }
|
||||||
|
* @param mapper the mapping function, ex: {@literal "(id, name) -> li(id + " " + name)"}
|
||||||
|
* @return DomContent containing mapped data {@literal (ex. docs: [li(1 Tom), li(2 Dick), li(3 Harry)])}
|
||||||
|
*/
|
||||||
|
public static <I, T> DomContent each(final Map<I, T> map, final BiFunction<I, T, DomContent> mapper) {
|
||||||
|
return rawHtml(map.entrySet().stream().map(entry -> mapper.andThen(DomContent::render).apply(entry.getKey(), entry.getValue())).collect(Collectors.joining()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,62 +4,6 @@ import j2html.tags.Tag;
|
|||||||
|
|
||||||
public class Attr {
|
public class Attr {
|
||||||
|
|
||||||
public static class ShortForm {
|
|
||||||
String id;
|
|
||||||
String classes;
|
|
||||||
|
|
||||||
private ShortForm(String id, String classes) {
|
|
||||||
this.id = id;
|
|
||||||
this.classes = classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasId() {
|
|
||||||
return id != null && !"".equals(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasClasses() {
|
|
||||||
return classes != null && !"".equals(classes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShortForm shortFormFromAttrsString(String attrs) {
|
|
||||||
if (!attrs.contains(".") && !attrs.contains(("#"))) {
|
|
||||||
throw new IllegalArgumentException("String must contain either id (#) or class (.)");
|
|
||||||
}
|
|
||||||
if (attrs.split("#").length > 2) {
|
|
||||||
throw new IllegalArgumentException("Only one id (#) allowed");
|
|
||||||
}
|
|
||||||
String id = "";
|
|
||||||
StringBuilder classes = new StringBuilder();
|
|
||||||
for (String attr : attrs.split("\\.")) {
|
|
||||||
if (attr.contains("#")) {
|
|
||||||
if (!attr.startsWith("#")) {
|
|
||||||
throw new IllegalArgumentException("# cannot be in the middle of string");
|
|
||||||
}
|
|
||||||
id = attr.replace("#", "");
|
|
||||||
} else {
|
|
||||||
classes.append(attr).append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ShortForm(id.trim(), classes.toString().trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends Tag<T>> T addTo(T tag, ShortForm shortForm) {
|
|
||||||
if (shortForm.hasId() && shortForm.hasClasses()) {
|
|
||||||
return tag.withId(shortForm.id).withClass(shortForm.classes);
|
|
||||||
}
|
|
||||||
if (shortForm.hasId()) {
|
|
||||||
return tag.withId(shortForm.id);
|
|
||||||
}
|
|
||||||
if (shortForm.hasClasses()) {
|
|
||||||
return tag.withClass(shortForm.classes);
|
|
||||||
}
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Attr() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String ACCEPT = "accept";
|
public static final String ACCEPT = "accept";
|
||||||
public static final String ACCEPT_CHARSET = "accept-charset";
|
public static final String ACCEPT_CHARSET = "accept-charset";
|
||||||
public static final String ACCESSKEY = "accesskey";
|
public static final String ACCESSKEY = "accesskey";
|
||||||
@@ -170,5 +114,60 @@ public class Attr {
|
|||||||
public static final String VALUE = "value";
|
public static final String VALUE = "value";
|
||||||
public static final String WIDTH = "width";
|
public static final String WIDTH = "width";
|
||||||
public static final String WRAP = "wrap";
|
public static final String WRAP = "wrap";
|
||||||
|
private Attr() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShortForm shortFormFromAttrsString(String attrs) {
|
||||||
|
if (!attrs.contains(".") && !attrs.contains(("#"))) {
|
||||||
|
throw new IllegalArgumentException("String must contain either id (#) or class (.)");
|
||||||
|
}
|
||||||
|
if (attrs.split("#").length > 2) {
|
||||||
|
throw new IllegalArgumentException("Only one id (#) allowed");
|
||||||
|
}
|
||||||
|
String id = "";
|
||||||
|
StringBuilder classes = new StringBuilder();
|
||||||
|
for (String attr : attrs.split("\\.")) {
|
||||||
|
if (attr.contains("#")) {
|
||||||
|
if (!attr.startsWith("#")) {
|
||||||
|
throw new IllegalArgumentException("# cannot be in the middle of string");
|
||||||
|
}
|
||||||
|
id = attr.replace("#", "");
|
||||||
|
} else {
|
||||||
|
classes.append(attr).append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ShortForm(id.trim(), classes.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Tag<T>> T addTo(T tag, ShortForm shortForm) {
|
||||||
|
if (shortForm.hasId() && shortForm.hasClasses()) {
|
||||||
|
return tag.withId(shortForm.id).withClass(shortForm.classes);
|
||||||
|
}
|
||||||
|
if (shortForm.hasId()) {
|
||||||
|
return tag.withId(shortForm.id);
|
||||||
|
}
|
||||||
|
if (shortForm.hasClasses()) {
|
||||||
|
return tag.withClass(shortForm.classes);
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShortForm {
|
||||||
|
String id;
|
||||||
|
String classes;
|
||||||
|
|
||||||
|
private ShortForm(String id, String classes) {
|
||||||
|
this.id = id;
|
||||||
|
this.classes = classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasId() {
|
||||||
|
return id != null && !"".equals(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasClasses() {
|
||||||
|
return classes != null && !"".equals(classes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import j2html.Config;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ContainerTag extends Tag<ContainerTag> {
|
public class ContainerTag extends Tag<ContainerTag> {
|
||||||
|
|
||||||
@@ -89,6 +90,18 @@ public class ContainerTag extends Tag<ContainerTag> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the DomContent-objects in the stream to the end of this element
|
||||||
|
*
|
||||||
|
* @param children Stream of DomContent-objects to be appended
|
||||||
|
* @return itself for easy chaining
|
||||||
|
*/
|
||||||
|
public ContainerTag with(Stream<DomContent> children) {
|
||||||
|
children.forEach(this::with);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call with-method based on condition
|
* Call with-method based on condition
|
||||||
* {@link #with(DomContent... children)}
|
* {@link #with(DomContent... children)}
|
||||||
@@ -137,24 +150,40 @@ public class ContainerTag extends Tag<ContainerTag> {
|
|||||||
private String renderFormatted(int lvl) throws IOException {
|
private String renderFormatted(int lvl) throws IOException {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
renderOpenTag(sb, null);
|
renderOpenTag(sb, null);
|
||||||
sb.append("\n");
|
if (hasTagName() && !isSelfFormattingTag()) {
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
if (!children.isEmpty()) {
|
if (!children.isEmpty()) {
|
||||||
for (DomContent c : children) {
|
for (DomContent c : children) {
|
||||||
lvl++;
|
lvl++;
|
||||||
if (c instanceof ContainerTag) {
|
if (c instanceof ContainerTag) {
|
||||||
sb.append(Config.indenter.indent(lvl, ((ContainerTag) c).renderFormatted(lvl)));
|
if (((ContainerTag) c).hasTagName()) {
|
||||||
|
sb.append(Config.indenter.indent(lvl, ((ContainerTag) c).renderFormatted(lvl)));
|
||||||
|
} else {
|
||||||
|
sb.append(Config.indenter.indent(lvl - 1, ((ContainerTag) c).renderFormatted(lvl - 1)));
|
||||||
|
}
|
||||||
|
} else if (isSelfFormattingTag()) {
|
||||||
|
sb.append(Config.indenter.indent(0, c.render()));
|
||||||
} else {
|
} else {
|
||||||
sb.append(Config.indenter.indent(lvl, c.render())).append("\n");
|
sb.append(Config.indenter.indent(lvl, c.render())).append("\n");
|
||||||
}
|
}
|
||||||
lvl--;
|
lvl--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append(Config.indenter.indent(lvl, ""));
|
if (!isSelfFormattingTag()) {
|
||||||
|
sb.append(Config.indenter.indent(lvl, ""));
|
||||||
|
}
|
||||||
renderCloseTag(sb);
|
renderCloseTag(sb);
|
||||||
sb.append("\n");
|
if (hasTagName()) {
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSelfFormattingTag() {
|
||||||
|
return "textarea".equals(tagName) || "pre".equals(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderModel(Appendable writer, Object model) throws IOException {
|
public void renderModel(Appendable writer, Object model) throws IOException {
|
||||||
renderOpenTag(writer, model);
|
renderOpenTag(writer, model);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ public class DomContentJoiner {
|
|||||||
sb.append(((String) o).trim()).append(delimiter);
|
sb.append(((String) o).trim()).append(delimiter);
|
||||||
} else if (o instanceof DomContent) {
|
} else if (o instanceof DomContent) {
|
||||||
sb.append(((DomContent) o).render().trim()).append(delimiter);
|
sb.append(((DomContent) o).render().trim()).append(delimiter);
|
||||||
|
} else if (o == null) {
|
||||||
|
//Discard null objects so iff/iffelse can be used with join
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("You can only join DomContent and String objects");
|
throw new RuntimeException("You can only join DomContent and String objects");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import static j2html.TagCreator.style;
|
|||||||
|
|
||||||
public class InlineStaticResource {
|
public class InlineStaticResource {
|
||||||
|
|
||||||
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
|
|
||||||
|
|
||||||
public static ContainerTag get(String path, TargetFormat format) {
|
public static ContainerTag get(String path, TargetFormat format) {
|
||||||
String fileString = getFileAsString(path);
|
String fileString = getFileAsString(path);
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@@ -45,5 +43,7 @@ public class InlineStaticResource {
|
|||||||
return s.hasNext() ? s.next() : "";
|
return s.hasNext() ? s.next() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import j2html.attributes.Attr;
|
|||||||
import j2html.attributes.Attribute;
|
import j2html.attributes.Attribute;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
public abstract class Tag<T extends Tag<T>> extends DomContent {
|
public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||||
protected String tagName;
|
protected String tagName;
|
||||||
@@ -18,6 +19,10 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
|||||||
return this.tagName;
|
return this.tagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean hasTagName() {
|
||||||
|
return tagName != null && !tagName.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
String renderOpenTag() throws IOException {
|
String renderOpenTag() throws IOException {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
renderOpenTag(stringBuilder, null);
|
renderOpenTag(stringBuilder, null);
|
||||||
@@ -31,6 +36,9 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderOpenTag(Appendable writer, Object model) throws IOException {
|
void renderOpenTag(Appendable writer, Object model) throws IOException {
|
||||||
|
if (!hasTagName()) { // avoid <null> and <> tags
|
||||||
|
return;
|
||||||
|
}
|
||||||
writer.append("<").append(tagName);
|
writer.append("<").append(tagName);
|
||||||
for (Attribute attribute : attributes) {
|
for (Attribute attribute : attributes) {
|
||||||
attribute.renderModel(writer, model);
|
attribute.renderModel(writer, model);
|
||||||
@@ -39,6 +47,9 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderCloseTag(Appendable writer) throws IOException {
|
void renderCloseTag(Appendable writer) throws IOException {
|
||||||
|
if (!hasTagName()) { // avoid <null> and <> tags
|
||||||
|
return;
|
||||||
|
}
|
||||||
writer.append("</");
|
writer.append("</");
|
||||||
writer.append(tagName);
|
writer.append(tagName);
|
||||||
writer.append(">");
|
writer.append(">");
|
||||||
@@ -79,6 +90,28 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
|||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified attribute. If the Tag previously contained an attribute with the same name, the old attribute is replaced by the specified attribute.
|
||||||
|
*
|
||||||
|
* @param attribute the attribute
|
||||||
|
* @return itself for easy chaining
|
||||||
|
*/
|
||||||
|
public T attr(Attribute attribute) {
|
||||||
|
Iterator<Attribute> iterator = attributes.iterator();
|
||||||
|
String name = attribute.getName();
|
||||||
|
if (name != null) {
|
||||||
|
// name == null is allowed, but those Attributes are not rendered. So we add them anyway.
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Attribute existingAttribute = iterator.next();
|
||||||
|
if (existingAttribute.getName().equals(name)) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attributes.add(attribute);
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a custom attribute without value
|
* Sets a custom attribute without value
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -65,13 +65,11 @@ import java.util.regex.PatternSyntaxException;
|
|||||||
|
|
||||||
public class CSSMin {
|
public class CSSMin {
|
||||||
|
|
||||||
private CSSMin() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(CSSMin.class.getName());
|
private static final Logger LOG = Logger.getLogger(CSSMin.class.getName());
|
||||||
|
|
||||||
static boolean debugLogging = false;
|
static boolean debugLogging = false;
|
||||||
|
|
||||||
|
private CSSMin() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify supplied CSS.
|
* Minify supplied CSS.
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
package j2html.utils;
|
package j2html.utils;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSMin.java 2006-02-13
|
* JSMin.java 2006-02-13
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
|
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
|
||||||
*
|
*
|
||||||
* This work is a translation from C to Java of jsmin.c published by
|
* This work is a translation from C to Java of jsmin.c published by
|
||||||
* Douglas Crockford. Permission is hereby granted to use the Java
|
* Douglas Crockford. Permission is hereby granted to use the Java
|
||||||
* version under the same conditions as the jsmin.c on which it is
|
* version under the same conditions as the jsmin.c on which it is
|
||||||
* based.
|
* based.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* jsmin.c 2003-04-21
|
* jsmin.c 2003-04-21
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* The Software shall be used for Good, not Evil.
|
* The Software shall be used for Good, not Evil.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* 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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -47,6 +47,16 @@ import java.io.PushbackInputStream;
|
|||||||
|
|
||||||
public class JSMin {
|
public class JSMin {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress a JS-string
|
* Compress a JS-string
|
||||||
*
|
*
|
||||||
@@ -66,19 +76,6 @@ public class JSMin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
* isAlphanum -- return true if the character is a letter, digit,
|
||||||
* underscore, dollar sign, or non-ASCII character.
|
* underscore, dollar sign, or non-ASCII character.
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
public class AnyContent{}
|
public class AnyContent {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
package j2html;
|
package j2html;
|
||||||
|
|
||||||
import static j2html.TagCreator.attrs;
|
|
||||||
import static j2html.TagCreator.body;
|
|
||||||
import static j2html.TagCreator.div;
|
|
||||||
import static j2html.TagCreator.h1;
|
|
||||||
import static j2html.TagCreator.h2;
|
|
||||||
import static j2html.TagCreator.head;
|
|
||||||
import static j2html.TagCreator.html;
|
|
||||||
import static j2html.TagCreator.p;
|
|
||||||
import static j2html.TagCreator.title;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
|
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
|
||||||
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
|
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
|
||||||
import com.carrotsearch.junitbenchmarks.Clock;
|
import com.carrotsearch.junitbenchmarks.Clock;
|
||||||
@@ -22,19 +12,28 @@ import j2html.tags.DomContent;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
|
import static j2html.TagCreator.attrs;
|
||||||
|
import static j2html.TagCreator.body;
|
||||||
|
import static j2html.TagCreator.div;
|
||||||
|
import static j2html.TagCreator.h1;
|
||||||
|
import static j2html.TagCreator.h2;
|
||||||
|
import static j2html.TagCreator.head;
|
||||||
|
import static j2html.TagCreator.html;
|
||||||
|
import static j2html.TagCreator.p;
|
||||||
|
import static j2html.TagCreator.title;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@BenchmarkOptions(callgc = false, benchmarkRounds = 50000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
|
@BenchmarkOptions(callgc = false, benchmarkRounds = 50000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
|
||||||
public class RenderPerformanceTest {
|
public class RenderPerformanceTest {
|
||||||
|
|
||||||
String expected = "<html><head><title>Browsertitle</title></head><body><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div class=\"button\"><div class=\"button-text\">Action!</div></div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></body></html>";
|
|
||||||
@Rule
|
@Rule
|
||||||
public TestRule benchmarkRun = new BenchmarkRule();
|
public TestRule benchmarkRun = new BenchmarkRule();
|
||||||
|
String expected = "<html><head><title>Browsertitle</title></head><body><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div class=\"button\"><div class=\"button-text\">Action!</div></div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></body></html>";
|
||||||
private DomContent template;
|
private DomContent template;
|
||||||
|
|
||||||
public RenderPerformanceTest() {
|
public RenderPerformanceTest() {
|
||||||
this.template =
|
this.template =
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
html(
|
html(
|
||||||
head(
|
head(
|
||||||
title(new BrowserTitle())
|
title(new BrowserTitle())
|
||||||
@@ -68,7 +67,7 @@ public class RenderPerformanceTest {
|
|||||||
|
|
||||||
private DomContent getDomContent(PageModel pageModel) throws Exception {
|
private DomContent getDomContent(PageModel pageModel) throws Exception {
|
||||||
return
|
return
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
html(
|
html(
|
||||||
head(
|
head(
|
||||||
title(pageModel.getTitle())
|
title(pageModel.getTitle())
|
||||||
|
|||||||
17
src/test/java/j2html/comparison/ComparisonData.java
Normal file
17
src/test/java/j2html/comparison/ComparisonData.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package j2html.comparison;
|
||||||
|
|
||||||
|
import j2html.comparison.model.Employee;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class ComparisonData {
|
||||||
|
|
||||||
|
public static List<Integer> tableNumbers = IntStream.range(1, 51).boxed().collect(Collectors.toList());
|
||||||
|
|
||||||
|
public static List<Employee> fiveHundredEmployees() {
|
||||||
|
return IntStream.range(0, 500).mapToObj(i -> new Employee(i, "Some name", "Some title")).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package j2html.comparison;
|
||||||
|
|
||||||
|
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
|
||||||
|
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
|
||||||
|
import com.carrotsearch.junitbenchmarks.Clock;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TestRule;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@BenchmarkOptions(callgc = false, benchmarkRounds = 20_000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
|
||||||
|
public class RenderPerformanceComparisonTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestRule benchmarkRun = new BenchmarkRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void j2htmlPerformance() throws Exception {
|
||||||
|
TestJ2html.helloWorld();
|
||||||
|
TestJ2html.fiveHundredEmployees();
|
||||||
|
TestJ2html.macros();
|
||||||
|
TestJ2html.multiplicationTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void velocityPerformance() throws Exception {
|
||||||
|
TestVelocity.helloWorld();
|
||||||
|
TestVelocity.fiveHundredEmployees();
|
||||||
|
TestVelocity.macros();
|
||||||
|
TestVelocity.multiplicationTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
src/test/java/j2html/comparison/TestJ2html.java
Normal file
30
src/test/java/j2html/comparison/TestJ2html.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package j2html.comparison;
|
||||||
|
|
||||||
|
import j2html.comparison.j2html.FiveHundredEmployees;
|
||||||
|
import j2html.comparison.j2html.HelloWorld;
|
||||||
|
import j2html.comparison.j2html.Macros;
|
||||||
|
import j2html.comparison.j2html.MultiplicationTable;
|
||||||
|
|
||||||
|
public class TestJ2html {
|
||||||
|
|
||||||
|
public static String helloWorld() {
|
||||||
|
return HelloWorld.tag.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fiveHundredEmployees() {
|
||||||
|
return FiveHundredEmployees.tag.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String macros() {
|
||||||
|
return Macros.tag.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String multiplicationTable() {
|
||||||
|
return MultiplicationTable.tag.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(MultiplicationTable.tag.renderFormatted());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
52
src/test/java/j2html/comparison/TestVelocity.java
Normal file
52
src/test/java/j2html/comparison/TestVelocity.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package j2html.comparison;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.velocity.VelocityContext;
|
||||||
|
import org.apache.velocity.app.VelocityEngine;
|
||||||
|
|
||||||
|
public class TestVelocity {
|
||||||
|
|
||||||
|
private static VelocityEngine velocityEngine;
|
||||||
|
|
||||||
|
static {
|
||||||
|
velocityEngine = new VelocityEngine();
|
||||||
|
velocityEngine.setProperty("resource.loader", "class");
|
||||||
|
velocityEngine.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String render(String templatePath, Map<String, Object> model) {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
velocityEngine.getTemplate(templatePath, StandardCharsets.UTF_8.name()).merge(
|
||||||
|
new VelocityContext(model), stringWriter
|
||||||
|
);
|
||||||
|
return stringWriter.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String helloWorld() {
|
||||||
|
return render("/comparison/velocity/helloWorld.vm", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fiveHundredEmployees() {
|
||||||
|
Map<String, Object> model = new HashMap<>();
|
||||||
|
model.put("employees", ComparisonData.fiveHundredEmployees());
|
||||||
|
return render("/comparison/velocity/fiveHundredEmployees.vm", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String macros() {
|
||||||
|
return render("/comparison/velocity/macros.vm", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String multiplicationTable() {
|
||||||
|
Map<String, Object> model = new HashMap<>();
|
||||||
|
model.put("tableNumbers", ComparisonData.tableNumbers);
|
||||||
|
return render("/comparison/velocity/multiplicationTable.vm", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(multiplicationTable());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package j2html.comparison.j2html;
|
||||||
|
|
||||||
|
import j2html.comparison.ComparisonData;
|
||||||
|
import j2html.tags.ContainerTag;
|
||||||
|
import static j2html.TagCreator.each;
|
||||||
|
import static j2html.TagCreator.li;
|
||||||
|
import static j2html.TagCreator.ul;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.join;
|
||||||
|
|
||||||
|
public class FiveHundredEmployees {
|
||||||
|
|
||||||
|
public static ContainerTag tag = ul(
|
||||||
|
each(ComparisonData.fiveHundredEmployees(), employee ->
|
||||||
|
li(join(employee.getId(), employee.getName(), employee.getTitle()))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
27
src/test/java/j2html/comparison/j2html/HelloWorld.java
Normal file
27
src/test/java/j2html/comparison/j2html/HelloWorld.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package j2html.comparison.j2html;
|
||||||
|
|
||||||
|
import j2html.tags.ContainerTag;
|
||||||
|
import static j2html.TagCreator.attrs;
|
||||||
|
import static j2html.TagCreator.body;
|
||||||
|
import static j2html.TagCreator.h1;
|
||||||
|
import static j2html.TagCreator.head;
|
||||||
|
import static j2html.TagCreator.html;
|
||||||
|
import static j2html.TagCreator.link;
|
||||||
|
import static j2html.TagCreator.main;
|
||||||
|
import static j2html.TagCreator.title;
|
||||||
|
|
||||||
|
public class HelloWorld {
|
||||||
|
|
||||||
|
public static ContainerTag tag = html(
|
||||||
|
head(
|
||||||
|
title("Title"),
|
||||||
|
link().withRel("stylesheet").withHref("/css/main.css")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
main(attrs("#main.content"),
|
||||||
|
h1("Heading!")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
46
src/test/java/j2html/comparison/j2html/Macros.java
Normal file
46
src/test/java/j2html/comparison/j2html/Macros.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package j2html.comparison.j2html;
|
||||||
|
|
||||||
|
import j2html.tags.ContainerTag;
|
||||||
|
import j2html.tags.DomContent;
|
||||||
|
import static j2html.TagCreator.attrs;
|
||||||
|
import static j2html.TagCreator.body;
|
||||||
|
import static j2html.TagCreator.div;
|
||||||
|
import static j2html.TagCreator.h1;
|
||||||
|
import static j2html.TagCreator.head;
|
||||||
|
import static j2html.TagCreator.html;
|
||||||
|
import static j2html.TagCreator.link;
|
||||||
|
import static j2html.TagCreator.main;
|
||||||
|
import static j2html.TagCreator.title;
|
||||||
|
|
||||||
|
public class Macros {
|
||||||
|
|
||||||
|
public static ContainerTag tag = mainLayout(
|
||||||
|
div(
|
||||||
|
h1("Example content"),
|
||||||
|
someMacro(1),
|
||||||
|
someMacro(2),
|
||||||
|
someMacro(3)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static ContainerTag mainLayout(DomContent content) {
|
||||||
|
return html(
|
||||||
|
head(
|
||||||
|
title("Title"),
|
||||||
|
link().withRel("stylesheet").withHref("/css/main.css")
|
||||||
|
),
|
||||||
|
body(
|
||||||
|
main(attrs("#main.content"),
|
||||||
|
content
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ContainerTag someMacro(int i) {
|
||||||
|
return div(
|
||||||
|
"Macro call " + i
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package j2html.comparison.j2html;
|
||||||
|
|
||||||
|
import j2html.comparison.ComparisonData;
|
||||||
|
import j2html.tags.ContainerTag;
|
||||||
|
import static j2html.TagCreator.each;
|
||||||
|
import static j2html.TagCreator.table;
|
||||||
|
import static j2html.TagCreator.tbody;
|
||||||
|
import static j2html.TagCreator.td;
|
||||||
|
import static j2html.TagCreator.tr;
|
||||||
|
|
||||||
|
public class MultiplicationTable {
|
||||||
|
|
||||||
|
public static ContainerTag tag = table(
|
||||||
|
tbody(
|
||||||
|
each(ComparisonData.tableNumbers, i -> tr(
|
||||||
|
each(ComparisonData.tableNumbers, j -> td(
|
||||||
|
String.valueOf(i * j)
|
||||||
|
))
|
||||||
|
))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
10
src/test/java/j2html/comparison/model/Employee.java
Normal file
10
src/test/java/j2html/comparison/model/Employee.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package j2html.comparison.model;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class Employee {
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
String title;
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package j2html.model;
|
package j2html.model;
|
||||||
|
|
||||||
import static j2html.TagCreator.div;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import j2html.tags.ContainerTag;
|
import j2html.tags.ContainerTag;
|
||||||
|
import java.io.IOException;
|
||||||
|
import static j2html.TagCreator.div;
|
||||||
|
|
||||||
public class Button extends Template<PageModel> {
|
public class Button extends Template<PageModel> {
|
||||||
|
|
||||||
@@ -37,4 +35,4 @@ class ButtonText extends Template<String> {
|
|||||||
public void renderTemplate(Appendable writer, String model) throws IOException {
|
public void renderTemplate(Appendable writer, String model) throws IOException {
|
||||||
writer.append(model);
|
writer.append(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ public class ButtonModel {
|
|||||||
public ButtonModel(String text) {
|
public ButtonModel(String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/test/java/j2html/model/DynamicHrefAttribute.java
Normal file
24
src/test/java/j2html/model/DynamicHrefAttribute.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package j2html.model;
|
||||||
|
|
||||||
|
import j2html.attributes.Attribute;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DynamicHrefAttribute extends Attribute {
|
||||||
|
|
||||||
|
public DynamicHrefAttribute() {
|
||||||
|
super("href");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderModel(Appendable writer, Object model) throws IOException {
|
||||||
|
writer.append(" ");
|
||||||
|
writer.append(getName());
|
||||||
|
writer.append("=\"");
|
||||||
|
writer.append(getUrl(model));
|
||||||
|
writer.append("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl(Object model) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package j2html.model;
|
package j2html.model;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import j2html.tags.DomContent;
|
import j2html.tags.DomContent;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public abstract class Template<T> extends DomContent {
|
public abstract class Template<T> extends DomContent {
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class InlineStaticResourceTest {
|
|||||||
String expectedJs = "<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>";
|
String expectedJs = "<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>";
|
||||||
String expectedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
|
String expectedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
|
||||||
String expectedEscapedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
|
String expectedEscapedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
|
||||||
String expectedAnyContent = "public class AnyContent{}" + EOL;
|
String expectedAnyContent = "public class AnyContent {" + EOL + "}" + EOL;
|
||||||
|
|
||||||
// classpath files
|
// classpath files
|
||||||
assertThat(styleWithInlineFile_min("/test.css").render(), is(expectedCss));
|
assertThat(styleWithInlineFile_min("/test.css").render(), is(expectedCss));
|
||||||
|
|||||||
58
src/test/java/j2html/tags/RenderFormattedTest.java
Normal file
58
src/test/java/j2html/tags/RenderFormattedTest.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package j2html.tags;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import static j2html.TagCreator.div;
|
||||||
|
import static j2html.TagCreator.each;
|
||||||
|
import static j2html.TagCreator.li;
|
||||||
|
import static j2html.TagCreator.p;
|
||||||
|
import static j2html.TagCreator.pre;
|
||||||
|
import static j2html.TagCreator.textarea;
|
||||||
|
import static j2html.TagCreator.ul;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
public class RenderFormattedTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormattedTags() throws Exception {
|
||||||
|
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormattedTags_doesntFormatPre() throws Exception {
|
||||||
|
assertThat(div(pre("public void renderModel(Appendable writer, Object model) throws IOException {\n" +
|
||||||
|
" writer.append(text);\n" +
|
||||||
|
" }")).renderFormatted(), is("<div>\n" +
|
||||||
|
" <pre>public void renderModel(Appendable writer, Object model) throws IOException {\n" +
|
||||||
|
" writer.append(text);\n" +
|
||||||
|
" }</pre>\n" +
|
||||||
|
"</div>\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormattedTags_doesntFormatTextArea() throws Exception {
|
||||||
|
assertThat(div(textarea("fred\ntom")).renderFormatted(), is("<div>\n" +
|
||||||
|
" <textarea>fred\n" +
|
||||||
|
"tom</textarea>\n" +
|
||||||
|
"</div>\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormattedTags_each() throws Exception {
|
||||||
|
assertThat(ul(each(asList(1, 2, 3), i -> li("Number " + i))).renderFormatted(), is(
|
||||||
|
"<ul>\n" +
|
||||||
|
" <li>\n" +
|
||||||
|
" Number 1\n" +
|
||||||
|
" </li>\n" +
|
||||||
|
" <li>\n" +
|
||||||
|
" Number 2\n" +
|
||||||
|
" </li>\n" +
|
||||||
|
" <li>\n" +
|
||||||
|
" Number 3\n" +
|
||||||
|
" </li>\n" +
|
||||||
|
"</ul>\n"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,9 +2,12 @@ package j2html.tags;
|
|||||||
|
|
||||||
import j2html.Config;
|
import j2html.Config;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.junit.Ignore;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import static j2html.TagCreator.*;
|
import static j2html.TagCreator.*;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -17,6 +20,14 @@ public class TagCreatorTest {
|
|||||||
|
|
||||||
List<Employee> employees = Arrays.asList(new Employee(1, "Name 1", "Title 1"), new Employee(2, "Name 2", "Title 2"), new Employee(3, "Name 3", "Title 3"));
|
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"));
|
||||||
|
|
||||||
|
Map<Integer, Employee> employeeMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
employeeMap.put(1, new Employee(1, "Name 1", "Title 1"));
|
||||||
|
employeeMap.put(2, new Employee(2, "Name 2", "Title 2"));
|
||||||
|
employeeMap.put(3, new Employee(3, "Name 3", "Title 3"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDocument() throws Exception {
|
public void testDocument() throws Exception {
|
||||||
@@ -39,6 +50,17 @@ public class TagCreatorTest {
|
|||||||
assertThat(actual, is(expected));
|
assertThat(actual, is(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIffOptional() {
|
||||||
|
String expected = "<div><p>Test</p><a href=\"#1\">Test</a></div>";
|
||||||
|
String actual = div(
|
||||||
|
p("Test"),
|
||||||
|
iff(Optional.of(1), i -> a("Test").withHref("#" + i)),
|
||||||
|
iff(Optional.empty(), i -> a("Tast").withHref("#2"))
|
||||||
|
).render();
|
||||||
|
assertThat(actual, is(expected));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIffElse() throws Exception {
|
public void testIffElse() throws Exception {
|
||||||
String expected = "<div><p>Tast</p></div>";
|
String expected = "<div><p>Tast</p></div>";
|
||||||
@@ -54,7 +76,13 @@ public class TagCreatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // Having some trouble with RetroLambda setup
|
public void testJoinWithNulls() throws Exception {
|
||||||
|
String expected = "This is my joined string. It has ignored null content in the middle.";
|
||||||
|
String actual = join("This is my joined string.", iff(false, "this should not be displayed"), "It has ignored null content in the middle.").render();
|
||||||
|
assertThat(actual, is(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testEach() throws Exception {
|
public void testEach() throws Exception {
|
||||||
String j2htmlMap = ul().with(
|
String j2htmlMap = ul().with(
|
||||||
li("Begin list"),
|
li("Begin list"),
|
||||||
@@ -70,12 +98,31 @@ public class TagCreatorTest {
|
|||||||
p(employee.title)
|
p(employee.title)
|
||||||
)).map(DomContent::render).collect(Collectors.joining()))
|
)).map(DomContent::render).collect(Collectors.joining()))
|
||||||
).render();
|
).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>"));
|
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>"));
|
||||||
|
assertThat(j2htmlMap.equals(javaMap), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEachWithMap() {
|
||||||
|
final String j2htmlMap = ul().with(
|
||||||
|
li("Begin list"),
|
||||||
|
each(employeeMap, entry -> li(entry.getKey() + "-" + entry.getValue().name))
|
||||||
|
).render();
|
||||||
|
|
||||||
|
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEachWithMapAndBiFunction() {
|
||||||
|
final String j2htmlMap = ul().with(
|
||||||
|
li("Begin list"),
|
||||||
|
each(employeeMap, (id, employee) -> li(id + "-" + employee.name))
|
||||||
|
).render();
|
||||||
|
|
||||||
|
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // Having some trouble with RetroLambda setup
|
|
||||||
public void testFilter() throws Exception {
|
public void testFilter() throws Exception {
|
||||||
String j2htmlFilter = ul().with(
|
String j2htmlFilter = ul().with(
|
||||||
li("Begin list"),
|
li("Begin list"),
|
||||||
@@ -91,8 +138,18 @@ public class TagCreatorTest {
|
|||||||
p(employee.title)
|
p(employee.title)
|
||||||
)).map(DomContent::render).collect(Collectors.joining()))
|
)).map(DomContent::render).collect(Collectors.joining()))
|
||||||
).render();
|
).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>"));
|
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>"));
|
||||||
|
assertThat(j2htmlFilter.equals(javaFilter), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEachWithStream() throws Exception {
|
||||||
|
final String j2htmlMap = ul().with(
|
||||||
|
li("Begin list"),
|
||||||
|
each(employeeMap.entrySet().stream().map(e -> li(e.getKey() + "-" + e.getValue().name)))
|
||||||
|
).render();
|
||||||
|
|
||||||
|
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package j2html.tags;
|
package j2html.tags;
|
||||||
|
|
||||||
import j2html.Config;
|
import j2html.Config;
|
||||||
|
import j2html.model.DynamicHrefAttribute;
|
||||||
|
import java.io.FileWriter;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import static j2html.TagCreator.body;
|
import static j2html.TagCreator.body;
|
||||||
import static j2html.TagCreator.div;
|
import static j2html.TagCreator.div;
|
||||||
@@ -92,5 +94,23 @@ public class TagTest {
|
|||||||
assertThat(testTagAttrWithoutAttr.render(), is("<a attribute></a>"));
|
assertThat(testTagAttrWithoutAttr.render(), is("<a attribute></a>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicAttribute() throws Exception {
|
||||||
|
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr(new DynamicHrefAttribute());
|
||||||
|
assertThat(testTagWithAttrValueNull.render(), is("<a href=\"/\"></a>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicAttributeReplacement() throws Exception {
|
||||||
|
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr("href", "/link").attr(new DynamicHrefAttribute());
|
||||||
|
assertThat(testTagWithAttrValueNull.render(), is("<a href=\"/\"></a>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderToFile() throws Exception {
|
||||||
|
FileWriter fileWriter = new FileWriter("file.txt");
|
||||||
|
div("Test").render(fileWriter);
|
||||||
|
fileWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
public class AnyContent{}
|
public class AnyContent {
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#* @vtlvariable name="employees" type="java.util.List<j2html.comparison.ComparisonData.Employee>" *#
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
#foreach($employee in $employees)
|
||||||
|
<li>$employee.id $employee.name $employee.title</li>
|
||||||
|
#end
|
||||||
|
</ul>
|
||||||
11
src/test/resources/comparison/velocity/helloWorld.vm
Normal file
11
src/test/resources/comparison/velocity/helloWorld.vm
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Title</title>
|
||||||
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="main" class="content">
|
||||||
|
<h1>Heading!</h1>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
src/test/resources/comparison/velocity/macros.vm
Normal file
28
src/test/resources/comparison/velocity/macros.vm
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#macro(mainLayout)
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Title</title>
|
||||||
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="main" class="content">
|
||||||
|
$!bodyContent
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
#end
|
||||||
|
|
||||||
|
#@mainLayout()
|
||||||
|
<div>
|
||||||
|
<h1>Example content</h1>
|
||||||
|
#someMacro(1)
|
||||||
|
#someMacro(2)
|
||||||
|
#someMacro(3)
|
||||||
|
</div>
|
||||||
|
#end
|
||||||
|
|
||||||
|
#macro(someMacro $callNumber)
|
||||||
|
<div>
|
||||||
|
Macro call $callNumber
|
||||||
|
</div>
|
||||||
|
#end
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
#foreach($i in $tableNumbers)
|
||||||
|
<tr>
|
||||||
|
#foreach($j in $tableNumbers)
|
||||||
|
#set($product = $i * $j)
|
||||||
|
<td>$product</td>
|
||||||
|
#end
|
||||||
|
</tr>
|
||||||
|
#end
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
Reference in New Issue
Block a user