diff --git a/build.gradle b/build.gradle index 3c4ff56..d0de31e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'nl.astraeus' -version '0.1.5-SNAPSHOT' +version '0.1.6-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'kotlin-dce-js' diff --git a/build.gradle b/build.gradle index 3c4ff56..d0de31e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'nl.astraeus' -version '0.1.5-SNAPSHOT' +version '0.1.6-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'kotlin-dce-js' diff --git a/komp.iml b/komp.iml index e2040a8..b220706 100644 --- a/komp.iml +++ b/komp.iml @@ -34,9 +34,9 @@ - - - + + + diff --git a/build.gradle b/build.gradle index 3c4ff56..d0de31e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'nl.astraeus' -version '0.1.5-SNAPSHOT' +version '0.1.6-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'kotlin-dce-js' diff --git a/komp.iml b/komp.iml index e2040a8..b220706 100644 --- a/komp.iml +++ b/komp.iml @@ -34,9 +34,9 @@ - - - + + + diff --git a/src/main/kotlin/nl/astraeus/komp/KompElement.kt b/src/main/kotlin/nl/astraeus/komp/KompElement.kt index 92471ec..a1c79b6 100644 --- a/src/main/kotlin/nl/astraeus/komp/KompElement.kt +++ b/src/main/kotlin/nl/astraeus/komp/KompElement.kt @@ -4,6 +4,7 @@ import kotlinx.html.Tag import kotlinx.html.TagConsumer import kotlinx.html.Unsafe +import org.w3c.dom.HTMLElement import org.w3c.dom.Node import org.w3c.dom.events.Event import org.w3c.dom.get @@ -25,20 +26,16 @@ class KompElement( val type: ElementType, - val komponent: Komponent?, + val komponent: Komponent, var text: String, var attributes: MutableMap? = null, val children: MutableList? = null, val events: MutableMap Unit>? = null ) { - constructor(text: String, type: ElementType) : this( + constructor(komponent: Komponent, text: String, type: ElementType) : this( type, - if (type == ElementType.KOMPONENT) { - throw IllegalStateException("Type KOMPONENT not allowed in String constructor") - } else { - null - }, + komponent, text, if (type == ElementType.TAG) { HashMap() @@ -68,7 +65,7 @@ /* shallow equals check */ fun equals(other: KompElement): Boolean { - if (komponent != null) { + if (other.isKomponent() && isKomponent()) { val result = komponent == other.komponent if (!result && Komponent.logEquals) { console.log("!= komponent", this, other) @@ -129,18 +126,13 @@ ElementType.KOMPONENT -> { val komp = komponent - if (komp == null) { - throw IllegalStateException("komponent == null in type Komponent!") - } else { + val kompElement = komp.create() + val element = kompElement.create() - val kompElement = komp.create() - val element = kompElement.create() + komp.kompElement = kompElement + komp.element = element - komp.kompElement = kompElement - komp.element = element - - element - } + element } ElementType.TEXT -> document.createTextNode(text) ElementType.UNSAFE -> { @@ -179,7 +171,34 @@ } (attributes?.entries)?.forEach { entry -> - result.setAttribute(entry.key, entry.value) + if (entry.key == "class") { + val classes = entry.value.split(" ") + val classNames = StringBuilder() + + for (cls in classes) { + val cssStyle = komponent?.declaredStyles?.get(cls) + + if (cssStyle != null) { + if (result is HTMLElement) { + for (index in 0 until cssStyle.length) { + val propertyName = cssStyle.item(index) + result.style.setProperty(propertyName, cssStyle.getPropertyValue(propertyName)) + } + } + } else { + classNames.append(cls) + classNames.append(" ") + } + } + + if (result !is HTMLElement) { + result.setAttribute(entry.key, entry.value) + } else { + result.className = classNames.toString() + } + } else { + result.setAttribute(entry.key, entry.value) + } } (events?.entries)?.forEach { event -> @@ -262,7 +281,9 @@ } } -class KompConsumer : TagConsumer { +class KompConsumer( + val komponent: Komponent +) : TagConsumer { val stack = ArrayList() var currentTag: KompElement? = null @@ -280,7 +301,7 @@ override fun onTagContent(content: CharSequence) { //console.log("KC.onTagContent", content) - currentTag?.children?.add(KompElement(content.toString(), ElementType.TEXT)) + currentTag?.children?.add(KompElement(komponent, content.toString(), ElementType.TEXT)) } override fun onTagContentEntity(entity: Entities) { @@ -294,7 +315,7 @@ block.invoke(txt) //console.log("KC.onTagContentUnsafe", txt) - currentTag?.children?.add(KompElement(txt.text, ElementType.UNSAFE)) + currentTag?.children?.add(KompElement(komponent, txt.text, ElementType.UNSAFE)) } override fun onTagEnd(tag: Tag) { @@ -326,7 +347,7 @@ stack.add(this) } - currentTag = KompElement(tag.tagName, ElementType.TAG) + currentTag = KompElement(komponent, tag.tagName, ElementType.TAG) currentTag?.attributes = tag.attributes } diff --git a/build.gradle b/build.gradle index 3c4ff56..d0de31e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'nl.astraeus' -version '0.1.5-SNAPSHOT' +version '0.1.6-SNAPSHOT' apply plugin: 'kotlin2js' apply plugin: 'kotlin-dce-js' diff --git a/komp.iml b/komp.iml index e2040a8..b220706 100644 --- a/komp.iml +++ b/komp.iml @@ -34,9 +34,9 @@ - - - + + + diff --git a/src/main/kotlin/nl/astraeus/komp/KompElement.kt b/src/main/kotlin/nl/astraeus/komp/KompElement.kt index 92471ec..a1c79b6 100644 --- a/src/main/kotlin/nl/astraeus/komp/KompElement.kt +++ b/src/main/kotlin/nl/astraeus/komp/KompElement.kt @@ -4,6 +4,7 @@ import kotlinx.html.Tag import kotlinx.html.TagConsumer import kotlinx.html.Unsafe +import org.w3c.dom.HTMLElement import org.w3c.dom.Node import org.w3c.dom.events.Event import org.w3c.dom.get @@ -25,20 +26,16 @@ class KompElement( val type: ElementType, - val komponent: Komponent?, + val komponent: Komponent, var text: String, var attributes: MutableMap? = null, val children: MutableList? = null, val events: MutableMap Unit>? = null ) { - constructor(text: String, type: ElementType) : this( + constructor(komponent: Komponent, text: String, type: ElementType) : this( type, - if (type == ElementType.KOMPONENT) { - throw IllegalStateException("Type KOMPONENT not allowed in String constructor") - } else { - null - }, + komponent, text, if (type == ElementType.TAG) { HashMap() @@ -68,7 +65,7 @@ /* shallow equals check */ fun equals(other: KompElement): Boolean { - if (komponent != null) { + if (other.isKomponent() && isKomponent()) { val result = komponent == other.komponent if (!result && Komponent.logEquals) { console.log("!= komponent", this, other) @@ -129,18 +126,13 @@ ElementType.KOMPONENT -> { val komp = komponent - if (komp == null) { - throw IllegalStateException("komponent == null in type Komponent!") - } else { + val kompElement = komp.create() + val element = kompElement.create() - val kompElement = komp.create() - val element = kompElement.create() + komp.kompElement = kompElement + komp.element = element - komp.kompElement = kompElement - komp.element = element - - element - } + element } ElementType.TEXT -> document.createTextNode(text) ElementType.UNSAFE -> { @@ -179,7 +171,34 @@ } (attributes?.entries)?.forEach { entry -> - result.setAttribute(entry.key, entry.value) + if (entry.key == "class") { + val classes = entry.value.split(" ") + val classNames = StringBuilder() + + for (cls in classes) { + val cssStyle = komponent?.declaredStyles?.get(cls) + + if (cssStyle != null) { + if (result is HTMLElement) { + for (index in 0 until cssStyle.length) { + val propertyName = cssStyle.item(index) + result.style.setProperty(propertyName, cssStyle.getPropertyValue(propertyName)) + } + } + } else { + classNames.append(cls) + classNames.append(" ") + } + } + + if (result !is HTMLElement) { + result.setAttribute(entry.key, entry.value) + } else { + result.className = classNames.toString() + } + } else { + result.setAttribute(entry.key, entry.value) + } } (events?.entries)?.forEach { event -> @@ -262,7 +281,9 @@ } } -class KompConsumer : TagConsumer { +class KompConsumer( + val komponent: Komponent +) : TagConsumer { val stack = ArrayList() var currentTag: KompElement? = null @@ -280,7 +301,7 @@ override fun onTagContent(content: CharSequence) { //console.log("KC.onTagContent", content) - currentTag?.children?.add(KompElement(content.toString(), ElementType.TEXT)) + currentTag?.children?.add(KompElement(komponent, content.toString(), ElementType.TEXT)) } override fun onTagContentEntity(entity: Entities) { @@ -294,7 +315,7 @@ block.invoke(txt) //console.log("KC.onTagContentUnsafe", txt) - currentTag?.children?.add(KompElement(txt.text, ElementType.UNSAFE)) + currentTag?.children?.add(KompElement(komponent, txt.text, ElementType.UNSAFE)) } override fun onTagEnd(tag: Tag) { @@ -326,7 +347,7 @@ stack.add(this) } - currentTag = KompElement(tag.tagName, ElementType.TAG) + currentTag = KompElement(komponent, tag.tagName, ElementType.TAG) currentTag?.attributes = tag.attributes } diff --git a/src/main/kotlin/nl/astraeus/komp/Komponent.kt b/src/main/kotlin/nl/astraeus/komp/Komponent.kt index 8d1cbe4..eaa41bd 100644 --- a/src/main/kotlin/nl/astraeus/komp/Komponent.kt +++ b/src/main/kotlin/nl/astraeus/komp/Komponent.kt @@ -1,8 +1,11 @@ package nl.astraeus.komp import kotlinx.html.HtmlBlockTag +import org.w3c.dom.HTMLDivElement import org.w3c.dom.HTMLElement import org.w3c.dom.Node +import org.w3c.dom.css.CSSStyleDeclaration +import kotlin.browser.document fun HtmlBlockTag.include(component: Komponent) { val consumer = this.consumer @@ -19,48 +22,49 @@ abstract class Komponent { var element: Node? = null var kompElement: KompElement? = null - var rendered = false + val declaredStyles: MutableMap = HashMap() open fun create(): KompElement { - val result = render(KompConsumer()) + val result = render(KompConsumer(this)) return result } abstract fun render(consumer: KompConsumer): KompElement - open fun refresh(forceRefresh: Boolean = false) { - if (!rendered || forceRefresh) { - element?.let { element -> - if (logRenderEvent) { - console.log("Rendering", this) - } + open fun declareStyle(className: String, block: CSSStyleDeclaration.() -> Unit) { + val style = (document.createElement("div") as HTMLDivElement).style + block(style) + declaredStyles[className] = style + } - val newElement = create() - - val replacedElement = if (updateStrategy == UpdateStrategy.REPLACE) { - //val replacedElement = replaceNode(newElement, element) - - replaceNode(newElement, element) - } else if (kompElement != null) { - kompElement?.let { - DomDiffer.replaceDiff(it, newElement, element) - } - } else { - newElement.create() - } - - kompElement = newElement - this.element = replacedElement - rendered = true + open fun refresh() { + element?.let { element -> + if (logRenderEvent) { + console.log("Rendering", this) } - } else { - update() + + val newElement = create() + + val replacedElement = if (updateStrategy == UpdateStrategy.REPLACE) { + //val replacedElement = replaceNode(newElement, element) + + replaceNode(newElement, element) + } else if (kompElement != null) { + kompElement?.let { + DomDiffer.replaceDiff(it, newElement, element) + } + } else { + newElement.create() + } + + kompElement = newElement + this.element = replacedElement } } open fun update() { - refresh(true) + refresh() } override fun equals(other: Any?): Boolean { @@ -70,14 +74,12 @@ other as Komponent if (kompElement != other.kompElement) return false - if (rendered != other.rendered) return false return true } override fun hashCode(): Int { var result = kompElement?.hashCode() ?: 0 - result = 31 * result + rendered.hashCode() return result } @@ -91,7 +93,7 @@ fun replaceNode(newKomponent: KompElement, oldElement: Node): Node { val newElement = newKomponent.create() - if (Komponent.logReplaceEvent) { + if (logReplaceEvent) { console.log("Replace", oldElement, newElement) } @@ -110,7 +112,7 @@ fun removeElement(element: Node) { val parent = element.parentElement ?: throw IllegalArgumentException("Element has no parent!?") - if (Komponent.logReplaceEvent) { + if (logReplaceEvent) { console.log("Remove", element) }