23 Commits

Author SHA1 Message Date
tipsy
66b298efe4 [maven-release-plugin] prepare release j2html-0.7 2015-10-24 14:36:53 +02:00
tipsy
ed44fc79e0 Revert "Prepare for .7 release"
This reverts commit c926322fb6.
2015-10-24 13:40:12 +02:00
tipsy
c926322fb6 Prepare for .7 release 2015-10-24 13:35:05 +02:00
tipsy
d52f86dd39 Add uneeded test 2015-10-24 13:21:41 +02:00
tipsy
5692033f90 Rename inline-file-method names 2015-10-22 16:05:30 +02:00
tipsy
8667fd31d7 Methods for escaped and unescaped file as string 2015-10-22 01:39:31 +02:00
tipsy
9ef6d645d8 Add method for reading any file 2015-10-21 23:10:12 +02:00
David
4a2f502e5d Update README.md 2015-10-21 20:55:02 +02:00
tipsy
f54f0a53e4 Log using logger instead of sout 2015-10-21 19:56:28 +02:00
tipsy
04439d79de Use enum in ISR class 2015-10-21 17:41:53 +02:00
tipsy
f2d6621570 Tiny refactor 2015-10-21 09:15:10 +02:00
tipsy
4f05b26dc1 Stop using properties in POM 2015-10-20 23:47:37 +02:00
tipsy
c2691df9c5 EOF newlines 2015-10-20 23:18:45 +02:00
tipsy
91b12a6da0 Move package 2015-10-20 21:10:52 +02:00
tipsy
ccd76527bc Add filereader for inline static files 2015-10-20 19:40:54 +02:00
tipsy
ef43af72a3 Java 7 support, cleanup 2015-10-19 20:22:58 +02:00
tipsy
5ad63ad1d6 Use apache commons lang for escaping 2015-10-19 20:22:57 +02:00
tipsy
e92b7ce527 Change to non-deprecated assert 2015-10-19 20:22:57 +02:00
David
7bbb3a34da Update LICENSE
Woops x)
2015-10-05 20:19:18 +02:00
David
7e3e827af5 Update README.md 2015-05-28 20:08:56 +02:00
tipsy
0f5639660d use american english spelling of license 2015-05-27 20:09:21 +02:00
David
aa64aca294 Create LICENCE 2015-05-27 20:04:35 +02:00
tipsy
6f11845140 [maven-release-plugin] prepare for next development iteration 2015-05-26 19:38:01 +02:00
22 changed files with 1189 additions and 321 deletions

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2015 David Åse
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,4 +1,37 @@
# j2html
Java to HTML generator. Enjoy typesafe HTML generation.
This project was inspired by [Gagawa](https://code.google.com/p/gagawa/)
The project webpage is [j2html.com](http://j2html.com)
##Getting started
###Add the maven dependency
```xml
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.5.0</version>
</dependency>
```
###Import TagCreator and start building HTML
```java
import static j2html.TagCreator.*;
public class Main {
public static void main(String[] args) {
body().with(
h1("Heading!").withClass("example"),
img().withSrc("img/hello.png")
).render();
}
}
```
The above Java will result in the following HTML:
```html
<body>
<h1 class="example">Heading!</h1>
<img src="img/hello.png">
</body>
```
Find more examples at http://j2html.com/examples.html

27
pom.xml
View File

@@ -10,7 +10,7 @@
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.5.0</version>
<version>0.7</version>
<name>j2html</name>
<description>Java to HTML builder with a fluent API</description>
@@ -39,16 +39,21 @@
<url>https://github.com/tipsy/j2html/issues</url>
</issueManagement>
<properties>
<jdk.version>1.8</jdk.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.google.javascript</groupId>
<artifactId>closure-compiler</artifactId>
<version>r2388</version>
</dependency>
</dependencies>
@@ -61,8 +66,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<source>1.7</source>
<target>1.7</target>
<optimize>true</optimize>
</configuration>
</plugin>
@@ -79,7 +84,7 @@
<configuration>
<rules>
<requireJavaVersion>
<version>[${jdk.version},)</version>
<version>[1.7,)</version>
</requireJavaVersion>
</rules>
</configuration>
@@ -127,4 +132,4 @@
</profile>
</profiles>
</project>
</project>

View File

@@ -1,170 +1,178 @@
package j2html;
import j2html.tags.ContainerTag;
import j2html.tags.EmptyTag;
import j2html.tags.Text;
import j2html.tags.UnescapedText;
import j2html.tags.*;
public class TagCreator {
public static ContainerTag tag(String tagName) { return new ContainerTag(tagName); }
public static EmptyTag emptyTag(String tagName) { return new EmptyTag(tagName); }
//Special tags
public static ContainerTag tag(String tagName) { return new ContainerTag(tagName); }
public static EmptyTag emptyTag(String tagName) { return new EmptyTag(tagName); }
public static Text text(String text) { return new Text(text); }
public static UnescapedText unsafeHtml(String html) { return new UnescapedText(html); }
public static Tag styleWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS); }
public static Tag scriptWithInlineFile(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS); }
public static Tag styleWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.CSS_MIN); }
public static Tag scriptWithInlineFile_min(String path) { return InlineStaticResource.get(path, InlineStaticResource.TargetFormat.JS_MIN); }
public static UnescapedText fileAsString(String path) { return new UnescapedText(InlineStaticResource.getFileAsString(path)); }
public static Text fileAsEscapedString(String path) { return new Text(InlineStaticResource.getFileAsString(path)); }
public static Text text(String text) { return new Text(text); }
public static UnescapedText unsafeHtml(String html) { return new UnescapedText(html); }
//EmptyTags
public static EmptyTag area() { return new EmptyTag("area"); }
public static EmptyTag base() { return new EmptyTag("base"); }
public static EmptyTag br() { return new EmptyTag("br"); }
public static EmptyTag col() { return new EmptyTag("col"); }
public static EmptyTag document() { return new EmptyTag("!DOCTYPE html"); }
public static EmptyTag embed() { return new EmptyTag("embed"); }
public static EmptyTag hr() { return new EmptyTag("hr"); }
public static EmptyTag img() { return new EmptyTag("img"); }
public static EmptyTag input() { return new EmptyTag("input"); }
public static EmptyTag keygen() { return new EmptyTag("keygen"); }
public static EmptyTag link() { return new EmptyTag("link"); }
public static EmptyTag meta() { return new EmptyTag("meta"); }
public static EmptyTag param() { return new EmptyTag("param"); }
public static EmptyTag source() { return new EmptyTag("source"); }
public static EmptyTag track() { return new EmptyTag("track"); }
public static EmptyTag wbr() { return new EmptyTag("wbr"); }
public static EmptyTag area() { return new EmptyTag("area"); }
public static EmptyTag base() { return new EmptyTag("base"); }
public static EmptyTag br() { return new EmptyTag("br"); }
public static EmptyTag col() { return new EmptyTag("col"); }
public static EmptyTag document() { return new EmptyTag("!DOCTYPE html"); }
public static EmptyTag embed() { return new EmptyTag("embed"); }
public static EmptyTag hr() { return new EmptyTag("hr"); }
public static EmptyTag img() { return new EmptyTag("img"); }
public static EmptyTag input() { return new EmptyTag("input"); }
public static EmptyTag keygen() { return new EmptyTag("keygen"); }
public static EmptyTag link() { return new EmptyTag("link"); }
public static EmptyTag meta() { return new EmptyTag("meta"); }
public static EmptyTag param() { return new EmptyTag("param"); }
public static EmptyTag source() { return new EmptyTag("source"); }
public static EmptyTag track() { return new EmptyTag("track"); }
public static EmptyTag wbr() { return new EmptyTag("wbr"); }
//ContainerTags
public static ContainerTag a() { return new ContainerTag("a"); }
public static ContainerTag a(String text) { return new ContainerTag("a").withText(text); }
public static ContainerTag abbr() { return new ContainerTag("abbr"); }
public static ContainerTag address() { return new ContainerTag("address"); }
public static ContainerTag article() { return new ContainerTag("article"); }
public static ContainerTag aside() { return new ContainerTag("aside"); }
public static ContainerTag audio() { return new ContainerTag("audio"); }
public static ContainerTag b() { return new ContainerTag("b"); }
public static ContainerTag b(String text) { return new ContainerTag("b").withText(text); }
public static ContainerTag bdi() { return new ContainerTag("bdi"); }
public static ContainerTag bdi(String text) { return new ContainerTag("bdi").withText(text); }
public static ContainerTag bdo() { return new ContainerTag("bdo"); }
public static ContainerTag bdo(String text) { return new ContainerTag("bdo").withText(text); }
public static ContainerTag blockquote() { return new ContainerTag("blockquote"); }
public static ContainerTag blockquote(String text) { return new ContainerTag("blockquote").withText(text); }
public static ContainerTag body() { return new ContainerTag("body"); }
public static ContainerTag button() { return new ContainerTag("button"); }
public static ContainerTag button(String text) { return new ContainerTag("button").withText(text); }
public static ContainerTag canvas() { return new ContainerTag("canvas"); }
public static ContainerTag caption() { return new ContainerTag("caption"); }
public static ContainerTag caption(String text) { return new ContainerTag("caption").withText(text); }
public static ContainerTag cite() { return new ContainerTag("cite"); }
public static ContainerTag cite(String text) { return new ContainerTag("cite").withText(text); }
public static ContainerTag code() { return new ContainerTag("code"); }
public static ContainerTag colgroup() { return new ContainerTag("colgroup"); }
public static ContainerTag datalist() { return new ContainerTag("datalist"); }
public static ContainerTag dd() { return new ContainerTag("dd"); }
public static ContainerTag dd(String text) { return new ContainerTag("dd").withText(text); }
public static ContainerTag del() { return new ContainerTag("del"); }
public static ContainerTag del(String text) { return new ContainerTag("del").withText(text); }
public static ContainerTag details() { return new ContainerTag("details"); }
public static ContainerTag dfn() { return new ContainerTag("dfn"); }
public static ContainerTag dfn(String text) { return new ContainerTag("dfn").withText(text); }
public static ContainerTag dialog() { return new ContainerTag("dialog"); }
public static ContainerTag dialog(String text) { return new ContainerTag("dialog").withText(text); }
public static ContainerTag div() { return new ContainerTag("div"); }
public static ContainerTag dl() { return new ContainerTag("dl"); }
public static ContainerTag dt() { return new ContainerTag("dt"); }
public static ContainerTag dt(String text) { return new ContainerTag("dt").withText(text); }
public static ContainerTag em() { return new ContainerTag("em"); }
public static ContainerTag em(String text) { return new ContainerTag("em").withText(text); }
public static ContainerTag fieldset() { return new ContainerTag("fieldset"); }
public static ContainerTag figcaption() { return new ContainerTag("figcaption"); }
public static ContainerTag figcaption(String text) { return new ContainerTag("figcaption").withText(text); }
public static ContainerTag figure() { return new ContainerTag("figure"); }
public static ContainerTag footer() { return new ContainerTag("footer"); }
public static ContainerTag form() { return new ContainerTag("form"); }
public static ContainerTag h1() { return new ContainerTag("h1"); }
public static ContainerTag h1(String text) { return new ContainerTag("h1").withText(text); }
public static ContainerTag h2() { return new ContainerTag("h2"); }
public static ContainerTag h2(String text) { return new ContainerTag("h2").withText(text); }
public static ContainerTag h3() { return new ContainerTag("h3"); }
public static ContainerTag h3(String text) { return new ContainerTag("h3").withText(text); }
public static ContainerTag h4() { return new ContainerTag("h4"); }
public static ContainerTag h4(String text) { return new ContainerTag("h4").withText(text); }
public static ContainerTag h5() { return new ContainerTag("h5"); }
public static ContainerTag h5(String text) { return new ContainerTag("h5").withText(text); }
public static ContainerTag h6() { return new ContainerTag("h6"); }
public static ContainerTag h6(String text) { return new ContainerTag("h6").withText(text); }
public static ContainerTag head() { return new ContainerTag("head"); }
public static ContainerTag header() { return new ContainerTag("header"); }
public static ContainerTag html() { return new ContainerTag("html"); }
public static ContainerTag i() { return new ContainerTag("i"); }
public static ContainerTag i(String text) { return new ContainerTag("i").withText(text); }
public static ContainerTag iframe() { return new ContainerTag("iframe"); }
public static ContainerTag ins() { return new ContainerTag("ins"); }
public static ContainerTag ins(String text) { return new ContainerTag("ins").withText(text); }
public static ContainerTag kbd() { return new ContainerTag("kbd"); }
public static ContainerTag label() { return new ContainerTag("label"); }
public static ContainerTag label(String text) { return new ContainerTag("label").withText(text); }
public static ContainerTag legend() { return new ContainerTag("legend"); }
public static ContainerTag legend(String text) { return new ContainerTag("legend").withText(text); }
public static ContainerTag li() { return new ContainerTag("li"); }
public static ContainerTag li(String text) { return new ContainerTag("li").withText(text); }
public static ContainerTag main() { return new ContainerTag("main"); }
public static ContainerTag map() { return new ContainerTag("map"); }
public static ContainerTag mark() { return new ContainerTag("mark"); }
public static ContainerTag menu() { return new ContainerTag("menu"); }
public static ContainerTag menuitem() { return new ContainerTag("menuitem"); }
public static ContainerTag meter() { return new ContainerTag("meter"); }
public static ContainerTag nav() { return new ContainerTag("nav"); }
public static ContainerTag noscript() { return new ContainerTag("noscript"); }
public static ContainerTag object() { return new ContainerTag("object"); }
public static ContainerTag ol() { return new ContainerTag("ol"); }
public static ContainerTag optgroup() { return new ContainerTag("optgroup"); }
public static ContainerTag option() { return new ContainerTag("option"); }
public static ContainerTag option(String text) { return new ContainerTag("option").withText(text); }
public static ContainerTag output() { return new ContainerTag("output"); }
public static ContainerTag p() { return new ContainerTag("p"); }
public static ContainerTag p(String text) { return new ContainerTag("p").withText(text); }
public static ContainerTag pre() { return new ContainerTag("pre"); }
public static ContainerTag progress() { return new ContainerTag("progress"); }
public static ContainerTag q() { return new ContainerTag("q"); }
public static ContainerTag q(String text) { return new ContainerTag("q").withText(text); }
public static ContainerTag rp() { return new ContainerTag("rp"); }
public static ContainerTag rt() { return new ContainerTag("rt"); }
public static ContainerTag ruby() { return new ContainerTag("ruby"); }
public static ContainerTag s() { return new ContainerTag("s"); }
public static ContainerTag s(String text) { return new ContainerTag("s").withText(text); }
public static ContainerTag samp() { return new ContainerTag("samp"); }
public static ContainerTag script() { return new ContainerTag("script"); }
public static ContainerTag section() { return new ContainerTag("section"); }
public static ContainerTag select() { return new ContainerTag("select"); }
public static ContainerTag small() { return new ContainerTag("small"); }
public static ContainerTag small(String text) { return new ContainerTag("small").withText(text); }
public static ContainerTag span() { return new ContainerTag("span"); }
public static ContainerTag span(String text) { return new ContainerTag("span").withText(text); }
public static ContainerTag strong() { return new ContainerTag("strong"); }
public static ContainerTag strong(String text) { return new ContainerTag("strong").withText(text); }
public static ContainerTag style() { return new ContainerTag("style"); }
public static ContainerTag sub() { return new ContainerTag("sub"); }
public static ContainerTag sub(String text) { return new ContainerTag("sub").withText(text); }
public static ContainerTag summary() { return new ContainerTag("summary"); }
public static ContainerTag summary(String text) { return new ContainerTag("summary").withText(text); }
public static ContainerTag sup() { return new ContainerTag("sup"); }
public static ContainerTag sup(String text) { return new ContainerTag("sup").withText(text); }
public static ContainerTag table() { return new ContainerTag("table"); }
public static ContainerTag tbody() { return new ContainerTag("tbody"); }
public static ContainerTag td() { return new ContainerTag("td"); }
public static ContainerTag td(String text) { return new ContainerTag("td").withText(text); }
public static ContainerTag textarea() { return new ContainerTag("textarea"); }
public static ContainerTag tfoot() { return new ContainerTag("tfoot"); }
public static ContainerTag th() { return new ContainerTag("th"); }
public static ContainerTag th(String text) { return new ContainerTag("th").withText(text); }
public static ContainerTag thead() { return new ContainerTag("thead"); }
public static ContainerTag time() { return new ContainerTag("time"); }
public static ContainerTag title() { return new ContainerTag("title"); }
public static ContainerTag title(String text) { return new ContainerTag("title").withText(text); }
public static ContainerTag tr() { return new ContainerTag("tr"); }
public static ContainerTag u() { return new ContainerTag("u"); }
public static ContainerTag u(String text) { return new ContainerTag("u").withText(text); }
public static ContainerTag ul() { return new ContainerTag("ul"); }
public static ContainerTag var() { return new ContainerTag("var"); }
public static ContainerTag video() { return new ContainerTag("video"); }
public static ContainerTag a() { return new ContainerTag("a"); }
public static ContainerTag a(String text) { return new ContainerTag("a").withText(text); }
public static ContainerTag abbr() { return new ContainerTag("abbr"); }
public static ContainerTag address() { return new ContainerTag("address"); }
public static ContainerTag article() { return new ContainerTag("article"); }
public static ContainerTag aside() { return new ContainerTag("aside"); }
public static ContainerTag audio() { return new ContainerTag("audio"); }
public static ContainerTag b() { return new ContainerTag("b"); }
public static ContainerTag b(String text) { return new ContainerTag("b").withText(text); }
public static ContainerTag bdi() { return new ContainerTag("bdi"); }
public static ContainerTag bdi(String text) { return new ContainerTag("bdi").withText(text); }
public static ContainerTag bdo() { return new ContainerTag("bdo"); }
public static ContainerTag bdo(String text) { return new ContainerTag("bdo").withText(text); }
public static ContainerTag blockquote() { return new ContainerTag("blockquote"); }
public static ContainerTag blockquote(String text) { return new ContainerTag("blockquote").withText(text); }
public static ContainerTag body() { return new ContainerTag("body"); }
public static ContainerTag button() { return new ContainerTag("button"); }
public static ContainerTag button(String text) { return new ContainerTag("button").withText(text); }
public static ContainerTag canvas() { return new ContainerTag("canvas"); }
public static ContainerTag caption() { return new ContainerTag("caption"); }
public static ContainerTag caption(String text) { return new ContainerTag("caption").withText(text); }
public static ContainerTag cite() { return new ContainerTag("cite"); }
public static ContainerTag cite(String text) { return new ContainerTag("cite").withText(text); }
public static ContainerTag code() { return new ContainerTag("code"); }
public static ContainerTag colgroup() { return new ContainerTag("colgroup"); }
public static ContainerTag datalist() { return new ContainerTag("datalist"); }
public static ContainerTag dd() { return new ContainerTag("dd"); }
public static ContainerTag dd(String text) { return new ContainerTag("dd").withText(text); }
public static ContainerTag del() { return new ContainerTag("del"); }
public static ContainerTag del(String text) { return new ContainerTag("del").withText(text); }
public static ContainerTag details() { return new ContainerTag("details"); }
public static ContainerTag dfn() { return new ContainerTag("dfn"); }
public static ContainerTag dfn(String text) { return new ContainerTag("dfn").withText(text); }
public static ContainerTag dialog() { return new ContainerTag("dialog"); }
public static ContainerTag dialog(String text) { return new ContainerTag("dialog").withText(text); }
public static ContainerTag div() { return new ContainerTag("div"); }
public static ContainerTag dl() { return new ContainerTag("dl"); }
public static ContainerTag dt() { return new ContainerTag("dt"); }
public static ContainerTag dt(String text) { return new ContainerTag("dt").withText(text); }
public static ContainerTag em() { return new ContainerTag("em"); }
public static ContainerTag em(String text) { return new ContainerTag("em").withText(text); }
public static ContainerTag fieldset() { return new ContainerTag("fieldset"); }
public static ContainerTag figcaption() { return new ContainerTag("figcaption"); }
public static ContainerTag figcaption(String text) { return new ContainerTag("figcaption").withText(text); }
public static ContainerTag figure() { return new ContainerTag("figure"); }
public static ContainerTag footer() { return new ContainerTag("footer"); }
public static ContainerTag form() { return new ContainerTag("form"); }
public static ContainerTag h1() { return new ContainerTag("h1"); }
public static ContainerTag h1(String text) { return new ContainerTag("h1").withText(text); }
public static ContainerTag h2() { return new ContainerTag("h2"); }
public static ContainerTag h2(String text) { return new ContainerTag("h2").withText(text); }
public static ContainerTag h3() { return new ContainerTag("h3"); }
public static ContainerTag h3(String text) { return new ContainerTag("h3").withText(text); }
public static ContainerTag h4() { return new ContainerTag("h4"); }
public static ContainerTag h4(String text) { return new ContainerTag("h4").withText(text); }
public static ContainerTag h5() { return new ContainerTag("h5"); }
public static ContainerTag h5(String text) { return new ContainerTag("h5").withText(text); }
public static ContainerTag h6() { return new ContainerTag("h6"); }
public static ContainerTag h6(String text) { return new ContainerTag("h6").withText(text); }
public static ContainerTag head() { return new ContainerTag("head"); }
public static ContainerTag header() { return new ContainerTag("header"); }
public static ContainerTag html() { return new ContainerTag("html"); }
public static ContainerTag i() { return new ContainerTag("i"); }
public static ContainerTag i(String text) { return new ContainerTag("i").withText(text); }
public static ContainerTag iframe() { return new ContainerTag("iframe"); }
public static ContainerTag ins() { return new ContainerTag("ins"); }
public static ContainerTag ins(String text) { return new ContainerTag("ins").withText(text); }
public static ContainerTag kbd() { return new ContainerTag("kbd"); }
public static ContainerTag label() { return new ContainerTag("label"); }
public static ContainerTag label(String text) { return new ContainerTag("label").withText(text); }
public static ContainerTag legend() { return new ContainerTag("legend"); }
public static ContainerTag legend(String text) { return new ContainerTag("legend").withText(text); }
public static ContainerTag li() { return new ContainerTag("li"); }
public static ContainerTag li(String text) { return new ContainerTag("li").withText(text); }
public static ContainerTag main() { return new ContainerTag("main"); }
public static ContainerTag map() { return new ContainerTag("map"); }
public static ContainerTag mark() { return new ContainerTag("mark"); }
public static ContainerTag menu() { return new ContainerTag("menu"); }
public static ContainerTag menuitem() { return new ContainerTag("menuitem"); }
public static ContainerTag meter() { return new ContainerTag("meter"); }
public static ContainerTag nav() { return new ContainerTag("nav"); }
public static ContainerTag noscript() { return new ContainerTag("noscript"); }
public static ContainerTag object() { return new ContainerTag("object"); }
public static ContainerTag ol() { return new ContainerTag("ol"); }
public static ContainerTag optgroup() { return new ContainerTag("optgroup"); }
public static ContainerTag option() { return new ContainerTag("option"); }
public static ContainerTag option(String text) { return new ContainerTag("option").withText(text); }
public static ContainerTag output() { return new ContainerTag("output"); }
public static ContainerTag p() { return new ContainerTag("p"); }
public static ContainerTag p(String text) { return new ContainerTag("p").withText(text); }
public static ContainerTag pre() { return new ContainerTag("pre"); }
public static ContainerTag progress() { return new ContainerTag("progress"); }
public static ContainerTag q() { return new ContainerTag("q"); }
public static ContainerTag q(String text) { return new ContainerTag("q").withText(text); }
public static ContainerTag rp() { return new ContainerTag("rp"); }
public static ContainerTag rt() { return new ContainerTag("rt"); }
public static ContainerTag ruby() { return new ContainerTag("ruby"); }
public static ContainerTag s() { return new ContainerTag("s"); }
public static ContainerTag s(String text) { return new ContainerTag("s").withText(text); }
public static ContainerTag samp() { return new ContainerTag("samp"); }
public static ContainerTag script() { return new ContainerTag("script"); }
public static ContainerTag section() { return new ContainerTag("section"); }
public static ContainerTag select() { return new ContainerTag("select"); }
public static ContainerTag small() { return new ContainerTag("small"); }
public static ContainerTag small(String text) { return new ContainerTag("small").withText(text); }
public static ContainerTag span() { return new ContainerTag("span"); }
public static ContainerTag span(String text) { return new ContainerTag("span").withText(text); }
public static ContainerTag strong() { return new ContainerTag("strong"); }
public static ContainerTag strong(String text) { return new ContainerTag("strong").withText(text); }
public static ContainerTag style() { return new ContainerTag("style"); }
public static ContainerTag sub() { return new ContainerTag("sub"); }
public static ContainerTag sub(String text) { return new ContainerTag("sub").withText(text); }
public static ContainerTag summary() { return new ContainerTag("summary"); }
public static ContainerTag summary(String text) { return new ContainerTag("summary").withText(text); }
public static ContainerTag sup() { return new ContainerTag("sup"); }
public static ContainerTag sup(String text) { return new ContainerTag("sup").withText(text); }
public static ContainerTag table() { return new ContainerTag("table"); }
public static ContainerTag tbody() { return new ContainerTag("tbody"); }
public static ContainerTag td() { return new ContainerTag("td"); }
public static ContainerTag td(String text) { return new ContainerTag("td").withText(text); }
public static ContainerTag textarea() { return new ContainerTag("textarea"); }
public static ContainerTag tfoot() { return new ContainerTag("tfoot"); }
public static ContainerTag th() { return new ContainerTag("th"); }
public static ContainerTag th(String text) { return new ContainerTag("th").withText(text); }
public static ContainerTag thead() { return new ContainerTag("thead"); }
public static ContainerTag time() { return new ContainerTag("time"); }
public static ContainerTag title() { return new ContainerTag("title"); }
public static ContainerTag title(String text) { return new ContainerTag("title").withText(text); }
public static ContainerTag tr() { return new ContainerTag("tr"); }
public static ContainerTag u() { return new ContainerTag("u"); }
public static ContainerTag u(String text) { return new ContainerTag("u").withText(text); }
public static ContainerTag ul() { return new ContainerTag("ul"); }
public static ContainerTag var() { return new ContainerTag("var"); }
public static ContainerTag video() { return new ContainerTag("video"); }
}

View File

@@ -1,6 +1,6 @@
package j2html.attributes;
import static j2html.utils.SimpleHtmlEscaper.escape;
import static org.apache.commons.lang3.StringEscapeUtils.*;
public class Attribute {
private String name;
@@ -8,7 +8,7 @@ public class Attribute {
public Attribute(String name, String value) {
this.name = name;
this.value = escape(value);
this.value = escapeHtml4(value);
}
public Attribute(String name) {

View File

@@ -45,7 +45,9 @@ public class ContainerTag extends Tag {
*/
public ContainerTag with(List<Tag> children) {
if (children != null) {
children.forEach(this::with);
for (Tag child : children) {
this.with(child);
}
}
return this;
}
@@ -114,17 +116,6 @@ public class ContainerTag extends Tag {
*/
@Override
public String render() {
//very slow
// return renderOpenTag() + children.stream().map(Tag::render).collect(Collectors.joining()) + renderCloseTag();
//pretty fast
// StringBuilder rendered = new StringBuilder(renderOpenTag());
// children.forEach(rendered::append);
// rendered.append(renderCloseTag());
// return rendered.toString();
//fastest
StringBuilder rendered = new StringBuilder(renderOpenTag());
if (children != null && children.size() > 0) {
for (Tag child : children) {

View File

@@ -0,0 +1,43 @@
package j2html.tags;
import j2html.utils.*;
import java.nio.file.*;
import static j2html.TagCreator.*;
public class InlineStaticResource {
public enum TargetFormat { CSS_MIN, CSS, JS_MIN, JS }
public static ContainerTag get(String path, TargetFormat format) {
ContainerTag errorAlert = script().with(unsafeHtml("alert('Unable to read file. File: \"" + path + "\", Type: \"" + format + "\"')"));
String fileString = getFileAsString(path);
if(fileString != null) {
switch(format) {
case CSS_MIN : return style().with(unsafeHtml(compressCss(fileString)));
case JS_MIN : return script().with(unsafeHtml(compressJs(fileString, path)));
case CSS : return style().with(unsafeHtml(fileString));
case JS : return script().with(unsafeHtml(fileString));
default : return errorAlert;
}
}
return errorAlert;
}
public static String getFileAsString(String path) {
try {
return new String(Files.readAllBytes(Paths.get(InlineStaticResource.class.getResource(path).toURI())), "UTF-8");
} catch (Exception e) {
return null;
}
}
private static String compressCss(String code) {
return CSSMin.compress(code);
}
private static String compressJs(String code, String debugPath) {
return JSMin.compressJs(code, debugPath);
}
}

View File

@@ -48,8 +48,6 @@ public abstract class Tag {
}
public String renderOpenTag() {
// final String tagAttributes = attributes.stream().map(Attribute::render).collect(Collectors.joining());
// return "<" + tag + tagAttributes + ">"; //too slow
String tagAttributes = "";
for (Attribute attribute : attributes) {
tagAttributes += attribute.render();

View File

@@ -1,7 +1,6 @@
package j2html.tags;
import static j2html.utils.SimpleHtmlEscaper.escape;
import static org.apache.commons.lang3.StringEscapeUtils.*;
public class Text extends Tag {
@@ -11,7 +10,7 @@ public class Text extends Tag {
@Override
public String render() {
return escape(tag);
return escapeHtml4(tag);
}
@Override

View File

@@ -0,0 +1,675 @@
/**
* * CSSMin Copyright License Agreement (BSD License)
*
* Copyright (c) 2011-2014, Barry van Oudtshoorn
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* - Neither the name of Barryvan nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* CSSMin takes in well-formed, human-readable CSS and reduces its size substantially.
* It removes unnecessary whitespace and comments, and orders the contents of CSS
* selectors alphabetically to enhance GZIP compression.
*
* Originally by Barry van Oudtshoorn, with bug reports, fixes, and contributions by
* <ul>
* <li>Kevin de Groote</li>
* <li>Pedro Pinheiro</li>
* <li>Asier Lostalé</li>
* <li>David Åse</li>
* </ul>
* Some code is based on the YUI CssCompressor code, by Julien Lecomte.
*
* @author Barry van Oudtshoorn
* Repo: https://github.com/barryvan/CSSMin
*/
package j2html.utils;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import java.util.regex.*;
public class CSSMin {
private static final Logger LOG = Logger.getLogger(CSSMin.class.getName());
protected static boolean debugLogging = false;
/**
* Minify CSS from a reader to a printstream.
*
* @param input Where to read the CSS from
*/
public static String compress(String input) {
try {
int k,
j, // Number of open braces
n; // Current position in stream
char curr;
BufferedReader br = new BufferedReader(new StringReader(input));
StringBuilder sb = new StringBuilder();
if (debugLogging) {
LOG.info("Reading file into StringBuffer...");
}
String s;
while ((s = br.readLine()) != null) {
if (s.trim().equals("")) continue;
sb.append(s);
}
if (debugLogging) {
LOG.info("Removing comments...");
}
// Find the start of the comment
n = 0;
while ((n = sb.indexOf("/*", n)) != -1) {
if (sb.charAt(n + 2) == '*') { // Retain special comments
n += 2;
continue;
}
k = sb.indexOf("*/", n + 2);
if (k == -1) {
throw new UnterminatedCommentException();
}
sb.delete(n, k + 2);
}
if (debugLogging) {
LOG.info(sb.toString());
LOG.info("\n\n");
}
if (debugLogging) {
LOG.info("Parsing and processing selectors...");
}
Vector<Selector> selectors = new Vector<>();
n = 0;
j = 0;
for (int i = 0; i < sb.length(); i++) {
curr = sb.charAt(i);
if (j < 0) {
throw new UnbalancedBracesException();
}
if (curr == '{') {
j++;
} else if (curr == '}') {
j--;
if (j == 0) {
try {
selectors.addElement(new Selector(sb.substring(n, i + 1)));
} catch (UnterminatedSelectorException usex) {
LOG.warning("Unterminated selector: " + usex.getMessage());
} catch (EmptySelectorBodyException ebex) {
if (debugLogging) {
LOG.warning("Empty selector body: " + ebex.getMessage());
}
}
n = i + 1;
}
}
}
StringBuilder result = new StringBuilder();
for (Selector selector : selectors) {
result.append(selector);
}
if (debugLogging) {
LOG.info("Process completed successfully.");
}
return result.toString();
} catch (UnterminatedCommentException ucex) {
LOG.warning("Unterminated comment.");
} catch (UnbalancedBracesException ubex) {
LOG.warning("Unbalanced braces.");
} catch (Exception ex) {
LOG.warning(ex.getMessage());
}
return null;
}
}
class Selector {
private static final Logger LOG = Logger.getLogger(Selector.class.getName());
private Property[] properties = null;
private Vector<Selector> subSelectors = null;
private String selector;
/**
* Creates a new Selector using the supplied strings.
*
* @param selector The selector; for example, "div { border: solid 1px red; color: blue; }"
* @throws IncompleteSelectorException, UnterminatedSelectorException, EmptySelectorBodyException If the selector is incomplete and cannot be parsed.
*/
public Selector(String selector) throws IncompleteSelectorException, UnterminatedSelectorException, EmptySelectorBodyException {
String[] parts = selector.split("\\{"); // We have to escape the { with a \ for the regex, which itself requires escaping for the string. Sigh.
if (parts.length < 2) {
throw new IncompleteSelectorException(selector);
}
this.selector = parts[0].trim();
// Simplify combinators
this.selector = this.selector.replaceAll("\\s?(\\+|~|,|=|~=|\\^=|\\$=|\\*=|\\|=|>)\\s?", "$1");
// We're dealing with a nested property, eg @-webkit-keyframes
if (parts.length > 2) {
this.subSelectors = new Vector<>();
parts = selector.split("(\\s*\\{\\s*)|(\\s*\\}\\s*)");
for (int i = 1; i < parts.length; i += 2) {
parts[i] = parts[i].trim();
parts[i + 1] = parts[i + 1].trim();
if (!(parts[i].equals("") || (parts[i + 1].equals("")))) {
this.subSelectors.addElement(new Selector(parts[i] + "{" + parts[i + 1] + "}"));
}
}
} else {
String contents = parts[parts.length - 1].trim();
if (CSSMin.debugLogging) {
LOG.info("Parsing selector: " + this.selector);
LOG.info("\t" + contents);
}
if (contents.charAt(contents.length() - 1) != '}') { // Ensure that we have a leading and trailing brace.
throw new UnterminatedSelectorException(selector);
}
if (contents.length() == 1) {
throw new EmptySelectorBodyException(selector);
}
contents = contents.substring(0, contents.length() - 2);
this.properties = new Property[0];
this.properties = parseProperties(contents).toArray(this.properties);
sortProperties(this.properties);
}
}
/**
* Prints out this selector and its contents nicely, with the contents sorted alphabetically.
*
* @return A string representing this selector, minified.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.selector).append("{");
if (this.subSelectors != null) {
for (Selector s : this.subSelectors) {
sb.append(s.toString());
}
}
if (this.properties != null) {
for (Property p : this.properties) {
sb.append(p.toString());
}
}
if (sb.charAt(sb.length() - 1) == ';') {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("}");
return sb.toString();
}
/**
* Parses out the properties of a selector's body.
*
* @param contents The body; for example, "border: solid 1px red; color: blue;"
* @return An array of properties parsed from this selector.
*/
private ArrayList<Property> parseProperties(String contents) {
ArrayList<String> parts = new ArrayList<>();
boolean bInsideString = false,
bInsideURL = false;
int j = 0;
String substr;
for (int i = 0; i < contents.length(); i++) {
if (bInsideString) { // If we're inside a string
bInsideString = !(contents.charAt(i) == '"');
} else if (bInsideURL) { // If we're inside a URL
bInsideURL = !(contents.charAt(i) == ')');
} else if (contents.charAt(i) == '"') {
bInsideString = true;
} else if (contents.charAt(i) == '(') {
if ((i - 3) > 0 && "url".equals(contents.substring(i - 3, i))) bInsideURL = true;
} else if (contents.charAt(i) == ';') {
substr = contents.substring(j, i);
if (!(substr.trim().equals(""))) parts.add(substr);
j = i + 1;
}
}
substr = contents.substring(j, contents.length());
if (!(substr.trim().equals(""))) parts.add(substr);
ArrayList<Property> results = new ArrayList<>();
for (String part : parts) {
try {
results.add(new Property(part));
} catch (IncompletePropertyException ipex) {
LOG.warning("Incomplete property in selector \"" + this.selector + "\": \"" + ipex.getMessage() + "\"");
}
}
return results;
}
/**
* Sorts the properties array to enhance gzipping.
*
* @param properties The array to be sorted.
*/
private void sortProperties(Property[] properties) {
Arrays.sort(properties);
}
}
class Property implements Comparable<Property> {
private static final Logger LOG = Logger.getLogger(Property.class.getName());
protected String property;
protected Part[] parts;
/**
* Creates a new Property using the supplied strings. Parses out the values of the property selector.
*
* @param property The property; for example, "border: solid 1px red;" or "-moz-box-shadow: 3px 3px 3px rgba(255, 255, 0, 0.5);".
* @throws IncompletePropertyException If the property is incomplete and cannot be parsed.
*/
public Property(String property) throws IncompletePropertyException {
try {
// Parse the property.
ArrayList<String> parts = new ArrayList<>();
boolean bCanSplit = true;
int j = 0;
String substr;
if (CSSMin.debugLogging) {
LOG.info("\t\tExamining property: " + property);
}
for (int i = 0; i < property.length(); i++) {
if (!bCanSplit) { // If we're inside a string
bCanSplit = (property.charAt(i) == '"');
} else if (property.charAt(i) == '"') {
bCanSplit = false;
} else if (property.charAt(i) == ':' && parts.size() < 1) {
substr = property.substring(j, i);
if (!(substr.trim().equals(""))) parts.add(substr);
j = i + 1;
}
}
substr = property.substring(j, property.length());
if (!(substr.trim().equals(""))) parts.add(substr);
if (parts.size() < 2) {
throw new IncompletePropertyException(property);
}
String prop = parts.get(0).trim();
if (!(prop.length() > 2 && prop.substring(0, 2).equals("--"))) {
prop = prop.toLowerCase();
}
this.property = prop;
this.parts = parseValues(simplifyColours(parts.get(1).trim().replaceAll(", ", ",")));
} catch (PatternSyntaxException e) {
// Invalid regular expression used.
}
}
/**
* Prints out this property nicely.
*
* @return A string representing this property, minified.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.property).append(":");
for (Part p : this.parts) {
sb.append(p.toString()).append(",");
}
sb.deleteCharAt(sb.length() - 1); // Delete the trailing comma.
sb.append(";");
if (CSSMin.debugLogging) {
LOG.info(sb.toString());
}
return sb.toString();
}
/**
* Compare this property with another.
*/
public int compareTo(Property other) {
// We can't just use String.compareTo(), because we need to sort properties that have hack prefixes last -- eg, *display should come after display.
String thisProp = this.property;
String thatProp = other.property;
if (thisProp.charAt(0) == '-') {
thisProp = thisProp.substring(1);
thisProp = thisProp.substring(thisProp.indexOf('-') + 1);
} else if (thisProp.charAt(0) < 65) {
thisProp = thisProp.substring(1);
}
if (thatProp.charAt(0) == '-') {
thatProp = thatProp.substring(1);
thatProp = thatProp.substring(thatProp.indexOf('-') + 1);
} else if (thatProp.charAt(0) < 65) {
thatProp = thatProp.substring(1);
}
return thisProp.compareTo(thatProp);
}
/**
* Parse the values out of a property.
*
* @param contents The property to parse
* @return An array of Parts
*/
private Part[] parseValues(String contents) {
String[] parts = contents.split(",");
Part[] results = new Part[parts.length];
for (int i = 0; i < parts.length; i++) {
try {
results[i] = new Part(parts[i], property);
} catch (Exception e) {
LOG.warning(e.getMessage());
results[i] = null;
}
}
return results;
}
private String simplifyColours(String contents) {
// This replacement, although it results in a smaller uncompressed file,
// actually makes the gzipped file bigger -- people tend to use rgba(0,0,0,0.x)
// quite a lot, which means that rgba(0,0,0,0) has its first eight or so characters
// compressed really efficiently; much more so than "transparent".
//contents = contents.replaceAll("rgba\\(0,0,0,0\\)", "transparent");
return simplifyRGBColours(contents);
}
// Convert rgb(51,102,153) to #336699 (this code largely based on YUI code)
private String simplifyRGBColours(String contents) {
StringBuffer newContents = new StringBuffer();
StringBuffer hexColour;
String[] rgbColours;
int colourValue;
Pattern pattern = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)");
Matcher matcher = pattern.matcher(contents);
while (matcher.find()) {
hexColour = new StringBuffer("#");
rgbColours = matcher.group(1).split(",");
for (String rgbColour : rgbColours) {
colourValue = Integer.parseInt(rgbColour);
if (colourValue < 16) {
hexColour.append("0");
}
hexColour.append(Integer.toHexString(colourValue));
}
matcher.appendReplacement(newContents, hexColour.toString());
}
matcher.appendTail(newContents);
return newContents.toString();
}
}
class Part {
String contents;
String property;
/**
* Create a new property by parsing the given string.
*
* @param contents The string to parse.
* @throws Exception If the part cannot be parsed.
*/
public Part(String contents, String property) throws Exception {
// Many of these regular expressions are adapted from those used in the YUI CSS Compressor.
// For simpler regexes.
this.contents = " " + contents;
this.property = property;
simplify();
}
private void simplify() {
// !important doesn't need to be spaced
this.contents = this.contents.replaceAll(" !important", "!important");
// Replace 0in, 0cm, etc. with just 0
this.contents = this.contents.replaceAll("(\\s)(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2");
this.contents = this.contents.trim();
// Simplify multiple zeroes
if (this.contents.equals("0 0 0 0")) this.contents = "0";
if (this.contents.equals("0 0 0")) this.contents = "0";
if (this.contents.equals("0 0")) this.contents = "0";
// Simplify multiple-parameter properties
simplifyParameters();
// Simplify font weights
simplifyFontWeights();
// Strip unnecessary quotes from url() and single-word parts, and make as much lowercase as possible.
simplifyQuotesAndCaps();
// Simplify colours
simplifyColourNames();
simplifyHexColours();
}
private void simplifyParameters() {
if (this.property.equals("background-size")) return;
StringBuilder newContents = new StringBuilder();
String[] params = this.contents.split(" ");
if (params.length == 4) {
// We can drop off the fourth item if the second and fourth items match
// ie turn 3px 0 3px 0 into 3px 0 3px
if (params[1].equalsIgnoreCase(params[3])) {
params = Arrays.copyOf(params, 3);
}
}
if (params.length == 3) {
// We can drop off the third item if the first and third items match
// ie turn 3px 0 3px into 3px 0
if (params[0].equalsIgnoreCase(params[2])) {
params = Arrays.copyOf(params, 2);
}
}
if (params.length == 2) {
// We can drop off the second item if the first and second items match
// ie turn 3px 3px into 3px
if (params[0].equalsIgnoreCase(params[1])) {
params = Arrays.copyOf(params, 1);
}
}
for (String param : params) {
newContents.append(param).append(" ");
}
newContents.deleteCharAt(newContents.length() - 1); // Delete the trailing space
this.contents = newContents.toString();
}
private void simplifyFontWeights() {
if (!this.property.equals("font-weight")) return;
String lcContents = this.contents.toLowerCase();
for (int i = 0; i < Constants.fontWeightNames.length; i++) {
if (lcContents.equals(Constants.fontWeightNames[i])) {
this.contents = Constants.fontWeightValues[i];
break;
}
}
}
private void simplifyQuotesAndCaps() {
// Strip quotes from URLs
if ((this.contents.length() > 4) && (this.contents.substring(0, 4).equalsIgnoreCase("url("))) {
this.contents = this.contents.replaceAll("(?i)url\\(('|\")?(.*?)\\1\\)", "url($2)");
} else if ((this.contents.length() > 4) && (this.contents.substring(0, 4).equalsIgnoreCase("var("))) {
this.contents = this.contents.replaceAll("\\s", "");
} else {
String[] words = this.contents.split("\\s");
if (words.length == 1) {
if (!this.property.equalsIgnoreCase("animation-name")) {
this.contents = this.contents.toLowerCase();
}
this.contents = this.contents.replaceAll("('|\")?(.*?)\1", "$2");
}
}
}
private void simplifyColourNames() {
String lcContents = this.contents.toLowerCase();
for (int i = 0; i < Constants.htmlColourNames.length; i++) {
if (lcContents.equals(Constants.htmlColourNames[i])) {
if (Constants.htmlColourValues[i].length() < Constants.htmlColourNames[i].length()) {
this.contents = Constants.htmlColourValues[i];
}
break;
} else if (lcContents.equals(Constants.htmlColourValues[i])) {
if (Constants.htmlColourNames[i].length() < Constants.htmlColourValues[i].length()) {
this.contents = Constants.htmlColourNames[i];
}
}
}
}
private void simplifyHexColours() {
StringBuffer newContents = new StringBuffer();
Pattern pattern = Pattern.compile("#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])");
Matcher matcher = pattern.matcher(this.contents);
while (matcher.find()) {
if (matcher.group(1).equalsIgnoreCase(matcher.group(2)) && matcher.group(3).equalsIgnoreCase(matcher.group(4)) && matcher.group(5).equalsIgnoreCase(matcher.group(6))) {
matcher.appendReplacement(newContents, "#" + matcher.group(1).toLowerCase() + matcher.group(3).toLowerCase() + matcher.group(5).toLowerCase());
} else {
matcher.appendReplacement(newContents, matcher.group().toLowerCase());
}
}
matcher.appendTail(newContents);
this.contents = newContents.toString();
}
/**
* Returns itself.
*
* @return this part's string representation.
*/
public String toString() {
return this.contents;
}
}
class UnterminatedCommentException extends Exception {}
class UnbalancedBracesException extends Exception {}
class IncompletePropertyException extends Exception {
String message = null;
public IncompletePropertyException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
class EmptySelectorBodyException extends Exception {
String message = null;
public EmptySelectorBodyException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
class UnterminatedSelectorException extends Exception {
String message = null;
public UnterminatedSelectorException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
class IncompleteSelectorException extends Exception {
String message = null;
public IncompleteSelectorException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
class Constants {
static final String[] htmlColourNames = { "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink", "indianred ", "indigo ", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgrey", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" };
static final String[] htmlColourValues = { "#f0f8ff", "#faebd7", "#00ffff", "#7fffd4", "#f0ffff", "#f5f5dc", "#ffe4c4", "#000", "#ffebcd", "#00f", "#8a2be2", "#a52a2a", "#deb887", "#5f9ea0", "#7fff00", "#d2691e", "#ff7f50", "#6495ed", "#fff8dc", "#dc143c", "#0ff", "#00008b", "#008b8b", "#b8860b", "#a9a9a9", "#006400", "#bdb76b", "#8b008b", "#556b2f", "#ff8c00", "#9932cc", "#8b0000", "#e9967a", "#8fbc8f", "#483d8b", "#2f4f4f", "#00ced1", "#9400d3", "#ff1493", "#00bfff", "#696969", "#1e90ff", "#b22222", "#fffaf0", "#228b22", "#f0f", "#dcdcdc", "#f8f8ff", "#ffd700", "#daa520", "#808080", "#008000", "#adff2f", "#f0fff0", "#ff69b4", "#cd5c5c", "#4b0082", "#fffff0", "#f0e68c", "#e6e6fa", "#fff0f5", "#7cfc00", "#fffacd", "#add8e6", "#f08080", "#e0ffff", "#fafad2", "#d3d3d3", "#90ee90", "#ffb6c1", "#ffa07a", "#20b2aa", "#87cefa", "#789", "#b0c4de", "#ffffe0", "#0f0", "#32cd32", "#faf0e6", "#f0f", "#800000", "#66cdaa", "#0000cd", "#ba55d3", "#9370d8", "#3cb371", "#7b68ee", "#00fa9a", "#48d1cc", "#c71585", "#191970", "#f5fffa", "#ffe4e1", "#ffe4b5", "#ffdead", "#000080", "#fdf5e6", "#808000", "#6b8e23", "#ffa500", "#ff4500", "#da70d6", "#eee8aa", "#98fb98", "#afeeee", "#d87093", "#ffefd5", "#ffdab9", "#cd853f", "#ffc0cb", "#dda0dd", "#b0e0e6", "#800080", "#f00", "#bc8f8f", "#4169e1", "#8b4513", "#fa8072", "#f4a460", "#2e8b57", "#fff5ee", "#a0522d", "#c0c0c0", "#87ceeb", "#6a5acd", "#708090", "#fffafa", "#00ff7f", "#4682b4", "#d2b48c", "#008080", "#d8bfd8", "#ff6347", "#40e0d0", "#ee82ee", "#f5deb3", "#fff", "#f5f5f5", "#ff0", "#9acd32" };
static final String[] fontWeightNames = { "normal", "bold", "bolder", "lighter" };
static final String[] fontWeightValues = { "400", "700", "900", "100" };
}

View File

@@ -0,0 +1,18 @@
package j2html.utils;
import com.google.javascript.jscomp.*;
import com.google.javascript.jscomp.Compiler;
public class JSMin {
public static String compressJs(String code, String sourcePath) {
com.google.javascript.jscomp.Compiler compiler = new Compiler();
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
SourceFile extern = SourceFile.fromCode("externs.js", "");
SourceFile input = SourceFile.fromCode(sourcePath, code);
compiler.compile(extern, input, options);
return compiler.toSource();
}
}

View File

@@ -1,28 +0,0 @@
package j2html.utils;
public class SimpleHtmlEscaper {
/**
* Simple approach from http://stackoverflow.com/a/25228492/4893160 ... good enough ?
* Apache StringEscapeUtils is extremely slow compared (probably because it's a lot safer!)
* @param s the string to be escaped
* @return the escaped string
*/
public static String escape(String s) {
if("".equals(s)){ return ""; }
if(s == null) { return null; }
StringBuilder out = new StringBuilder(Math.max(16, s.length()));
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') {
out.append("&#");
out.append((int) c);
out.append(';');
} else {
out.append(c);
}
}
return out.toString();
}
}

View File

@@ -3,7 +3,7 @@ package j2html.attributes;
import j2html.tags.ContainerTag;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
public class AttributeTest {

View File

@@ -3,7 +3,7 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
public class ComplexRenderTest {

View File

@@ -3,7 +3,7 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
public class ConvenienceMethodTest {

View File

@@ -3,7 +3,7 @@ package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.*;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
public class TagCreatorTest {
@@ -14,8 +14,13 @@ public class TagCreatorTest {
assertEquals(tag("tagname").render(), "<tagname></tagname>");
assertEquals(emptyTag("tagname").render(), "<tagname>");
assertEquals(text("text").render(), "text");
assertEquals(text("<script>").render(), "&#60;script&#62;");
assertEquals(text("<script> and \"</script>\"").render(), "&lt;script&gt; and &quot;&lt;/script&gt;&quot;");
assertEquals(unsafeHtml("<script>").render(), "<script>");
assertEquals(styleWithInlineFile_min("/test.css").render(), "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>");
assertEquals(scriptWithInlineFile_min("/test.js").render(), "<script>(function(){console.log(15)})();</script>");
assertEquals(fileAsString("/test.html").render(), "<body>\r\n"+" Any content\r\n"+"</body>\r\n");
assertEquals(fileAsEscapedString("/test.html").render(), "&lt;body&gt;\r\n"+" Any content\r\n"+"&lt;/body&gt;\r\n");
assertEquals(fileAsString("/test.java").render(), "public class AnyContent{}\r\n");
//EmptyTags
assertEquals(document().render(), "<!DOCTYPE html>");
@@ -170,4 +175,4 @@ public class TagCreatorTest {
assertEquals(video().render(), "<video></video>");
}
}
}

View File

@@ -35,4 +35,4 @@ public class TagTest {
assertEquals(testTag.renderCloseTag(), "</a>");
}
}
}

View File

@@ -1,97 +0,0 @@
package performancetester;
import j2html.tags.ContainerTag;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import static j2html.TagCreator.*;
import static org.junit.Assert.assertEquals;
public class RenderSpeed {
/**
* This test class is only used during development of j2html, to see if changes to data-types and rendering
* techniques have a positive or negative impact
*/
public int iterations = 100000;
public int precision = 10;
@Test
public void testFullPageRenderSpeed() {
ContainerTag complexTestTag = html().with(body().with(header(), main().with(p("Main stuff...")), footer().condWith(1 == 1, p("Conditional with!"))));
String expectedResult = "<html><body><header></header><main><p>Main stuff...</p></main><footer><p>Conditional with!</p></footer></body></html>";
assertEquals(complexTestTag.render(), (expectedResult));
String methodName = new Object(){}.getClass().getEnclosingMethod().getName();
measureAvgMethodTime(this::fullPageRenderTest, iterations, precision, methodName);
}
@Test
public void testAttributeRenderSpeed() {
String methodName = new Object(){}.getClass().getEnclosingMethod().getName();
measureAvgMethodTime(this::attributeRenderTest, iterations, precision, methodName);
}
public void attributeRenderTest(int i) {
tag("div " + i)
.attr("just", "adding")
.attr("some", "pretty")
.attr("random", "attributes")
.attr("to", "this")
.attr("div", "here").render();
}
public String fullPageRenderTest(int i) {
return html().with(
head().with(
title().withText("Test " + i)
),
body().with(
header().with(
h1("Test Header")
),
main().with(
h2("Test Form"),
div().with(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password"),
input().withType("password").withName("repeatPassword").withPlaceholder("Repeat password"),
input().withType("password").withName("repeatPasswordAgain").withPlaceholder("Repeat password again"),
button().withType("submit").withText("Login")
),
div().withText(
"<script>alert(1)</script>"
)
),
footer().withText("Test Footer"),
script().withSrc("/testScript.js")
)
).render();
}
/**
* Please tell me if there is a proper way to do this :D
*
* @param method the method to measure
* @param iterations the number of times to run the method
* @param precision the number of times to run the timer
* @param methodName the name of the method (only used for output)
*/
private void measureAvgMethodTime(IntConsumer method, int iterations, int precision, String methodName) {
double averageTime = LongStream.range(0, precision).map(l -> measureMethodTime(method, iterations)).average().getAsDouble();
System.out.println("\n" + methodName + ": " + averageTime + "ms was avg runtime per " + String.format("%,d", iterations) + " iterations (ran " + precision + " times) \n");
}
private long measureMethodTime(IntConsumer method, int iterations) {
long startTime = System.nanoTime();
IntStream.range(0, iterations).parallel().forEach(method);
long endTime = System.nanoTime();
System.out.print(TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ");
return TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
}
}

View File

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

View File

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

View File

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

View File

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