initial commit
This commit is contained in:
commit
f5d00d8913
342 changed files with 140728 additions and 0 deletions
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
/.settings
|
||||
/.classpath
|
||||
/.project
|
||||
/.gradle
|
||||
**/data
|
||||
**/work
|
||||
**/logs
|
||||
**/.idea
|
||||
**/target
|
||||
**/out
|
||||
**/build
|
||||
.DS_Store
|
||||
*.iml
|
||||
*~
|
||||
*.key
|
||||
*.crt
|
202
LICENSE.txt
Normal file
202
LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
35
build.gradle
Normal file
35
build.gradle
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
plugins {
|
||||
id 'maven-publish'
|
||||
id 'signing'
|
||||
id "io.github.gradle-nexus.publish-plugin" version "2.0.0-rc-1"
|
||||
}
|
||||
|
||||
wrapper {
|
||||
gradleVersion = libs.versions.gradle.get()
|
||||
distributionType = Wrapper.DistributionType.BIN
|
||||
}
|
||||
|
||||
ext {
|
||||
user = 'joerg'
|
||||
name = 'j2html'
|
||||
description = 'Java to HTML generator'
|
||||
inceptionYear = '2024'
|
||||
url = 'https://xbib.org/' + user + '/' + name
|
||||
scmUrl = 'https://xbib.org/' + user + '/' + name
|
||||
scmConnection = 'scm:git:git://xbib.org/' + user + '/' + name + '.git'
|
||||
scmDeveloperConnection = 'scm:git:ssh://forgejo@xbib.org:' + user + '/' + name + '.git'
|
||||
issueManagementSystem = 'Github'
|
||||
issueManagementUrl = ext.scmUrl + '/issues'
|
||||
licenseName = 'The Apache License, Version 2.0'
|
||||
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply from: rootProject.file('gradle/repositories/maven.gradle')
|
||||
apply from: rootProject.file('gradle/compile/java.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
apply from: rootProject.file('gradle/publish/maven.gradle')
|
||||
apply from: rootProject.file('gradle/publish/forgejo.gradle')
|
||||
}
|
||||
apply from: rootProject.file('gradle/publish/sonatype.gradle')
|
3
gradle.properties
Normal file
3
gradle.properties
Normal file
|
@ -0,0 +1,3 @@
|
|||
group = org.xbib
|
||||
name = j2html
|
||||
version = 1.6.0
|
29
gradle/compile/java.gradle
Normal file
29
gradle/compile/java.gradle
Normal file
|
@ -0,0 +1,29 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
modularity.inferModulePath.set(true)
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Implementation-Version': project.version)
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.fork = true
|
||||
options.forkOptions.jvmArgs += ['-Duser.language=en','-Duser.country=US']
|
||||
options.compilerArgs.add('-Xlint:all')
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
13
gradle/documentation/asciidoc.gradle
Normal file
13
gradle/documentation/asciidoc.gradle
Normal file
|
@ -0,0 +1,13 @@
|
|||
apply plugin: 'org.xbib.gradle.plugin.asciidoctor'
|
||||
|
||||
asciidoctor {
|
||||
attributes 'source-highlighter': 'coderay',
|
||||
toc: 'left',
|
||||
doctype: 'book',
|
||||
icons: 'font',
|
||||
encoding: 'utf-8',
|
||||
sectlink: true,
|
||||
sectanchors: true,
|
||||
linkattrs: true,
|
||||
imagesdir: 'img'
|
||||
}
|
8
gradle/ide/idea.gradle
Normal file
8
gradle/ide/idea.gradle
Normal file
|
@ -0,0 +1,8 @@
|
|||
apply plugin: 'idea'
|
||||
|
||||
idea {
|
||||
module {
|
||||
outputDir file('build/classes/java/main')
|
||||
testOutputDir file('build/classes/java/test')
|
||||
}
|
||||
}
|
16
gradle/publish/forgejo.gradle
Normal file
16
gradle/publish/forgejo.gradle
Normal file
|
@ -0,0 +1,16 @@
|
|||
if (project.hasProperty('forgeJoToken')) {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://xbib.org/api/packages/joerg/maven'
|
||||
credentials(HttpHeaderCredentials) {
|
||||
name = "Authorization"
|
||||
value = "token ${project.property('forgeJoToken')}"
|
||||
}
|
||||
authentication {
|
||||
header(HttpHeaderAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
gradle/publish/ivy.gradle
Normal file
27
gradle/publish/ivy.gradle
Normal file
|
@ -0,0 +1,27 @@
|
|||
apply plugin: 'ivy-publish'
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
ivy {
|
||||
url = "https://xbib.org/repo"
|
||||
}
|
||||
}
|
||||
publications {
|
||||
ivy(IvyPublication) {
|
||||
from components.java
|
||||
descriptor {
|
||||
license {
|
||||
name = 'The Apache License, Version 2.0'
|
||||
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
author {
|
||||
name = 'Jörg Prante'
|
||||
url = 'http://example.com/users/jane'
|
||||
}
|
||||
descriptor.description {
|
||||
text = rootProject.ext.description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
gradle/publish/maven.gradle
Normal file
51
gradle/publish/maven.gradle
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
publishing {
|
||||
publications {
|
||||
"${project.name}"(MavenPublication) {
|
||||
from components.java
|
||||
pom {
|
||||
artifactId = project.name
|
||||
name = project.name
|
||||
description = rootProject.ext.description
|
||||
url = rootProject.ext.url
|
||||
inceptionYear = rootProject.ext.inceptionYear
|
||||
packaging = 'jar'
|
||||
organization {
|
||||
name = 'xbib'
|
||||
url = 'https://xbib.org'
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'jprante'
|
||||
name = 'Jörg Prante'
|
||||
email = 'joergprante@gmail.com'
|
||||
url = 'https://xbib.org/joerg'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = rootProject.ext.scmUrl
|
||||
connection = rootProject.ext.scmConnection
|
||||
developerConnection = rootProject.ext.scmDeveloperConnection
|
||||
}
|
||||
issueManagement {
|
||||
system = rootProject.ext.issueManagementSystem
|
||||
url = rootProject.ext.issueManagementUrl
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name = rootProject.ext.licenseName
|
||||
url = rootProject.ext.licenseUrl
|
||||
distribution = 'repo'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty("signing.keyId")) {
|
||||
apply plugin: 'signing'
|
||||
signing {
|
||||
sign publishing.publications."${project.name}"
|
||||
}
|
||||
}
|
12
gradle/publish/sonatype.gradle
Normal file
12
gradle/publish/sonatype.gradle
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
|
||||
nexusPublishing {
|
||||
repositories {
|
||||
sonatype {
|
||||
username = project.property('ossrhUsername')
|
||||
password = project.property('ossrhPassword')
|
||||
packageGroup = "org.xbib"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
gradle/quality/checkstyle.gradle
Normal file
19
gradle/quality/checkstyle.gradle
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
tasks.withType(Checkstyle) {
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
xml.getRequired().set(true)
|
||||
html.getRequired().set(true)
|
||||
}
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
configFile = rootProject.file('gradle/quality/checkstyle.xml')
|
||||
ignoreFailures = true
|
||||
showViolations = true
|
||||
checkstyleMain {
|
||||
source = sourceSets.main.allSource
|
||||
}
|
||||
}
|
333
gradle/quality/checkstyle.xml
Normal file
333
gradle/quality/checkstyle.xml
Normal file
|
@ -0,0 +1,333 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!-- This is a checkstyle configuration file. For descriptions of
|
||||
what the following rules do, please see the checkstyle configuration
|
||||
page at http://checkstyle.sourceforge.net/config.html -->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
<property name="fileNamePattern" value=".*(Example|Test|module-info)(\$.*)?"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<!-- Checks that there are no tab characters in the file.
|
||||
-->
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Checks that FIXME is not used in comments. TODO is preferred.
|
||||
-->
|
||||
<property name="format" value="((//.*)|(\*.*))FIXME" />
|
||||
<property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Checks that TODOs are named. (Actually, just that they are followed
|
||||
by an open paren.)
|
||||
-->
|
||||
<property name="format" value="((//.*)|(\*.*))TODO[^(]" />
|
||||
<property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."' />
|
||||
</module>
|
||||
|
||||
<module name="JavadocPackage">
|
||||
<!-- Checks that each Java package has a Javadoc file used for commenting.
|
||||
Only allows a package-info.java, not package.html. -->
|
||||
</module>
|
||||
|
||||
<!-- All Java AST specific tests live under TreeWalker module. -->
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!--
|
||||
|
||||
IMPORT CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="RedundantImport">
|
||||
<!-- Checks for redundant import statements. -->
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="ImportOrder">
|
||||
<!-- Checks for out of order import statements. -->
|
||||
|
||||
<property name="severity" value="warning"/>
|
||||
<!-- <property name="tokens" value="IMPORT, STATIC_IMPORT"/> -->
|
||||
<property name="separated" value="false"/>
|
||||
<property name="groups" value="*"/>
|
||||
<!-- <property name="option" value="above"/> -->
|
||||
<property name="sortStaticImportsAlphabetically" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="CustomImportOrder">
|
||||
<!-- <property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###STATIC"/> -->
|
||||
<!-- <property name="specialImportsRegExp" value="^javax\."/> -->
|
||||
<!-- <property name="standardPackageRegExp" value="^java\."/> -->
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="false"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
|
||||
JAVADOC CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<module name="JavadocMethod">
|
||||
<property name="accessModifiers" value="protected"/>
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocType">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocStyle">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
|
||||
NAMING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<!-- Item 38 - Adhere to generally accepted naming conventions -->
|
||||
|
||||
<module name="PackageName">
|
||||
<!-- Validates identifiers for package names against the
|
||||
supplied expression. -->
|
||||
<!-- Here the default checkstyle rule restricts package name parts to
|
||||
seven characters, this is not in line with common practice at Google.
|
||||
-->
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="TypeNameCheck">
|
||||
<!-- Validates static, final fields against the
|
||||
expression "^[A-Z][a-zA-Z0-9]*$". -->
|
||||
<metadata name="altname" value="TypeName"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ConstantNameCheck">
|
||||
<!-- Validates non-private, static, final fields against the supplied
|
||||
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
|
||||
<metadata name="altname" value="ConstantName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="false"/>
|
||||
<property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="StaticVariableNameCheck">
|
||||
<!-- Validates static, non-final fields against the supplied
|
||||
expression "^[a-z][a-zA-Z0-9]*_?$". -->
|
||||
<metadata name="altname" value="StaticVariableName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MemberNameCheck">
|
||||
<!-- Validates non-static members against the supplied expression. -->
|
||||
<metadata name="altname" value="MemberName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodNameCheck">
|
||||
<!-- Validates identifiers for method names. -->
|
||||
<metadata name="altname" value="MethodName"/>
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ParameterName">
|
||||
<!-- Validates identifiers for method parameters against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName">
|
||||
<!-- Validates identifiers for local final variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalVariableName">
|
||||
<!-- Validates identifiers for local variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
LENGTH and CODING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<module name="LeftCurly">
|
||||
<!-- Checks for placement of the left curly brace ('{'). -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="RightCurly">
|
||||
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
|
||||
the same line. e.g., the following example is fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
} else
|
||||
</pre>
|
||||
-->
|
||||
<!-- This next example is not fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
}
|
||||
else
|
||||
</pre>
|
||||
-->
|
||||
<property name="option" value="same"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<!-- Checks for braces around if and else blocks -->
|
||||
<module name="NeedBraces">
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
|
||||
</module>
|
||||
|
||||
<module name="UpperEll">
|
||||
<!-- Checks that long constants are defined with an upper ell.-->
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="FallThrough">
|
||||
<!-- Warn about falling through to the next case statement. Similar to
|
||||
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
|
||||
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
|
||||
some other variants which we don't publicized to promote consistency).
|
||||
-->
|
||||
<property name="reliefPattern"
|
||||
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
MODIFIERS CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="ModifierOrder">
|
||||
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
|
||||
8.4.3. The prescribed order is:
|
||||
public, protected, private, abstract, static, final, transient, volatile,
|
||||
synchronized, native, strictfp
|
||||
-->
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
WHITESPACE CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="WhitespaceAround">
|
||||
<!-- Checks that various tokens are surrounded by whitespace.
|
||||
This includes most binary operators and keywords followed
|
||||
by regular or curly braces.
|
||||
-->
|
||||
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
|
||||
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
|
||||
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
||||
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
||||
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
|
||||
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
|
||||
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="WhitespaceAfter">
|
||||
<!-- Checks that commas, semicolons and typecasts are followed by
|
||||
whitespace.
|
||||
-->
|
||||
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceAfter">
|
||||
<!-- Checks that there is no whitespace after various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
|
||||
UNARY_PLUS"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore">
|
||||
<!-- Checks that there is no whitespace before various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="ParenPad">
|
||||
<!-- Checks that there is no whitespace before close parens or after
|
||||
open parens.
|
||||
-->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
|
||||
<module name="LineLength">
|
||||
<!-- Checks if a line is too long. -->
|
||||
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="128"/>
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<!--
|
||||
The default ignore pattern exempts the following elements:
|
||||
- import statements
|
||||
- long URLs inside comments
|
||||
-->
|
||||
|
||||
<property name="ignorePattern"
|
||||
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
|
||||
default="^(package .*;\s*)|(import .*;\s*)|( *(\*|//).*https?://.*)$"/>
|
||||
</module>
|
||||
</module>
|
||||
|
11
gradle/quality/cyclonedx.gradle
Normal file
11
gradle/quality/cyclonedx.gradle
Normal file
|
@ -0,0 +1,11 @@
|
|||
cyclonedxBom {
|
||||
includeConfigs = [ 'runtimeClasspath' ]
|
||||
skipConfigs = [ 'compileClasspath', 'testCompileClasspath' ]
|
||||
projectType = "library"
|
||||
schemaVersion = "1.4"
|
||||
destination = file("build/reports")
|
||||
outputName = "bom"
|
||||
outputFormat = "json"
|
||||
includeBomSerialNumber = true
|
||||
componentVersion = "2.0.0"
|
||||
}
|
17
gradle/quality/pmd.gradle
Normal file
17
gradle/quality/pmd.gradle
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
apply plugin: 'pmd'
|
||||
|
||||
tasks.withType(Pmd) {
|
||||
ignoreFailures = true
|
||||
reports {
|
||||
xml.getRequired().set(true)
|
||||
html.getRequired().set(true)
|
||||
}
|
||||
}
|
||||
|
||||
pmd {
|
||||
ignoreFailures = true
|
||||
consoleOutput = false
|
||||
toolVersion = "6.51.0"
|
||||
ruleSetFiles = rootProject.files('gradle/quality/pmd/category/java/bestpractices.xml')
|
||||
}
|
10
gradle/quality/sonarqube.gradle
Normal file
10
gradle/quality/sonarqube.gradle
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectName", "${project.group} ${project.name}"
|
||||
property "sonar.sourceEncoding", "UTF-8"
|
||||
property "sonar.tests", "src/test/java"
|
||||
property "sonar.scm.provider", "git"
|
||||
property "sonar.junit.reportsPath", "build/test-results/test/"
|
||||
}
|
||||
}
|
15
gradle/quality/spotbugs.gradle
Normal file
15
gradle/quality/spotbugs.gradle
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
apply plugin: 'com.github.spotbugs'
|
||||
|
||||
spotbugs {
|
||||
effort = "max"
|
||||
reportLevel = "low"
|
||||
ignoreFailures = true
|
||||
}
|
||||
|
||||
spotbugsMain {
|
||||
reports {
|
||||
xml.getRequired().set(false)
|
||||
html.getRequired().set(true)
|
||||
}
|
||||
}
|
4
gradle/repositories/maven.gradle
Normal file
4
gradle/repositories/maven.gradle
Normal file
|
@ -0,0 +1,4 @@
|
|||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
22
gradle/test/jmh.gradle
Normal file
22
gradle/test/jmh.gradle
Normal file
|
@ -0,0 +1,22 @@
|
|||
sourceSets {
|
||||
jmh {
|
||||
java.srcDirs = ['src/jmh/java']
|
||||
resources.srcDirs = ['src/jmh/resources']
|
||||
compileClasspath += sourceSets.main.runtimeClasspath
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
jmhImplementation 'org.openjdk.jmh:jmh-core:1.34'
|
||||
jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.34'
|
||||
}
|
||||
|
||||
task jmh(type: JavaExec, group: 'jmh', dependsOn: jmhClasses) {
|
||||
mainClass.set('org.openjdk.jmh.Main')
|
||||
classpath = sourceSets.jmh.compileClasspath + sourceSets.jmh.runtimeClasspath
|
||||
project.file('build/reports/jmh').mkdirs()
|
||||
args '-rf', 'json'
|
||||
args '-rff', project.file('build/reports/jmh/result.json')
|
||||
}
|
||||
|
||||
classes.finalizedBy(jmhClasses)
|
35
gradle/test/junit5.gradle
Normal file
35
gradle/test/junit5.gradle
Normal file
|
@ -0,0 +1,35 @@
|
|||
dependencies {
|
||||
testImplementation testLibs.junit.jupiter.api
|
||||
testImplementation testLibs.hamcrest
|
||||
testRuntimeOnly testLibs.junit.jupiter.engine
|
||||
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
failFast = false
|
||||
jvmArgs '--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED',
|
||||
'--add-exports=java.base/jdk.internal.ref=ALL-UNNAMED',
|
||||
'--add-exports=java.base/sun.nio.ch=ALL-UNNAMED',
|
||||
'--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED',
|
||||
'--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED',
|
||||
'--add-opens=jdk.compiler/com.sun.tools.javac=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.lang=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.lang.reflect=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.io=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.nio=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.util=ALL-UNNAMED'
|
||||
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||
testLogging {
|
||||
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
||||
}
|
||||
afterSuite { desc, result ->
|
||||
if (!desc.parent) {
|
||||
println "\nTest result: ${result.resultType}"
|
||||
println "Test summary: ${result.testCount} tests, " +
|
||||
"${result.successfulTestCount} succeeded, " +
|
||||
"${result.failedTestCount} failed, " +
|
||||
"${result.skippedTestCount} skipped"
|
||||
}
|
||||
}
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
gradlew
vendored
Executable file
249
gradlew
vendored
Executable file
|
@ -0,0 +1,249 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
gradlew.bat
vendored
Normal file
92
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
5
j2html-codegen/build.gradle
Normal file
5
j2html-codegen/build.gradle
Normal file
|
@ -0,0 +1,5 @@
|
|||
dependencies {
|
||||
implementation libs.jsoup
|
||||
implementation libs.javapoet
|
||||
testImplementation testLibs.mockito.core
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.xbib.j2html.codegen.Model.Node;
|
||||
import static org.xbib.j2html.codegen.Model.Metadata.ON_OFF;
|
||||
import static org.xbib.j2html.codegen.Model.Metadata.SELF_CLOSING;
|
||||
|
||||
public class Generator {
|
||||
|
||||
public static final ClassName INSTANCE = ClassName.get("j2html.tags", "IInstance");
|
||||
|
||||
public static final ClassName TAG = ClassName.get("j2html.tags", "Tag");
|
||||
|
||||
public static final ClassName EMPTY_TAG = ClassName.get("j2html.tags", "EmptyTag");
|
||||
|
||||
public static final ClassName CONTAINER_TAG = ClassName.get("j2html.tags", "ContainerTag");
|
||||
|
||||
/*public static void main(String... args) throws IOException {
|
||||
Path path = Paths.get("j2html-codegen", "src", "test", "resources", "html.model");
|
||||
String definitions = new String(Files.readAllBytes(path));
|
||||
Model model = new Model();
|
||||
Parser.parse(definitions, model);
|
||||
Path dir = Paths.get("/j2html/generated-source");
|
||||
Files.createDirectories(dir);
|
||||
generate(dir, "j2html.tags.attributes", "j2html.tags.specialized", model);
|
||||
}*/
|
||||
|
||||
public static void generate(Path root,
|
||||
String attributePkg,
|
||||
String elementPkg,
|
||||
Model model) throws IOException {
|
||||
Map<String, JavaFile> attributes = generateAttributePackage(attributePkg, model);
|
||||
for (JavaFile file : attributes.values()) {
|
||||
file.writeTo(root);
|
||||
}
|
||||
Map<String, JavaFile> elements = generateElementPackage(elementPkg, model, attributes);
|
||||
for (JavaFile file : elements.values()) {
|
||||
file.writeTo(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, JavaFile> generateElementPackage(String pkg, Model model, Map<String, JavaFile> attributes) {
|
||||
Map<String, JavaFile> files = new HashMap<>();
|
||||
for (Node element : model.elements()) {
|
||||
ClassName className = ClassName.get(pkg, capitalize(element.name) + "Tag");
|
||||
TypeSpec.Builder type = defineElementClass(element, className);
|
||||
for (Node attribute : element.children) {
|
||||
JavaFile file = attributes.get(attribute.name);
|
||||
type.addSuperinterface(ParameterizedTypeName.get(ClassName.get(file.packageName, file.typeSpec.name),
|
||||
className));
|
||||
}
|
||||
files.put(element.name, JavaFile.builder(pkg, type.build()).skipJavaLangImports(true).build());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private static Map<String, JavaFile> generateAttributePackage(String pkg, Model model) {
|
||||
Map<String, JavaFile> files = new HashMap<>();
|
||||
for (Node attribute : model.attributes()) {
|
||||
TypeSpec.Builder type = defineAttributeClass(pkg, attribute);
|
||||
if (attribute.type.equals(Node.Type.STRING)) {
|
||||
defineStringAttributeMethods(attribute, type);
|
||||
} else if (attribute.type.equals(Node.Type.BOOLEAN) && !attribute.is(ON_OFF)) {
|
||||
defineBooleanAttributeMethods(attribute, type);
|
||||
} else if (attribute.type.equals(Node.Type.BOOLEAN) && attribute.is(ON_OFF)) {
|
||||
defineOnOffAttributeMethods(attribute, type);
|
||||
}
|
||||
files.put(attribute.name, JavaFile.builder(pkg, type.build()).skipJavaLangImports(true).build());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private static TypeSpec.Builder defineElementClass(Node element, ClassName className) {
|
||||
MethodSpec constructor = MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addStatement("super(\"" + element.name + "\")")
|
||||
.build();
|
||||
TypeSpec.Builder type = TypeSpec.classBuilder(className)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.superclass(ParameterizedTypeName.get(element.is(SELF_CLOSING) ? EMPTY_TAG : CONTAINER_TAG, className))
|
||||
.addMethod(constructor);
|
||||
return type;
|
||||
}
|
||||
|
||||
private static TypeSpec.Builder defineAttributeClass(String pkg, Node attribute) {
|
||||
ClassName name = ClassName.get(pkg, "I" + capitalize(attribute.name));
|
||||
return TypeSpec.interfaceBuilder(name)
|
||||
.addSuperinterface(ParameterizedTypeName.get(INSTANCE, TypeVariableName.get("T")))
|
||||
.addTypeVariable(TypeVariableName.get("T", ParameterizedTypeName.get(TAG, TypeVariableName.get("T"))))
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
}
|
||||
|
||||
private static void defineBooleanAttributeMethods(Node attribute, TypeSpec.Builder type) {
|
||||
MethodSpec with = MethodSpec.methodBuilder(methodName("is", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addStatement("return self().attr(\"" + attribute.name + "\")")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
MethodSpec withCond = MethodSpec.methodBuilder(methodName("withCond", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addParameter(TypeName.BOOLEAN, "enable", Modifier.FINAL)
|
||||
.addStatement("return enable ? self().attr(\"" + attribute.name + "\") : self()")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
type.addMethod(with);
|
||||
type.addMethod(withCond);
|
||||
}
|
||||
|
||||
private static void defineOnOffAttributeMethods(Node attribute, TypeSpec.Builder type) {
|
||||
MethodSpec with = MethodSpec.methodBuilder(methodName("is", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addStatement("return self().attr(\"" + attribute.name + "\", \"on\")")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
MethodSpec withCond = MethodSpec.methodBuilder(methodName("withCond", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addParameter(TypeName.BOOLEAN, "enable", Modifier.FINAL)
|
||||
.addStatement("return enable ? self().attr(\"" + attribute.name + "\", \"on\") : self()")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
type.addMethod(with);
|
||||
type.addMethod(withCond);
|
||||
}
|
||||
|
||||
private static void defineStringAttributeMethods(Node attribute, TypeSpec.Builder type) {
|
||||
MethodSpec with = MethodSpec.methodBuilder(methodName("with", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addParameter(String.class, parameter(attribute), Modifier.FINAL)
|
||||
.addStatement("return self().attr(\"" + attribute.name + "\", " + parameter(attribute) + ")")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
|
||||
MethodSpec withCond = MethodSpec.methodBuilder(methodName("withCond", attribute.name))
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addParameter(TypeName.BOOLEAN, "enable", Modifier.FINAL)
|
||||
.addParameter(String.class, parameter(attribute), Modifier.FINAL)
|
||||
.addStatement("return enable ? self().attr(\"" + attribute.name + "\", " + parameter(attribute) + ") : self()")
|
||||
.returns(TypeVariableName.get("T"))
|
||||
.build();
|
||||
|
||||
type.addMethod(with);
|
||||
type.addMethod(withCond);
|
||||
}
|
||||
|
||||
private static String parameter(Node attribute) {
|
||||
return attribute.name + "_";
|
||||
}
|
||||
|
||||
private static String methodName(String... words) {
|
||||
String[] camelCase = new String[words.length];
|
||||
camelCase[0] = words[0];
|
||||
for (int i = 1; i < words.length; i++) {
|
||||
camelCase[i] = capitalize(words[i]);
|
||||
}
|
||||
return String.join("", camelCase);
|
||||
}
|
||||
|
||||
private static String capitalize(String word) {
|
||||
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
179
j2html-codegen/src/main/java/org/xbib/j2html/codegen/Model.java
Normal file
179
j2html-codegen/src/main/java/org/xbib/j2html/codegen/Model.java
Normal file
|
@ -0,0 +1,179 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static org.xbib.j2html.codegen.Model.Metadata.ON_OFF;
|
||||
import static org.xbib.j2html.codegen.Model.Metadata.SELF_CLOSING;
|
||||
import static org.xbib.j2html.codegen.Model.Node.Type.BOOLEAN;
|
||||
import static org.xbib.j2html.codegen.Model.Node.Type.ELEMENT;
|
||||
import static org.xbib.j2html.codegen.Model.Node.Type.STRING;
|
||||
|
||||
public class Model implements Parser.Listener {
|
||||
|
||||
private final Map<String, Node> elements;
|
||||
private final Map<String, Node> attributes;
|
||||
|
||||
public Model() {
|
||||
elements = new LinkedHashMap<>();
|
||||
attributes = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public Collection<Node> elements() {
|
||||
return elements.values();
|
||||
}
|
||||
|
||||
public Collection<Node> attributes() {
|
||||
return attributes.values();
|
||||
}
|
||||
|
||||
public Node addElement(String name) {
|
||||
return add(ELEMENT, name, elements);
|
||||
}
|
||||
|
||||
public Node addBooleanAttribute(String name) {
|
||||
return add(BOOLEAN, name, attributes);
|
||||
}
|
||||
|
||||
public Node addStringAttribute(String name) {
|
||||
return add(STRING, name, attributes);
|
||||
}
|
||||
|
||||
public Node element(String name) {
|
||||
if (!elements.containsKey(name)) {
|
||||
throw new NodeDoesNotExist(name);
|
||||
}
|
||||
return elements.get(name);
|
||||
}
|
||||
|
||||
public Node attribute(String name) {
|
||||
if (!attributes.containsKey(name)) {
|
||||
throw new NodeDoesNotExist(name);
|
||||
}
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
private Node add(Node.Type type, String name, Map<String, Node> nodes) {
|
||||
if (nodes.containsKey(name)) {
|
||||
throw new NodeAlreadyExists(name);
|
||||
}
|
||||
|
||||
Node node = new Node(type, name);
|
||||
nodes.put(name, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lineCommented(int line, String txt) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void elementDefined(int line, String name) {
|
||||
attempt(() -> addElement(name), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emptyElementDefined(int line, String name) {
|
||||
attempt(() -> addElement(name).annotate(SELF_CLOSING), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void booleanDefined(int line, String name) {
|
||||
attempt(() -> addBooleanAttribute(name), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOffDefined(int line, String name) {
|
||||
attempt(() -> addBooleanAttribute(name).annotate(ON_OFF), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stringDefined(int line, String name) {
|
||||
attempt(() -> addStringAttribute(name), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeDefined(int line, String element, String name) {
|
||||
attempt(() -> element(element).addChild(attribute(name)), line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidLine(int line, String txt) {
|
||||
throw new RuntimeException("Invalid line [" + line + "]: " + txt);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface Unsafe {
|
||||
void call() throws RuntimeException;
|
||||
}
|
||||
|
||||
private void attempt(Unsafe operation, int line) {
|
||||
try {
|
||||
operation.call();
|
||||
} catch (RuntimeException e) {
|
||||
throw new InvalidModel(e, line);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Node {
|
||||
enum Type {
|
||||
ELEMENT,
|
||||
BOOLEAN,
|
||||
STRING
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
public final String name;
|
||||
public final List<Metadata> metadata;
|
||||
public final List<Node> children;
|
||||
|
||||
private Node(Type type, String name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.metadata = new ArrayList<>();
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void annotate(Metadata meta) {
|
||||
metadata.add(meta);
|
||||
}
|
||||
|
||||
public void addChild(Node node) {
|
||||
children.add(node);
|
||||
}
|
||||
|
||||
public boolean is(Metadata annotation) {
|
||||
return metadata.contains(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Metadata {
|
||||
SELF_CLOSING,
|
||||
ON_OFF,
|
||||
OBSOLETE
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class InvalidModel extends RuntimeException {
|
||||
public InvalidModel(Exception cause, int line) {
|
||||
super(cause.getMessage() + ". At line " + line, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NodeAlreadyExists extends RuntimeException {
|
||||
public NodeAlreadyExists(String name) {
|
||||
super("Node already exists: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NodeDoesNotExist extends RuntimeException {
|
||||
public NodeDoesNotExist(String name) {
|
||||
super("Node does not exist: " + name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Parser {
|
||||
|
||||
private static final Pattern EMPTY_LINE_PATTERN = Pattern.compile("\\s*");
|
||||
private static final Pattern COMMENT_PATTERN = Pattern.compile("#.*");
|
||||
private static final Pattern NODE_PATTERN = Pattern.compile("(?<type>ELEMENT|EMPTY-ELEMENT|BOOLEAN|ONOFF|STRING)\\[(?<name>\\S+)\\]");
|
||||
private static final Pattern ATTRIBUTE_PATTERN = Pattern.compile("ATTRIBUTE\\[(?<element>\\S+):(?<name>\\S+)\\]");
|
||||
|
||||
public interface Listener {
|
||||
void lineCommented(int line, String txt);
|
||||
|
||||
void elementDefined(int line, String name);
|
||||
|
||||
void emptyElementDefined(int line, String name);
|
||||
|
||||
void booleanDefined(int line, String name);
|
||||
|
||||
void onOffDefined(int line, String name);
|
||||
|
||||
void stringDefined(int line, String name);
|
||||
|
||||
void attributeDefined(int line, String element, String name);
|
||||
|
||||
void invalidLine(int line, String txt);
|
||||
}
|
||||
|
||||
public static void parse(String txt, Listener listener) {
|
||||
String[] lines = txt.split("[\r\n]+");
|
||||
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
int number = i + 1;
|
||||
String line = lines[i];
|
||||
|
||||
if (match(EMPTY_LINE_PATTERN, line)) continue;
|
||||
|
||||
if (match(COMMENT_PATTERN, line, matcher -> {
|
||||
listener.lineCommented(number, line);
|
||||
})) continue;
|
||||
|
||||
if (match(NODE_PATTERN, line, matcher -> {
|
||||
String type = matcher.group("type");
|
||||
String name = matcher.group("name");
|
||||
switch (type) {
|
||||
case "ELEMENT":
|
||||
listener.elementDefined(number, name);
|
||||
break;
|
||||
case "EMPTY-ELEMENT":
|
||||
listener.emptyElementDefined(number, name);
|
||||
break;
|
||||
case "BOOLEAN":
|
||||
listener.booleanDefined(number, name);
|
||||
break;
|
||||
case "ONOFF":
|
||||
listener.onOffDefined(number, name);
|
||||
break;
|
||||
case "STRING":
|
||||
listener.stringDefined(number, name);
|
||||
break;
|
||||
}
|
||||
})) continue;
|
||||
|
||||
if (match(ATTRIBUTE_PATTERN, line, matcher -> {
|
||||
listener.attributeDefined(
|
||||
number,
|
||||
matcher.group("element"),
|
||||
matcher.group("name")
|
||||
);
|
||||
})) continue;
|
||||
|
||||
listener.invalidLine(number, line);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean match(Pattern pattern, String txt) {
|
||||
return pattern.matcher(txt).matches();
|
||||
}
|
||||
|
||||
private static boolean match(Pattern pattern, String txt, Consumer<Matcher> onMatch) {
|
||||
Matcher matcher = pattern.matcher(txt);
|
||||
if (matcher.matches()) {
|
||||
onMatch.accept(matcher);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package org.xbib.j2html.codegen.generators;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.xbib.j2html.codegen.model.AttrD;
|
||||
import org.xbib.j2html.codegen.model.AttributesList;
|
||||
|
||||
public final class AttributeInterfaceCodeGenerator {
|
||||
|
||||
private static final String relPath = "tags/attributes/";
|
||||
|
||||
public static void generate(final Path absPath,
|
||||
final boolean delete) throws IOException {
|
||||
for (final AttrD attr : AttributesList.attributesDescriptive()) {
|
||||
final Path path = makePath(attr.attr, absPath);
|
||||
final String interfaceName = interfaceNameFromAttribute(attr.attr) + "<T extends Tag<T>>";
|
||||
final String interfaceStr = getInterfaceTemplate(
|
||||
interfaceName,
|
||||
Optional.of("IInstance<T>"),
|
||||
Arrays.asList("j2html.tags.Tag", "j2html.tags.IInstance"),
|
||||
interfaceNameFromAttribute(attr.attr).substring(1),
|
||||
attr
|
||||
);
|
||||
if (!delete) {
|
||||
Files.write(path, interfaceStr.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPackage() {
|
||||
return "package j2html.tags.attributes;\n";
|
||||
}
|
||||
|
||||
private static String makeReturnTypeAndMethodName(final String name) {
|
||||
return "default " + "T " + name;
|
||||
}
|
||||
|
||||
private static String getInterfaceTemplate(
|
||||
final String interfaceName,
|
||||
final Optional<String> optExtends,
|
||||
final List<String> imports,
|
||||
final String interfaceNameSimple,
|
||||
final AttrD attrD
|
||||
) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(getPackage());
|
||||
sb.append("\n");
|
||||
for (String importName : imports) {
|
||||
sb.append("import ").append(importName).append(";\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
sb.append("public interface ")
|
||||
.append(interfaceName);
|
||||
optExtends.ifPresent(ext -> sb.append(" extends ").append(ext).append(" "));
|
||||
sb.append(" {\n");
|
||||
final String attrName = interfaceNameSimple.toLowerCase();
|
||||
final String paramName = attrName + "_";
|
||||
writeAttributeMethod(interfaceNameSimple, attrD, sb, attrName, paramName);
|
||||
writeAttributeMethodCond(interfaceNameSimple, attrD, sb, attrName, paramName);
|
||||
sb.append("}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void addAttributeNoArg(final StringBuilder sb, final String attrName) {
|
||||
sb.append("self().attr(\"");
|
||||
if (attrName.equals("autocomplete")) {
|
||||
sb.append(attrName).append("\",\"on\"");
|
||||
} else {
|
||||
sb.append(attrName).append("\"");
|
||||
}
|
||||
sb.append(");\n");
|
||||
}
|
||||
|
||||
private static void writeAttributeMethodCond(String interfaceNameSimple,
|
||||
AttrD attrD,
|
||||
StringBuilder sb,
|
||||
String attrName,
|
||||
String paramName) {
|
||||
sb.append(makeReturnTypeAndMethodName("withCond" + interfaceNameSimple));
|
||||
if (attrD.hasArgument) {
|
||||
sb.append("(final boolean enable, final String ").append(paramName).append(") {");
|
||||
sb.append("if (enable){\n");
|
||||
sb.append("self().attr(\"").append(attrName).append("\", ").append(paramName).append(");\n");
|
||||
sb.append("}\n");
|
||||
sb.append("return self();\n");
|
||||
} else {
|
||||
sb.append("(final boolean enable) {");
|
||||
sb.append("if (enable){\n");
|
||||
addAttributeNoArg(sb, attrName);
|
||||
sb.append("}\n");
|
||||
sb.append("return self();\n");
|
||||
}
|
||||
sb.append("}\n");
|
||||
}
|
||||
|
||||
private static void writeAttributeMethod(String interfaceNameSimple,
|
||||
AttrD attrD,
|
||||
StringBuilder sb,
|
||||
String attrName,
|
||||
String paramName) {
|
||||
sb.append(makeReturnTypeAndMethodName(((attrD.hasArgument) ? "with" : "is") + interfaceNameSimple));
|
||||
if (attrD.hasArgument) {
|
||||
sb.append("(final String ").append(paramName).append(") {")
|
||||
.append("return self().attr(\"").append(attrName).append("\", ").append(paramName).append(");\n");
|
||||
} else {
|
||||
sb.append("() {");
|
||||
addAttributeNoArg(sb, attrName);
|
||||
sb.append("return self();\n");
|
||||
}
|
||||
sb.append("}\n");
|
||||
}
|
||||
|
||||
public static String interfaceNameFromAttribute(String attribute) {
|
||||
String res = attribute.substring(0, 1).toUpperCase() + attribute.substring(1);
|
||||
return "I" + res;
|
||||
}
|
||||
|
||||
private static Path makePath(String tagLowerCase, final Path absPath) {
|
||||
final String filename = interfaceNameFromAttribute(tagLowerCase) + ".java";
|
||||
return Paths.get(absPath.toString(), relPath, filename);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package org.xbib.j2html.codegen.generators;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.xbib.j2html.codegen.model.AttributesList;
|
||||
|
||||
public final class SpecializedTagClassCodeGenerator {
|
||||
|
||||
private static final String relPath = "tags/specialized";
|
||||
|
||||
public static void generate(final Path absPath, final boolean delete) throws IOException {
|
||||
for (final String tag : TagCreatorCodeGenerator.emptyTags()) {
|
||||
final String className = classNameFromTag(tag);
|
||||
final Path path = makePath(absPath, tag);
|
||||
final List<String> interfaceNames = getInterfaceNamesForTag(tag);
|
||||
final String classString =
|
||||
getClassTemplate(
|
||||
className,
|
||||
Optional.of("EmptyTag<" + className + ">"),
|
||||
Arrays.asList("j2html.tags.EmptyTag", "j2html.tags.attributes.*"),
|
||||
tag,
|
||||
interfaceNames
|
||||
);
|
||||
if (!delete) {
|
||||
Files.write(path, classString.getBytes());
|
||||
}
|
||||
}
|
||||
for (final String tag : TagCreatorCodeGenerator.containerTags()) {
|
||||
final Path path = makePath(absPath, tag);
|
||||
final String className = classNameFromTag(tag);
|
||||
final List<String> interfaceNames = getInterfaceNamesForTag(tag);
|
||||
final String classString = getClassTemplate(className,
|
||||
Optional.of("ContainerTag<" + className + ">"),
|
||||
Arrays.asList("j2html.tags.ContainerTag", "j2html.tags.attributes.*"),
|
||||
tag,
|
||||
interfaceNames
|
||||
);
|
||||
if (delete) {
|
||||
if (Files.exists(path)) {
|
||||
Files.delete(path);
|
||||
}
|
||||
} else {
|
||||
Files.write(path, classString.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String classNameFromTag(String tageNameLowerCase) {
|
||||
String res = tageNameLowerCase.substring(0, 1).toUpperCase() + tageNameLowerCase.substring(1);
|
||||
return res + "Tag";
|
||||
}
|
||||
|
||||
private static Path makePath(final Path absPath, String tagLowerCase) {
|
||||
final String filename = classNameFromTag(tagLowerCase) + ".java";
|
||||
return Paths.get(absPath.toString(), relPath, filename);
|
||||
}
|
||||
|
||||
private static String getPackage() {
|
||||
return "package j2html.tags.specialized;\n";
|
||||
}
|
||||
|
||||
private static String getClassTemplate(final String className,
|
||||
final Optional<String> optExtends,
|
||||
final List<String> imports,
|
||||
final String tag,
|
||||
final List<String> interfaces
|
||||
) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(getPackage());
|
||||
sb.append("\n");
|
||||
for (String importName : imports) {
|
||||
sb.append("import ").append(importName).append(";\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
sb.append("public final class ")
|
||||
.append(className)
|
||||
.append(" ");
|
||||
optExtends.ifPresent(ext -> sb.append("extends ").append(ext).append(" "));
|
||||
if (!interfaces.isEmpty()) {
|
||||
sb.append("\n");
|
||||
sb.append("implements ");
|
||||
final List<String> genericInterfaceNames = interfaces.stream().map(iName -> iName + "<" + className + ">")
|
||||
.collect(Collectors.toList());
|
||||
sb.append(String.join(",", genericInterfaceNames));
|
||||
}
|
||||
sb.append(" {\n");
|
||||
sb.append("public ")
|
||||
.append(className)
|
||||
.append("() {")
|
||||
.append("super(\"").append(tag).append("\");")
|
||||
.append("}\n");
|
||||
sb.append("}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static List<String> getInterfaceNamesForTag(final String tagNameLowercase) {
|
||||
return AttributesList.getCustomAttributesForHtmlTag(tagNameLowercase)
|
||||
.stream()
|
||||
.map(AttributeInterfaceCodeGenerator::interfaceNameFromAttribute)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package org.xbib.j2html.codegen.generators;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class TagCreatorCodeGenerator {
|
||||
|
||||
public static List<String> emptyTags() {
|
||||
return Arrays.asList(
|
||||
"area",
|
||||
"base",
|
||||
"br",
|
||||
"col",
|
||||
"embed",
|
||||
"hr",
|
||||
"img",
|
||||
"input",
|
||||
"keygen",
|
||||
"link",
|
||||
"meta",
|
||||
"param",
|
||||
"source",
|
||||
"track",
|
||||
"wbr"
|
||||
);
|
||||
}
|
||||
|
||||
public static List<String> containerTags() {
|
||||
return Arrays.asList(
|
||||
"a",
|
||||
"abbr",
|
||||
"address",
|
||||
"article",
|
||||
"aside",
|
||||
"audio",
|
||||
"b",
|
||||
"bdi",
|
||||
"bdo",
|
||||
"blockquote",
|
||||
"body",
|
||||
"button",
|
||||
"canvas",
|
||||
"caption",
|
||||
"cite",
|
||||
"code",
|
||||
"colgroup",
|
||||
"data",
|
||||
"datalist",
|
||||
"dd",
|
||||
"del",
|
||||
"details",
|
||||
"dfn",
|
||||
"dialog",
|
||||
"div",
|
||||
"dl",
|
||||
"dt",
|
||||
"em",
|
||||
"fieldset",
|
||||
"figcaption",
|
||||
"figure",
|
||||
"footer",
|
||||
"form",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"head",
|
||||
"header",
|
||||
"html",
|
||||
"i",
|
||||
"iframe",
|
||||
"ins",
|
||||
"kbd",
|
||||
"label",
|
||||
"legend",
|
||||
"li",
|
||||
"main",
|
||||
"map",
|
||||
"mark",
|
||||
"menu",
|
||||
"menuitem",
|
||||
"meter",
|
||||
"nav",
|
||||
"noscript",
|
||||
"object",
|
||||
"ol",
|
||||
"optgroup",
|
||||
"option",
|
||||
"output",
|
||||
"p",
|
||||
"picture",
|
||||
"pre",
|
||||
"progress",
|
||||
"q",
|
||||
"rp",
|
||||
"rt",
|
||||
"ruby",
|
||||
"s",
|
||||
"samp",
|
||||
"script",
|
||||
"section",
|
||||
"select",
|
||||
"slot",
|
||||
"small",
|
||||
"span",
|
||||
"strong",
|
||||
"style",
|
||||
"sub",
|
||||
"summary",
|
||||
"sup",
|
||||
"table",
|
||||
"tbody",
|
||||
"td",
|
||||
"template",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
"thead",
|
||||
"time",
|
||||
"title",
|
||||
"tr",
|
||||
"u",
|
||||
"ul",
|
||||
"var",
|
||||
"video"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.xbib.j2html.codegen.model;
|
||||
|
||||
public final class AttrD {
|
||||
|
||||
public final String attr;
|
||||
|
||||
public final boolean hasArgument;
|
||||
|
||||
public final String[] tags;
|
||||
|
||||
public AttrD(final String attr, boolean hasArgument) {
|
||||
this.attr = attr;
|
||||
this.hasArgument = hasArgument;
|
||||
this.tags = new String[]{};
|
||||
}
|
||||
|
||||
public AttrD(final String attr, boolean hasArgument, final String... tags) {
|
||||
this.attr = attr;
|
||||
this.hasArgument = hasArgument;
|
||||
this.tags = tags;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package org.xbib.j2html.codegen.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class AttributesList {
|
||||
|
||||
public static List<String> getCustomAttributesForHtmlTag(final String tagLowercase) {
|
||||
final List<String> attrs = new ArrayList<>();
|
||||
for (AttrD attrD : attributesDescriptive()) {
|
||||
if (
|
||||
Arrays.asList(attrD.tags).contains(tagLowercase)
|
||||
) {
|
||||
attrs.add(attrD.attr);
|
||||
}
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
public static List<AttrD> attributesDescriptive() {
|
||||
return Arrays.asList(
|
||||
new AttrD("accept", true, "input"),
|
||||
new AttrD("action", true, "form"),
|
||||
new AttrD("alt", true, "area", "img", "input"),
|
||||
new AttrD("async", false, "script"),
|
||||
new AttrD("autocomplete", false, "form", "input"),
|
||||
new AttrD("autofocus", false, "button", "input", "select", "textarea"),
|
||||
new AttrD("autoplay", false, "audio", "video"),
|
||||
new AttrD("charset", true, "meta", "script"),
|
||||
new AttrD("checked", false, "input"),
|
||||
new AttrD("cite", true, "blockquote", "del", "ins", "q"),
|
||||
new AttrD("cols", true, "textarea"),
|
||||
new AttrD("colspan", true, "td", "th"),
|
||||
new AttrD("content", true, "meta"),
|
||||
new AttrD("controls", false, "audio", "video"),
|
||||
new AttrD("coords", true, "area"),
|
||||
new AttrD("data", true, "object"),
|
||||
new AttrD("datetime", true, "del", "ins", "time"),
|
||||
new AttrD("default", false, "track"),
|
||||
new AttrD("defer", false, "script"),
|
||||
new AttrD("dirname", true, "input", "textarea"),
|
||||
new AttrD("disabled", false, "button", "fieldset", "input", "optgroup", "option", "select", "textarea"),
|
||||
new AttrD("download", false, "a", "area"),
|
||||
new AttrD("enctype", true, "form"),
|
||||
new AttrD("for", true, "label", "output"),
|
||||
new AttrD("form", true, "button", "fieldset", "input", "label", "meter", "object", "output", "select", "textarea"),
|
||||
new AttrD("formaction", true, "button", "input"),
|
||||
new AttrD("headers", true, "td", "th"),
|
||||
new AttrD("height", true, "canvas", "embed", "iframe", "img", "input", "object", "video"),
|
||||
new AttrD("high", true, "meter"),
|
||||
new AttrD("href", true, "a", "area", "base", "link"),
|
||||
new AttrD("hreflang", true, "a", "area", "link"),
|
||||
new AttrD("ismap", false, "img"),
|
||||
new AttrD("kind", true, "track"),
|
||||
new AttrD("label", true, "track", "option", "optgroup"),
|
||||
new AttrD("list", true, "input"),
|
||||
new AttrD("loop", false, "audio", "video"),
|
||||
new AttrD("low", true, "meter"),
|
||||
new AttrD("max", true, "input", "meter", "progress"),
|
||||
new AttrD("maxlength", true, "input", "textarea"),
|
||||
new AttrD("media", true, "a", "area", "link", "source", "style"),
|
||||
new AttrD("method", true, "form"),
|
||||
new AttrD("min", true, "input", "meter"),
|
||||
new AttrD("multiple", false, "input", "select"),
|
||||
new AttrD("muted", false, "video", "audio"),
|
||||
new AttrD("name", true, "button", "fieldset", "form", "iframe", "input", "map", "meta", "object", "output", "param", "select", "slot", "textarea"),
|
||||
new AttrD("novalidate", false, "form"),
|
||||
new AttrD("onabort", true, "audio", "embed", "img", "object", "video"),
|
||||
new AttrD("onafterprint", true, "body"),
|
||||
new AttrD("onbeforeprint", true, "body"),
|
||||
new AttrD("onbeforeunload", true, "body"),
|
||||
new AttrD("oncanplay", true, "audio", "embed", "object", "video"),
|
||||
new AttrD("oncanplaythrough", true, "audio", "video"),
|
||||
new AttrD("oncuechange", true, "track"),
|
||||
new AttrD("ondurationchange", true, "audio", "video"),
|
||||
new AttrD("onemptied", true, "audio", "video"),
|
||||
new AttrD("onended", true, "audio", "video"),
|
||||
new AttrD("onerror", true, "audio", "body", "embed", "img", "object", "script", "style", "video"),
|
||||
new AttrD("onhashchange", true, "body"),
|
||||
new AttrD("onload", true, "body", "iframe", "img", "input", "link", "script", "style"),
|
||||
new AttrD("onloadeddata", true, "audio", "video"),
|
||||
new AttrD("onloadedmetadata", true, "audio", "video"),
|
||||
new AttrD("onloadstart", true, "audio", "video"),
|
||||
new AttrD("onoffline", true, "body"),
|
||||
new AttrD("ononline", true, "body"),
|
||||
new AttrD("onpagehide", true, "body"),
|
||||
new AttrD("onpageshow", true, "body"),
|
||||
new AttrD("onpause", true, "audio", "video"),
|
||||
new AttrD("onplay", true, "audio", "video"),
|
||||
new AttrD("onplaying", true, "audio", "video"),
|
||||
new AttrD("onpopstate", true, "body"),
|
||||
new AttrD("onprogress", true, "audio", "video"),
|
||||
new AttrD("onratechange", true, "audio", "video"),
|
||||
new AttrD("onreset", true, "form"),
|
||||
new AttrD("onresize", true, "body"),
|
||||
new AttrD("onsearch", true, "input"),
|
||||
new AttrD("onseeked", true, "audio", "video"),
|
||||
new AttrD("onseeking", true, "audio", "video"),
|
||||
new AttrD("onstalled", true, "audio", "video"),
|
||||
new AttrD("onstorage", true, "body"),
|
||||
new AttrD("onsubmit", true, "form"),
|
||||
new AttrD("onsuspend", true, "audio", "video"),
|
||||
new AttrD("ontimeupdate", true, "audio", "video"),
|
||||
new AttrD("ontoggle", true, "details"),
|
||||
new AttrD("onunload", true, "body"),
|
||||
new AttrD("onvolumechanged", true, "audio", "video"),
|
||||
new AttrD("onwaiting", true, "audio", "video"),
|
||||
new AttrD("open", false, "details"),
|
||||
new AttrD("optimum", true, "meter"),
|
||||
new AttrD("pattern", true, "input"),
|
||||
new AttrD("placeholder", true, "input", "textarea"),
|
||||
new AttrD("poster", true, "video"),
|
||||
new AttrD("preload", true, "audio", "video"),
|
||||
new AttrD("readonly", false, "input", "textarea"),
|
||||
new AttrD("rel", true, "a", "area", "form", "link"),
|
||||
new AttrD("required", false, "input", "select", "textarea"),
|
||||
new AttrD("reversed", false, "ol"),
|
||||
new AttrD("rows", true, "textarea"),
|
||||
new AttrD("rowspan", true, "td", "th"),
|
||||
new AttrD("sandbox", false, "iframe"),
|
||||
new AttrD("scope", true, "th"),
|
||||
new AttrD("selected", false, "option"),
|
||||
new AttrD("shape", true, "area"),
|
||||
new AttrD("size", true, "input", "select"),
|
||||
new AttrD("sizes", true, "img", "link", "source"),
|
||||
new AttrD("span", true, "col", "colgroup"),
|
||||
new AttrD("src", true, "audio", "embed", "iframe", "img", "input", "script", "source", "track", "video"),
|
||||
new AttrD("srcdoc", true, "iframe"),
|
||||
new AttrD("srclang", true, "track"),
|
||||
new AttrD("srcset", true, "img", "source"),
|
||||
new AttrD("start", true, "ol"),
|
||||
new AttrD("step", true, "input"),
|
||||
new AttrD("target", true, "a", "area", "base", "form"),
|
||||
new AttrD("type", true, "a", "button", "embed", "input", "link", "menu", "object", "script", "source", "style"),
|
||||
new AttrD("usemap", true, "img", "object"),
|
||||
new AttrD("value", true, "button", "data", "input", "li", "option", "meter", "progress", "param"),
|
||||
new AttrD("width", true, "canvas", "embed", "iframe", "img", "input", "object", "video"),
|
||||
new AttrD("wrap", true, "textarea")
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import org.xbib.j2html.codegen.wattsi.WattsiSource;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.j2html.codegen.generators.TagCreatorCodeGenerator;
|
||||
import org.xbib.j2html.codegen.wattsi.ElementDefinition;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class CodeGeneratorComplianceTests {
|
||||
|
||||
private static WattsiSource specification;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws IOException {
|
||||
Path source = Paths.get("src","test","resources","2022-01.wattsi");
|
||||
Document doc = Jsoup.parse(source.toFile(), "UTF-8", "https://html.spec.whatwg.org/");
|
||||
specification = new WattsiSource(doc);
|
||||
}
|
||||
|
||||
private Set<String> generatedElements(){
|
||||
Set<String> elements = new HashSet<>();
|
||||
elements.addAll(TagCreatorCodeGenerator.emptyTags());
|
||||
elements.addAll(TagCreatorCodeGenerator.containerTags());
|
||||
return elements;
|
||||
}
|
||||
|
||||
private Set<String> specifiedElements(WattsiSource source){
|
||||
Set<String> elements = new HashSet<>();
|
||||
for(ElementDefinition element : source.elementDefinitions()){
|
||||
elements.add(element.name());
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
// TODO restore this test once a policy has been determined for obsolete elements.
|
||||
public void all_wattsi_elements_are_defined_in_the_code_generator() {
|
||||
Set<String> generated = generatedElements();
|
||||
List<String> undefined = specification.elementDefinitions().stream()
|
||||
.filter(element -> !element.isObsolete())
|
||||
.filter(element -> !generated.contains(element.name()))
|
||||
.map(ElementDefinition::name)
|
||||
.collect(toList());
|
||||
assertEquals(emptyList(), undefined);
|
||||
// Currently missing (and mostly deprecated):
|
||||
// hgroup
|
||||
}
|
||||
|
||||
@Test
|
||||
public void only_wattsi_elements_are_defined_in_the_code_generator(){
|
||||
Set<String> specified = specifiedElements(specification);
|
||||
List<String> invalid = generatedElements().stream()
|
||||
.filter(element -> !specified.contains(element))
|
||||
.collect(toList());
|
||||
assertEquals(emptyList(), invalid);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class GenerateTest {
|
||||
|
||||
@Test
|
||||
public void generate() throws IOException {
|
||||
try (InputStream inputStream = getClass().getResourceAsStream("/html.model")) {
|
||||
String definitions = new String(inputStream.readAllBytes());
|
||||
Model model = new Model();
|
||||
Parser.parse(definitions, model);
|
||||
Path dir = Paths.get("build/generated/sources/j2html");
|
||||
Files.createDirectories(dir);
|
||||
Generator.generate(dir, "j2html.tags.attributes", "j2html.tags.specialized", model);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package org.xbib.j2html.codegen;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import org.mockito.Mockito;
|
||||
import org.xbib.j2html.codegen.Parser;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ParserTest {
|
||||
|
||||
private void verifyParsing(String txt, Consumer<Parser.Listener> checks) {
|
||||
Parser.Listener listener = mock(Parser.Listener.class);
|
||||
Parser.parse(txt, listener);
|
||||
checks.accept(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void an_empty_input_has_no_events() {
|
||||
verifyParsing("", Mockito::verifyNoInteractions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whitespace_has_no_events() {
|
||||
verifyParsing(" \t\t\t\t", Mockito::verifyNoInteractions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commented_lines_are_signaled() {
|
||||
verifyParsing("#Comment 1.\n# Comment B?", listener -> {
|
||||
InOrder order = inOrder(listener);
|
||||
order.verify(listener).lineCommented(1, "#Comment 1.");
|
||||
order.verify(listener).lineCommented(2, "# Comment B?");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void node_definitions_are_signaled() {
|
||||
verifyParsing("ELEMENT[a]\nEMPTY-ELEMENT[b]\nBOOLEAN[c]\nONOFF[d]\nSTRING[e]", listener -> {
|
||||
InOrder order = inOrder(listener);
|
||||
order.verify(listener).elementDefined(1, "a");
|
||||
order.verify(listener).emptyElementDefined(2, "b");
|
||||
order.verify(listener).booleanDefined(3, "c");
|
||||
order.verify(listener).onOffDefined(4, "d");
|
||||
order.verify(listener).stringDefined(5, "e");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attribute_definitions_are_signaled() {
|
||||
verifyParsing("ATTRIBUTE[a:b]", listener -> {
|
||||
InOrder order = inOrder(listener);
|
||||
order.verify(listener).attributeDefined(1, "a", "b");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalid_lines_are_signaled() {
|
||||
verifyParsing("lol, I dunno!\nIt Broke...", listener -> {
|
||||
InOrder order = inOrder(listener);
|
||||
order.verify(listener).invalidLine(1, "lol, I dunno!");
|
||||
order.verify(listener).invalidLine(2, "It Broke...");
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.xbib.j2html.codegen.wattsi;
|
||||
|
||||
public interface AttributeDefinition {
|
||||
|
||||
String name();
|
||||
|
||||
boolean appliesTo(ElementDefinition element);
|
||||
|
||||
boolean isObsolete();
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.xbib.j2html.codegen.wattsi;
|
||||
|
||||
public interface ElementDefinition {
|
||||
|
||||
String name();
|
||||
|
||||
boolean isSelfClosing();
|
||||
|
||||
boolean isObsolete();
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.xbib.j2html.codegen.wattsi;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
public class WattsiGenerator {
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
Path source = Paths.get(args[0]);
|
||||
Document doc = Jsoup.parse(source.toFile(), "UTF-8", "https://html.spec.whatwg.org/");
|
||||
WattsiSource wattsi = new WattsiSource(doc);
|
||||
List<ElementDefinition> elements = wattsi.elementDefinitions();
|
||||
List<AttributeDefinition> attributes = wattsi.attributeDefinitions();
|
||||
for (ElementDefinition element : elements) {
|
||||
ClassName className = ClassName.get(
|
||||
"com.j2html",
|
||||
capitalize(element.name()) + "Tag"
|
||||
);
|
||||
TypeSpec.Builder type = TypeSpec.classBuilder(className)
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
if (element.isObsolete()) {
|
||||
type.addAnnotation(Deprecated.class);
|
||||
}
|
||||
|
||||
for (AttributeDefinition attribute : attributes) {
|
||||
if (attribute.appliesTo(element)) {
|
||||
String name = methodName("with", attribute.name().split("-"));
|
||||
MethodSpec.Builder setter = MethodSpec.methodBuilder(name)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.returns(className)
|
||||
.addStatement("return this");
|
||||
|
||||
if (attribute.isObsolete()) {
|
||||
setter.addAnnotation(Deprecated.class);
|
||||
}
|
||||
|
||||
type.addMethod(setter.build());
|
||||
}
|
||||
}
|
||||
System.out.println(type.build());
|
||||
}
|
||||
}
|
||||
|
||||
private static String methodName(String prefix, String... words) {
|
||||
String[] tmp = new String[words.length + 1];
|
||||
tmp[0] = prefix;
|
||||
System.arraycopy(words, 0, tmp, 1, words.length);
|
||||
return methodName(tmp);
|
||||
}
|
||||
|
||||
private static String methodName(String... words) {
|
||||
String[] camelCase = new String[words.length];
|
||||
camelCase[0] = words[0];
|
||||
for (int i = 1; i < words.length; i++) {
|
||||
camelCase[i] = capitalize(words[i]);
|
||||
}
|
||||
return String.join("", camelCase);
|
||||
}
|
||||
|
||||
private static String capitalize(String word) {
|
||||
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package org.xbib.j2html.codegen.wattsi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.Node;
|
||||
import org.jsoup.nodes.TextNode;
|
||||
import org.jsoup.select.Elements;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class WattsiSource {
|
||||
|
||||
private final Document doc;
|
||||
|
||||
private final Set<Reference> obsolete = new HashSet<>();
|
||||
|
||||
public WattsiSource(Document doc) {
|
||||
this.doc = doc;
|
||||
// Find where obsolete elements are defined or referenced.
|
||||
Elements obsoleteElements = doc.select("p:contains(Elements in the following list are entirely obsolete) + dl");
|
||||
// Convert definitions into references to record obsolete elements.
|
||||
obsoleteElements.select("dt > dfn[element]")
|
||||
.stream()
|
||||
.map(WattsiElement::new)
|
||||
.map(WattsiElement::reference)
|
||||
.forEach(obsolete::add);
|
||||
// Extract references to record obsolete elements.
|
||||
obsoleteElements.select("dt > code")
|
||||
.stream()
|
||||
.map(Element::childNodes)
|
||||
.map(Reference::from)
|
||||
.forEach(obsolete::add);
|
||||
Elements obsoleteAttributes = doc.select("p:contains(The following attributes are obsolete) + dl");
|
||||
obsoleteAttributes.select("dt > dfn[element-attr]").stream()
|
||||
.map(WattsiAttribute::new)
|
||||
.map(WattsiAttribute::reference)
|
||||
.forEach(obsolete::add);
|
||||
}
|
||||
|
||||
public List<ElementDefinition> elementDefinitions() {
|
||||
return doc.select("dfn[element]").stream()
|
||||
.map(WattsiElement::new)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public List<AttributeDefinition> attributeDefinitions() {
|
||||
return doc.select("dfn[element-attr]").stream()
|
||||
.map(WattsiAttribute::new)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public class WattsiElement implements ElementDefinition {
|
||||
private final Element dfn;
|
||||
|
||||
WattsiElement(Element dfn) {
|
||||
if (!"dfn".equals(dfn.tagName())) {
|
||||
throw new IllegalArgumentException("Element cannot be defined from: " + dfn);
|
||||
}
|
||||
if (!dfn.hasAttr("element")) {
|
||||
throw new IllegalArgumentException("Does not define an element: " + dfn);
|
||||
}
|
||||
if (dfn.childrenSize() != 1) {
|
||||
throw new IllegalArgumentException("Element cannot have multiple definitions: " + dfn);
|
||||
}
|
||||
this.dfn = dfn;
|
||||
}
|
||||
|
||||
private Reference reference() {
|
||||
return Reference.from(dfn.childNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
if (dfn.hasAttr("data-x")) {
|
||||
return dfn.attr("data-x");
|
||||
}
|
||||
return Reference.from(dfn.childNodes()).key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelfClosing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObsolete() {
|
||||
return obsolete.contains(reference());
|
||||
}
|
||||
}
|
||||
|
||||
public class WattsiAttribute implements AttributeDefinition {
|
||||
private final Element dfn;
|
||||
|
||||
WattsiAttribute(Element dfn) {
|
||||
if (!"dfn".equals(dfn.tagName())) {
|
||||
throw new IllegalArgumentException("Attribute cannot be defined from: " + dfn);
|
||||
}
|
||||
if (!dfn.hasAttr("element-attr")) {
|
||||
throw new IllegalArgumentException("Does not define an attribute: " + dfn);
|
||||
}
|
||||
if (dfn.childrenSize() != 1) {
|
||||
throw new IllegalArgumentException("Attribute cannot have multiple definitions: " + dfn);
|
||||
}
|
||||
|
||||
this.dfn = dfn;
|
||||
}
|
||||
|
||||
private Reference reference() {
|
||||
return Reference.from(dfn.childNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return reference().text;
|
||||
}
|
||||
|
||||
private List<String> targets() {
|
||||
if (dfn.hasAttr("for")) {
|
||||
return Arrays.asList(dfn.attr("for").trim().split(","));
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(ElementDefinition element) {
|
||||
return targets().contains(element.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObsolete() {
|
||||
return obsolete.contains(reference());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Reference {
|
||||
private final String key;
|
||||
private final String text;
|
||||
|
||||
Reference(String key, String text) {
|
||||
this.key = key;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + "[" + text + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Reference reference = (Reference) o;
|
||||
return key.equals(reference.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key);
|
||||
}
|
||||
|
||||
public static Reference from(List<Node> nodes) {
|
||||
if (nodes.stream().allMatch(n -> n instanceof TextNode)) {
|
||||
String txt = nodes.stream()
|
||||
.map(n -> (TextNode) n)
|
||||
.map(TextNode::text)
|
||||
.collect(Collectors.joining(" "));
|
||||
return new Reference(txt, txt);
|
||||
}
|
||||
for (Node node : nodes) {
|
||||
if (node instanceof Element element) {
|
||||
if (element.is("code") || element.is("span")) {
|
||||
if (element.hasAttr("data-x")) {
|
||||
return new Reference(element.attr("data-x").toLowerCase(), element.text());
|
||||
} else {
|
||||
return new Reference(element.text().toLowerCase(), element.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
128553
j2html-codegen/src/test/resources/2022-01.wattsi
Normal file
128553
j2html-codegen/src/test/resources/2022-01.wattsi
Normal file
File diff suppressed because it is too large
Load diff
622
j2html-codegen/src/test/resources/html.model
Normal file
622
j2html-codegen/src/test/resources/html.model
Normal file
|
@ -0,0 +1,622 @@
|
|||
EMPTY-ELEMENT[area]
|
||||
EMPTY-ELEMENT[base]
|
||||
EMPTY-ELEMENT[br]
|
||||
EMPTY-ELEMENT[col]
|
||||
EMPTY-ELEMENT[embed]
|
||||
EMPTY-ELEMENT[hr]
|
||||
EMPTY-ELEMENT[img]
|
||||
EMPTY-ELEMENT[input]
|
||||
EMPTY-ELEMENT[keygen]
|
||||
EMPTY-ELEMENT[link]
|
||||
EMPTY-ELEMENT[meta]
|
||||
EMPTY-ELEMENT[param]
|
||||
EMPTY-ELEMENT[source]
|
||||
EMPTY-ELEMENT[track]
|
||||
EMPTY-ELEMENT[wbr]
|
||||
|
||||
ELEMENT[a]
|
||||
ELEMENT[abbr]
|
||||
ELEMENT[address]
|
||||
ELEMENT[article]
|
||||
ELEMENT[aside]
|
||||
ELEMENT[audio]
|
||||
ELEMENT[b]
|
||||
ELEMENT[bdi]
|
||||
ELEMENT[bdo]
|
||||
ELEMENT[blockquote]
|
||||
ELEMENT[body]
|
||||
ELEMENT[button]
|
||||
ELEMENT[canvas]
|
||||
ELEMENT[caption]
|
||||
ELEMENT[cite]
|
||||
ELEMENT[code]
|
||||
ELEMENT[colgroup]
|
||||
ELEMENT[data]
|
||||
ELEMENT[datalist]
|
||||
ELEMENT[dd]
|
||||
ELEMENT[del]
|
||||
ELEMENT[details]
|
||||
ELEMENT[dfn]
|
||||
ELEMENT[dialog]
|
||||
ELEMENT[div]
|
||||
ELEMENT[dl]
|
||||
ELEMENT[dt]
|
||||
ELEMENT[em]
|
||||
ELEMENT[fieldset]
|
||||
ELEMENT[figcaption]
|
||||
ELEMENT[figure]
|
||||
ELEMENT[footer]
|
||||
ELEMENT[form]
|
||||
ELEMENT[h1]
|
||||
ELEMENT[h2]
|
||||
ELEMENT[h3]
|
||||
ELEMENT[h4]
|
||||
ELEMENT[h5]
|
||||
ELEMENT[h6]
|
||||
ELEMENT[head]
|
||||
ELEMENT[header]
|
||||
ELEMENT[html]
|
||||
ELEMENT[i]
|
||||
ELEMENT[iframe]
|
||||
ELEMENT[ins]
|
||||
ELEMENT[kbd]
|
||||
ELEMENT[label]
|
||||
ELEMENT[legend]
|
||||
ELEMENT[li]
|
||||
ELEMENT[main]
|
||||
ELEMENT[map]
|
||||
ELEMENT[mark]
|
||||
ELEMENT[menu]
|
||||
ELEMENT[menuitem]
|
||||
ELEMENT[meter]
|
||||
ELEMENT[nav]
|
||||
ELEMENT[noscript]
|
||||
ELEMENT[object]
|
||||
ELEMENT[ol]
|
||||
ELEMENT[optgroup]
|
||||
ELEMENT[option]
|
||||
ELEMENT[output]
|
||||
ELEMENT[p]
|
||||
ELEMENT[picture]
|
||||
ELEMENT[pre]
|
||||
ELEMENT[progress]
|
||||
ELEMENT[q]
|
||||
ELEMENT[rp]
|
||||
ELEMENT[rt]
|
||||
ELEMENT[ruby]
|
||||
ELEMENT[s]
|
||||
ELEMENT[samp]
|
||||
ELEMENT[script]
|
||||
ELEMENT[section]
|
||||
ELEMENT[select]
|
||||
ELEMENT[slot]
|
||||
ELEMENT[small]
|
||||
ELEMENT[span]
|
||||
ELEMENT[strong]
|
||||
ELEMENT[style]
|
||||
ELEMENT[sub]
|
||||
ELEMENT[summary]
|
||||
ELEMENT[sup]
|
||||
ELEMENT[table]
|
||||
ELEMENT[tbody]
|
||||
ELEMENT[td]
|
||||
ELEMENT[template]
|
||||
ELEMENT[textarea]
|
||||
ELEMENT[tfoot]
|
||||
ELEMENT[th]
|
||||
ELEMENT[thead]
|
||||
ELEMENT[time]
|
||||
ELEMENT[title]
|
||||
ELEMENT[tr]
|
||||
ELEMENT[u]
|
||||
ELEMENT[ul]
|
||||
ELEMENT[var]
|
||||
ELEMENT[video]
|
||||
|
||||
STRING[accept]
|
||||
ATTRIBUTE[input:accept]
|
||||
|
||||
STRING[action]
|
||||
ATTRIBUTE[form:action]
|
||||
|
||||
STRING[alt]
|
||||
ATTRIBUTE[area:alt]
|
||||
ATTRIBUTE[img:alt]
|
||||
ATTRIBUTE[input:alt]
|
||||
|
||||
BOOLEAN[async]
|
||||
ATTRIBUTE[script:async]
|
||||
|
||||
ONOFF[autocomplete]
|
||||
ATTRIBUTE[form:autocomplete]
|
||||
ATTRIBUTE[input:autocomplete]
|
||||
|
||||
BOOLEAN[autofocus]
|
||||
ATTRIBUTE[button:autofocus]
|
||||
ATTRIBUTE[input:autofocus]
|
||||
ATTRIBUTE[select:autofocus]
|
||||
ATTRIBUTE[textarea:autofocus]
|
||||
|
||||
BOOLEAN[autoplay]
|
||||
ATTRIBUTE[audio:autoplay]
|
||||
ATTRIBUTE[video:autoplay]
|
||||
|
||||
STRING[charset]
|
||||
ATTRIBUTE[meta:charset]
|
||||
ATTRIBUTE[script:charset]
|
||||
|
||||
BOOLEAN[checked]
|
||||
ATTRIBUTE[input:checked]
|
||||
|
||||
STRING[cite]
|
||||
ATTRIBUTE[blockquote:cite]
|
||||
ATTRIBUTE[del:cite]
|
||||
ATTRIBUTE[ins:cite]
|
||||
ATTRIBUTE[q:cite]
|
||||
|
||||
STRING[cols]
|
||||
ATTRIBUTE[textarea:cols]
|
||||
|
||||
STRING[colspan]
|
||||
ATTRIBUTE[td:colspan]
|
||||
ATTRIBUTE[th:colspan]
|
||||
|
||||
STRING[content]
|
||||
ATTRIBUTE[meta:content]
|
||||
|
||||
BOOLEAN[controls]
|
||||
ATTRIBUTE[audio:controls]
|
||||
ATTRIBUTE[video:controls]
|
||||
|
||||
STRING[coords]
|
||||
ATTRIBUTE[area:coords]
|
||||
|
||||
STRING[data]
|
||||
ATTRIBUTE[object:data]
|
||||
|
||||
STRING[datetime]
|
||||
ATTRIBUTE[del:datetime]
|
||||
ATTRIBUTE[ins:datetime]
|
||||
ATTRIBUTE[time:datetime]
|
||||
|
||||
BOOLEAN[default]
|
||||
ATTRIBUTE[track:default]
|
||||
|
||||
BOOLEAN[defer]
|
||||
ATTRIBUTE[script:defer]
|
||||
|
||||
STRING[dirname]
|
||||
ATTRIBUTE[input:dirname]
|
||||
ATTRIBUTE[textarea:dirname]
|
||||
|
||||
BOOLEAN[disabled]
|
||||
ATTRIBUTE[button:disabled]
|
||||
ATTRIBUTE[fieldset:disabled]
|
||||
ATTRIBUTE[input:disabled]
|
||||
ATTRIBUTE[optgroup:disabled]
|
||||
ATTRIBUTE[option:disabled]
|
||||
ATTRIBUTE[select:disabled]
|
||||
ATTRIBUTE[textarea:disabled]
|
||||
|
||||
BOOLEAN[download]
|
||||
ATTRIBUTE[a:download]
|
||||
ATTRIBUTE[area:download]
|
||||
|
||||
STRING[enctype]
|
||||
ATTRIBUTE[form:enctype]
|
||||
|
||||
STRING[for]
|
||||
ATTRIBUTE[label:for]
|
||||
ATTRIBUTE[output:for]
|
||||
|
||||
STRING[form]
|
||||
ATTRIBUTE[button:form]
|
||||
ATTRIBUTE[fieldset:form]
|
||||
ATTRIBUTE[input:form]
|
||||
ATTRIBUTE[label:form]
|
||||
ATTRIBUTE[meter:form]
|
||||
ATTRIBUTE[object:form]
|
||||
ATTRIBUTE[output:form]
|
||||
ATTRIBUTE[select:form]
|
||||
ATTRIBUTE[textarea:form]
|
||||
|
||||
STRING[formaction]
|
||||
ATTRIBUTE[button:formaction]
|
||||
ATTRIBUTE[input:formaction]
|
||||
|
||||
STRING[headers]
|
||||
ATTRIBUTE[td:headers]
|
||||
ATTRIBUTE[th:headers]
|
||||
|
||||
STRING[height]
|
||||
ATTRIBUTE[canvas:height]
|
||||
ATTRIBUTE[embed:height]
|
||||
ATTRIBUTE[iframe:height]
|
||||
ATTRIBUTE[img:height]
|
||||
ATTRIBUTE[input:height]
|
||||
ATTRIBUTE[object:height]
|
||||
ATTRIBUTE[video:height]
|
||||
|
||||
STRING[high]
|
||||
ATTRIBUTE[meter:high]
|
||||
|
||||
STRING[href]
|
||||
ATTRIBUTE[a:href]
|
||||
ATTRIBUTE[area:href]
|
||||
ATTRIBUTE[base:href]
|
||||
ATTRIBUTE[link:href]
|
||||
|
||||
STRING[hreflang]
|
||||
ATTRIBUTE[a:hreflang]
|
||||
ATTRIBUTE[area:hreflang]
|
||||
ATTRIBUTE[link:hreflang]
|
||||
|
||||
BOOLEAN[ismap]
|
||||
ATTRIBUTE[img:ismap]
|
||||
|
||||
STRING[kind]
|
||||
ATTRIBUTE[track:kind]
|
||||
|
||||
STRING[label]
|
||||
ATTRIBUTE[track:label]
|
||||
ATTRIBUTE[option:label]
|
||||
ATTRIBUTE[optgroup:label]
|
||||
|
||||
STRING[list]
|
||||
ATTRIBUTE[input:list]
|
||||
|
||||
BOOLEAN[loop]
|
||||
ATTRIBUTE[audio:loop]
|
||||
ATTRIBUTE[video:loop]
|
||||
|
||||
STRING[low]
|
||||
ATTRIBUTE[meter:low]
|
||||
|
||||
STRING[max]
|
||||
ATTRIBUTE[input:max]
|
||||
ATTRIBUTE[meter:max]
|
||||
ATTRIBUTE[progress:max]
|
||||
|
||||
STRING[maxlength]
|
||||
ATTRIBUTE[input:maxlength]
|
||||
ATTRIBUTE[textarea:maxlength]
|
||||
|
||||
STRING[media]
|
||||
ATTRIBUTE[a:media]
|
||||
ATTRIBUTE[area:media]
|
||||
ATTRIBUTE[link:media]
|
||||
ATTRIBUTE[source:media]
|
||||
ATTRIBUTE[style:media]
|
||||
|
||||
STRING[method]
|
||||
ATTRIBUTE[form:method]
|
||||
|
||||
STRING[min]
|
||||
ATTRIBUTE[input:min]
|
||||
ATTRIBUTE[meter:min]
|
||||
|
||||
BOOLEAN[multiple]
|
||||
ATTRIBUTE[input:multiple]
|
||||
ATTRIBUTE[select:multiple]
|
||||
|
||||
BOOLEAN[muted]
|
||||
ATTRIBUTE[video:muted]
|
||||
ATTRIBUTE[audio:muted]
|
||||
|
||||
STRING[name]
|
||||
ATTRIBUTE[button:name]
|
||||
ATTRIBUTE[fieldset:name]
|
||||
ATTRIBUTE[form:name]
|
||||
ATTRIBUTE[iframe:name]
|
||||
ATTRIBUTE[input:name]
|
||||
ATTRIBUTE[map:name]
|
||||
ATTRIBUTE[meta:name]
|
||||
ATTRIBUTE[object:name]
|
||||
ATTRIBUTE[output:name]
|
||||
ATTRIBUTE[param:name]
|
||||
ATTRIBUTE[select:name]
|
||||
ATTRIBUTE[slot:name]
|
||||
ATTRIBUTE[textarea:name]
|
||||
|
||||
BOOLEAN[novalidate]
|
||||
ATTRIBUTE[form:novalidate]
|
||||
|
||||
STRING[onabort]
|
||||
ATTRIBUTE[audio:onabort]
|
||||
ATTRIBUTE[embed:onabort]
|
||||
ATTRIBUTE[img:onabort]
|
||||
ATTRIBUTE[object:onabort]
|
||||
ATTRIBUTE[video:onabort]
|
||||
|
||||
STRING[onafterprint]
|
||||
ATTRIBUTE[body:onafterprint]
|
||||
|
||||
STRING[onbeforeprint]
|
||||
ATTRIBUTE[body:onbeforeprint]
|
||||
|
||||
STRING[onbeforeunload]
|
||||
ATTRIBUTE[body:onbeforeunload]
|
||||
|
||||
STRING[oncanplay]
|
||||
ATTRIBUTE[audio:oncanplay]
|
||||
ATTRIBUTE[embed:oncanplay]
|
||||
ATTRIBUTE[object:oncanplay]
|
||||
ATTRIBUTE[video:oncanplay]
|
||||
|
||||
STRING[oncanplaythrough]
|
||||
ATTRIBUTE[audio:oncanplaythrough]
|
||||
ATTRIBUTE[video:oncanplaythrough]
|
||||
|
||||
STRING[oncuechange]
|
||||
ATTRIBUTE[track:oncuechange]
|
||||
|
||||
STRING[ondurationchange]
|
||||
ATTRIBUTE[audio:ondurationchange]
|
||||
ATTRIBUTE[video:ondurationchange]
|
||||
|
||||
STRING[onemptied]
|
||||
ATTRIBUTE[audio:onemptied]
|
||||
ATTRIBUTE[video:onemptied]
|
||||
|
||||
STRING[onended]
|
||||
ATTRIBUTE[audio:onended]
|
||||
ATTRIBUTE[video:onended]
|
||||
|
||||
STRING[onerror]
|
||||
ATTRIBUTE[audio:onerror]
|
||||
ATTRIBUTE[body:onerror]
|
||||
ATTRIBUTE[embed:onerror]
|
||||
ATTRIBUTE[img:onerror]
|
||||
ATTRIBUTE[object:onerror]
|
||||
ATTRIBUTE[script:onerror]
|
||||
ATTRIBUTE[style:onerror]
|
||||
ATTRIBUTE[video:onerror]
|
||||
|
||||
STRING[onhashchange]
|
||||
ATTRIBUTE[body:onhashchange]
|
||||
|
||||
STRING[onload]
|
||||
ATTRIBUTE[body:onload]
|
||||
ATTRIBUTE[iframe:onload]
|
||||
ATTRIBUTE[img:onload]
|
||||
ATTRIBUTE[input:onload]
|
||||
ATTRIBUTE[link:onload]
|
||||
ATTRIBUTE[script:onload]
|
||||
ATTRIBUTE[style:onload]
|
||||
|
||||
STRING[onloadeddata]
|
||||
ATTRIBUTE[audio:onloadeddata]
|
||||
ATTRIBUTE[video:onloadeddata]
|
||||
|
||||
STRING[onloadedmetadata]
|
||||
ATTRIBUTE[audio:onloadedmetadata]
|
||||
ATTRIBUTE[video:onloadedmetadata]
|
||||
|
||||
STRING[onloadstart]
|
||||
ATTRIBUTE[audio:onloadstart]
|
||||
ATTRIBUTE[video:onloadstart]
|
||||
|
||||
STRING[onoffline]
|
||||
ATTRIBUTE[body:onoffline]
|
||||
|
||||
STRING[ononline]
|
||||
ATTRIBUTE[body:ononline]
|
||||
|
||||
STRING[onpagehide]
|
||||
ATTRIBUTE[body:onpagehide]
|
||||
|
||||
STRING[onpageshow]
|
||||
ATTRIBUTE[body:onpageshow]
|
||||
|
||||
STRING[onpause]
|
||||
ATTRIBUTE[audio:onpause]
|
||||
ATTRIBUTE[video:onpause]
|
||||
|
||||
STRING[onplay]
|
||||
ATTRIBUTE[audio:onplay]
|
||||
ATTRIBUTE[video:onplay]
|
||||
|
||||
STRING[onplaying]
|
||||
ATTRIBUTE[audio:onplaying]
|
||||
ATTRIBUTE[video:onplaying]
|
||||
|
||||
STRING[onpopstate]
|
||||
ATTRIBUTE[body:onpopstate]
|
||||
|
||||
STRING[onprogress]
|
||||
ATTRIBUTE[audio:onprogress]
|
||||
ATTRIBUTE[video:onprogress]
|
||||
|
||||
STRING[onratechange]
|
||||
ATTRIBUTE[audio:onratechange]
|
||||
ATTRIBUTE[video:onratechange]
|
||||
|
||||
STRING[onreset]
|
||||
ATTRIBUTE[form:onreset]
|
||||
|
||||
STRING[onresize]
|
||||
ATTRIBUTE[body:onresize]
|
||||
|
||||
STRING[onsearch]
|
||||
ATTRIBUTE[input:onsearch]
|
||||
|
||||
STRING[onseeked]
|
||||
ATTRIBUTE[audio:onseeked]
|
||||
ATTRIBUTE[video:onseeked]
|
||||
|
||||
STRING[onseeking]
|
||||
ATTRIBUTE[audio:onseeking]
|
||||
ATTRIBUTE[video:onseeking]
|
||||
|
||||
STRING[onstalled]
|
||||
ATTRIBUTE[audio:onstalled]
|
||||
ATTRIBUTE[video:onstalled]
|
||||
|
||||
STRING[onstorage]
|
||||
ATTRIBUTE[body:onstorage]
|
||||
|
||||
STRING[onsubmit]
|
||||
ATTRIBUTE[form:onsubmit]
|
||||
|
||||
STRING[onsuspend]
|
||||
ATTRIBUTE[audio:onsuspend]
|
||||
ATTRIBUTE[video:onsuspend]
|
||||
|
||||
STRING[ontimeupdate]
|
||||
ATTRIBUTE[audio:ontimeupdate]
|
||||
ATTRIBUTE[video:ontimeupdate]
|
||||
|
||||
STRING[ontoggle]
|
||||
ATTRIBUTE[details:ontoggle]
|
||||
|
||||
STRING[onunload]
|
||||
ATTRIBUTE[body:onunload]
|
||||
|
||||
STRING[onvolumechanged]
|
||||
ATTRIBUTE[audio:onvolumechanged]
|
||||
ATTRIBUTE[video:onvolumechanged]
|
||||
|
||||
STRING[onwaiting]
|
||||
ATTRIBUTE[audio:onwaiting]
|
||||
ATTRIBUTE[video:onwaiting]
|
||||
|
||||
BOOLEAN[open]
|
||||
ATTRIBUTE[details:open]
|
||||
|
||||
STRING[optimum]
|
||||
ATTRIBUTE[meter:optimum]
|
||||
|
||||
STRING[pattern]
|
||||
ATTRIBUTE[input:pattern]
|
||||
|
||||
STRING[placeholder]
|
||||
ATTRIBUTE[input:placeholder]
|
||||
ATTRIBUTE[textarea:placeholder]
|
||||
|
||||
STRING[poster]
|
||||
ATTRIBUTE[video:poster]
|
||||
|
||||
STRING[preload]
|
||||
ATTRIBUTE[audio:preload]
|
||||
ATTRIBUTE[video:preload]
|
||||
|
||||
BOOLEAN[readonly]
|
||||
ATTRIBUTE[input:readonly]
|
||||
ATTRIBUTE[textarea:readonly]
|
||||
|
||||
STRING[rel]
|
||||
ATTRIBUTE[a:rel]
|
||||
ATTRIBUTE[area:rel]
|
||||
ATTRIBUTE[form:rel]
|
||||
ATTRIBUTE[link:rel]
|
||||
|
||||
BOOLEAN[required]
|
||||
ATTRIBUTE[input:required]
|
||||
ATTRIBUTE[select:required]
|
||||
ATTRIBUTE[textarea:required]
|
||||
|
||||
BOOLEAN[reversed]
|
||||
ATTRIBUTE[ol:reversed]
|
||||
|
||||
STRING[rows]
|
||||
ATTRIBUTE[textarea:rows]
|
||||
|
||||
STRING[rowspan]
|
||||
ATTRIBUTE[td:rowspan]
|
||||
ATTRIBUTE[th:rowspan]
|
||||
|
||||
BOOLEAN[sandbox]
|
||||
ATTRIBUTE[iframe:sandbox]
|
||||
|
||||
STRING[scope]
|
||||
ATTRIBUTE[th:scope]
|
||||
|
||||
BOOLEAN[selected]
|
||||
ATTRIBUTE[option:selected]
|
||||
|
||||
STRING[shape]
|
||||
ATTRIBUTE[area:shape]
|
||||
|
||||
STRING[size]
|
||||
ATTRIBUTE[input:size]
|
||||
ATTRIBUTE[select:size]
|
||||
|
||||
STRING[sizes]
|
||||
ATTRIBUTE[img:sizes]
|
||||
ATTRIBUTE[link:sizes]
|
||||
ATTRIBUTE[source:sizes]
|
||||
|
||||
STRING[span]
|
||||
ATTRIBUTE[col:span]
|
||||
ATTRIBUTE[colgroup:span]
|
||||
|
||||
STRING[src]
|
||||
ATTRIBUTE[audio:src]
|
||||
ATTRIBUTE[embed:src]
|
||||
ATTRIBUTE[iframe:src]
|
||||
ATTRIBUTE[img:src]
|
||||
ATTRIBUTE[input:src]
|
||||
ATTRIBUTE[script:src]
|
||||
ATTRIBUTE[source:src]
|
||||
ATTRIBUTE[track:src]
|
||||
ATTRIBUTE[video:src]
|
||||
|
||||
STRING[srcdoc]
|
||||
ATTRIBUTE[iframe:srcdoc]
|
||||
|
||||
STRING[srclang]
|
||||
ATTRIBUTE[track:srclang]
|
||||
|
||||
STRING[srcset]
|
||||
ATTRIBUTE[img:srcset]
|
||||
ATTRIBUTE[source:srcset]
|
||||
|
||||
STRING[start]
|
||||
ATTRIBUTE[ol:start]
|
||||
|
||||
STRING[step]
|
||||
ATTRIBUTE[input:step]
|
||||
|
||||
STRING[target]
|
||||
ATTRIBUTE[a:target]
|
||||
ATTRIBUTE[area:target]
|
||||
ATTRIBUTE[base:target]
|
||||
ATTRIBUTE[form:target]
|
||||
|
||||
STRING[type]
|
||||
ATTRIBUTE[a:type]
|
||||
ATTRIBUTE[button:type]
|
||||
ATTRIBUTE[embed:type]
|
||||
ATTRIBUTE[input:type]
|
||||
ATTRIBUTE[link:type]
|
||||
ATTRIBUTE[menu:type]
|
||||
ATTRIBUTE[object:type]
|
||||
ATTRIBUTE[script:type]
|
||||
ATTRIBUTE[source:type]
|
||||
ATTRIBUTE[style:type]
|
||||
|
||||
STRING[usemap]
|
||||
ATTRIBUTE[img:usemap]
|
||||
ATTRIBUTE[object:usemap]
|
||||
|
||||
STRING[value]
|
||||
ATTRIBUTE[button:value]
|
||||
ATTRIBUTE[data:value]
|
||||
ATTRIBUTE[input:value]
|
||||
ATTRIBUTE[li:value]
|
||||
ATTRIBUTE[option:value]
|
||||
ATTRIBUTE[meter:value]
|
||||
ATTRIBUTE[progress:value]
|
||||
ATTRIBUTE[param:value]
|
||||
|
||||
STRING[width]
|
||||
ATTRIBUTE[canvas:width]
|
||||
ATTRIBUTE[embed:width]
|
||||
ATTRIBUTE[iframe:width]
|
||||
ATTRIBUTE[img:width]
|
||||
ATTRIBUTE[input:width]
|
||||
ATTRIBUTE[object:width]
|
||||
ATTRIBUTE[video:width]
|
||||
|
||||
STRING[wrap]
|
||||
ATTRIBUTE[textarea:wrap]
|
5
j2html/build.gradle
Normal file
5
j2html/build.gradle
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
dependencies {
|
||||
testImplementation testLibs.velocity
|
||||
testImplementation testLibs.junit.benchmarks
|
||||
}
|
9
j2html/src/main/java/module-info.java
Normal file
9
j2html/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
module org.xbib.j2html {
|
||||
exports org.xbib.j2html;
|
||||
exports org.xbib.j2html.attributes;
|
||||
exports org.xbib.j2html.rendering;
|
||||
exports org.xbib.j2html.tags;
|
||||
exports org.xbib.j2html.tags.attributes;
|
||||
exports org.xbib.j2html.tags.specialized;
|
||||
exports org.xbib.j2html.utils;
|
||||
}
|
152
j2html/src/main/java/org/xbib/j2html/Config.java
Normal file
152
j2html/src/main/java/org/xbib/j2html/Config.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
package org.xbib.j2html;
|
||||
|
||||
import org.xbib.j2html.utils.CSSMin;
|
||||
import org.xbib.j2html.utils.EscapeUtil;
|
||||
import org.xbib.j2html.utils.Indenter;
|
||||
import org.xbib.j2html.utils.JSMin;
|
||||
import org.xbib.j2html.utils.Minifier;
|
||||
import org.xbib.j2html.utils.TextEscaper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class 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 <a href="https://github.com/barryvan/CSSMin">CSSMin</a>
|
||||
*/
|
||||
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 enable/disable closing empty tags
|
||||
* The default is to NOT close them
|
||||
*/
|
||||
public static boolean closeEmptyTags = false;
|
||||
|
||||
private static final String FOUR_SPACES = " ";
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private TextEscaper _textEscaper;
|
||||
private Minifier _cssMinifier;
|
||||
private Minifier _jsMinifier;
|
||||
private boolean _closeEmptyTags;
|
||||
private Indenter _indenter;
|
||||
|
||||
|
||||
private Config(
|
||||
TextEscaper _textEscaper,
|
||||
Minifier _cssMinifier,
|
||||
Minifier _jsMinifier,
|
||||
boolean _closeEmptyTags,
|
||||
Indenter _indenter
|
||||
) {
|
||||
this._textEscaper = _textEscaper;
|
||||
this._cssMinifier = _cssMinifier;
|
||||
this._jsMinifier = _jsMinifier;
|
||||
this._closeEmptyTags = _closeEmptyTags;
|
||||
this._indenter = _indenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy constructor.
|
||||
*
|
||||
* @param original The Config to copy fields from.
|
||||
*/
|
||||
private Config(Config original) {
|
||||
this._textEscaper = original._textEscaper;
|
||||
this._cssMinifier = original._cssMinifier;
|
||||
this._jsMinifier = original._jsMinifier;
|
||||
this._closeEmptyTags = original._closeEmptyTags;
|
||||
this._indenter = original._indenter;
|
||||
}
|
||||
|
||||
public TextEscaper textEscaper() {
|
||||
return _textEscaper;
|
||||
}
|
||||
|
||||
public Minifier cssMinifier() {
|
||||
return _cssMinifier;
|
||||
}
|
||||
|
||||
public Minifier jsMinifier() {
|
||||
return _jsMinifier;
|
||||
}
|
||||
|
||||
public boolean closeEmptyTags() {
|
||||
return _closeEmptyTags;
|
||||
}
|
||||
|
||||
public Indenter indenter() {
|
||||
return _indenter;
|
||||
}
|
||||
|
||||
public Config withTextEscaper(TextEscaper textEscaper){
|
||||
Config copy = new Config(this);
|
||||
copy._textEscaper = textEscaper;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Config withCssMinifier(Minifier cssMinifier){
|
||||
Config copy = new Config(this);
|
||||
copy._cssMinifier = cssMinifier;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Config withJsMinifier(Minifier jsMinifier){
|
||||
Config copy = new Config(this);
|
||||
copy._jsMinifier = jsMinifier;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Config withEmptyTagsClosed(boolean closeEmptyTags){
|
||||
Config copy = new Config(this);
|
||||
copy._closeEmptyTags = closeEmptyTags;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Config withIndenter(Indenter indenter){
|
||||
Config copy = new Config(this);
|
||||
copy._indenter = indenter;
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static final Config DEFAULTS = new Config(
|
||||
EscapeUtil::escape,
|
||||
CSSMin::compressCss,
|
||||
JSMin::compressJs,
|
||||
false,
|
||||
(level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text
|
||||
);
|
||||
|
||||
public static Config defaults() {
|
||||
return DEFAULTS;
|
||||
}
|
||||
|
||||
public static Config global() {
|
||||
return new Config(
|
||||
textEscaper,
|
||||
cssMinifier,
|
||||
jsMinifier,
|
||||
closeEmptyTags,
|
||||
indenter
|
||||
);
|
||||
}
|
||||
|
||||
}
|
1017
j2html/src/main/java/org/xbib/j2html/TagCreator.java
Normal file
1017
j2html/src/main/java/org/xbib/j2html/TagCreator.java
Normal file
File diff suppressed because it is too large
Load diff
182
j2html/src/main/java/org/xbib/j2html/attributes/Attr.java
Normal file
182
j2html/src/main/java/org/xbib/j2html/attributes/Attr.java
Normal file
|
@ -0,0 +1,182 @@
|
|||
package org.xbib.j2html.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public abstract class Attr {
|
||||
|
||||
public static final String ACCEPT = "accept";
|
||||
public static final String ACCEPT_CHARSET = "accept-charset";
|
||||
public static final String ACCESSKEY = "accesskey";
|
||||
public static final String ACTION = "action";
|
||||
public static final String ALIGN = "align";
|
||||
public static final String ALT = "alt";
|
||||
public static final String ASYNC = "async";
|
||||
public static final String AUTOCOMPLETE = "autocomplete";
|
||||
public static final String AUTOFOCUS = "autofocus";
|
||||
public static final String AUTOPLAY = "autoplay";
|
||||
public static final String AUTOSAVE = "autosave";
|
||||
public static final String BORDER = "border";
|
||||
public static final String BUFFERED = "buffered";
|
||||
public static final String CHALLENGE = "challenge";
|
||||
public static final String CHARSET = "charset";
|
||||
public static final String CHECKED = "checked";
|
||||
public static final String CITE = "cite";
|
||||
public static final String CLASS = "class";
|
||||
public static final String COLOR = "color";
|
||||
public static final String COLS = "cols";
|
||||
public static final String COLSPAN = "colspan";
|
||||
public static final String CONTENT = "content";
|
||||
public static final String CONTENTEDITABLE = "contenteditable";
|
||||
public static final String CONTEXTMENU = "contextmenu";
|
||||
public static final String CONTROLS = "controls";
|
||||
public static final String COORDS = "coords";
|
||||
public static final String DATA = "data";
|
||||
public static final String DATETIME = "datetime";
|
||||
public static final String DEFAULT = "default";
|
||||
public static final String DEFER = "defer";
|
||||
public static final String DIR = "dir";
|
||||
public static final String DIRNAME = "dirname";
|
||||
public static final String DISABLED = "disabled";
|
||||
public static final String DOWNLOAD = "download";
|
||||
public static final String DRAGGABLE = "draggable";
|
||||
public static final String DROPZONE = "dropzone";
|
||||
public static final String ENCTYPE = "enctype";
|
||||
public static final String FOR = "for";
|
||||
public static final String FORM = "form";
|
||||
public static final String FORMACTION = "formaction";
|
||||
public static final String HEADERS = "headers";
|
||||
public static final String HEIGHT = "height";
|
||||
public static final String HIDDEN = "hidden";
|
||||
public static final String HIGH = "high";
|
||||
public static final String HREF = "href";
|
||||
public static final String HREFLANG = "hreflang";
|
||||
public static final String HTTP_EQUIV = "http-equiv";
|
||||
public static final String ICON = "icon";
|
||||
public static final String ID = "id";
|
||||
public static final String IS = "is";
|
||||
public static final String ISMAP = "ismap";
|
||||
public static final String ITEMPROP = "itemprop";
|
||||
public static final String KEYTYPE = "keytype";
|
||||
public static final String KIND = "kind";
|
||||
public static final String LABEL = "label";
|
||||
public static final String LANG = "lang";
|
||||
public static final String LANGUAGE = "language";
|
||||
public static final String LIST = "list";
|
||||
public static final String LOOP = "loop";
|
||||
public static final String LOW = "low";
|
||||
public static final String MANIFEST = "manifest";
|
||||
public static final String MAX = "max";
|
||||
public static final String MAXLENGTH = "maxlength";
|
||||
public static final String MEDIA = "media";
|
||||
public static final String METHOD = "method";
|
||||
public static final String MIN = "min";
|
||||
public static final String MULTIPLE = "multiple";
|
||||
public static final String NAME = "name";
|
||||
public static final String NOVALIDATE = "novalidate";
|
||||
public static final String OPEN = "open";
|
||||
public static final String OPTIMUM = "optimum";
|
||||
public static final String PATTERN = "pattern";
|
||||
public static final String PING = "ping";
|
||||
public static final String PLACEHOLDER = "placeholder";
|
||||
public static final String POSTER = "poster";
|
||||
public static final String PRELOAD = "preload";
|
||||
public static final String PUBDATE = "pubdate";
|
||||
public static final String RADIOGROUP = "radiogroup";
|
||||
public static final String READONLY = "readonly";
|
||||
public static final String REL = "rel";
|
||||
public static final String REQUIRED = "required";
|
||||
public static final String REVERSED = "reversed";
|
||||
public static final String ROLE = "role";
|
||||
public static final String ROWS = "rows";
|
||||
public static final String ROWSPAN = "rowspan";
|
||||
public static final String SANDBOX = "sandbox";
|
||||
public static final String SCOPE = "scope";
|
||||
public static final String SCOPED = "scoped";
|
||||
public static final String SEAMLESS = "seamless";
|
||||
public static final String SELECTED = "selected";
|
||||
public static final String SHAPE = "shape";
|
||||
public static final String SIZE = "size";
|
||||
public static final String SIZES = "sizes";
|
||||
public static final String SLOT = "slot";
|
||||
public static final String SPAN = "span";
|
||||
public static final String SPELLCHECK = "spellcheck";
|
||||
public static final String SRC = "src";
|
||||
public static final String SRCDOC = "srcdoc";
|
||||
public static final String SRCLANG = "srclang";
|
||||
public static final String SRCSET = "srcset";
|
||||
public static final String START = "start";
|
||||
public static final String STEP = "step";
|
||||
public static final String STYLE = "style";
|
||||
public static final String SUMMARY = "summary";
|
||||
public static final String TABINDEX = "tabindex";
|
||||
public static final String TARGET = "target";
|
||||
public static final String TITLE = "title";
|
||||
public static final String TYPE = "type";
|
||||
public static final String USEMAP = "usemap";
|
||||
public static final String VALUE = "value";
|
||||
public static final String WIDTH = "width";
|
||||
public static final String WRAP = "wrap";
|
||||
public static final String TRANSLATE = "translate";
|
||||
|
||||
public static ShortForm shortFormFromAttrsString(String attrs) {
|
||||
if (!attrs.contains(".") && !attrs.contains(("#"))) {
|
||||
throw new IllegalArgumentException("String must contain either id (#) or class (.)");
|
||||
}
|
||||
if (attrs.split("#").length > 2) {
|
||||
throw new IllegalArgumentException("Only one id (#) allowed");
|
||||
}
|
||||
String id = "";
|
||||
StringBuilder classes = new StringBuilder();
|
||||
for (String attr : attrs.split("\\.")) {
|
||||
if (attr.contains("#")) {
|
||||
if (!attr.startsWith("#")) {
|
||||
throw new IllegalArgumentException("# cannot be in the middle of string");
|
||||
}
|
||||
id = attr.replace("#", "");
|
||||
} else {
|
||||
classes.append(attr).append(" ");
|
||||
}
|
||||
}
|
||||
return new ShortForm(id.trim(), classes.toString().trim());
|
||||
}
|
||||
|
||||
public static <T extends Tag<T>> T addTo(T tag, Attr attr) {
|
||||
if (null != attr)
|
||||
attr.addTo(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public abstract <T extends Tag<T>> T addTo(T tag);
|
||||
|
||||
public static class ShortForm extends Attr {
|
||||
String id;
|
||||
String classes;
|
||||
|
||||
private ShortForm(String id, String classes) {
|
||||
this.id = id;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
boolean hasId() {
|
||||
return id != null && !"".equals(id);
|
||||
}
|
||||
|
||||
boolean hasClasses() {
|
||||
return classes != null && !"".equals(classes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Tag<T>> T addTo(T tag) {
|
||||
if (hasId() && hasClasses()) {
|
||||
return tag.withId(id).withClass(classes);
|
||||
}
|
||||
if (hasId()) {
|
||||
return tag.withId(id);
|
||||
}
|
||||
if (hasClasses()) {
|
||||
return tag.withClass(classes);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package org.xbib.j2html.attributes;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.rendering.TagBuilder;
|
||||
import org.xbib.j2html.tags.Renderable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Attribute implements Renderable {
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
public Attribute(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Attribute(String name) {
|
||||
this.name = name;
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void renderModel(Appendable writer, Object model) throws IOException {
|
||||
if (writer instanceof TagBuilder) {
|
||||
if (name != null) {
|
||||
if (value != null) {
|
||||
((TagBuilder) writer).appendAttribute(name, value);
|
||||
} else {
|
||||
((TagBuilder) writer).appendBooleanAttribute(name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
writer.append(' ');
|
||||
writer.append(name);
|
||||
if (value != null) {
|
||||
writer.append("=\"");
|
||||
writer.append(Config.textEscaper.escape(value));
|
||||
writer.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void render(TagBuilder builder, Object model) throws IOException {
|
||||
// Maintain compatibility with classes that extend Attribute, for now...
|
||||
renderModel(builder, model);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
182
j2html/src/main/java/org/xbib/j2html/rendering/FlatHtml.java
Normal file
182
j2html/src/main/java/org/xbib/j2html/rendering/FlatHtml.java
Normal file
|
@ -0,0 +1,182 @@
|
|||
package org.xbib.j2html.rendering;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.utils.TextEscaper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Composes HTML without any extra line breaks or indentation.
|
||||
*
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
*/
|
||||
public class FlatHtml<T extends Appendable> implements HtmlBuilder<T> {
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate flat HTML using
|
||||
* Config defaults.
|
||||
*
|
||||
* @param out The Appendable to which HTML will be appended.
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
* @return An HtmlBuilder for flat HTML.
|
||||
*/
|
||||
public static <T extends Appendable> FlatHtml<T> into(T out) {
|
||||
return new FlatHtml<>(out, Config.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate flat HTML using
|
||||
* the given Config.
|
||||
*
|
||||
* @param out The Appendable to which HTML will be appended.
|
||||
* @param config The Config which will specify text escapement, tag closing, etc.
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
* @return An HtmlBuilder for flat HTML.
|
||||
*/
|
||||
public static <T extends Appendable> FlatHtml<T> into(T out, Config config) {
|
||||
return new FlatHtml<>(out, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate flat HTML in memory
|
||||
* using Config defaults.
|
||||
*
|
||||
* @return An HtmlBuilder for flat HTML.
|
||||
*/
|
||||
public static FlatHtml<StringBuilder> inMemory() {
|
||||
return into(new StringBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate flat HTML in memory
|
||||
* using the given Config.
|
||||
* @param config The Config which will specify text escapement, tag closing, etc.
|
||||
* @return An HtmlBuilder for flat HTML.
|
||||
*/
|
||||
public static FlatHtml<StringBuilder> inMemory(Config config) {
|
||||
return into(new StringBuilder(), config);
|
||||
}
|
||||
|
||||
private final T out;
|
||||
private final TextEscaper textEscaper;
|
||||
private final TagBuilder enclosingElementAttributes;
|
||||
private final TagBuilder emptyElementAttributes;
|
||||
|
||||
private FlatHtml(T out, Config config) {
|
||||
this.out = out;
|
||||
this.textEscaper = config.textEscaper();
|
||||
this.enclosingElementAttributes = new FlatTagBuilder(false);
|
||||
this.emptyElementAttributes = new FlatTagBuilder(config.closeEmptyTags());
|
||||
}
|
||||
|
||||
public T output() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(CharSequence csq) throws IOException {
|
||||
out.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(CharSequence csq, int start, int end) throws IOException {
|
||||
out.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(char c) throws IOException {
|
||||
out.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendStartTag(String name) throws IOException {
|
||||
out.append("<").append(name);
|
||||
return enclosingElementAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendEndTag(String name) throws IOException {
|
||||
out.append("</").append(name).append(">");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendEmptyTag(String name) throws IOException {
|
||||
out.append("<").append(name);
|
||||
return emptyElementAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendEscapedText(String txt) throws IOException {
|
||||
out.append(textEscaper.escape(txt));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendUnescapedText(String txt) throws IOException {
|
||||
out.append(txt);
|
||||
return this;
|
||||
}
|
||||
|
||||
private class FlatTagBuilder implements TagBuilder {
|
||||
|
||||
private final boolean closeTag;
|
||||
|
||||
private FlatTagBuilder(boolean closeTag) {
|
||||
this.closeTag = closeTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendAttribute(String name, String value) throws IOException {
|
||||
out.append(" ")
|
||||
.append(name)
|
||||
.append("=\"")
|
||||
.append(textEscaper.escape(value))
|
||||
.append("\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendBooleanAttribute(String name) throws IOException {
|
||||
out.append(" ").append(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> completeTag() throws IOException {
|
||||
if (closeTag) {
|
||||
out.append("/");
|
||||
}
|
||||
out.append(">");
|
||||
|
||||
return FlatHtml.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(CharSequence csq) throws IOException {
|
||||
out.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(CharSequence csq, int start, int end) throws IOException {
|
||||
out.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(char c) throws IOException {
|
||||
out.append(c);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package org.xbib.j2html.rendering;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implementations of HtmlBuilder are wrappers around an
|
||||
* Appendable, and support appending HTML-specific character
|
||||
* sequences to that Appendable.
|
||||
* <p>
|
||||
* Note: HtmlBuilder extends Appendable for compatibility with
|
||||
* previous version of this library. This extension will probably be
|
||||
* removed in the future, so avoid relying on the deprecated methods
|
||||
* of this interface.
|
||||
*
|
||||
* @param <T> The type of the Appendable. Used so that the
|
||||
* same type can be returned to the caller, allowing
|
||||
* for additional work to be done on the Appendable
|
||||
* without the need for manual casting.
|
||||
*/
|
||||
public interface HtmlBuilder<T extends Appendable> extends Appendable {
|
||||
|
||||
/**
|
||||
* Appends a start tag with the given name to the output. The
|
||||
* returned TagBuilder is then used to append attributes
|
||||
* and eventually complete the start tag.
|
||||
*
|
||||
* @param name The name of the start tag.
|
||||
* @return An TagBuilder which can append attributes to the start tag.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
TagBuilder appendStartTag(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends an end tag with the given name to the output.
|
||||
*
|
||||
* @param name The name of the end tag.
|
||||
* @return An HtmlBuilder that can continue appending HTML to the output.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
HtmlBuilder<T> appendEndTag(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends an empty tag with the given name to the output. The
|
||||
* returned TagBuilder is then used to append attributes
|
||||
* and eventually complete the empty tag.
|
||||
*
|
||||
* @param name The name of the empty tag.
|
||||
* @return An TagBuilder which can append attributes to the empty tag.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
TagBuilder appendEmptyTag(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends escaped text to the output.
|
||||
*
|
||||
* @param txt The text to append.
|
||||
* @return An HtmlBuilder that can continue appending HTML to the output.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
HtmlBuilder<T> appendEscapedText(String txt) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends unescaped text to the output.
|
||||
*
|
||||
* @param txt The text to append.
|
||||
* @return An HtmlBuilder that can continue appending HTML to the output.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
HtmlBuilder<T> appendUnescapedText(String txt) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the Appendable that was being wrapped.
|
||||
*
|
||||
* @return The original Appendable.
|
||||
*/
|
||||
T output();
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
HtmlBuilder<T> append(CharSequence csq) throws IOException;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
HtmlBuilder<T> append(CharSequence csq, int start, int end) throws IOException;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
HtmlBuilder<T> append(char c) throws IOException;
|
||||
}
|
246
j2html/src/main/java/org/xbib/j2html/rendering/IndentedHtml.java
Normal file
246
j2html/src/main/java/org/xbib/j2html/rendering/IndentedHtml.java
Normal file
|
@ -0,0 +1,246 @@
|
|||
package org.xbib.j2html.rendering;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.utils.Indenter;
|
||||
import org.xbib.j2html.utils.TextEscaper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* Composes HTML with lines breaks and indentation between tags and text.
|
||||
*
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
*/
|
||||
public class IndentedHtml<T extends Appendable> implements HtmlBuilder<T> {
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate indented HTML using
|
||||
* Config defaults.
|
||||
*
|
||||
* @param out The Appendable to which HTML will be appended.
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
* @return An HtmlBuilder for indented HTML.
|
||||
*/
|
||||
public static final <T extends Appendable> IndentedHtml<T> into(T out) {
|
||||
return new IndentedHtml<>(out, Config.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate indented HTML using
|
||||
* the given Config.
|
||||
*
|
||||
* @param out The Appendable to which HTML will be appended.
|
||||
* @param config The Config which will specify indentation, text escapement, tag closing, etc.
|
||||
* @param <T> The type of the Appendable to which HTML will be appended.
|
||||
* @return An HtmlBuilder for indented HTML.
|
||||
*/
|
||||
public static final <T extends Appendable> IndentedHtml<T> into(T out, Config config) {
|
||||
return new IndentedHtml<>(out, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate indented HTML in memory using
|
||||
* Config defaults.
|
||||
*
|
||||
* @return An HtmlBuilder for indented HTML.
|
||||
*/
|
||||
public static final IndentedHtml<StringBuilder> inMemory() {
|
||||
return into(new StringBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HtmlBuilder that will generate indented HTML in memory using
|
||||
* the given Config.
|
||||
*
|
||||
* @param config The Config which will specify indentation, text escapement, tag closing, etc.
|
||||
* @return An HtmlBuilder for indented HTML.
|
||||
*/
|
||||
public static final IndentedHtml<StringBuilder> inMemory(Config config) {
|
||||
return into(new StringBuilder(), config);
|
||||
}
|
||||
|
||||
private final T out;
|
||||
private final Indenter indenter;
|
||||
private final TextEscaper textEscaper;
|
||||
private final TagBuilder enclosingElementAttributes;
|
||||
private final TagBuilder emptyElementAttributes;
|
||||
|
||||
// Dealing with preformatted elements (pre and textarea) requires
|
||||
// that we know what our parent elements are. To do that we use
|
||||
// a stack; adding items as start tags are created, and removing them
|
||||
// as those tags are closed. Determining whether or not we are
|
||||
// currently rendering into a preformatted element is as simple as
|
||||
// asking if any tags on the stack match a preformatted element name.
|
||||
private final Deque<String> trace = new ArrayDeque<>();
|
||||
|
||||
private IndentedHtml(T out, Config config) {
|
||||
this.out = out;
|
||||
this.indenter = config.indenter();
|
||||
this.textEscaper = config.textEscaper();
|
||||
this.enclosingElementAttributes = new IndentedTagBuilder(false);
|
||||
this.emptyElementAttributes = new IndentedTagBuilder(config.closeEmptyTags());
|
||||
}
|
||||
|
||||
private boolean isContentSelfFormatting() {
|
||||
return trace.contains("pre") || trace.contains("textarea");
|
||||
}
|
||||
|
||||
private int lvl() {
|
||||
return trace.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendStartTag(String name) throws IOException {
|
||||
if (!isContentSelfFormatting()) {
|
||||
out.append(indenter.indent(lvl(), ""));
|
||||
}
|
||||
|
||||
trace.push(name);
|
||||
|
||||
out.append("<").append(name);
|
||||
return enclosingElementAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendEndTag(String name) throws IOException {
|
||||
if (!name.equals(trace.peek())) {
|
||||
throw new RuntimeException("Incorrect element closed: " + name + ". Expected: " + trace.peek());
|
||||
}
|
||||
|
||||
if (!isContentSelfFormatting()) {
|
||||
trace.pop();
|
||||
out.append(indenter.indent(lvl(), ""));
|
||||
} else {
|
||||
trace.pop();
|
||||
}
|
||||
|
||||
out.append("</").append(name).append(">");
|
||||
|
||||
if (!isContentSelfFormatting()) {
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendEmptyTag(String name) throws IOException {
|
||||
if (!isContentSelfFormatting()) {
|
||||
out.append(indenter.indent(lvl(), ""));
|
||||
}
|
||||
out.append("<").append(name);
|
||||
return emptyElementAttributes;
|
||||
}
|
||||
|
||||
private void appendLines(String txt) throws IOException {
|
||||
if (!isContentSelfFormatting()) {
|
||||
String[] lines = txt.split("\n");
|
||||
for (String line : lines) {
|
||||
out.append(indenter.indent(lvl(), line)).append("\n");
|
||||
}
|
||||
} else {
|
||||
out.append(txt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendEscapedText(String txt) throws IOException {
|
||||
appendLines(textEscaper.escape(txt));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> appendUnescapedText(String txt) throws IOException {
|
||||
appendLines(txt);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T output() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(CharSequence csq) throws IOException {
|
||||
out.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(CharSequence csq, int start, int end) throws IOException {
|
||||
out.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HtmlBuilder<T> append(char c) throws IOException {
|
||||
out.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private class IndentedTagBuilder implements TagBuilder {
|
||||
|
||||
private final boolean closeTag;
|
||||
|
||||
private IndentedTagBuilder(boolean closeTag) {
|
||||
this.closeTag = closeTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendAttribute(String name, String value) throws IOException {
|
||||
out.append(" ")
|
||||
.append(name)
|
||||
.append("=\"")
|
||||
.append(textEscaper.escape(value))
|
||||
.append("\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagBuilder appendBooleanAttribute(String name) throws IOException {
|
||||
out.append(" ").append(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlBuilder<T> completeTag() throws IOException {
|
||||
if (closeTag) {
|
||||
out.append("/");
|
||||
}
|
||||
out.append(">");
|
||||
|
||||
if (!isContentSelfFormatting()) {
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
return IndentedHtml.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(CharSequence csq) throws IOException {
|
||||
out.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(CharSequence csq, int start, int end) throws IOException {
|
||||
out.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TagBuilder append(char c) throws IOException {
|
||||
out.append(c);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package org.xbib.j2html.rendering;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implementations of TagBuilder are used to append HTML tag
|
||||
* attributes to an Appendable. TagBuilders are scoped to the
|
||||
* creation and completion of a specific tag, and should not be used
|
||||
* outside of that tag.
|
||||
* <p>
|
||||
* Note: TagBuilder extends Appendable for compatibility with
|
||||
* previous version of this library. This extension will probably be
|
||||
* removed in the future, so avoid relying on the deprecated methods
|
||||
* of this interface.
|
||||
*/
|
||||
public interface TagBuilder extends Appendable {
|
||||
|
||||
/**
|
||||
* Appends an key/value pair as an HTML attribute to the current tag.
|
||||
*
|
||||
* @param name The name of an attribute.
|
||||
* @param value The value of an attribute.
|
||||
* @return An TagBuilder which can continue appending attributes.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
TagBuilder appendAttribute(String name, String value) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends a name, as a boolean HTML attribute to the current tag.
|
||||
*
|
||||
* @param name The name of the boolean attribute.
|
||||
* @return An TagBuilder which can continue appending attributes.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
TagBuilder appendBooleanAttribute(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends any characters which are necessary to close the current tag,
|
||||
* and returns an HtmlBuilder that can continue appending to the output.
|
||||
*
|
||||
* @return An HtmlBuilder that can continue appending HTML to the output.
|
||||
* @throws IOException When the Appendable throws an IOException.
|
||||
*/
|
||||
HtmlBuilder<? extends Appendable> completeTag() throws IOException;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
TagBuilder append(CharSequence csq) throws IOException;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
TagBuilder append(CharSequence csq, int start, int end) throws IOException;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
TagBuilder append(char c) throws IOException;
|
||||
}
|
186
j2html/src/main/java/org/xbib/j2html/tags/ContainerTag.java
Normal file
186
j2html/src/main/java/org/xbib/j2html/tags/ContainerTag.java
Normal file
|
@ -0,0 +1,186 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.attributes.Attribute;
|
||||
import org.xbib.j2html.rendering.TagBuilder;
|
||||
import org.xbib.j2html.rendering.FlatHtml;
|
||||
import org.xbib.j2html.rendering.HtmlBuilder;
|
||||
import org.xbib.j2html.rendering.IndentedHtml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ContainerTag<T extends ContainerTag<T>> extends Tag<T> {
|
||||
|
||||
protected List<DomContent> children;
|
||||
|
||||
public ContainerTag(String tagName) {
|
||||
super(tagName);
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends a DomContent-object to the end of this element
|
||||
*
|
||||
* @param child DomContent-object to be appended
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T with(DomContent child) {
|
||||
if (this == child) {
|
||||
throw new RuntimeException("Cannot append a tag to itself.");
|
||||
}
|
||||
if (child != null) {
|
||||
// in some cases, like when using iff(), we ignore null children
|
||||
children.add(child);
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call with-method based on condition
|
||||
* {@link #with(DomContent child)}
|
||||
*
|
||||
* @param condition the condition to use
|
||||
* @param child DomContent-object to be appended if condition met
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T condWith(boolean condition, DomContent child) {
|
||||
return condition ? this.with(child) : self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends a list of DomContent-objects to the end of this element
|
||||
*
|
||||
* @param children DomContent-objects to be appended
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T with(Iterable<? extends DomContent> children) {
|
||||
if (children != null) {
|
||||
for (DomContent child : children) {
|
||||
this.with(child);
|
||||
}
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call with-method based on condition
|
||||
* {@link #with(java.lang.Iterable)}
|
||||
*
|
||||
* @param condition the condition to use
|
||||
* @param children DomContent-objects to be appended if condition met
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T condWith(boolean condition, Iterable<? extends DomContent> children) {
|
||||
return condition ? this.with(children) : self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the DomContent-objects to the end of this element
|
||||
*
|
||||
* @param children DomContent-objects to be appended
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T with(DomContent... children) {
|
||||
for (DomContent child : children) {
|
||||
with(child);
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the DomContent-objects in the stream to the end of this element
|
||||
*
|
||||
* @param children Stream of DomContent-objects to be appended
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T with(Stream<DomContent> children) {
|
||||
children.forEach(this::with);
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call with-method based on condition
|
||||
* {@link #with(DomContent... children)}
|
||||
*
|
||||
* @param condition the condition to use
|
||||
* @param children DomContent-objects to be appended if condition met
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T condWith(boolean condition, DomContent... children) {
|
||||
return condition ? this.with(children) : self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends a Text-object to this element
|
||||
*
|
||||
* @param text the text to be appended
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T withText(String text) {
|
||||
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, 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() {
|
||||
try {
|
||||
return render(IndentedHtml.into(new StringBuilder(), Config.global())).toString();
|
||||
}catch (IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Appendable> A render(HtmlBuilder<A> builder, Object model) throws IOException {
|
||||
if (hasTagName()) {
|
||||
TagBuilder tagBuilder = builder.appendStartTag(getTagName());
|
||||
for(Attribute attribute : getAttributes()){
|
||||
attribute.render(tagBuilder, model);
|
||||
}
|
||||
tagBuilder.completeTag();
|
||||
}
|
||||
|
||||
for(DomContent child : children){
|
||||
child.render(builder, model);
|
||||
}
|
||||
|
||||
if(hasTagName()) {
|
||||
builder.appendEndTag(getTagName());
|
||||
}
|
||||
|
||||
return builder.output();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
public abstract class DomContent implements Renderable {
|
||||
@Override
|
||||
public String toString() {
|
||||
return render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
public class DomContentJoiner {
|
||||
|
||||
public static UnescapedText join(CharSequence delimiter, boolean fixPeriodAndCommaSpacing, Object... stringOrDomObjects) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < stringOrDomObjects.length; i++) {
|
||||
Object o = stringOrDomObjects[i];
|
||||
if (o instanceof String) {
|
||||
sb.append(((String) o).trim());
|
||||
} else if (o instanceof DomContent) {
|
||||
sb.append(((DomContent) o).render().trim());
|
||||
} else if (o == null) {
|
||||
//Discard null objects so iff/iffelse can be used with join
|
||||
continue;
|
||||
} else {
|
||||
throw new RuntimeException("You can only join DomContent and String objects");
|
||||
}
|
||||
if (i < stringOrDomObjects.length-1) {
|
||||
sb.append(delimiter);
|
||||
}
|
||||
}
|
||||
String joined = sb.toString().trim();
|
||||
if (fixPeriodAndCommaSpacing) {
|
||||
joined = joined.replaceAll("\\s\\.", ".");
|
||||
joined = joined.replaceAll("\\s\\,", ",");
|
||||
}
|
||||
return new UnescapedText(joined);
|
||||
}
|
||||
|
||||
}
|
42
j2html/src/main/java/org/xbib/j2html/tags/EmptyTag.java
Normal file
42
j2html/src/main/java/org/xbib/j2html/tags/EmptyTag.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.attributes.Attribute;
|
||||
import org.xbib.j2html.rendering.TagBuilder;
|
||||
import org.xbib.j2html.rendering.FlatHtml;
|
||||
import org.xbib.j2html.rendering.HtmlBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class EmptyTag<T extends EmptyTag<T>> extends Tag<T> {
|
||||
|
||||
public EmptyTag(String tagName) {
|
||||
super(tagName);
|
||||
if (tagName == null) {
|
||||
throw new IllegalArgumentException("Illegal tag name: null");
|
||||
}
|
||||
if ("".equals(tagName)) {
|
||||
throw new IllegalArgumentException("Illegal tag name: \"\"");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Appendable> A render(HtmlBuilder<A> builder, Object model) throws IOException {
|
||||
TagBuilder attrs = builder.appendEmptyTag(getTagName());
|
||||
for (Attribute attr : getAttributes()) {
|
||||
attr.render(attrs, model);
|
||||
}
|
||||
attrs.completeTag();
|
||||
return builder.output();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
20
j2html/src/main/java/org/xbib/j2html/tags/IInstance.java
Normal file
20
j2html/src/main/java/org/xbib/j2html/tags/IInstance.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
public interface IInstance<T> {
|
||||
|
||||
//to get the actual instance
|
||||
// (every implementing class would have to implement: { return this; }
|
||||
// public T self();
|
||||
|
||||
// this method shows up in autocomplete.
|
||||
// this is really undesireable as it does not do anything.
|
||||
@SuppressWarnings("unchecked")
|
||||
default T self() {
|
||||
//we know that the implementing class will supply
|
||||
//its own type as the type argument.
|
||||
//therefore every instance of IInstance can assume it
|
||||
//is also of type T
|
||||
|
||||
return (T) this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static org.xbib.j2html.TagCreator.rawHtml;
|
||||
import static org.xbib.j2html.TagCreator.script;
|
||||
import static org.xbib.j2html.TagCreator.style;
|
||||
|
||||
public class InlineStaticResource {
|
||||
|
||||
public static ContainerTag<? extends Tag<?>> get(String path, TargetFormat format) {
|
||||
String fileString = getFileAsString(path);
|
||||
return switch (format) {
|
||||
case CSS_MIN -> style().with(rawHtml(Config.cssMinifier.minify(fileString)));
|
||||
case JS_MIN -> script().with(rawHtml(Config.jsMinifier.minify((fileString))));
|
||||
case CSS -> style().with(rawHtml(fileString));
|
||||
case JS -> script().with(rawHtml(fileString));
|
||||
};
|
||||
}
|
||||
|
||||
public static String getFileAsString(String path) {
|
||||
try {
|
||||
return streamToString(InlineStaticResource.class.getResourceAsStream(path));
|
||||
} catch (Exception expected) {
|
||||
try {
|
||||
return streamToString(new FileInputStream(path));
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("Couldn't find file with path='" + path + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String streamToString(InputStream inputStream) {
|
||||
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
|
||||
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
|
||||
|
||||
}
|
||||
|
81
j2html/src/main/java/org/xbib/j2html/tags/Renderable.java
Normal file
81
j2html/src/main/java/org/xbib/j2html/tags/Renderable.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.rendering.FlatHtml;
|
||||
import org.xbib.j2html.rendering.HtmlBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
|
||||
public interface Renderable {
|
||||
|
||||
/**
|
||||
* Render the Renderable and it's children using the supplied builder.
|
||||
*
|
||||
* @param builder A builder that can compose HTML elements.
|
||||
* @param model A model object to provide data for children to render.
|
||||
* @param <T> The type of the Appendable which HTML is being appended to.
|
||||
* @return The Appendable to which HTML has been appended.
|
||||
* @throws IOException
|
||||
*/
|
||||
default <T extends Appendable> T render(HtmlBuilder<T> builder, Object model) throws IOException {
|
||||
// This method should be overridden by any internal classes.
|
||||
// renderModel() is only being called to support backwards
|
||||
// compatibility.
|
||||
renderModel(builder, model);
|
||||
return builder.output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Renderable and it's children using the supplied builder.
|
||||
*
|
||||
* @param builder A builder that can compose HTML elements.
|
||||
* @param <T> The type of the Appendable to which HTML is being appended.
|
||||
* @return The Appendable to which HTML has been appended.
|
||||
* @throws IOException
|
||||
*/
|
||||
default <T extends Appendable> T render(HtmlBuilder<T> builder) throws IOException {
|
||||
return render(builder, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a StringBuilder and use it to render the Renderable and it's
|
||||
* children
|
||||
*/
|
||||
default String render() {
|
||||
try {
|
||||
return render(FlatHtml.into(new StringBuilder(), Config.global())).toString();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Renderable and it's children using the supplied writer
|
||||
*
|
||||
* @param writer the current writer
|
||||
*/
|
||||
@Deprecated
|
||||
default void render(Appendable writer) throws IOException {
|
||||
if (writer instanceof HtmlBuilder) {
|
||||
render((HtmlBuilder<? extends Appendable>) writer);
|
||||
} else {
|
||||
render(FlatHtml.into(writer, Config.global()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Renderable and it's children using the supplied writer and a model.
|
||||
*
|
||||
* @param writer the current writer
|
||||
* @param model a model object to provide data for children to render
|
||||
*/
|
||||
@Deprecated
|
||||
default void renderModel(Appendable writer, Object model) throws IOException {
|
||||
// This method is a placeholder to support any client classes
|
||||
// which previously extended Renderable implementers, such as Tags.
|
||||
// No internal classes should implement this method; except to support
|
||||
// compatibility. Instead they should implement rendering with an HtmlBuilder.
|
||||
throw new RuntimeException("Renderable.renderModel(Appendable writer, Object model) has been deprecated. Please use Renderable.render(HtmlBuilder<T> builder, Object model) instead.");
|
||||
}
|
||||
}
|
213
j2html/src/main/java/org/xbib/j2html/tags/Tag.java
Normal file
213
j2html/src/main/java/org/xbib/j2html/tags/Tag.java
Normal file
|
@ -0,0 +1,213 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.attributes.Attr;
|
||||
import org.xbib.j2html.attributes.Attribute;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public abstract class Tag<T extends Tag<T>> extends DomContent implements IInstance<T> {
|
||||
private final String tagName;
|
||||
private final ArrayList<Attribute> attributes;
|
||||
|
||||
protected Tag(String tagName) {
|
||||
this.tagName = tagName;
|
||||
this.attributes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getTagName() {
|
||||
return this.tagName;
|
||||
}
|
||||
|
||||
protected boolean hasTagName() {
|
||||
return tagName != null && !tagName.isEmpty();
|
||||
}
|
||||
|
||||
protected ArrayList<Attribute> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute on an element
|
||||
*
|
||||
* @param name the attribute
|
||||
* @param value the attribute value
|
||||
*/
|
||||
boolean setAttribute(String name, String value) {
|
||||
if (value == null) {
|
||||
return attributes.add(new Attribute(name));
|
||||
}
|
||||
for (Attribute attribute : attributes) {
|
||||
if (attribute.getName().equals(name)) {
|
||||
attribute.setValue(value); // update with new value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return attributes.add(new Attribute(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom attribute
|
||||
*
|
||||
* @param attribute the attribute name
|
||||
* @param value the attribute value
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T attr(String attribute, Object value) {
|
||||
setAttribute(attribute, value == null ? null : String.valueOf(value));
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified attribute. If the Tag previously contained an attribute with the same name, the old attribute is replaced by the specified attribute.
|
||||
*
|
||||
* @param attribute the attribute
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T attr(Attribute attribute) {
|
||||
Iterator<Attribute> iterator = attributes.iterator();
|
||||
String name = attribute.getName();
|
||||
if (name != null) {
|
||||
// name == null is allowed, but those Attributes are not rendered. So we add them anyway.
|
||||
while (iterator.hasNext()) {
|
||||
Attribute existingAttribute = iterator.next();
|
||||
if (existingAttribute.getName().equals(name)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
attributes.add(attribute);
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom attribute without value
|
||||
*
|
||||
* @param attribute the attribute name
|
||||
* @return itself for easy chaining
|
||||
* @see Tag#attr(String, Object)
|
||||
*/
|
||||
public T attr(String attribute) {
|
||||
return attr(attribute, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call attr-method based on condition
|
||||
* {@link #attr(String attribute, Object value)}
|
||||
*
|
||||
* @param condition the condition
|
||||
* @param attribute the attribute name
|
||||
* @param value the attribute value
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T condAttr(boolean condition, String attribute, String value) {
|
||||
return (condition ? attr(attribute, value) : self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Tag)) {
|
||||
return false;
|
||||
}
|
||||
return ((Tag<?>) obj).render().equals(this.render());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience methods that call attr with predefined attributes
|
||||
*
|
||||
* @return itself for easy chaining
|
||||
*/
|
||||
public T withClasses(String... classes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : classes) {
|
||||
sb.append(s != null ? s : "").append(" ");
|
||||
}
|
||||
return attr(Attr.CLASS, sb.toString().trim());
|
||||
}
|
||||
|
||||
/*
|
||||
Tag.java contains all Global Attributes, Attributes which are
|
||||
valid on all HTML Tags. Reference:
|
||||
https://www.w3schools.com/tags/ref_standardattributes.asp
|
||||
Attributes:
|
||||
|
||||
accesskey
|
||||
class
|
||||
contenteditable
|
||||
data-*
|
||||
dir
|
||||
draggable
|
||||
hidden
|
||||
id
|
||||
lang
|
||||
spellcheck
|
||||
style
|
||||
tabindex
|
||||
title
|
||||
translate
|
||||
*/
|
||||
|
||||
public T withAccesskey(String accesskey){ return attr(Attr.ACCESSKEY, accesskey); }
|
||||
|
||||
public T withClass(String className) { return attr(Attr.CLASS, className); }
|
||||
|
||||
public T isContenteditable(){ return attr(Attr.CONTENTEDITABLE, "true"); }
|
||||
|
||||
public T withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
|
||||
|
||||
public T withDir(String dir) { return attr(Attr.DIR, dir); }
|
||||
|
||||
public T isDraggable(){ return attr(Attr.DRAGGABLE, "true"); }
|
||||
|
||||
public T isHidden() { return attr(Attr.HIDDEN, null); }
|
||||
|
||||
public T withId(String id) { return attr(Attr.ID, id); }
|
||||
|
||||
public T withIs(String element){ return attr(Attr.IS, element); }
|
||||
|
||||
public T withLang(String lang) { return attr(Attr.LANG, lang); }
|
||||
|
||||
public T withSlot(String name){ return attr(Attr.SLOT, name); }
|
||||
|
||||
public T isSpellcheck(){ return attr(Attr.SPELLCHECK, "true"); }
|
||||
|
||||
public T withStyle(String style) { return attr(Attr.STYLE, style); }
|
||||
|
||||
public T withTabindex(int index){ return attr(Attr.TABINDEX, index); }
|
||||
|
||||
public T withTitle(String title) { return attr(Attr.TITLE, title); }
|
||||
|
||||
public T isTranslate(){ return attr(Attr.TRANSLATE, "yes"); }
|
||||
|
||||
// ----- start of withCond$ATTR variants -----
|
||||
public T withCondAccessKey(boolean condition, String accesskey){ return condAttr(condition, Attr.ACCESSKEY, accesskey); }
|
||||
|
||||
public T withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
|
||||
|
||||
public T withCondContenteditable(boolean condition){ return attr(Attr.CONTENTEDITABLE, (condition)?"true":"false");}
|
||||
|
||||
public T withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
|
||||
|
||||
public T withCondDir(boolean condition, String dir) { return condAttr(condition, Attr.DIR, dir); }
|
||||
|
||||
public T withCondDraggable(boolean condition){ return attr(Attr.DRAGGABLE, (condition)?"true":"false"); }
|
||||
|
||||
public T withCondHidden(boolean condition) { return condAttr(condition, Attr.HIDDEN, null); }
|
||||
|
||||
public T withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
|
||||
|
||||
public T withCondIs(boolean condition, String element){ return condAttr(condition, Attr.IS, element); }
|
||||
|
||||
public T withCondLang(boolean condition, String lang) { return condAttr(condition, Attr.LANG, lang); }
|
||||
|
||||
public T withCondSlot(boolean condition, String name){ return condAttr(condition, Attr.SLOT, name); }
|
||||
|
||||
public T withCondSpellcheck(boolean condition){ return attr(Attr.SPELLCHECK, (condition)?"true":"false"); }
|
||||
|
||||
public T withCondStyle(boolean condition, String style) { return condAttr(condition, Attr.STYLE, style); }
|
||||
|
||||
public T withCondTabindex(boolean condition, int index){ return condAttr(condition, Attr.TABINDEX, index+""); }
|
||||
|
||||
public T withCondTitle(boolean condition, String title) { return condAttr(condition, Attr.TITLE, title); }
|
||||
|
||||
public T withCondTranslate(boolean condition){ return attr(Attr.TRANSLATE, (condition)?"yes":"no"); }
|
||||
}
|
33
j2html/src/main/java/org/xbib/j2html/tags/Text.java
Normal file
33
j2html/src/main/java/org/xbib/j2html/tags/Text.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.rendering.FlatHtml;
|
||||
import org.xbib.j2html.rendering.HtmlBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Text extends DomContent {
|
||||
|
||||
private final String text;
|
||||
|
||||
public Text(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Appendable> T render(HtmlBuilder<T> builder, Object model) throws IOException {
|
||||
builder.appendEscapedText(String.valueOf(text));
|
||||
return builder.output();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
40
j2html/src/main/java/org/xbib/j2html/tags/UnescapedText.java
Normal file
40
j2html/src/main/java/org/xbib/j2html/tags/UnescapedText.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package org.xbib.j2html.tags;
|
||||
|
||||
import org.xbib.j2html.Config;
|
||||
import org.xbib.j2html.rendering.FlatHtml;
|
||||
import org.xbib.j2html.rendering.HtmlBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnescapedText extends DomContent {
|
||||
|
||||
private final String text;
|
||||
|
||||
public UnescapedText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Appendable> T render(HtmlBuilder<T> builder, Object model) throws IOException {
|
||||
builder.appendUnescapedText(String.valueOf(text));
|
||||
return builder.output();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof UnescapedText)) {
|
||||
return false;
|
||||
}
|
||||
return ((UnescapedText) obj).render().equals(this.render());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAccept<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withAccept(final String accept_) {
|
||||
return self().attr("accept", accept_);
|
||||
}
|
||||
|
||||
default T withCondAccept(final boolean enable, final String accept_) {
|
||||
return enable ? self().attr("accept", accept_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAction<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withAction(final String action_) {
|
||||
return self().attr("action", action_);
|
||||
}
|
||||
|
||||
default T withCondAction(final boolean enable, final String action_) {
|
||||
return enable ? self().attr("action", action_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAlt<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withAlt(final String alt_) {
|
||||
return self().attr("alt", alt_);
|
||||
}
|
||||
|
||||
default T withCondAlt(final boolean enable, final String alt_) {
|
||||
return enable ? self().attr("alt", alt_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAsync<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isAsync() {
|
||||
return self().attr("async");
|
||||
}
|
||||
|
||||
default T withCondAsync(final boolean enable) {
|
||||
return enable ? self().attr("async") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAutocomplete<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isAutocomplete() {
|
||||
return self().attr("autocomplete", "on");
|
||||
}
|
||||
|
||||
default T withCondAutocomplete(final boolean enable) {
|
||||
return enable ? self().attr("autocomplete", "on") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAutofocus<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isAutofocus() {
|
||||
return self().attr("autofocus");
|
||||
}
|
||||
|
||||
default T withCondAutofocus(final boolean enable) {
|
||||
return enable ? self().attr("autofocus") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IAutoplay<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isAutoplay() {
|
||||
return self().attr("autoplay");
|
||||
}
|
||||
|
||||
default T withCondAutoplay(final boolean enable) {
|
||||
return enable ? self().attr("autoplay") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ICharset<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withCharset(final String charset_) {
|
||||
return self().attr("charset", charset_);
|
||||
}
|
||||
|
||||
default T withCondCharset(final boolean enable, final String charset_) {
|
||||
return enable ? self().attr("charset", charset_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IChecked<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isChecked() {
|
||||
return self().attr("checked");
|
||||
}
|
||||
|
||||
default T withCondChecked(final boolean enable) {
|
||||
return enable ? self().attr("checked") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ICite<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withCite(final String cite_) {
|
||||
return self().attr("cite", cite_);
|
||||
}
|
||||
|
||||
default T withCondCite(final boolean enable, final String cite_) {
|
||||
return enable ? self().attr("cite", cite_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ICols<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withCols(final String cols_) {
|
||||
return self().attr("cols", cols_);
|
||||
}
|
||||
|
||||
default T withCondCols(final boolean enable, final String cols_) {
|
||||
return enable ? self().attr("cols", cols_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IColspan<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withColspan(final String colspan_) {
|
||||
return self().attr("colspan", colspan_);
|
||||
}
|
||||
|
||||
default T withCondColspan(final boolean enable, final String colspan_) {
|
||||
return enable ? self().attr("colspan", colspan_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IContent<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withContent(final String content_) {
|
||||
return self().attr("content", content_);
|
||||
}
|
||||
|
||||
default T withCondContent(final boolean enable, final String content_) {
|
||||
return enable ? self().attr("content", content_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IControls<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isControls() {
|
||||
return self().attr("controls");
|
||||
}
|
||||
|
||||
default T withCondControls(final boolean enable) {
|
||||
return enable ? self().attr("controls") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ICoords<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withCoords(final String coords_) {
|
||||
return self().attr("coords", coords_);
|
||||
}
|
||||
|
||||
default T withCondCoords(final boolean enable, final String coords_) {
|
||||
return enable ? self().attr("coords", coords_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IData<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withData(final String data_) {
|
||||
return self().attr("data", data_);
|
||||
}
|
||||
|
||||
default T withCondData(final boolean enable, final String data_) {
|
||||
return enable ? self().attr("data", data_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDatetime<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withDatetime(final String datetime_) {
|
||||
return self().attr("datetime", datetime_);
|
||||
}
|
||||
|
||||
default T withCondDatetime(final boolean enable, final String datetime_) {
|
||||
return enable ? self().attr("datetime", datetime_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDefault<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isDefault() {
|
||||
return self().attr("default");
|
||||
}
|
||||
|
||||
default T withCondDefault(final boolean enable) {
|
||||
return enable ? self().attr("default") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDefer<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isDefer() {
|
||||
return self().attr("defer");
|
||||
}
|
||||
|
||||
default T withCondDefer(final boolean enable) {
|
||||
return enable ? self().attr("defer") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDirname<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withDirname(final String dirname_) {
|
||||
return self().attr("dirname", dirname_);
|
||||
}
|
||||
|
||||
default T withCondDirname(final boolean enable, final String dirname_) {
|
||||
return enable ? self().attr("dirname", dirname_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDisabled<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isDisabled() {
|
||||
return self().attr("disabled");
|
||||
}
|
||||
|
||||
default T withCondDisabled(final boolean enable) {
|
||||
return enable ? self().attr("disabled") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IDownload<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isDownload() {
|
||||
return self().attr("download");
|
||||
}
|
||||
|
||||
default T withCondDownload(final boolean enable) {
|
||||
return enable ? self().attr("download") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IEnctype<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withEnctype(final String enctype_) {
|
||||
return self().attr("enctype", enctype_);
|
||||
}
|
||||
|
||||
default T withCondEnctype(final boolean enable, final String enctype_) {
|
||||
return enable ? self().attr("enctype", enctype_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IFor<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withFor(final String for_) {
|
||||
return self().attr("for", for_);
|
||||
}
|
||||
|
||||
default T withCondFor(final boolean enable, final String for_) {
|
||||
return enable ? self().attr("for", for_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IForm<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withForm(final String form_) {
|
||||
return self().attr("form", form_);
|
||||
}
|
||||
|
||||
default T withCondForm(final boolean enable, final String form_) {
|
||||
return enable ? self().attr("form", form_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IFormaction<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withFormaction(final String formaction_) {
|
||||
return self().attr("formaction", formaction_);
|
||||
}
|
||||
|
||||
default T withCondFormaction(final boolean enable, final String formaction_) {
|
||||
return enable ? self().attr("formaction", formaction_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IHeaders<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withHeaders(final String headers_) {
|
||||
return self().attr("headers", headers_);
|
||||
}
|
||||
|
||||
default T withCondHeaders(final boolean enable, final String headers_) {
|
||||
return enable ? self().attr("headers", headers_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IHeight<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withHeight(final String height_) {
|
||||
return self().attr("height", height_);
|
||||
}
|
||||
|
||||
default T withCondHeight(final boolean enable, final String height_) {
|
||||
return enable ? self().attr("height", height_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IHigh<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withHigh(final String high_) {
|
||||
return self().attr("high", high_);
|
||||
}
|
||||
|
||||
default T withCondHigh(final boolean enable, final String high_) {
|
||||
return enable ? self().attr("high", high_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IHref<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withHref(final String href_) {
|
||||
return self().attr("href", href_);
|
||||
}
|
||||
|
||||
default T withCondHref(final boolean enable, final String href_) {
|
||||
return enable ? self().attr("href", href_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IHreflang<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withHreflang(final String hreflang_) {
|
||||
return self().attr("hreflang", hreflang_);
|
||||
}
|
||||
|
||||
default T withCondHreflang(final boolean enable, final String hreflang_) {
|
||||
return enable ? self().attr("hreflang", hreflang_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IIsmap<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isIsmap() {
|
||||
return self().attr("ismap");
|
||||
}
|
||||
|
||||
default T withCondIsmap(final boolean enable) {
|
||||
return enable ? self().attr("ismap") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IKind<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withKind(final String kind_) {
|
||||
return self().attr("kind", kind_);
|
||||
}
|
||||
|
||||
default T withCondKind(final boolean enable, final String kind_) {
|
||||
return enable ? self().attr("kind", kind_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ILabel<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withLabel(final String label_) {
|
||||
return self().attr("label", label_);
|
||||
}
|
||||
|
||||
default T withCondLabel(final boolean enable, final String label_) {
|
||||
return enable ? self().attr("label", label_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IList<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withList(final String list_) {
|
||||
return self().attr("list", list_);
|
||||
}
|
||||
|
||||
default T withCondList(final boolean enable, final String list_) {
|
||||
return enable ? self().attr("list", list_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ILoop<T extends Tag<T>> extends IInstance<T> {
|
||||
default T isLoop() {
|
||||
return self().attr("loop");
|
||||
}
|
||||
|
||||
default T withCondLoop(final boolean enable) {
|
||||
return enable ? self().attr("loop") : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface ILow<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withLow(final String low_) {
|
||||
return self().attr("low", low_);
|
||||
}
|
||||
|
||||
default T withCondLow(final boolean enable, final String low_) {
|
||||
return enable ? self().attr("low", low_) : self();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.xbib.j2html.tags.attributes;
|
||||
|
||||
import org.xbib.j2html.tags.IInstance;
|
||||
import org.xbib.j2html.tags.Tag;
|
||||
|
||||
public interface IMax<T extends Tag<T>> extends IInstance<T> {
|
||||
default T withMax(final String max_) {
|
||||
return self().attr("max", max_);
|
||||
}
|
||||
|
||||
default T withCondMax(final boolean enable, final String max_) {
|
||||
return enable ? self().attr("max", max_) : self();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue