Merge pull request #187 from obecker/htmltag

Remove manual tags, use only generated tags
This commit is contained in:
Scott Embler
2021-06-12 15:14:01 -04:00
committed by GitHub
11 changed files with 74 additions and 160 deletions

View File

@@ -16,15 +16,15 @@ For preventing performance regressions, there are Tests.
## Coding Style
There is a ```.editorconfig``` and a ```eclipse_formatting_profile.xml```
There is a `.editorconfig` and a `eclipse_formatting_profile.xml`
What sticks out is that end of line is CRLF ```'\r\n'``` for this Project.
What sticks out is that end of line is CRLF `'\r\n'` for this Project.
This means that if you're on Linux ```'\n'```, you have to configure git to handle this
This means that if you're on Linux `'\n'`, you have to configure git to handle this
correctly so that you have the correct EOL in your working directory,
and the EOL is also correct in the repository itself.
For this purpose, j2html has a ```.gitattributes``` file.
For this purpose, j2html has a `.gitattributes` file.
[Guide to configuring EOL with git](https://docs.github.com/en/github/using-git/configuring-git-to-handle-line-endings)
@@ -33,7 +33,7 @@ If you are on Windows, there should be no Problems.
### Reformatting of generated Java Code
As this Projects makes use of Code-Generation techniques in order to generate a more typesafe API without too much manual Work,
there is the ```code_gen/``` directory which contains everything needed to generate the code.
there is the `code_gen/` directory which contains everything needed to generate the code.
For simplicity (and also to avoid extra dependencies), they do not format the code correctly.
@@ -57,8 +57,8 @@ This is **the** central class in J2HTML. It provides the methods
for users of J2HTML to generate all HTML Tags.
It contains methods like
```
public static HtmlTag html(HeadTag head, BodyTag body){
return new HtmlTag(head, body);
public static HtmlTag html(DomContent... dc) {
return new HtmlTag().with(dc);
}
```
which can be used in Projects using this dependency as
@@ -80,20 +80,20 @@ html(
Each HTML Tag has it's own class, which makes it possible for each Tag to have
the correct Attributes and Methods to set those Attributes.
The classes are located in ```library/src/main/java/j2html/tags/specialized/``` and follow the naming convention ```tag_name + 'Tag.java'```, e.g. ```BodyTag.java```.
The classes are located in `library/src/main/java/j2html/tags/specialized/generated` and follow the naming convention `tag_name + 'Tag.java'`, e.g. `BodyTag.java`.
Notice that the first letter of the Tag is in uppercase.
Each Tag-specific class ```implements``` interfaces which correspond to the Attributes that can be set on these Tags.
Each Tag-specific class `implements` interfaces which correspond to the Attributes that can be set on these Tags.
For Reference which Tags support which Attributes, see [HTML Attribute Reference](https://www.w3schools.com/tags/ref_attributes.asp).
For Example, ```ButtonTag``` might implement ```IType<ButtonTag>``` which says it can have an Attribute ```type```, which may later show up like ```<button type="submit"></button>```.
For Example, `ButtonTag` might implement `IType<ButtonTag>` which says it can have an Attribute `type`, which may later show up like `<button type="submit"></button>`.
### How are the Attributes of HTML Tags implemented?
Each Attribute has it's own interface in ```src/main/java/j2html/tags/attributes/``` and follows the naming convention ```"I" + attribute_name + '.java'```, e.g. ```IAccept.java```. Notice that the first letter of the Attribute is in uppercase.
Each Attribute has it's own interface in `src/main/java/j2html/tags/attributes/` and follows the naming convention `"I" + attribute_name + '.java'`, e.g. `IAccept.java`. Notice that the first letter of the Attribute is in uppercase.
Dissecting ```IAccept.java```:
Dissecting `IAccept.java`:
```
public interface IAccept<T extends Tag> extends IInstance<T> {
@@ -110,8 +110,8 @@ public interface IAccept<T extends Tag> extends IInstance<T> {
}
```
As you can see, **IAccept** extends ```IInstance<T>``` which provides only the ```self()``` Method to access an instance of type ```T```.
All attribute-specific interfaces extend ```IInstance<T>```.
As you can see, **IAccept** extends `IInstance<T>` which provides only the `self()` Method to access an instance of type `T`.
All attribute-specific interfaces extend `IInstance<T>`.
```
public interface IInstance<T> {
@@ -119,26 +119,23 @@ public interface IInstance<T> {
}
```
```IInstance<T>``` is cheating the type system because ```self()``` returns an instance of type ```T```, but the implementing class
`IInstance<T>` is cheating the type system because `self()` returns an instance of type `T`, but the implementing class
technically does not have to supply it's own type as the type argument. But by convention, in this Project, the implementing class
always supplies it's own type as the type argument.
But in ```default``` methods in interfaces there is AFAIK no way to obtain the type of the class that is implementing the interface.
But in `default` methods in interfaces there is AFAIK no way to obtain the type of the class that is implementing the interface.
If you find a way, that would be a great PR.
### Special classes/interfaces besides TagCreator.java
There are 3 classes which contain code-generating methods in ```code_gen/src/main/java/j2html_codegen/generators/```:
There are 3 classes which contain code-generating methods in `code_gen/src/main/java/j2html_codegen/generators/`:
- AttributeInterfaceCodeGenerator.java (generating the interfaces for the attributes)
- SpecializedTagClassCodeGenerator.java (generating the classes for the tags)
- TagCreatorCodeGenerator.java (generating some contents of TagCreator.java)
- `AttributeInterfaceCodeGenerator.java` (generating the interfaces for the attributes)
- `SpecializedTagClassCodeGenerator.java` (generating the classes for the tags)
- `TagCreatorCodeGenerator.java` (generating some contents of `TagCreator.java`)
### Other special classes / interfaces in J2HTML
- HtmlTag, BodyTag, HeadTag are special because they are handwritten and have special semantics in HTML: they can only be used once.
This is not modeled fully in J2HTML though.
- **Tag.java** is the base class for every tag and extends DomContent
- **EmptyTag.java** is the base class for all Tags which have no contents
- **ContainerTag.java** is the base class for all Tags which can contain other tags
@@ -150,7 +147,7 @@ Attributes differ in their 'type' . Some of them can be set with numbers (which
Others can only be set or not set, others still have 3 states: set, unset, and not present.
To model these propertise, a single Attribute can be described by an instance of **AttrD.java**.
```library/src/main/java/j2html/tags/generators/AttributesList.java``` contains the different Attributes, their properties,
`library/src/main/java/j2html/tags/generators/AttributesList.java` contains the different Attributes, their properties,
and the Tags they can be set on. It is the starting point for adding new Attributes and customizing their properties.

View File

@@ -96,7 +96,7 @@ public final class TagCreatorCodeGenerator {
"bdi",
"bdo",
"blockquote",
//"body" BodyTag is managed manually,
"body",
"button",
"canvas",
"caption",
@@ -124,9 +124,9 @@ public final class TagCreatorCodeGenerator {
"h4",
"h5",
"h6",
//"head", HeadTag is managed manually
"head",
"header",
//"html" HtmlTag is managed manually
"html",
"i",
"iframe",
"ins",

View File

@@ -9,7 +9,6 @@ import j2html.tags.InlineStaticResource;
import j2html.tags.Tag;
import j2html.tags.Text;
import j2html.tags.UnescapedText;
import j2html.tags.specialized.manual.*;
import j2html.tags.specialized.generated.*;
import java.util.Collection;
@@ -220,44 +219,27 @@ public class TagCreator {
public static DomContent document() {
return rawHtml("<!DOCTYPE html>");
}
// -- start of manually managed tags --
// EmptyTags
//ContainerTags
public static HtmlTag html() {
return new HtmlTag();
}
public static HtmlTag html(String text) { return html().withText(text); }
public static HtmlTag html(DomContent... dc) { return html().with(dc); }
public static HtmlTag html(Attr.ShortForm shortAttr) {
return Attr.addTo(new HtmlTag(), shortAttr);
return Attr.addTo(html(), shortAttr);
}
public static HtmlTag html(HeadTag head){
return new HtmlTag(head);
public static HtmlTag html(Attr.ShortForm shortAttr, String text) {
return Attr.addTo(html(text), shortAttr);
}
public static HtmlTag html(BodyTag body){
return new HtmlTag(body);
public static HtmlTag html(Attr.ShortForm shortAttr, DomContent... dc) {
return Attr.addTo(html(dc), shortAttr);
}
public static HtmlTag html(HeadTag head, BodyTag body){
return new HtmlTag(head, body);
}
public static HtmlTag html(Attr.ShortForm shortAttr, HeadTag head){
return Attr.addTo(new HtmlTag(head), shortAttr);
}
public static HtmlTag html(Attr.ShortForm shortAttr, BodyTag body){
return Attr.addTo(new HtmlTag(body), shortAttr);
}
public static HtmlTag html(Attr.ShortForm shortAttr, HeadTag head, BodyTag body){
return Attr.addTo(new HtmlTag(head, body), shortAttr);
}
public static BodyTag body() {
return new BodyTag();
}
@@ -306,14 +288,6 @@ public class TagCreator {
return Attr.addTo(new HeadTag().with(dc), shortAttr);
}
// -- end of manually managed tags --
// EmptyTags, generated in class j2html.tags.generators.TagCreatorCodeGenerator
public static AreaTag area () { return new AreaTag(); }
public static AreaTag area (Attr.ShortForm shortAttr) { return Attr.addTo( new AreaTag(), shortAttr); }

View File

@@ -0,0 +1,26 @@
package j2html.tags.specialized.generated;
import j2html.tags.ContainerTag;
import j2html.tags.attributes.*;
public final class BodyTag extends ContainerTag<BodyTag>
implements
IOnafterprint<BodyTag>,
IOnbeforeprint<BodyTag>,
IOnbeforeunload<BodyTag>,
IOnerror<BodyTag>,
IOnhashchange<BodyTag>,
IOnload<BodyTag>,
IOnoffline<BodyTag>,
IOnonline<BodyTag>,
IOnpagehide<BodyTag>,
IOnpageshow<BodyTag>,
IOnpopstate<BodyTag>,
IOnresize<BodyTag>,
IOnstorage<BodyTag>,
IOnunload<BodyTag> {
public BodyTag() {
super("body");
}
}

View File

@@ -1,4 +1,4 @@
package j2html.tags.specialized.manual;
package j2html.tags.specialized.generated;
import j2html.tags.ContainerTag;

View File

@@ -0,0 +1,10 @@
package j2html.tags.specialized.generated;
import j2html.tags.ContainerTag;
public final class HtmlTag extends ContainerTag<HtmlTag> {
public HtmlTag() {
super("html");
}
}

View File

@@ -1,10 +0,0 @@
package j2html.tags.specialized.manual;
import j2html.tags.ContainerTag;
public final class BodyTag extends ContainerTag<BodyTag> {
public BodyTag() {
super("body");
}
}

View File

@@ -1,83 +0,0 @@
package j2html.tags.specialized.manual;
import j2html.Config;
import j2html.attributes.Attribute;
import j2html.rendering.TagBuilder;
import j2html.rendering.FlatHtml;
import j2html.rendering.HtmlBuilder;
import j2html.rendering.IndentedHtml;
import j2html.tags.Tag;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Optional;
public final class HtmlTag extends Tag<HtmlTag> {
private final Optional<HeadTag> head;
private final Optional<BodyTag> body;
public HtmlTag() {
super("html");
head = Optional.empty();
body = Optional.empty();
}
public HtmlTag(HeadTag head) {
super("html");
this.head = Optional.of(head);
this.body = Optional.empty();
}
public HtmlTag(BodyTag body) {
super("html");
this.head = Optional.empty();
this.body = Optional.of(body);
}
public HtmlTag(HeadTag head, BodyTag body) {
super("html");
this.head = Optional.of(head);
this.body = Optional.of(body);
}
@Override
public <T extends Appendable> T render(HtmlBuilder<T> builder, Object model) throws IOException {
TagBuilder tagBuilder = builder.appendStartTag("html");
for(Attribute attribute : getAttributes()){
attribute.render(tagBuilder, model);
}
tagBuilder.completeTag();
if(head.isPresent()){
head.get().render(builder, model);
}
if(body.isPresent()){
body.get().render(builder, model);
}
builder.appendEndTag("html");
return builder.output();
}
public String renderFormatted() {
try {
return render(IndentedHtml.into(new StringBuilder(), Config.global())).toString();
}catch (IOException e){
throw new UncheckedIOException(e);
}
}
@Override
@Deprecated
public void renderModel(Appendable writer, Object model) throws IOException {
HtmlBuilder<?> builder = (writer instanceof HtmlBuilder)
? (HtmlBuilder<?>) writer
: FlatHtml.into(writer, Config.global());
render(builder, model);
}
}

View File

@@ -1,6 +1,6 @@
package j2html.comparison.j2html;
import j2html.tags.specialized.manual.HtmlTag;
import j2html.tags.specialized.generated.HtmlTag;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;

View File

@@ -2,7 +2,7 @@ package j2html.comparison.j2html;
import j2html.tags.ContainerTag;
import j2html.tags.DomContent;
import j2html.tags.specialized.manual.HtmlTag;
import j2html.tags.specialized.generated.HtmlTag;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;

View File

@@ -3,13 +3,13 @@ package j2html.tags;
import j2html.Config;
import j2html.attributes.Attribute;
import j2html.model.DynamicHrefAttribute;
import j2html.tags.specialized.generated.HtmlTag;
import java.io.File;
import java.io.FileWriter;
import j2html.tags.specialized.manual.HtmlTag;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.footer;