Dim diff option
This commit is contained in:
82
build.gradle
82
build.gradle
@@ -1,82 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
ext.kotlin_version = '1.3.70'
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "http://nexus.astraeus.nl/nexus/content/groups/public"
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("org.jetbrains.kotlin.js") version "1.3.70"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'idea'
|
|
||||||
apply plugin: 'maven'
|
|
||||||
apply plugin: 'maven-publish'
|
|
||||||
|
|
||||||
group 'nl.astraeus'
|
|
||||||
version '0.1.17-SNAPSHOT'
|
|
||||||
/*
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
target {
|
|
||||||
browser {
|
|
||||||
webpackTask {
|
|
||||||
output.libraryTarget = "umd"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileKotlinJs.kotlinOptions.moduleKind = "umd"
|
|
||||||
*/
|
|
||||||
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
name = "komp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "http://nexus.astraeus.nl/nexus/content/groups/public"
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
ext {
|
|
||||||
kotlin_version = '1.3.70'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
|
||||||
compile 'org.jetbrains.kotlinx:kotlinx-html-js:0.7.1'
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadArchives {
|
|
||||||
//println 'user: ' + nexusUsername
|
|
||||||
repositories {
|
|
||||||
mavenDeployer {
|
|
||||||
repository(url: "http://nexus.astraeus.nl/nexus/content/repositories/releases") {
|
|
||||||
authentication(userName: nexusUsername, password: nexusPassword)
|
|
||||||
}
|
|
||||||
snapshotRepository(url: "http://nexus.astraeus.nl/nexus/content/repositories/snapshots") {
|
|
||||||
authentication(userName: nexusUsername, password: nexusPassword)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
compileKotlin2Js {
|
|
||||||
kotlinOptions.sourceMap = true
|
|
||||||
kotlinOptions.sourceMapEmbedSources = "always"
|
|
||||||
|
|
||||||
// remaining configuration options
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
77
build.gradle.kts
Normal file
77
build.gradle.kts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform") version "1.4-M2-eap-68"
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "nl.astraeus"
|
||||||
|
version = "0.1.20-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url = uri("https://dl.bintray.com/kotlin/kotlin-dev")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
/* Targets configuration omitted.
|
||||||
|
* To find out how to configure the targets, please follow the link:
|
||||||
|
* https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets */
|
||||||
|
js {
|
||||||
|
browser {
|
||||||
|
//produceKotlinLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
|
||||||
|
//implementation("org.jetbrains.kotlinx:kotlinx-html:0.7.2-build-1711")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jsMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
|
||||||
|
api("org.jetbrains.kotlinx:kotlinx-html-js:0.7.2-build-1716")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "releases"
|
||||||
|
// change to point to your repo, e.g. http://my.org/repo
|
||||||
|
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/releases")
|
||||||
|
credentials {
|
||||||
|
val nexusUsername: String by project
|
||||||
|
val nexusPassword: String by project
|
||||||
|
|
||||||
|
username = nexusUsername
|
||||||
|
password = nexusPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "snapshots"
|
||||||
|
// change to point to your repo, e.g. http://my.org/repo
|
||||||
|
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/snapshots")
|
||||||
|
credentials {
|
||||||
|
val nexusUsername: String by project
|
||||||
|
val nexusPassword: String by project
|
||||||
|
|
||||||
|
username = nexusUsername
|
||||||
|
password = nexusPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publications {
|
||||||
|
val kotlinMultiplatform by getting {
|
||||||
|
//artifactId = "kotlin-css-generator"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
komp.iml
33
komp.iml
@@ -1,41 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.id="komp" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="nl.astraeus" external.system.module.version="0.1.17-SNAPSHOT" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="komp" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="nl.astraeus" external.system.module.version="0.1.20-SNAPSHOT" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="kotlin-language" name="Kotlin">
|
|
||||||
<configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false">
|
|
||||||
<testOutputPath>$MODULE_DIR$/build/classes/kotlin/test/komp_test.js</testOutputPath>
|
|
||||||
<compilerSettings />
|
|
||||||
<compilerArguments>
|
|
||||||
<option name="outputFile" value="$MODULE_DIR$/build/classes/kotlin/main/komp.js" />
|
|
||||||
<option name="noStdlib" value="true" />
|
|
||||||
<option name="sourceMap" value="true" />
|
|
||||||
<option name="sourceMapEmbedSources" value="always" />
|
|
||||||
<option name="metaInfo" value="true" />
|
|
||||||
<option name="target" value="v5" />
|
|
||||||
<option name="main" value="call" />
|
|
||||||
<option name="languageVersion" value="1.3" />
|
|
||||||
<option name="apiVersion" value="1.3" />
|
|
||||||
<option name="pluginOptions">
|
|
||||||
<array />
|
|
||||||
</option>
|
|
||||||
<option name="pluginClasspaths">
|
|
||||||
<array />
|
|
||||||
</option>
|
|
||||||
<option name="errors">
|
|
||||||
<ArgumentParseErrors />
|
|
||||||
</option>
|
|
||||||
</compilerArguments>
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/out" />
|
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Kotlin SDK" jdkType="KotlinSDK" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
5
komp.ipr
5
komp.ipr
@@ -27,6 +27,9 @@
|
|||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="1.8" />
|
||||||
|
</component>
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
<file url="PROJECT" charset="UTF-8" />
|
<file url="PROJECT" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
@@ -218,7 +221,7 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/komp_test.iml" filepath="$PROJECT_DIR$/komp_test.iml" group="komp" />
|
<module fileurl="file://$PROJECT_DIR$/komp_test.iml" filepath="$PROJECT_DIR$/komp_test.iml" group="komp" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/classes" />
|
<output url="file://$PROJECT_DIR$/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
|
|||||||
@@ -39,6 +39,17 @@
|
|||||||
<content url="file://$MODULE_DIR$/src/test/resources" />
|
<content url="file://$MODULE_DIR$/src/test/resources" />
|
||||||
<orderEntry type="jdk" jdkName="Kotlin SDK" jdkType="KotlinSDK" />
|
<orderEntry type="jdk" jdkName="Kotlin SDK" jdkType="KotlinSDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module" module-name="komp_main" scope="TEST" />
|
||||||
|
<orderEntry type="module-library" scope="TEST">
|
||||||
|
<library>
|
||||||
|
<CLASSES>
|
||||||
|
<root url="file://$MODULE_DIR$/build/classes/kotlin/main" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</orderEntry>
|
||||||
|
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.3.70" level="project" />
|
||||||
<orderEntry type="module-library" scope="RUNTIME">
|
<orderEntry type="module-library" scope="RUNTIME">
|
||||||
<library>
|
<library>
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
@@ -48,45 +59,9 @@
|
|||||||
<SOURCES />
|
<SOURCES />
|
||||||
</library>
|
</library>
|
||||||
</orderEntry>
|
</orderEntry>
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.1" level="project" />
|
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.70" level="project" />
|
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.1" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.1" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.3.70" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.70" level="project" />
|
||||||
<orderEntry type="module-library" scope="TEST">
|
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.1" level="project" />
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="file://$MODULE_DIR$/build/classes/kotlin/main" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module-library" scope="TEST">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="file://$MODULE_DIR$/build/classes/kotlin/main" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.3.70/41513becdc85a89799b74028a81c39c364ba3465/kotlin-stdlib-js-1.3.70.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.1/f3a744916effcbe728d38e4bfd732f9694d18fa9/kotlinx-html-js-0.7.1.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.70/3fa8dd6c896d635e78201e5e811545f3846dec04/kotlin-stdlib-common-1.3.70.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.1/26651a49fdc0e6abf8a61182b01d6bb0a6bb427e/kotlinx-html-common-0.7.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
<orderEntry type="module" module-name="komp_main" scope="TEST" />
|
|
||||||
<orderEntry type="module-library" scope="RUNTIME">
|
|
||||||
<library>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.1/f3a744916effcbe728d38e4bfd732f9694d18fa9/kotlinx-html-js-0.7.1.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.3.70/41513becdc85a89799b74028a81c39c364ba3465/kotlin-stdlib-js-1.3.70.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.70/3fa8dd6c896d635e78201e5e811545f3846dec04/kotlin-stdlib-common-1.3.70.jar!/" />
|
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.1/26651a49fdc0e6abf8a61182b01d6bb0a6bb427e/kotlinx-html-common-0.7.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</orderEntry>
|
|
||||||
</component>
|
</component>
|
||||||
<component name="TestModuleProperties" production-module="komp_main" />
|
<component name="TestModuleProperties" production-module="komp_main" />
|
||||||
</module>
|
</module>
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
rootProject.name = 'komp'
|
|
||||||
|
|
||||||
enableFeaturePreview('GRADLE_METADATA')
|
|
||||||
16
settings.gradle.kts
Normal file
16
settings.gradle.kts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
|
||||||
|
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-dev") }
|
||||||
|
|
||||||
|
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
|
||||||
|
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
maven { setUrl("https://plugins.gradle.org/m2/") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "komp"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
195
src/jsMain/kotlin/nl/astraeus/komp/DiffPatch.kt
Normal file
195
src/jsMain/kotlin/nl/astraeus/komp/DiffPatch.kt
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
package nl.astraeus.komp
|
||||||
|
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
|
import org.w3c.dom.Node
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import org.w3c.dom.get
|
||||||
|
|
||||||
|
object DiffPatch {
|
||||||
|
|
||||||
|
fun updateNode(oldNode: Node, newNode: Node): Node {
|
||||||
|
if (oldNode is HTMLElement && newNode is HTMLElement) {
|
||||||
|
if (oldNode.nodeName == newNode.nodeName) {
|
||||||
|
if (oldNode.getAttribute("data-komp-hash") != null &&
|
||||||
|
oldNode.getAttribute("data-komp-hash") == newNode.getAttribute("data-komp-hash")) {
|
||||||
|
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Skip node, hash equals", oldNode, newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldNode
|
||||||
|
} else {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Update attributes", oldNode.innerHTML, newNode.innerHTML)
|
||||||
|
}
|
||||||
|
updateAttributes(oldNode, newNode);
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Update children", oldNode.innerHTML, newNode.innerHTML)
|
||||||
|
}
|
||||||
|
updateChildren(oldNode, newNode)
|
||||||
|
updateEvents(oldNode, newNode)
|
||||||
|
return oldNode
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Replace node ee", oldNode.innerHTML, newNode.innerHTML)
|
||||||
|
}
|
||||||
|
replaceNode(oldNode, newNode)
|
||||||
|
return newNode
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (oldNode.nodeType == newNode.nodeType && oldNode.nodeType == 3.toShort()) {
|
||||||
|
if (oldNode.textContent != newNode.textContent) {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Updating text content", oldNode, newNode)
|
||||||
|
}
|
||||||
|
oldNode.textContent = newNode.textContent
|
||||||
|
return oldNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Replace node", oldNode, newNode)
|
||||||
|
}
|
||||||
|
replaceNode(oldNode, newNode)
|
||||||
|
return newNode
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAttributes(oldNode: HTMLElement, newNode: HTMLElement) {
|
||||||
|
// removed attributes
|
||||||
|
for (index in 0 until oldNode.attributes.length) {
|
||||||
|
val attr = oldNode.attributes[index]
|
||||||
|
|
||||||
|
if (attr != null && newNode.attributes[attr.name] == null) {
|
||||||
|
oldNode.removeAttribute(attr.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index in 0 until newNode.attributes.length) {
|
||||||
|
val attr = newNode.attributes[index]
|
||||||
|
|
||||||
|
if (attr != null) {
|
||||||
|
val oldAttr = oldNode.attributes[attr.name]
|
||||||
|
|
||||||
|
if (oldAttr == null || oldAttr.value != attr.value) {
|
||||||
|
oldNode.setAttribute(attr.name, attr.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateChildren(oldNode: HTMLElement, newNode: HTMLElement) {
|
||||||
|
// todo: add 1 look ahead/back
|
||||||
|
var oldIndex = 0
|
||||||
|
var newIndex = 0
|
||||||
|
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("updateChildren old/new count", oldNode.childNodes.length, newNode.childNodes.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
while(newIndex < newNode.childNodes.length) {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log(">>> updateChildren old/new count", oldNode.childNodes, newNode.childNodes)
|
||||||
|
console.log("Update Old/new", oldIndex, newIndex)
|
||||||
|
}
|
||||||
|
val newChildNode = newNode.childNodes[newIndex]
|
||||||
|
|
||||||
|
if (oldIndex < oldNode.childNodes.length) {
|
||||||
|
val oldChildNode = oldNode.childNodes[oldIndex]
|
||||||
|
|
||||||
|
if (oldChildNode != null && newChildNode != null) {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Update node Old/new", oldChildNode, newChildNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNode(oldChildNode, newChildNode)
|
||||||
|
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("--- Updated Old/new", oldNode.children, newNode.children)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Null node", oldChildNode, newChildNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Append Old/new/node", oldIndex, newIndex, newChildNode)
|
||||||
|
}
|
||||||
|
oldNode.append(newChildNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("<<< Updated Old/new", oldNode.children, newNode.children)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldIndex++
|
||||||
|
newIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
while(oldIndex < oldNode.childNodes.length) {
|
||||||
|
oldNode.childNodes[oldIndex]?.also {
|
||||||
|
if (Komponent.logReplaceEvent) {
|
||||||
|
console.log("Remove old node", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldNode.removeChild(it)
|
||||||
|
}
|
||||||
|
oldIndex++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateEvents(oldNode: HTMLElement, newNode: HTMLElement) {
|
||||||
|
val oldEvents = mutableListOf<String>()
|
||||||
|
oldEvents.addAll((oldNode.getAttribute("data-komp-events") ?: "").split(","))
|
||||||
|
|
||||||
|
val newEvents = (newNode.getAttribute("data-komp-events") ?: "").split(",")
|
||||||
|
|
||||||
|
for (event in newEvents) {
|
||||||
|
if (event.isNotBlank()) {
|
||||||
|
val oldNodeEvent = oldNode.asDynamic()["event-$event"]
|
||||||
|
val newNodeEvent = newNode.asDynamic()["event-$event"]
|
||||||
|
if (oldNodeEvent != null) {
|
||||||
|
oldNode.removeEventListener(event, oldNodeEvent as ((Event) -> Unit), null)
|
||||||
|
}
|
||||||
|
if (newNodeEvent != null) {
|
||||||
|
oldNode.addEventListener(event, newNodeEvent as ((Event) -> Unit), null)
|
||||||
|
oldNode.asDynamic()["event-$event"] = newNodeEvent
|
||||||
|
}
|
||||||
|
oldEvents.remove(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (event in oldEvents) {
|
||||||
|
if (event.isNotBlank()) {
|
||||||
|
val oldNodeEvent = oldNode.asDynamic()["event-$event"]
|
||||||
|
if (oldNodeEvent != null) {
|
||||||
|
oldNode.removeEventListener(event, oldNodeEvent as ((Event) -> Unit), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode.getAttribute("data-komp-events")?.also {
|
||||||
|
oldNode.setAttribute("data-komp-events", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceNode(oldNode: Node, newNode: Node) {
|
||||||
|
oldNode.parentNode?.also { parent ->
|
||||||
|
val clone = newNode.cloneNode(true)
|
||||||
|
if (newNode is HTMLElement) {
|
||||||
|
val events = (newNode.getAttribute("data-komp-events") ?: "").split(",")
|
||||||
|
for (event in events) {
|
||||||
|
val foundEvent = newNode.asDynamic()["event-$event"]
|
||||||
|
if (foundEvent != null) {
|
||||||
|
clone.addEventListener(event, foundEvent as ((Event) -> Unit), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.replaceChild(clone, oldNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
package nl.astraeus.komp
|
package nl.astraeus.komp
|
||||||
|
|
||||||
import kotlinx.html.DefaultUnsafe
|
import kotlinx.html.*
|
||||||
import kotlinx.html.Entities
|
import org.w3c.dom.*
|
||||||
import kotlinx.html.Tag
|
|
||||||
import kotlinx.html.TagConsumer
|
|
||||||
import kotlinx.html.Unsafe
|
|
||||||
import org.w3c.dom.Document
|
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import org.w3c.dom.Node
|
|
||||||
import org.w3c.dom.asList
|
|
||||||
import org.w3c.dom.css.CSSStyleDeclaration
|
import org.w3c.dom.css.CSSStyleDeclaration
|
||||||
import org.w3c.dom.events.Event
|
import org.w3c.dom.events.Event
|
||||||
import kotlin.browser.document
|
import kotlin.browser.document
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline fun HTMLElement.setEvent(name: String, noinline callback : (Event) -> Unit) : Unit {
|
private inline fun HTMLElement.setEvent(name: String, noinline callback : (Event) -> Unit) : Unit {
|
||||||
asDynamic()[name] = callback
|
val eventName = if (name.startsWith("on")) { name.substring(2) } else { name }
|
||||||
|
addEventListener(eventName, callback, null)
|
||||||
|
//asDynamic()[name] = callback
|
||||||
|
val events = getAttribute("data-komp-events") ?: ""
|
||||||
|
|
||||||
|
setAttribute("data-komp-events", if (events.isBlank()) { eventName } else { "$events,$eventName" })
|
||||||
|
asDynamic()["event-$eventName"] = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HtmlConsumer : TagConsumer<HTMLElement> {
|
interface HtmlConsumer : TagConsumer<HTMLElement> {
|
||||||
@@ -73,13 +72,27 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTagEnd(tag: Tag) {
|
override fun onTagEnd(tag: Tag) {
|
||||||
|
var hash = 0
|
||||||
if (path.isEmpty() || path.last().tagName.toLowerCase() != tag.tagName.toLowerCase()) {
|
if (path.isEmpty() || path.last().tagName.toLowerCase() != tag.tagName.toLowerCase()) {
|
||||||
throw IllegalStateException("We haven't entered tag ${tag.tagName} but trying to leave")
|
throw IllegalStateException("We haven't entered tag ${tag.tagName} but trying to leave")
|
||||||
}
|
}
|
||||||
|
|
||||||
val element = path.last()
|
val element = path.last()
|
||||||
|
|
||||||
|
for (index in 0 until element.childNodes.length) {
|
||||||
|
val child = element.childNodes[index]
|
||||||
|
if (child is HTMLElement) {
|
||||||
|
|
||||||
|
hash = hash * 37 + (child.getAttribute("data-komp-hash")?.toInt() ?: 0)
|
||||||
|
} else {
|
||||||
|
hash = hash * 37 + (child?.textContent?.hashCode() ?: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tag.attributesEntries.forEach {
|
tag.attributesEntries.forEach {
|
||||||
|
hash = hash * 37 + it.key.hashCode()
|
||||||
|
hash = hash * 37 + it.value.hashCode()
|
||||||
|
|
||||||
if (it.key == "class") {
|
if (it.key == "class") {
|
||||||
val classes = it.value.split(Regex("\\s+"))
|
val classes = it.value.split(Regex("\\s+"))
|
||||||
val classNames = StringBuilder()
|
val classNames = StringBuilder()
|
||||||
@@ -121,6 +134,8 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element.setAttribute("data-komp-hash", hash.toString())
|
||||||
|
|
||||||
lastLeaved = path.removeAt(path.lastIndex)
|
lastLeaved = path.removeAt(path.lastIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +33,11 @@ class DummyKomponent: Komponent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class UpdateStrategy {
|
||||||
|
REPLACE,
|
||||||
|
DOM_DIFF
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Komponent {
|
abstract class Komponent {
|
||||||
var element: Node? = null
|
var element: Node? = null
|
||||||
val declaredStyles: MutableMap<String, CSSStyleDeclaration> = HashMap()
|
val declaredStyles: MutableMap<String, CSSStyleDeclaration> = HashMap()
|
||||||
@@ -68,10 +73,18 @@ abstract class Komponent {
|
|||||||
val newElement = create()
|
val newElement = create()
|
||||||
|
|
||||||
if (oldElement != null) {
|
if (oldElement != null) {
|
||||||
|
if (updateStrategy == UpdateStrategy.REPLACE) {
|
||||||
if (logReplaceEvent) {
|
if (logReplaceEvent) {
|
||||||
console.log("Replacing", oldElement, newElement)
|
console.log("Replacing", oldElement, newElement)
|
||||||
}
|
}
|
||||||
oldElement.parentNode?.replaceChild(newElement, oldElement)
|
oldElement.parentNode?.replaceChild(newElement, oldElement)
|
||||||
|
element = newElement
|
||||||
|
} else {
|
||||||
|
if (logReplaceEvent) {
|
||||||
|
console.log("DomDiffing", oldElement, newElement)
|
||||||
|
}
|
||||||
|
element = DiffPatch.updateNode(oldElement, newElement)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +104,7 @@ abstract class Komponent {
|
|||||||
companion object {
|
companion object {
|
||||||
var logRenderEvent = false
|
var logRenderEvent = false
|
||||||
var logReplaceEvent = false
|
var logReplaceEvent = false
|
||||||
|
var updateStrategy = UpdateStrategy.DOM_DIFF
|
||||||
|
|
||||||
fun create(parent: HTMLElement, component: Komponent, insertAsFirst: Boolean = false) {
|
fun create(parent: HTMLElement, component: Komponent, insertAsFirst: Boolean = false) {
|
||||||
val element = component.create()
|
val element = component.create()
|
||||||
@@ -102,4 +116,5 @@ abstract class Komponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Bla</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<script src="../../kotlin-js-min/main/kotlin.js"></script>
|
|
||||||
<script src="../../kotlin-js-min/main/kotlinx-html-js.js"></script>
|
|
||||||
<script src="../../kotlin-js-min/main/komp.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user