Bump version to 1.2.10, simplify attribute and event handling in ElementExtensions, and remove deprecated logic in HtmlBuilder.
Some checks failed
Gradle CI / build (push) Has been cancelled
Some checks failed
Gradle CI / build (push) Has been cancelled
This commit is contained in:
@@ -11,7 +11,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "nl.astraeus"
|
group = "nl.astraeus"
|
||||||
version = "1.2.9"
|
version = "1.2.10"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
@@ -40,14 +40,6 @@ fun Element.printTree(indent: Int = 0): String {
|
|||||||
}
|
}
|
||||||
result.append(") {")
|
result.append(") {")
|
||||||
result.append("\n")
|
result.append("\n")
|
||||||
for ((name, event) in getKompEvents()) {
|
|
||||||
result.append(indent.asSpaces())
|
|
||||||
result.append("on")
|
|
||||||
result.append(name)
|
|
||||||
result.append(" -> ")
|
|
||||||
result.append(event)
|
|
||||||
result.append("\n")
|
|
||||||
}
|
|
||||||
for (index in 0 until childNodes.length) {
|
for (index in 0 until childNodes.length) {
|
||||||
childNodes[index]?.let {
|
childNodes[index]?.let {
|
||||||
if (it is Element) {
|
if (it is Element) {
|
||||||
@@ -65,55 +57,52 @@ fun Element.printTree(indent: Int = 0): String {
|
|||||||
return result.toString()
|
return result.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Element.setKompAttribute(attributeName: String, value: String?) {
|
internal fun Element.setKompAttribute(attributeName: String, value: String) {
|
||||||
//val attributeName = name.lowercase()
|
if (this is HTMLInputElement) {
|
||||||
if (value == null || value.isBlank()) {
|
when (attributeName) {
|
||||||
if (this is HTMLInputElement) {
|
"checked" -> {
|
||||||
when (attributeName) {
|
checked = "checked" == value
|
||||||
"checked" -> {
|
|
||||||
checked = false
|
|
||||||
}
|
|
||||||
"class" -> {
|
|
||||||
className = ""
|
|
||||||
}
|
|
||||||
"value" -> {
|
|
||||||
this.value = ""
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
removeAttribute(attributeName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
removeAttribute(attributeName)
|
"class" -> {
|
||||||
}
|
className = value
|
||||||
} else {
|
}
|
||||||
if (this is HTMLInputElement) {
|
|
||||||
when (attributeName) {
|
"value" -> {
|
||||||
"checked" -> {
|
this.value = value
|
||||||
checked = "checked" == value
|
}
|
||||||
}
|
|
||||||
"class" -> {
|
else -> {
|
||||||
className = value
|
setAttribute(attributeName, value)
|
||||||
}
|
|
||||||
"value" -> {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
setAttribute(attributeName, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (this.getAttribute(attributeName) != value) {
|
|
||||||
setAttribute(attributeName, value)
|
|
||||||
}
|
}
|
||||||
|
} else if (this.getAttribute(attributeName) != value) {
|
||||||
|
setAttribute(attributeName, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Element.clearKompEvents() {
|
internal fun Element.clearKompAttribute(attributeName: String) {
|
||||||
val events = getKompEvents()
|
if (this is HTMLInputElement) {
|
||||||
for ((name, event) in getKompEvents()) {
|
when (attributeName) {
|
||||||
removeEventListener(name, event)
|
"checked" -> {
|
||||||
|
checked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
"class" -> {
|
||||||
|
className = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
"value" -> {
|
||||||
|
this.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
removeAttribute(attributeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeAttribute(attributeName)
|
||||||
}
|
}
|
||||||
events.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
|
internal fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
|
||||||
@@ -123,22 +112,9 @@ internal fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
getKompEvents()[eventName] = event
|
|
||||||
|
|
||||||
this.addEventListener(eventName, event)
|
this.addEventListener(eventName, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Element.getKompEvents(): MutableMap<String, (Event) -> Unit> {
|
|
||||||
var map = this.asDynamic()["komp-events"] as? MutableMap<String, (Event) -> Unit>
|
|
||||||
|
|
||||||
if (map == null) {
|
|
||||||
map = mutableMapOf()
|
|
||||||
this.asDynamic()["komp-events"] = map
|
|
||||||
}
|
|
||||||
|
|
||||||
return map
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun Element.findElementIndex(): Int {
|
internal fun Element.findElementIndex(): Int {
|
||||||
val childNodes = parentElement?.children
|
val childNodes = parentElement?.children
|
||||||
if (childNodes != null) {
|
if (childNodes != null) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import org.w3c.dom.get
|
|||||||
data class ElementIndex(
|
data class ElementIndex(
|
||||||
val parent: Node,
|
val parent: Node,
|
||||||
var childIndex: Int,
|
var childIndex: Int,
|
||||||
var setAttr: MutableSet<String> = mutableSetOf()
|
|
||||||
) {
|
) {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "${parent.nodeName}[$childIndex]"
|
return "${parent.nodeName}[$childIndex]"
|
||||||
@@ -39,7 +38,6 @@ fun ArrayList<ElementIndex>.currentPosition(): ElementIndex? {
|
|||||||
|
|
||||||
fun ArrayList<ElementIndex>.nextElement() {
|
fun ArrayList<ElementIndex>.nextElement() {
|
||||||
this.lastOrNull()?.let {
|
this.lastOrNull()?.let {
|
||||||
it.setAttr.clear()
|
|
||||||
it.childIndex++
|
it.childIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,12 +57,6 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// current element should become parent
|
// current element should become parent
|
||||||
/*
|
|
||||||
val ce = komponent.element
|
|
||||||
if (ce != null) {
|
|
||||||
append(ce as Element)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
komponent.create(
|
komponent.create(
|
||||||
currentPosition.last().parent as Element,
|
currentPosition.last().parent as Element,
|
||||||
currentPosition.last().childIndex
|
currentPosition.last().childIndex
|
||||||
@@ -100,39 +94,26 @@ class HtmlBuilder(
|
|||||||
"onTagStart, [${tag.tagName}, ${tag.namespace ?: ""}], currentPosition: $currentPosition"
|
"onTagStart, [${tag.tagName}, ${tag.namespace ?: ""}], currentPosition: $currentPosition"
|
||||||
}
|
}
|
||||||
|
|
||||||
currentNode = currentPosition.currentElement()
|
currentNode = if (tag.namespace != null) {
|
||||||
|
document.createElementNS(tag.namespace, tag.tagName)
|
||||||
|
} else {
|
||||||
|
document.createElement(tag.tagName)
|
||||||
|
}
|
||||||
|
|
||||||
if (currentNode == null) {
|
if (currentNode == null) {
|
||||||
logReplace { "onTagStart, currentNode1: $currentNode" }
|
logReplace { "onTagStart, currentNode1: $currentNode" }
|
||||||
currentNode = if (tag.namespace != null) {
|
|
||||||
document.createElementNS(tag.namespace, tag.tagName)
|
|
||||||
} else {
|
|
||||||
document.createElement(tag.tagName)
|
|
||||||
}
|
|
||||||
|
|
||||||
logReplace { "onTagStart, currentElement1.1: $currentNode" }
|
logReplace { "onTagStart, currentElement1.1: $currentNode" }
|
||||||
currentPosition.currentParent().appendChild(currentNode!!)
|
currentPosition.currentParent().appendChild(currentNode!!)
|
||||||
} else if (
|
} else {
|
||||||
!currentNode?.asElement()?.tagName.equals(tag.tagName, true) ||
|
logReplace {
|
||||||
(
|
"onTagStart, currentElement, namespace: ${currentNode?.asElement()?.namespaceURI} -> ${tag.namespace}"
|
||||||
tag.namespace != null &&
|
}
|
||||||
!currentNode?.asElement()?.namespaceURI.equals(tag.namespace, true)
|
logReplace {
|
||||||
)
|
"onTagStart, currentElement, replace: ${currentNode?.asElement()?.tagName} -> ${tag.tagName}"
|
||||||
) {
|
}
|
||||||
logReplace {
|
|
||||||
"onTagStart, currentElement, namespace: ${currentNode?.asElement()?.namespaceURI} -> ${tag.namespace}"
|
|
||||||
}
|
|
||||||
logReplace {
|
|
||||||
"onTagStart, currentElement, replace: ${currentNode?.asElement()?.tagName} -> ${tag.tagName}"
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = if (tag.namespace != null) {
|
currentPosition.replace(currentNode!!)
|
||||||
document.createElementNS(tag.namespace, tag.tagName)
|
|
||||||
} else {
|
|
||||||
document.createElement(tag.tagName)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPosition.replace(currentNode!!)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentElement = currentNode as? Element ?: currentElement
|
currentElement = currentNode as? Element ?: currentElement
|
||||||
@@ -144,15 +125,8 @@ class HtmlBuilder(
|
|||||||
firstTag = false
|
firstTag = false
|
||||||
}
|
}
|
||||||
|
|
||||||
currentElement?.clearKompEvents()
|
|
||||||
|
|
||||||
// if currentElement = checkbox make sure it's cleared
|
|
||||||
(currentElement as? HTMLInputElement)?.checked = false
|
|
||||||
|
|
||||||
currentPosition.lastOrNull()?.setAttr?.clear()
|
|
||||||
for (entry in tag.attributesEntries) {
|
for (entry in tag.attributesEntries) {
|
||||||
currentElement!!.setKompAttribute(entry.key, entry.value)
|
currentElement?.setKompAttribute(entry.key, entry.value)
|
||||||
currentPosition.lastOrNull()?.setAttr?.add(entry.key)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,11 +155,10 @@ class HtmlBuilder(
|
|||||||
checkTag("onTagAttributeChange", tag)
|
checkTag("onTagAttributeChange", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentElement?.setKompAttribute(attribute, value)
|
|
||||||
if (value == null || value.isEmpty()) {
|
if (value == null || value.isEmpty()) {
|
||||||
currentPosition.currentPosition()?.setAttr?.remove(attribute)
|
currentElement?.clearKompAttribute(attribute)
|
||||||
} else {
|
} else {
|
||||||
currentPosition.currentPosition()?.setAttr?.add(attribute)
|
currentElement?.setKompAttribute(attribute, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,25 +195,6 @@ class HtmlBuilder(
|
|||||||
checkTag("onTagEnd", tag)
|
checkTag("onTagEnd", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentElement != null) {
|
|
||||||
val setAttrs: Set<String> = currentPosition.currentPosition()?.setAttr ?: setOf()
|
|
||||||
|
|
||||||
// remove attributes that where not set
|
|
||||||
val element = currentElement
|
|
||||||
if (element?.hasAttributes() == true) {
|
|
||||||
for (index in 0 until element.attributes.length) {
|
|
||||||
val attribute = element.attributes[index]
|
|
||||||
if (attribute?.name != null) {
|
|
||||||
val attr = attribute.name
|
|
||||||
|
|
||||||
if (!setAttrs.contains(attr)) {
|
|
||||||
element.setKompAttribute(attr, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPosition.pop()
|
currentPosition.pop()
|
||||||
|
|
||||||
currentNode = currentPosition.currentElement()
|
currentNode = currentPosition.currentElement()
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class TestClassUpdate {
|
|||||||
Komponent.create(div, classComponent)
|
Komponent.create(div, classComponent)
|
||||||
|
|
||||||
// Verify initial state - should have the class
|
// Verify initial state - should have the class
|
||||||
val contentDiv = div.querySelector("div")
|
var contentDiv = div.querySelector("div")
|
||||||
println("[DEBUG_LOG] Initial DOM: ${div.printTree()}")
|
println("[DEBUG_LOG] Initial DOM: ${div.printTree()}")
|
||||||
assertTrue(contentDiv?.classList?.contains("test-class") ?: false, "Div should have the class initially")
|
assertTrue(contentDiv?.classList?.contains("test-class") ?: false, "Div should have the class initially")
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ class TestClassUpdate {
|
|||||||
classComponent.requestImmediateUpdate()
|
classComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the class was removed
|
// Verify the class was removed
|
||||||
|
contentDiv = div.querySelector("div")
|
||||||
println("[DEBUG_LOG] After class removal: ${div.printTree()}")
|
println("[DEBUG_LOG] After class removal: ${div.printTree()}")
|
||||||
assertFalse(contentDiv?.classList?.contains("test-class") ?: true, "Class should be removed after update")
|
assertFalse(contentDiv?.classList?.contains("test-class") ?: true, "Class should be removed after update")
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class TestClassUpdate {
|
|||||||
classComponent.requestImmediateUpdate()
|
classComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the class was added back
|
// Verify the class was added back
|
||||||
|
contentDiv = div.querySelector("div")
|
||||||
println("[DEBUG_LOG] After class added back: ${div.printTree()}")
|
println("[DEBUG_LOG] After class added back: ${div.printTree()}")
|
||||||
assertTrue(contentDiv?.classList?.contains("test-class") ?: false, "Class should be added back")
|
assertTrue(contentDiv?.classList?.contains("test-class") ?: false, "Class should be added back")
|
||||||
|
|
||||||
@@ -63,6 +65,7 @@ class TestClassUpdate {
|
|||||||
classComponent.requestImmediateUpdate()
|
classComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the class was changed
|
// Verify the class was changed
|
||||||
|
contentDiv = div.querySelector("div")
|
||||||
println("[DEBUG_LOG] After class name change: ${div.printTree()}")
|
println("[DEBUG_LOG] After class name change: ${div.printTree()}")
|
||||||
assertFalse(contentDiv?.classList?.contains("test-class") ?: true, "Old class should be removed")
|
assertFalse(contentDiv?.classList?.contains("test-class") ?: true, "Old class should be removed")
|
||||||
assertTrue(contentDiv?.classList?.contains("new-class") ?: false, "New class should be added")
|
assertTrue(contentDiv?.classList?.contains("new-class") ?: false, "New class should be added")
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ class TestInsert {
|
|||||||
tableComponent.addRow("First Row")
|
tableComponent.addRow("First Row")
|
||||||
|
|
||||||
// Verify the row was added
|
// Verify the row was added
|
||||||
val rowsAfterFirstInsert = table.querySelectorAll("tr")
|
val rowsAfterFirstInsert = div.querySelector("table")?.querySelectorAll("tr")
|
||||||
assertEquals(1, rowsAfterFirstInsert.length, "Table should have one row after insertion")
|
assertEquals(1, rowsAfterFirstInsert?.length, "Table should have one row after insertion")
|
||||||
val firstRowCell = table.querySelector("tr td")
|
val firstRowCell = div.querySelector("table")?.querySelector("tr td")
|
||||||
assertNotNull(firstRowCell, "First row cell should exist")
|
assertNotNull(firstRowCell, "First row cell should exist")
|
||||||
assertEquals("First Row", firstRowCell.textContent, "Row content should match")
|
assertEquals("First Row", firstRowCell.textContent, "Row content should match")
|
||||||
|
|
||||||
@@ -87,12 +87,12 @@ class TestInsert {
|
|||||||
tableComponent.addRow("Second Row")
|
tableComponent.addRow("Second Row")
|
||||||
|
|
||||||
// Verify both rows are present
|
// Verify both rows are present
|
||||||
val rowsAfterSecondInsert = table.querySelectorAll("tr")
|
val rowsAfterSecondInsert = div.querySelector("table")?.querySelectorAll("tr")
|
||||||
assertEquals(2, rowsAfterSecondInsert.length, "Table should have two rows after second insertion")
|
assertEquals(2, rowsAfterSecondInsert?.length, "Table should have two rows after second insertion")
|
||||||
val allCells = table.querySelectorAll("tr td")
|
val allCells = div.querySelector("table")?.querySelectorAll("tr td")
|
||||||
assertEquals(2, allCells.length, "Table should have two cells")
|
assertEquals(2, allCells?.length, "Table should have two cells")
|
||||||
assertEquals("First Row", allCells.item(0)?.textContent, "First row content should match")
|
assertEquals("First Row", allCells?.item(0)?.textContent, "First row content should match")
|
||||||
assertEquals("Second Row", allCells.item(1)?.textContent, "Second row content should match")
|
assertEquals("Second Row", allCells?.item(1)?.textContent, "Second row content should match")
|
||||||
|
|
||||||
// Print the DOM tree for debugging
|
// Print the DOM tree for debugging
|
||||||
println("Table DOM: ${div.printTree()}")
|
println("Table DOM: ${div.printTree()}")
|
||||||
|
|||||||
@@ -12,57 +12,68 @@ import kotlin.test.assertNull
|
|||||||
* Test class for verifying style attribute updates and removals
|
* Test class for verifying style attribute updates and removals
|
||||||
*/
|
*/
|
||||||
class StyleKomponent : Komponent() {
|
class StyleKomponent : Komponent() {
|
||||||
var includeStyle = true
|
var includeStyle = true
|
||||||
var styleValue = "color: red;"
|
var styleValue = "color: red;"
|
||||||
|
|
||||||
override fun HtmlBuilder.render() {
|
override fun HtmlBuilder.render() {
|
||||||
div {
|
div {
|
||||||
if (includeStyle) {
|
if (includeStyle) {
|
||||||
style = styleValue
|
style = styleValue
|
||||||
}
|
}
|
||||||
+"Content"
|
+"Content"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestStyleUpdate {
|
class TestStyleUpdate {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testStyleRemoval() {
|
fun testStyleRemoval() {
|
||||||
// Create a test component
|
// Create a test component
|
||||||
val styleComponent = StyleKomponent()
|
val styleComponent = StyleKomponent()
|
||||||
val div = document.createElement("div") as HTMLDivElement
|
val div = document.createElement("div") as HTMLDivElement
|
||||||
|
|
||||||
// Render it
|
// Render it
|
||||||
Komponent.create(div, styleComponent)
|
Komponent.create(div, styleComponent)
|
||||||
|
|
||||||
// Verify initial state - should have the style
|
// Verify initial state - should have the style
|
||||||
val contentDiv = div.querySelector("div")
|
var contentDiv = div.querySelector("div")
|
||||||
println("[DEBUG_LOG] Initial DOM: ${div.printTree()}")
|
println("[DEBUG_LOG] Initial DOM: ${div.printTree()}")
|
||||||
assertEquals("color: red;", contentDiv?.getAttribute("style"), "Div should have the style initially")
|
assertEquals(
|
||||||
|
"color: red;",
|
||||||
|
contentDiv?.getAttribute("style"),
|
||||||
|
"Div should have the style initially"
|
||||||
|
)
|
||||||
|
|
||||||
// Update to remove the style
|
// Update to remove the style
|
||||||
styleComponent.includeStyle = false
|
styleComponent.includeStyle = false
|
||||||
styleComponent.requestImmediateUpdate()
|
styleComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the style was removed
|
// Verify the style was removed
|
||||||
println("[DEBUG_LOG] After style removal: ${div.printTree()}")
|
contentDiv = div.querySelector("div")
|
||||||
assertNull(contentDiv?.getAttribute("style"), "Style should be removed after update")
|
println("[DEBUG_LOG] After style removal: ${div.printTree()}")
|
||||||
|
assertNull(contentDiv?.getAttribute("style"), "Style should be removed after update")
|
||||||
|
|
||||||
// Add the style back
|
// Add the style back
|
||||||
styleComponent.includeStyle = true
|
styleComponent.includeStyle = true
|
||||||
styleComponent.requestImmediateUpdate()
|
styleComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the style was added back
|
// Verify the style was added back
|
||||||
println("[DEBUG_LOG] After style added back: ${div.printTree()}")
|
contentDiv = div.querySelector("div")
|
||||||
assertEquals("color: red;", contentDiv?.getAttribute("style"), "Style should be added back")
|
println("[DEBUG_LOG] After style added back: ${div.printTree()}")
|
||||||
|
assertEquals("color: red;", contentDiv?.getAttribute("style"), "Style should be added back")
|
||||||
|
|
||||||
// Change the style value
|
// Change the style value
|
||||||
styleComponent.styleValue = "color: blue;"
|
styleComponent.styleValue = "color: blue;"
|
||||||
styleComponent.requestImmediateUpdate()
|
styleComponent.requestImmediateUpdate()
|
||||||
|
|
||||||
// Verify the style was changed
|
// Verify the style was changed
|
||||||
println("[DEBUG_LOG] After style value change: ${div.printTree()}")
|
contentDiv = div.querySelector("div")
|
||||||
assertEquals("color: blue;", contentDiv?.getAttribute("style"), "Style should be updated to new value")
|
println("[DEBUG_LOG] After style value change: ${div.printTree()}")
|
||||||
}
|
assertEquals(
|
||||||
|
"color: blue;",
|
||||||
|
contentDiv?.getAttribute("style"),
|
||||||
|
"Style should be updated to new value"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user