Compare commits
35 Commits
j2html-1.0
...
j2html-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb3f28a09f | ||
|
|
368241313d | ||
|
|
4288924f8f | ||
|
|
9948095c08 | ||
|
|
56090046b5 | ||
|
|
d45af42650 | ||
|
|
7d65f91f44 | ||
|
|
aecf5e71d6 | ||
|
|
cf47772c89 | ||
|
|
897c53d830 | ||
|
|
1e29d81107 | ||
|
|
dee3efb8e7 | ||
|
|
ee82201dfb | ||
|
|
691680ea51 | ||
|
|
0853692e80 | ||
|
|
c2bc4b3209 | ||
|
|
ff9d138f63 | ||
|
|
f778f4df3c | ||
|
|
a0b060ac42 | ||
|
|
4161be67bb | ||
|
|
863527f684 | ||
|
|
5ef2dd3ec5 | ||
|
|
fc3bb29b6a | ||
|
|
ef5777e54a | ||
|
|
cfc1489399 | ||
|
|
8112dad1bb | ||
|
|
235dec78ed | ||
|
|
6316dd2262 | ||
|
|
5667d7c68d | ||
|
|
13911d5f57 | ||
|
|
0bc6e274db | ||
|
|
325afd463c | ||
|
|
f331eb9eb3 | ||
|
|
d37dc1cac6 | ||
|
|
dab61bd662 |
@@ -13,12 +13,12 @@ The project webpage is [j2html.com](http://j2html.com).
|
||||
<dependency>
|
||||
<groupId>com.j2html</groupId>
|
||||
<artifactId>j2html</artifactId>
|
||||
<version>0.99</version>
|
||||
<version>1.2.0</version>
|
||||
</dependency>
|
||||
```
|
||||
### OR the gradle dependency
|
||||
```
|
||||
compile 'com.j2html:j2html:0.99'
|
||||
compile 'com.j2html:j2html:1.2.0'
|
||||
```
|
||||
|
||||
### Import TagCreator and start building HTML
|
||||
|
||||
3
pom.xml
3
pom.xml
@@ -10,7 +10,7 @@
|
||||
|
||||
<groupId>com.j2html</groupId>
|
||||
<artifactId>j2html</artifactId>
|
||||
<version>1.0.0-RC</version>
|
||||
<version>1.2.1</version>
|
||||
|
||||
<name>j2html</name>
|
||||
<description>Java to HTML builder with a fluent API</description>
|
||||
@@ -70,6 +70,7 @@
|
||||
<version>2.5.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<?m2e ignore?>
|
||||
<goals>
|
||||
<goal>process-main</goal>
|
||||
<goal>process-test</goal>
|
||||
|
||||
50
src/main/java/j2html/Config.java
Normal file
50
src/main/java/j2html/Config.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package j2html;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import j2html.utils.CSSMin;
|
||||
import j2html.utils.EscapeUtil;
|
||||
import j2html.utils.Indenter;
|
||||
import j2html.utils.JSMin;
|
||||
import j2html.utils.Minifier;
|
||||
import j2html.utils.TextEscaper;
|
||||
|
||||
public class Config {
|
||||
|
||||
private static String FOUR_SPACES = " ";
|
||||
|
||||
private Config() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Change this to configure text-escaping
|
||||
* For example, to disable escaping, do <code>{@code Config.textEscaper = text -> text;}</code>
|
||||
*/
|
||||
public static TextEscaper textEscaper = EscapeUtil::escape;
|
||||
|
||||
/**
|
||||
* Change this to configure css-minification.
|
||||
* The default minifier is https://github.com/barryvan/CSSMin
|
||||
*/
|
||||
public static Minifier cssMinifier = CSSMin::compressCss;
|
||||
|
||||
/**
|
||||
* Change this to configure js-minification.
|
||||
* The default minifier is a simple whitespace/newline stripper
|
||||
*/
|
||||
public static Minifier jsMinifier = JSMin::compressJs;
|
||||
|
||||
/**
|
||||
* Change this to configure indentation when rendering formatted html
|
||||
* The default is four spaces
|
||||
*/
|
||||
public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;
|
||||
|
||||
|
||||
/**
|
||||
* Change this to configure enable/disable closing empty tags
|
||||
* The default is to NOT close them
|
||||
*/
|
||||
public static boolean closeEmptyTags = false;
|
||||
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public class TagCreator {
|
||||
*/
|
||||
public static String document(ContainerTag htmlTag) {
|
||||
if (htmlTag.getTagName().equals("html")) {
|
||||
return new EmptyTag("!DOCTYPE html").render() + htmlTag.render();
|
||||
return document().render() + htmlTag.render();
|
||||
}
|
||||
throw new IllegalArgumentException("Only HTML-tag can follow document declaration");
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class TagCreator {
|
||||
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); }
|
||||
|
||||
public static EmptyTag document() { return new EmptyTag("!DOCTYPE html"); }
|
||||
public static DomContent document() { return rawHtml("<!DOCTYPE html>"); }
|
||||
|
||||
// EmptyTags, generated in class j2html.tags.TagCreatorCodeGenerator
|
||||
public static EmptyTag area() { return new EmptyTag("area"); }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package j2html.attributes;
|
||||
|
||||
|
||||
import j2html.utils.SimpleEscaper;
|
||||
import j2html.Config;
|
||||
|
||||
public class Attribute {
|
||||
private String name;
|
||||
@@ -9,7 +9,7 @@ public class Attribute {
|
||||
|
||||
public Attribute(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = SimpleEscaper.escape(value);
|
||||
this.value = Config.textEscaper.escape(value);
|
||||
}
|
||||
|
||||
public Attribute(String name) {
|
||||
|
||||
@@ -4,13 +4,15 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import j2html.Config;
|
||||
|
||||
public class ContainerTag extends Tag<ContainerTag> {
|
||||
|
||||
private List<DomContent> children;
|
||||
|
||||
public ContainerTag(String tagName) {
|
||||
super(tagName);
|
||||
this.children = new ArrayList<DomContent>();
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +113,12 @@ public class ContainerTag extends Tag<ContainerTag> {
|
||||
return with(new Text(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of child nodes this tag element contains
|
||||
*/
|
||||
public int getNumChildren() {
|
||||
return children.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the ContainerTag and its children
|
||||
@@ -120,7 +128,7 @@ public class ContainerTag extends Tag<ContainerTag> {
|
||||
@Override
|
||||
public String render() {
|
||||
StringBuilder rendered = new StringBuilder(renderOpenTag());
|
||||
if (children != null && !children.isEmpty()) {
|
||||
if (!children.isEmpty()) {
|
||||
for (DomContent child : children) {
|
||||
rendered.append(child.render());
|
||||
}
|
||||
@@ -129,6 +137,34 @@ public class ContainerTag extends Tag<ContainerTag> {
|
||||
return rendered.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the ContainerTag and its children, adding newlines before each
|
||||
* child and using Config.indenter to indent child based on how deep
|
||||
* in the tree it is
|
||||
*
|
||||
* @return the rendered and formatted string
|
||||
*/
|
||||
public String renderFormatted() {
|
||||
return renderFormatted(0);
|
||||
}
|
||||
|
||||
private String renderFormatted(int lvl) {
|
||||
StringBuilder sb = new StringBuilder(renderOpenTag() + "\n");
|
||||
if (!children.isEmpty()) {
|
||||
for (DomContent c : children) {
|
||||
lvl++;
|
||||
if (c instanceof ContainerTag) {
|
||||
sb.append(Config.indenter.indent(lvl, ((ContainerTag) c).renderFormatted(lvl)));
|
||||
} else {
|
||||
sb.append(Config.indenter.indent(lvl, c.render())).append("\n");
|
||||
}
|
||||
lvl--;
|
||||
}
|
||||
}
|
||||
sb.append(Config.indenter.indent(lvl, renderCloseTag())).append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Appendable writer) throws IOException {
|
||||
writer.append(renderOpenTag());
|
||||
|
||||
@@ -6,9 +6,9 @@ public class DomContentJoiner {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object o : stringOrDomObjects) {
|
||||
if (o instanceof String) {
|
||||
sb.append(((String) o).trim()).append(" ");
|
||||
sb.append(((String) o).trim()).append(delimiter);
|
||||
} else if (o instanceof DomContent) {
|
||||
sb.append(((DomContent) o).render().trim()).append(" ");
|
||||
sb.append(((DomContent) o).render().trim()).append(delimiter);
|
||||
} else {
|
||||
throw new RuntimeException("You can only join DomContent and String objects");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package j2html.tags;
|
||||
|
||||
import j2html.Config;
|
||||
|
||||
public class EmptyTag extends Tag<EmptyTag> {
|
||||
|
||||
public EmptyTag(String tagName) {
|
||||
@@ -8,6 +10,10 @@ public class EmptyTag extends Tag<EmptyTag> {
|
||||
|
||||
@Override
|
||||
public String render() {
|
||||
if (Config.closeEmptyTags) {
|
||||
String tag = renderOpenTag();
|
||||
return tag.substring(0, tag.length() - 1) + "/>";
|
||||
}
|
||||
return renderOpenTag();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package j2html.tags;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
import j2html.utils.CSSMin;
|
||||
import j2html.utils.JSMin;
|
||||
import j2html.Config;
|
||||
|
||||
import static j2html.TagCreator.*;
|
||||
|
||||
@@ -16,8 +15,8 @@ public class InlineStaticResource {
|
||||
public static ContainerTag get(String path, TargetFormat format) {
|
||||
String fileString = getFileAsString(path);
|
||||
switch (format) {
|
||||
case CSS_MIN : return style().with(rawHtml(CSSMin.compress(fileString)));
|
||||
case JS_MIN : return script().with(rawHtml(JSMin.compressJs(fileString)));
|
||||
case CSS_MIN : return style().with(rawHtml(Config.cssMinifier.minify(fileString)));
|
||||
case JS_MIN : return script().with(rawHtml(Config.jsMinifier.minify((fileString))));
|
||||
case CSS : return style().with(rawHtml(fileString));
|
||||
case JS : return script().with(rawHtml(fileString));
|
||||
default : throw new RuntimeException("Invalid target format");
|
||||
@@ -26,27 +25,19 @@ public class InlineStaticResource {
|
||||
|
||||
public static String getFileAsString(String path) {
|
||||
try {
|
||||
return readFileAsString(InlineStaticResource.class.getResource(path).getPath());
|
||||
} catch (Exception e1) {
|
||||
return streamToString(InlineStaticResource.class.getResourceAsStream(path));
|
||||
} catch (Exception expected) { // we don't ask users to specify classpath or file-system
|
||||
try {
|
||||
return readFileAsString(path);
|
||||
} catch (Exception e2) {
|
||||
return streamToString(new FileInputStream(path));
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("Couldn't find file with path='" + path + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kjheimark <3
|
||||
*/
|
||||
private static String readFileAsString(String path) throws IOException {
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int c;
|
||||
while ((c = bufferedReader.read()) >= 0 && c >= 0) {
|
||||
sb.append((char) c);
|
||||
}
|
||||
return sb.toString();
|
||||
private static String streamToString(InputStream inputStream) {
|
||||
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package j2html.tags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import j2html.attributes.Attr;
|
||||
import j2html.attributes.Attribute;
|
||||
@@ -14,7 +12,7 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
|
||||
protected Tag(String tagName) {
|
||||
this.tagName = tagName;
|
||||
this.attributes = new ArrayList<Attribute>();
|
||||
this.attributes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getTagName() {
|
||||
@@ -63,8 +61,8 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
* @param value the attribute value
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T attr(String attribute, String value) {
|
||||
setAttribute(attribute, value);
|
||||
public T attr(String attribute, Object value) {
|
||||
setAttribute(attribute, value == null ? null : String.valueOf(value));
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@@ -73,7 +71,7 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
*
|
||||
* @param attribute the attribute name
|
||||
* @return itself for easy chaining
|
||||
* @see Tag#attr(String, String)
|
||||
* @see Tag#attr(String, Object)
|
||||
*/
|
||||
public T attr(String attribute) {
|
||||
return attr(attribute, null);
|
||||
@@ -82,7 +80,7 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
|
||||
/**
|
||||
* Call attr-method based on condition
|
||||
* {@link #attr(String attribute, String value)}
|
||||
* {@link #attr(String attribute, Object value)}
|
||||
*
|
||||
* @param condition the condition
|
||||
* @param attribute the attribute name
|
||||
@@ -105,6 +103,7 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
|
||||
/**
|
||||
* Convenience methods that call attr with predefined attributes
|
||||
*
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
|
||||
@@ -125,13 +124,16 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
public T withCharset(String charset) { return attr(Attr.CHARSET, charset); }
|
||||
public T withClass(String className) { return attr(Attr.CLASS, className); }
|
||||
public T withContent(String content) { return attr(Attr.CONTENT, content); }
|
||||
public T withDir(String dir) { return attr(Attr.DIR, dir); }
|
||||
public T withHref(String href) { return attr(Attr.HREF, href); }
|
||||
public T withId(String id) { return attr(Attr.ID, id); }
|
||||
public T withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
|
||||
public T withLang(String lang) { return attr(Attr.LANG, lang); }
|
||||
public T withMethod(String method) { return attr(Attr.METHOD, method); }
|
||||
public T withName(String name) { return attr(Attr.NAME, name); }
|
||||
public T withPlaceholder(String placeholder) { return attr(Attr.PLACEHOLDER, placeholder); }
|
||||
public T withTarget(String target) { return attr(Attr.TARGET, target); }
|
||||
public T withTitle(String title) { return attr(Attr.TITLE, title); }
|
||||
public T withType(String type) { return attr(Attr.TYPE, type); }
|
||||
public T withRel(String rel) { return attr(Attr.REL, rel); }
|
||||
public T withRole(String role) { return attr(Attr.ROLE, role); }
|
||||
@@ -148,13 +150,16 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
|
||||
public T withCharset(boolean condition, String charset) { return condAttr(condition, Attr.CHARSET, charset); }
|
||||
public T withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
|
||||
public T withCondContent(boolean condition, String content) { return condAttr(condition, Attr.CONTENT, content); }
|
||||
public T withCondDir(boolean condition, String dir) { return condAttr(condition, Attr.DIR, dir); }
|
||||
public T withCondHref(boolean condition, String href) { return condAttr(condition, Attr.HREF, href); }
|
||||
public T withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
|
||||
public T withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
|
||||
public T withCondLang(boolean condition, String lang) { return condAttr(condition, Attr.LANG, lang); }
|
||||
public T withCondMethod(boolean condition, String method) { return condAttr(condition, Attr.METHOD, method); }
|
||||
public T withCondName(boolean condition, String name) { return condAttr(condition, Attr.NAME, name); }
|
||||
public T withCondPlaceholder(boolean condition, String placeholder) { return condAttr(condition, Attr.PLACEHOLDER, placeholder); }
|
||||
public T withCondTarget(boolean condition, String target) { return condAttr(condition, Attr.TARGET, target); }
|
||||
public T withCondTitle(boolean condition, String title) { return condAttr(condition, Attr.TITLE, title); }
|
||||
public T withCondType(boolean condition, String type) { return condAttr(condition, Attr.TYPE, type); }
|
||||
public T withCondRel(boolean condition, String rel) { return condAttr(condition, Attr.REL, rel); }
|
||||
public T withCondSrc(boolean condition, String src) { return condAttr(condition, Attr.SRC, src); }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package j2html.tags;
|
||||
|
||||
import j2html.utils.SimpleEscaper;
|
||||
import j2html.Config;
|
||||
|
||||
public class Text extends DomContent {
|
||||
|
||||
@@ -12,7 +12,7 @@ public class Text extends DomContent {
|
||||
|
||||
@Override
|
||||
public String render() {
|
||||
return SimpleEscaper.escape(text);
|
||||
return Config.textEscaper.escape(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* * CSSMin Copyright License Agreement (BSD License)
|
||||
* <p>
|
||||
* Copyright (c) 2011-2014, Barry van Oudtshoorn
|
||||
@@ -79,11 +79,11 @@ public class CSSMin {
|
||||
* @param input the CSS
|
||||
* @return the compressed version
|
||||
*/
|
||||
public static String compress(String input) {
|
||||
public static String compressCss(String input) {
|
||||
try {
|
||||
int k,
|
||||
j, // Number of open braces
|
||||
n; // Current position in stream
|
||||
j, // Number of open braces
|
||||
n; // Current position in stream
|
||||
char curr;
|
||||
|
||||
BufferedReader br = new BufferedReader(new StringReader(input));
|
||||
@@ -124,7 +124,7 @@ public class CSSMin {
|
||||
if (debugLogging) {
|
||||
LOG.info("Parsing and processing selectors...");
|
||||
}
|
||||
Vector<Selector> selectors = new Vector<Selector>();
|
||||
Vector<Selector> selectors = new Vector<>();
|
||||
n = 0;
|
||||
j = 0;
|
||||
for (int i = 0; i < sb.length(); i++) {
|
||||
@@ -203,7 +203,7 @@ class Selector {
|
||||
|
||||
// We're dealing with a nested property, eg @-webkit-keyframes
|
||||
if (parts.length > 2) {
|
||||
this.subSelectors = new Vector<Selector>();
|
||||
this.subSelectors = new Vector<>();
|
||||
parts = selector.split("(\\s*\\{\\s*)|(\\s*\\}\\s*)");
|
||||
for (int i = 1; i < parts.length; i += 2) {
|
||||
parts[i] = parts[i].trim();
|
||||
@@ -224,7 +224,8 @@ class Selector {
|
||||
if (contents.length() == 1) {
|
||||
throw new EmptySelectorBodyException(selector);
|
||||
}
|
||||
contents = contents.substring(0, contents.length() - 2);
|
||||
int endIndex = contents.endsWith(";}") ? 2 : 1;
|
||||
contents = contents.substring(0, contents.length() - endIndex);
|
||||
|
||||
this.properties = new Property[0];
|
||||
this.properties = parseProperties(contents).toArray(this.properties);
|
||||
@@ -264,9 +265,9 @@ class Selector {
|
||||
* @return An array of properties parsed from this selector.
|
||||
*/
|
||||
private ArrayList<Property> parseProperties(String contents) {
|
||||
ArrayList<String> parts = new ArrayList<String>();
|
||||
ArrayList<String> parts = new ArrayList<>();
|
||||
boolean bInsideString = false,
|
||||
bInsideURL = false;
|
||||
bInsideURL = false;
|
||||
int j = 0;
|
||||
String substr;
|
||||
for (int i = 0; i < contents.length(); i++) {
|
||||
@@ -293,7 +294,7 @@ class Selector {
|
||||
parts.add(substr);
|
||||
}
|
||||
|
||||
ArrayList<Property> results = new ArrayList<Property>();
|
||||
ArrayList<Property> results = new ArrayList<>();
|
||||
for (String part : parts) {
|
||||
try {
|
||||
results.add(new Property(part));
|
||||
@@ -331,7 +332,7 @@ class Property implements Comparable<Property> {
|
||||
Property(String property) throws IncompletePropertyException {
|
||||
try {
|
||||
// Parse the property.
|
||||
ArrayList<String> parts = new ArrayList<String>();
|
||||
ArrayList<String> parts = new ArrayList<>();
|
||||
boolean bCanSplit = true;
|
||||
int j = 0;
|
||||
String substr;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package j2html.utils;
|
||||
|
||||
public class SimpleEscaper {
|
||||
public class EscapeUtil {
|
||||
|
||||
public static String escape(String s) {
|
||||
if (s == null) {
|
||||
6
src/main/java/j2html/utils/Indenter.java
Normal file
6
src/main/java/j2html/utils/Indenter.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package j2html.utils;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Indenter {
|
||||
String indent(int level, String text);
|
||||
}
|
||||
@@ -302,4 +302,4 @@ public class JSMin {
|
||||
private class UnterminatedRegExpLiteralException extends Exception {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
6
src/main/java/j2html/utils/Minifier.java
Normal file
6
src/main/java/j2html/utils/Minifier.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package j2html.utils;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Minifier {
|
||||
String minify(String s);
|
||||
}
|
||||
6
src/main/java/j2html/utils/TextEscaper.java
Normal file
6
src/main/java/j2html/utils/TextEscaper.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package j2html.utils;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TextEscaper {
|
||||
String escape(String text);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import java.util.concurrent.Callable;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import j2html.utils.SimpleEscaper;
|
||||
import j2html.utils.EscapeUtil;
|
||||
|
||||
public class PerformanceTest {
|
||||
|
||||
@@ -30,8 +30,8 @@ public class PerformanceTest {
|
||||
|
||||
@Test
|
||||
public void test_escaper_performnce() throws Exception {
|
||||
timeEscaper("SimpleEscaper#short", () -> SimpleEscaper.escape(shortTestString));
|
||||
timeEscaper("SimpleEscaper#long", () -> SimpleEscaper.escape(longTestString));
|
||||
timeEscaper("SimpleEscaper#short", () -> EscapeUtil.escape(shortTestString));
|
||||
timeEscaper("SimpleEscaper#long", () -> EscapeUtil.escape(longTestString));
|
||||
timeEscaper("ApacheEscaper#short", () -> StringEscapeUtils.escapeHtml4(shortTestString));
|
||||
timeEscaper("ApacheEscaper#long", () -> StringEscapeUtils.escapeHtml4(longTestString));
|
||||
}
|
||||
|
||||
38
src/test/java/j2html/TextEscaperTest.java
Normal file
38
src/test/java/j2html/TextEscaperTest.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package j2html;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import j2html.utils.EscapeUtil;
|
||||
import j2html.utils.TextEscaper;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class TextEscaperTest {
|
||||
|
||||
@Test
|
||||
public void testTextEscaper() throws Exception {
|
||||
String expected = "<div></div>";
|
||||
assertThat("default text escaper works",
|
||||
Config.textEscaper.escape("<div></div>"), is(expected));
|
||||
|
||||
Config.textEscaper = new NoOpEscaper();
|
||||
assertThat("user can change text escaper implementation",
|
||||
Config.textEscaper, is(instanceOf(NoOpEscaper.class)));
|
||||
|
||||
expected = "<div></div>";
|
||||
assertThat("user provided text escaper actually works",
|
||||
Config.textEscaper.escape("<div></div>"), is(expected));
|
||||
Config.textEscaper = EscapeUtil::escape; // reset escaper
|
||||
}
|
||||
|
||||
private static class NoOpEscaper implements TextEscaper {
|
||||
|
||||
@Override
|
||||
public String escape(String text) {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,25 +2,10 @@ package j2html.tags;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import j2html.TagCreator;
|
||||
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.iff;
|
||||
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 j2html.TagCreator.*;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@@ -87,10 +72,82 @@ public class ComplexRenderTest {
|
||||
).render();
|
||||
}
|
||||
|
||||
private String renderTest3() {
|
||||
boolean USER_SHOULD_LOG_IN = true;
|
||||
boolean USER_SHOULD_SIGN_UP = false;
|
||||
return document().render() + "\n" +
|
||||
html(
|
||||
head(
|
||||
title("Test")
|
||||
),
|
||||
body(
|
||||
header(
|
||||
h1(
|
||||
text("Test Header "),
|
||||
a("with link").withHref("http://example.com"),
|
||||
text(".")
|
||||
)
|
||||
),
|
||||
main(
|
||||
h2("Test Form"),
|
||||
div(
|
||||
input().withType("email").withName("email").withPlaceholder("Email"),
|
||||
input().withType("password").withName("password").withPlaceholder("Password"),
|
||||
iff(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")),
|
||||
iff(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
|
||||
)
|
||||
),
|
||||
footer("Test Footer").attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id"),
|
||||
script().withSrc("/testScript.js")
|
||||
)
|
||||
).renderFormatted();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexRender() {
|
||||
String expectedResult = "<!DOCTYPE html><html><head><title>Test</title></head><body><header><h1>Test Header <a href=\"http://example.com\">with link</a>.</h1></header><main><h2>Test Form</h2><div><input type=\"email\" name=\"email\" placeholder=\"Email\"><input type=\"password\" name=\"password\" placeholder=\"Password\"><button type=\"submit\">Login</button></div></main><footer class=\"footer\" id=\"id\">Test Footer</footer><script src=\"/testScript.js\"></script></body></html>";
|
||||
assertThat(renderTest(), is(expectedResult));
|
||||
assertThat(renderTest2(), is(expectedResult));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexRender_formatted() {
|
||||
assertThat(renderTest3(),
|
||||
is("<!DOCTYPE html>\n"
|
||||
+ "<html>\n"
|
||||
+ " <head>\n"
|
||||
+ " <title>\n"
|
||||
+ " Test\n"
|
||||
+ " </title>\n"
|
||||
+ " </head>\n"
|
||||
+ " <body>\n"
|
||||
+ " <header>\n"
|
||||
+ " <h1>\n"
|
||||
+ " Test Header \n"
|
||||
+ " <a href=\"http://example.com\">\n"
|
||||
+ " with link\n"
|
||||
+ " </a>\n"
|
||||
+ " .\n"
|
||||
+ " </h1>\n"
|
||||
+ " </header>\n"
|
||||
+ " <main>\n"
|
||||
+ " <h2>\n"
|
||||
+ " Test Form\n"
|
||||
+ " </h2>\n"
|
||||
+ " <div>\n"
|
||||
+ " <input type=\"email\" name=\"email\" placeholder=\"Email\">\n"
|
||||
+ " <input type=\"password\" name=\"password\" placeholder=\"Password\">\n"
|
||||
+ " <button type=\"submit\">\n"
|
||||
+ " Login\n"
|
||||
+ " </button>\n"
|
||||
+ " </div>\n"
|
||||
+ " </main>\n"
|
||||
+ " <footer class=\"footer\" id=\"id\">\n"
|
||||
+ " Test Footer\n"
|
||||
+ " </footer>\n"
|
||||
+ " <script src=\"/testScript.js\">\n"
|
||||
+ " </script>\n"
|
||||
+ " </body>\n"
|
||||
+ "</html>\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public class ConvenienceMethodTest {
|
||||
assertThat(input().withName("test-name").render(), is("<input name=\"test-name\">"));
|
||||
assertThat(input().withPlaceholder("test-placeholder").render(), is("<input placeholder=\"test-placeholder\">"));
|
||||
assertThat(a().withTarget("_blank").render(), is("<a target=\"_blank\"></a>"));
|
||||
assertThat(a().withTitle("Title").render(), is("<a title=\"Title\"></a>"));
|
||||
assertThat(input().withType("email").render(), is("<input type=\"email\">"));
|
||||
assertThat(link().withRel("stylesheet").render(), is("<link rel=\"stylesheet\">"));
|
||||
assertThat(link().withRole("role").render(), is("<link role=\"role\">"));
|
||||
|
||||
@@ -24,6 +24,7 @@ public class InlineStaticResourceTest {
|
||||
|
||||
// classpath files
|
||||
assertThat(styleWithInlineFile_min("/test.css").render(), is(expectedCss));
|
||||
assertThat(styleWithInlineFile_min("/test-without-trailing-semis.css").render(), is(expectedCss));
|
||||
assertThat(scriptWithInlineFile_min("/test.js").render(), is(expectedJs));
|
||||
assertThat(fileAsString("/test.html").render(), is(expectedHtml));
|
||||
assertThat(fileAsEscapedString("/test.html").render(), is(expectedEscapedHtml));
|
||||
@@ -42,4 +43,4 @@ public class InlineStaticResourceTest {
|
||||
styleWithInlineFile_min("NOT A FILE");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import j2html.Config;
|
||||
|
||||
import static j2html.TagCreator.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TagCreatorTest {
|
||||
|
||||
@@ -16,6 +19,17 @@ public class TagCreatorTest {
|
||||
|
||||
List<Employee> employees = Arrays.asList(new Employee(1, "Name 1", "Title 1"), new Employee(2, "Name 2", "Title 2"), new Employee(3, "Name 3", "Title 3"));
|
||||
|
||||
|
||||
@Test
|
||||
public void testDocument() throws Exception {
|
||||
Config.closeEmptyTags = true;
|
||||
assertEquals("<!DOCTYPE html>", document().render());
|
||||
assertEquals("<!DOCTYPE html><html></html>", document(html()));
|
||||
Config.closeEmptyTags = false;
|
||||
assertEquals("<!DOCTYPE html>", document().render());
|
||||
assertEquals("<!DOCTYPE html><html></html>", document(html()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIff() throws Exception {
|
||||
String expected = "<div><p>Test</p><a href=\"#\">Test</a></div>";
|
||||
|
||||
@@ -2,17 +2,11 @@ package j2html.tags;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static j2html.TagCreator.body;
|
||||
import static j2html.TagCreator.div;
|
||||
import static j2html.TagCreator.footer;
|
||||
import static j2html.TagCreator.header;
|
||||
import static j2html.TagCreator.html;
|
||||
import static j2html.TagCreator.iff;
|
||||
import static j2html.TagCreator.main;
|
||||
import static j2html.TagCreator.p;
|
||||
import static j2html.TagCreator.tag;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import j2html.Config;
|
||||
|
||||
import static j2html.TagCreator.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class TagTest {
|
||||
|
||||
@@ -44,6 +38,19 @@ public class TagTest {
|
||||
assertThat(testTag.renderCloseTag(), is("</a>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfClosingTags() throws Exception {
|
||||
Config.closeEmptyTags = true;
|
||||
assertThat(img().withSrc("/test.png").render(), is("<img src=\"/test.png\"/>"));
|
||||
assertThat(input().withType("text").render(), is("<input type=\"text\"/>"));
|
||||
Config.closeEmptyTags = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormattedTags() throws Exception { // better test in ComplexRenderTest.java
|
||||
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() throws Exception {
|
||||
Tag tagOne = tag("p").withClass("class").withText("Test");
|
||||
@@ -51,6 +58,16 @@ public class TagTest {
|
||||
assertThat(tagOne.equals(tagTwo), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptObjectValueAttribute() throws Exception {
|
||||
ContainerTag complexTestTag = new ContainerTag("input")
|
||||
.attr("attr1", "value1")
|
||||
.attr("attr2", 2)
|
||||
.attr("attr3", null);
|
||||
String expectedResult = "<input attr1=\"value1\" attr2=\"2\" attr3>";
|
||||
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithClasses() throws Exception {
|
||||
String expected = "<div class=\"c1 c2\"></div>";
|
||||
|
||||
7
src/test/resources/test-without-trailing-semis.css
Normal file
7
src/test/resources/test-without-trailing-semis.css
Normal file
@@ -0,0 +1,7 @@
|
||||
body {
|
||||
background: goldenrod;
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 10px
|
||||
}
|
||||
Reference in New Issue
Block a user