From b55bc03a8c47dbf625ed71df09406d58f183fa7b Mon Sep 17 00:00:00 2001 From: RicardoGomes07 Date: Mon, 16 Mar 2026 13:28:15 +0000 Subject: [PATCH 1/3] Add Tbody as a valid HtmlPage root element and root builder with tests --- .../src/main/java/htmlflow/HtmlPage.java | 11 +- .../kotlin/htmlflow/HtmlFlowExtensions.kt | 3 + .../test/TestKotlinExtensionsOnPartials.kt | 102 +++++++++++++++++- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/htmlflow-core/src/main/java/htmlflow/HtmlPage.java b/htmlflow-core/src/main/java/htmlflow/HtmlPage.java index c03a4e6..55c35bc 100644 --- a/htmlflow-core/src/main/java/htmlflow/HtmlPage.java +++ b/htmlflow-core/src/main/java/htmlflow/HtmlPage.java @@ -33,11 +33,8 @@ import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.net.URL; -import org.xmlet.htmlapifaster.Element; -import org.xmlet.htmlapifaster.Html; -import org.xmlet.htmlapifaster.Tr; -import org.xmlet.htmlapifaster.Div; -import org.xmlet.htmlapifaster.Span; + +import org.xmlet.htmlapifaster.*; /** * The root container for HTML elements. It is responsible for managing the {@code @@ -90,6 +87,10 @@ public final Span span() { return new Span<>(this); } + public final Tbody tbody() { + return new Tbody<>(this); + } + /** * Returns a new instance of HtmlFlow with the same properties of this object but with indented * set to the value of isIndented parameter. diff --git a/htmlflow-kotlin/src/main/kotlin/htmlflow/HtmlFlowExtensions.kt b/htmlflow-kotlin/src/main/kotlin/htmlflow/HtmlFlowExtensions.kt index dbdc093..225d2fa 100644 --- a/htmlflow-kotlin/src/main/kotlin/htmlflow/HtmlFlowExtensions.kt +++ b/htmlflow-kotlin/src/main/kotlin/htmlflow/HtmlFlowExtensions.kt @@ -8,6 +8,7 @@ import org.xmlet.htmlapifaster.Div import org.xmlet.htmlapifaster.Element import org.xmlet.htmlapifaster.Html import org.xmlet.htmlapifaster.Span +import org.xmlet.htmlapifaster.Tbody import org.xmlet.htmlapifaster.Text import org.xmlet.htmlapifaster.Tr @@ -31,6 +32,8 @@ inline fun HtmlPage.tr(block: Tr.() -> Unit): HtmlPage = this.tr().app inline fun HtmlPage.span(block: Span.() -> Unit): HtmlPage = this.span().apply(block).l +inline fun HtmlPage.tbody(block: Tbody.() -> Unit): HtmlPage = this.tbody().apply(block).l + /** Text node property. */ inline var , Z : Element<*, *>> T.text: T get() = self() diff --git a/htmlflow-kotlin/src/test/kotlin/htmlflow/test/TestKotlinExtensionsOnPartials.kt b/htmlflow-kotlin/src/test/kotlin/htmlflow/test/TestKotlinExtensionsOnPartials.kt index 717f5e2..fcb5bf1 100644 --- a/htmlflow-kotlin/src/test/kotlin/htmlflow/test/TestKotlinExtensionsOnPartials.kt +++ b/htmlflow-kotlin/src/test/kotlin/htmlflow/test/TestKotlinExtensionsOnPartials.kt @@ -380,6 +380,52 @@ data class Agent( } data class Counter(val count: Int) + @Test + fun testThatTbodyElementCanBeUsedOnHtmlDocAndHtmlView(){ + val agentsTableDoc = + StringBuilder() + .apply { + doc { + tbody { + tr { + td { text("James Bond") } + td { text("bond@mi6.gov.uk") } + td { text("007") } + } + tr { + td { text("Ethan Hunt") } + td { text("ehunt@imf.gov") } + td { text("001") } + } + } + } + }.toString() + + assertEquals(expectedAgentsTableDoc, agentsTableDoc) + + val agents = listOf( + Agent("Jason Bourne", "bourne@cia.gov", "002"), + Agent("Napoleon Solo", "solo@uncle.org", "003") + ) + + val agentsTableView = + view> { + tbody { + dyn { agents: List -> + agents.forEach { agent -> + tr { + td { text(agent.name) } + td { text(agent.email) } + td { text(agent.id) } + } + } + } + } + }.render(agents) + + assertEquals(expectedAgentsTableView, agentsTableView) + } + } private const val expectedFavoriteMoviesView = @@ -463,4 +509,58 @@ private val expectedCounterSpans = The counter 2 has the value 1 -""" \ No newline at end of file +""" + + +private const val expectedAgentsTableDoc = + """ + + + + James Bond + + + bond@mi6.gov.uk + + + 007 + + + + + Ethan Hunt + + + ehunt@imf.gov + + + 001 + + +""" + +private const val expectedAgentsTableView = + """ + + + Jason Bourne + + + bourne@cia.gov + + + 002 + + + + + Napoleon Solo + + + solo@uncle.org + + + 003 + + +""" \ No newline at end of file From e9955762c0c3bbea296f8277fe9c665882d6ccda Mon Sep 17 00:00:00 2001 From: Miguel Gamboa Date: Thu, 26 Mar 2026 09:56:13 +0000 Subject: [PATCH 2/3] Missing import of TBody --- htmlflow-core/src/main/java/htmlflow/HtmlPage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/htmlflow-core/src/main/java/htmlflow/HtmlPage.java b/htmlflow-core/src/main/java/htmlflow/HtmlPage.java index c3c30ce..55cd194 100644 --- a/htmlflow-core/src/main/java/htmlflow/HtmlPage.java +++ b/htmlflow-core/src/main/java/htmlflow/HtmlPage.java @@ -37,6 +37,7 @@ import org.xmlet.htmlapifaster.Element; import org.xmlet.htmlapifaster.Html; import org.xmlet.htmlapifaster.Span; +import org.xmlet.htmlapifaster.Tbody; import org.xmlet.htmlapifaster.Tr; /** From 1ab62e619a897d7e90121bbcc6929620ff6cbeba Mon Sep 17 00:00:00 2001 From: Paulo Afonso Carvalho Date: Fri, 27 Mar 2026 15:01:56 +0000 Subject: [PATCH 3/3] Add Agent model and implement agents table body view with unit test --- .../test/java/htmlflow/test/TestTable.java | 45 +++++++++++++++++++ .../test/java/htmlflow/test/model/Agent.java | 24 ++++++++++ .../java/htmlflow/test/views/HtmlTables.java | 13 ++++++ 3 files changed, 82 insertions(+) create mode 100644 htmlflow-core/src/test/java/htmlflow/test/model/Agent.java diff --git a/htmlflow-core/src/test/java/htmlflow/test/TestTable.java b/htmlflow-core/src/test/java/htmlflow/test/TestTable.java index 99282d1..bca0ba4 100644 --- a/htmlflow-core/src/test/java/htmlflow/test/TestTable.java +++ b/htmlflow-core/src/test/java/htmlflow/test/TestTable.java @@ -25,6 +25,7 @@ import htmlflow.HtmlFlow; import htmlflow.HtmlView; +import htmlflow.test.model.Agent; import htmlflow.test.model.Priority; import htmlflow.test.model.Status; import htmlflow.test.model.Task; @@ -244,6 +245,20 @@ public void testTableWithPartialsBindingTwice() { validateBindingTable(view.render(dataSource)); } + @Test + public void testRenderTableBody() { + List agents = Arrays.asList( + new Agent(1, "Agent Smith " + 1, "void"+ 1 +"@null.org"), + new Agent(2, "Agent Smith " + 2, "void"+ 2 +"@null.org"), + new Agent(3, "Agent Smith " + 3, "void"+ 3 +"@null.org") + ); + + String actualTableBody = HtmlTables.agentsTableBodyView.render(agents); + + assertEquals(expectedTableBodyPartial, actualTableBody); + + } + static void validateBindingTable(String actual){ Iterator iter = NEWLINE .splitAsStream(actual) @@ -311,4 +326,34 @@ private static void assertSimpleHtmlView(byte[] html, int[][] output) { } } } + + private final static String expectedTableBodyPartial = + """ + + + + Agent Smith 1 + + + void1@null.org + + + + + Agent Smith 2 + + + void2@null.org + + + + + Agent Smith 3 + + + void3@null.org + + + + """.trim(); } diff --git a/htmlflow-core/src/test/java/htmlflow/test/model/Agent.java b/htmlflow-core/src/test/java/htmlflow/test/model/Agent.java new file mode 100644 index 0000000..360662b --- /dev/null +++ b/htmlflow-core/src/test/java/htmlflow/test/model/Agent.java @@ -0,0 +1,24 @@ +package htmlflow.test.model; + +public class Agent { + private final long id; + private final String name; + private final String email; + + public Agent(long id, String name, String email) { + this.id = id; + this.name = name; + this.email = email; + } + + public long getId() { + return id; + } + public String getName() { + return name; + } + public String getEmail() { + return email; + } + +} diff --git a/htmlflow-core/src/test/java/htmlflow/test/views/HtmlTables.java b/htmlflow-core/src/test/java/htmlflow/test/views/HtmlTables.java index 93fe588..1caad92 100644 --- a/htmlflow-core/src/test/java/htmlflow/test/views/HtmlTables.java +++ b/htmlflow-core/src/test/java/htmlflow/test/views/HtmlTables.java @@ -28,6 +28,7 @@ import htmlflow.HtmlPage; import htmlflow.HtmlTemplate; import htmlflow.HtmlView; +import htmlflow.test.model.Agent; import htmlflow.test.model.Task; import org.xmlet.htmlapifaster.EnumRelType; import org.xmlet.htmlapifaster.EnumTypeContentType; @@ -201,4 +202,16 @@ public static void taskTableView(HtmlPage view){ .__() // body .__() // html ); + + public static HtmlView agentsTableBodyView = HtmlFlow.view(view -> view + .tbody() + .>dynamic((tbody, agents) -> agents.forEach(agent -> + tbody + .tr() + .td().text(agent.getName()).__() + .td().text(agent.getEmail()).__() + .__() // tr + )) + .__() + ); }