12 Commits

Author SHA1 Message Date
963e934953 Fix svg/unsafe, add onBeforeUpdate, v. 0.5.6 2021-08-19 09:53:16 +02:00
0ccbe105b7 Fix memoize option, v. 0.5.5 2021-08-18 11:07:26 +02:00
dac465a161 Fixes 2021-07-11 13:29:34 +02:00
48708580ca Cleanup 2021-07-02 19:47:27 +02:00
1e6e34bec5 Do updates immediatly 2021-07-02 19:45:48 +02:00
fa6252832b Cleanup 2021-06-29 17:21:27 +02:00
d0442e785f VDom implementation 2021-04-05 17:21:45 +02:00
68fde339a8 Remove replace option 2021-03-31 16:17:01 +02:00
e87f7ba540 Fix events, fix per komponent hash 2021-03-31 16:01:42 +02:00
0a1ab1f326 Fix CI build 2021-02-10 14:18:44 +01:00
695a11efdb Fix build 2021-02-10 13:44:08 +01:00
66b3fb3c22 Merge remember branch, Update to 0.2.5-SNAPSHOT 2021-02-10 13:20:07 +01:00
14 changed files with 1001 additions and 841 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,6 @@
# Created by .ignore support plugin (hsz.mobi) # Created by .ignore support plugin (hsz.mobi)
build
.gradle
web/js/generated web/js/generated
gradle.properties gradle.properties
local.properties local.properties

View File

@@ -1,27 +1,23 @@
plugins { plugins {
kotlin("multiplatform") version "1.4.30" kotlin("multiplatform") version "1.5.21"
`maven-publish` `maven-publish`
} }
group = "nl.astraeus" group = "nl.astraeus"
version = "0.2.5-SNAPSHOT" version = "0.5.7-SNAPSHOT"
repositories { repositories {
mavenCentral() mavenCentral()
jcenter()
} }
kotlin { 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(BOTH) { js(BOTH) {
browser { browser {
//produceKotlinLibrary()
testTask { testTask {
useKarma { useKarma {
useChromeHeadless() useChromiumHeadless()
//useChromeHeadless()
} }
} }
} }
@@ -32,7 +28,7 @@ kotlin {
dependencies { dependencies {
implementation(kotlin("stdlib-common")) implementation(kotlin("stdlib-common"))
api("org.jetbrains.kotlinx:kotlinx-html-js:0.7.2") api("org.jetbrains.kotlinx:kotlinx-html-js:0.7.3")
} }
} }
val jsMain by getting { val jsMain by getting {
@@ -50,34 +46,34 @@ kotlin {
publishing { publishing {
repositories { repositories {
maven { if (project.properties["nexusUsername"] != null) {
name = "releases" maven {
// change to point to your repo, e.g. http://my.org/repo name = "releases"
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/releases") url = uri("https://nexus.astraeus.nl/nexus/content/repositories/releases")
credentials { credentials {
val nexusUsername: String by project val nexusUsername: String by project
val nexusPassword: String by project val nexusPassword: String by project
username = nexusUsername username = nexusUsername
password = nexusPassword password = nexusPassword
}
} }
} maven {
maven { name = "snapshots"
name = "snapshots" url = uri("https://nexus.astraeus.nl/nexus/content/repositories/snapshots")
// change to point to your repo, e.g. http://my.org/repo credentials {
url = uri("http://nexus.astraeus.nl/nexus/content/repositories/snapshots") val nexusUsername: String by project
credentials { val nexusPassword: String by project
val nexusUsername: String by project
val nexusPassword: String by project
username = nexusUsername username = nexusUsername
password = nexusPassword password = nexusPassword
}
} }
} else {
println("Publishing disabled properties not found.")
} }
} }
publications { publications {
val kotlinMultiplatform by getting { val kotlinMultiplatform by getting {}
//artifactId = "kotlin-css-generator"
}
} }
} }

View File

@@ -1,5 +1,5 @@
#Wed Mar 04 13:29:12 CET 2020 #Wed Mar 04 13:29:12 CET 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="komp:commonMain" 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.type="sourceSet" external.system.module.version="0.2.4-SNAPSHOT" type="JAVA_MODULE" version="4"> <module external.linked.project.id="komp:commonMain" 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.type="sourceSet" external.system.module.version="0.5.6-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="Common (experimental) " allPlatforms="JS []/JVM [1.6]/Native []/Native [general]" useProjectSettings="false" isTestModule="false" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-jsLegacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-jsIr/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin;/home/rnentjes/Development/komp/komp/src/commonMain/kotlin"> <configuration version="3" platform="Common (experimental) " allPlatforms="JS []/JVM [1.8]/Native []/Native [general]" useProjectSettings="false" isTestModule="false" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-js-legacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-js-ir/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin">
<newMppModelJpsModuleKind>SOURCE_SET_HOLDER</newMppModelJpsModuleKind> <newMppModelJpsModuleKind>SOURCE_SET_HOLDER</newMppModelJpsModuleKind>
<compilerSettings /> <compilerSettings />
<compilerArguments> <compilerArguments>
<option name="languageVersion" value="1.4" /> <option name="languageVersion" value="1.5" />
<option name="apiVersion" value="1.4" /> <option name="apiVersion" value="1.5" />
<option name="pluginOptions"> <option name="pluginOptions">
<array /> <array />
</option> </option>
<option name="pluginClasspaths"> <option name="pluginClasspaths">
<array> <array>
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.30/7d0085e5781847da84580d16239c1c4e0980bdb0/kotlin-scripting-jvm-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.5.21/8143908a15163e634fecb87013ed4a139170b032/kotlin-scripting-jvm-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.30/c7896c5c6b504f44e7cf9f5719d4393e20680666/kotlin-scripting-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.5.21/5d271f9e7e7191902f8c0d45c600f5b57a284036/kotlin-scripting-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.30/d10d1e10f47006ee08162dde039e38ac487de4ac/kotlin-stdlib-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.21/2f537cad7e9eeb9da73738c8812e1e4cf9b62e4e/kotlin-stdlib-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/bb9a3173350f55732416ee27956ea8f9b81f4dbb/kotlin-stdlib-common-1.4.30.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.30/b9c2a1fab9217623fc0fbadf6190e77eed6f054d/kotlin-script-runtime-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.21/96d49e89873fde985750af354b6eabb60cfa999b/kotlin-script-runtime-1.5.21.jar" />
</array> </array>
</option> </option>
<option name="multiPlatform" value="true" /> <option name="multiPlatform" value="true" />
@@ -32,7 +32,7 @@
<content url="file://$MODULE_DIR$/src/commonMain" /> <content url="file://$MODULE_DIR$/src/commonMain" />
<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="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.30" level="project" /> <orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.5.21" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.2" level="project" /> <orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.3" level="project" />
</component> </component>
</module> </module>

View File

@@ -1,28 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="komp:commonTest" 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.type="sourceSet" external.system.module.version="0.2.4-SNAPSHOT" type="JAVA_MODULE" version="4"> <module external.linked.project.id="komp:commonTest" 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.type="sourceSet" external.system.module.version="0.5.6-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="Common (experimental) " allPlatforms="JS []/JVM [1.6]/Native []/Native [general]" useProjectSettings="false" isTestModule="true" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-jsLegacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-jsIr/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin;/home/rnentjes/Development/komp/komp/src/commonMain/kotlin"> <configuration version="3" platform="Common (experimental) " allPlatforms="JS []/JVM [1.8]/Native []/Native [general]" useProjectSettings="false" isTestModule="true" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-js-legacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-js-ir/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin">
<newMppModelJpsModuleKind>SOURCE_SET_HOLDER</newMppModelJpsModuleKind> <newMppModelJpsModuleKind>SOURCE_SET_HOLDER</newMppModelJpsModuleKind>
<externalSystemTestTasks> <externalSystemTestTasks>
<externalSystemTestTask>jsLegacyBrowserTest|komp:jsTest|jsLegacy</externalSystemTestTask> <externalSystemTestTask>jsLegacyBrowserTest|komp:jsTest|jsLegacy</externalSystemTestTask>
</externalSystemTestTasks> </externalSystemTestTasks>
<compilerSettings /> <compilerSettings />
<compilerArguments> <compilerArguments>
<option name="languageVersion" value="1.4" /> <option name="languageVersion" value="1.5" />
<option name="apiVersion" value="1.4" /> <option name="apiVersion" value="1.5" />
<option name="pluginOptions"> <option name="pluginOptions">
<array /> <array />
</option> </option>
<option name="pluginClasspaths"> <option name="pluginClasspaths">
<array> <array>
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.30/7d0085e5781847da84580d16239c1c4e0980bdb0/kotlin-scripting-jvm-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.5.21/8143908a15163e634fecb87013ed4a139170b032/kotlin-scripting-jvm-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.30/c7896c5c6b504f44e7cf9f5719d4393e20680666/kotlin-scripting-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.5.21/5d271f9e7e7191902f8c0d45c600f5b57a284036/kotlin-scripting-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.30/d10d1e10f47006ee08162dde039e38ac487de4ac/kotlin-stdlib-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.21/2f537cad7e9eeb9da73738c8812e1e4cf9b62e4e/kotlin-stdlib-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/bb9a3173350f55732416ee27956ea8f9b81f4dbb/kotlin-stdlib-common-1.4.30.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.30/b9c2a1fab9217623fc0fbadf6190e77eed6f054d/kotlin-script-runtime-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.21/96d49e89873fde985750af354b6eabb60cfa999b/kotlin-script-runtime-1.5.21.jar" />
</array> </array>
</option> </option>
<option name="multiPlatform" value="true" /> <option name="multiPlatform" value="true" />
@@ -36,9 +36,9 @@
<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.commonMain" scope="TEST" /> <orderEntry type="module" module-name="komp.commonMain" scope="TEST" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.4.30" level="project" /> <orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.5.21" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.2" level="project" /> <orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.30" level="project" /> <orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.3" level="project" />
</component> </component>
<component name="TestModuleProperties" production-module="komp.commonMain" /> <component name="TestModuleProperties" production-module="komp.commonMain" />
</module> </module>

View File

@@ -1,5 +1,5 @@
<?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.2.4-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.5.6-SNAPSHOT" type="JAVA_MODULE" version="4">
<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$">

190
komp.ipr
View File

@@ -49,6 +49,60 @@
<element id="module-output" name="komp.jsMain" /> <element id="module-output" name="komp.jsMain" />
</root> </root>
</artifact> </artifact>
<artifact type="jar" name="komp-jslegacy-0.2.5-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.2.5-SNAPSHOT.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.3.0-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.3.0-SNAPSHOT.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.4.0-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.4.0-SNAPSHOT.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.4.1">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.4.1.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.5.1">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.5.1.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.5.2">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.5.2.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.5.3">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.5.3.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.5.4">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.5.4.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
<artifact type="jar" name="komp-jslegacy-0.5.6-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="komp-jslegacy-0.5.6-SNAPSHOT.jar">
<element id="module-output" name="komp.jsMain" />
</root>
</artifact>
</component> </component>
<component name="CheckStyle-IDEA"> <component name="CheckStyle-IDEA">
<option name="configuration"> <option name="configuration">
@@ -248,6 +302,80 @@
</group> </group>
</component> </component>
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" /> <component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
<component name="ProjectCodeStyleConfiguration">
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="140" />
<H2CodeStyleSettings version="6">
<option name="USE_GENERAL_STYLE" value="false" />
</H2CodeStyleSettings>
<H2CodeStyleSettings version="6">
<option name="USE_GENERAL_STYLE" value="false" />
</H2CodeStyleSettings>
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="5" />
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="50" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="99" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="99" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
<option name="ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS" value="true" />
<option name="ALIGN_CONSECUTIVE_ASSIGNMENTS" value="true" />
<option name="ALIGN_SUBSEQUENT_SIMPLE_METHODS" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="RESOURCE_LIST_WRAP" value="5" />
<option name="RESOURCE_LIST_LPAREN_ON_NEXT_LINE" value="true" />
<option name="RESOURCE_LIST_RPAREN_ON_NEXT_LINE" value="true" />
<option name="EXTENDS_LIST_WRAP" value="5" />
<option name="THROWS_LIST_WRAP" value="5" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="PARENTHESES_EXPRESSION_LPAREN_WRAP" value="true" />
<option name="PARENTHESES_EXPRESSION_RPAREN_WRAP" value="true" />
<option name="BINARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="FOR_STATEMENT_WRAP" value="5" />
<option name="FOR_STATEMENT_LPAREN_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="ASSERT_STATEMENT_WRAP" value="5" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="ENUM_CONSTANTS_WRAP" value="5" />
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/komp.iml" filepath="$PROJECT_DIR$/komp.iml" /> <module fileurl="file://$PROJECT_DIR$/komp.iml" filepath="$PROJECT_DIR$/komp.iml" />
@@ -255,6 +383,8 @@
<module fileurl="file://$PROJECT_DIR$/komp.commonTest.iml" filepath="$PROJECT_DIR$/komp.commonTest.iml" /> <module fileurl="file://$PROJECT_DIR$/komp.commonTest.iml" filepath="$PROJECT_DIR$/komp.commonTest.iml" />
<module fileurl="file://$PROJECT_DIR$/komp.jsMain.iml" filepath="$PROJECT_DIR$/komp.jsMain.iml" /> <module fileurl="file://$PROJECT_DIR$/komp.jsMain.iml" filepath="$PROJECT_DIR$/komp.jsMain.iml" />
<module fileurl="file://$PROJECT_DIR$/komp.jsTest.iml" filepath="$PROJECT_DIR$/komp.jsTest.iml" /> <module fileurl="file://$PROJECT_DIR$/komp.jsTest.iml" filepath="$PROJECT_DIR$/komp.jsTest.iml" />
<module fileurl="file://$PROJECT_DIR$/komp_main.iml" filepath="$PROJECT_DIR$/komp_main.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" default="true" 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">
@@ -296,6 +426,13 @@
<option name="url" value="https://jcenter.bintray.com/" /> <option name="url" value="https://jcenter.bintray.com/" />
</remote-repository> </remote-repository>
</component> </component>
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
<component name="RunManager"> <component name="RunManager">
<configuration default="true" type="Applet" factoryName="Applet"> <configuration default="true" type="Applet" factoryName="Applet">
<option name="WIDTH" value="400" /> <option name="WIDTH" value="400" />
@@ -359,7 +496,6 @@
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
<component name="accountSettings"> <component name="accountSettings">
<option name="activeRegion" value="us-east-1" />
<option name="recentlyUsedRegions"> <option name="recentlyUsedRegions">
<list> <list>
<option value="us-east-1" /> <option value="us-east-1" />
@@ -367,67 +503,51 @@
</option> </option>
</component> </component>
<component name="libraryTable"> <component name="libraryTable">
<library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.30" type="kotlin.common"> <library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.5.21" type="kotlin.common">
<CLASSES> <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/bb9a3173350f55732416ee27956ea8f9b81f4dbb/kotlin-stdlib-common-1.4.30.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/5b8f86fea035328fc9e8c660773037a3401ce25f/kotlin-stdlib-common-1.5.21-javadoc.jar!/" />
</JAVADOC>
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/9427471650876e86fdb0dd878f147ff15c57eac0/kotlin-stdlib-common-1.4.30-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/64f0dd5eac2d479a65bc077185d9a8f661c948fe/kotlin-stdlib-common-1.5.21-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
<library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.4.30" type="kotlin.js"> <library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21" type="kotlin.js">
<CLASSES> <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.4.30/6c66d1db9c724b087c3a6f37aecffd24d0b14f26/kotlin-stdlib-js-1.4.30.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.5.21/9b22e0c2e0dcf2ba9f27e45a48944d05b0384bc3/kotlin-stdlib-js-1.5.21.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.4.30/5729944dc91bf28689461fe44b9e401fd41a84a7/kotlin-stdlib-js-1.4.30-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.5.21/dcd3e87dab1d7ecc7f2952d5d213e20f977bbddc/kotlin-stdlib-js-1.5.21-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
<library name="Gradle: org.jetbrains.kotlin:kotlin-test-annotations-common:1.4.30" type="kotlin.common"> <library name="Gradle: org.jetbrains.kotlin:kotlin-test-js:1.5.21" type="kotlin.js">
<CLASSES> <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-annotations-common/1.4.30/e77a76b23fc3007baf57a9d3354fdd318fe1fa88/kotlin-test-annotations-common-1.4.30.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-js/1.5.21/db9c8e994715fb1edd5bef91db179b60347cbfc9/kotlin-test-js-1.5.21.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-annotations-common/1.4.30/57512e29ee20defe37d54ce19507d599b0f2113/kotlin-test-annotations-common-1.4.30-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-js/1.5.21/8e70170db077d3f421c3fb6d24468b3938990f4a/kotlin-test-js-1.5.21-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
<library name="Gradle: org.jetbrains.kotlin:kotlin-test-common:1.4.30" type="kotlin.common"> <library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.3" type="kotlin.common">
<CLASSES> <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-common/1.4.30/823ed87441680d1334a1f0d23781c0089e16c0a6/kotlin-test-common-1.4.30.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.3/4f3df7b2096bce6fef3e532ca1ccff13bd15a6bc/kotlinx-html-metadata-0.7.3.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-common/1.4.30/d1818d1bdc457b51289f006884a260b56a55cb77/kotlin-test-common-1.4.30-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.3/f4eb48699d893b863f142a3c30e1ddddd13b876/kotlinx-html-common-0.7.3-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
<library name="Gradle: org.jetbrains.kotlin:kotlin-test-js:1.4.30" type="kotlin.js"> <library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.3" type="kotlin.js">
<CLASSES> <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-js/1.4.30/5b1cb1ec31a344f6aa1047d6cae3a268825cb724/kotlin-test-js-1.4.30.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.3/93a1ab4269d3a567e05088d1237eedbc2efd03c9/kotlinx-html-jslegacy-0.7.3.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-test-js/1.4.30/8e70170db077d3f421c3fb6d24468b3938990f4a/kotlin-test-js-1.4.30-sources.jar!/" /> <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.3/fc3bc71d1c037b715689112c95c44b96bb2409ea/kotlinx-html-js-0.7.3-sources.jar!/" />
</SOURCES>
</library>
<library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.2" type="kotlin.common">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.2/7da838083337896b558cab2884c4118709a58769/kotlinx-html-metadata-0.7.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.7.2/866bbbfe0a81d49cdf19fd149adafbb938b35be4/kotlinx-html-common-0.7.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.2" type="kotlin.js">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.2/baf7e494e549776d0ae3e0ee225804a513f5dc26/kotlinx-html-jslegacy-0.7.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.7.2/b09bfd3565058174afa3fd0888743f8b8dca5406/kotlinx-html-js-0.7.2-sources.jar!/" />
</SOURCES> </SOURCES>
</library> </library>
</component> </component>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="komp:jsMain" 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.type="sourceSet" external.system.module.version="0.2.4-SNAPSHOT" type="JAVA_MODULE" version="4"> <module external.linked.project.id="komp:jsMain" 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.type="sourceSet" external.system.module.version="0.5.6-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false" isTestModule="false" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-jsLegacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-jsIr/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin;/home/rnentjes/Development/komp/komp/src/commonMain/kotlin"> <configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false" isTestModule="false" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-js-legacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-js-ir/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin">
<dependsOnModuleNames>komp:commonMain</dependsOnModuleNames> <dependsOnModuleNames>komp:commonMain</dependsOnModuleNames>
<sourceSets> <sourceSets>
<sourceSet>komp.commonMain</sourceSet> <sourceSet>komp.commonMain</sourceSet>
@@ -10,25 +10,25 @@
<newMppModelJpsModuleKind>COMPILATION_AND_SOURCE_SET_HOLDER</newMppModelJpsModuleKind> <newMppModelJpsModuleKind>COMPILATION_AND_SOURCE_SET_HOLDER</newMppModelJpsModuleKind>
<compilerSettings /> <compilerSettings />
<compilerArguments> <compilerArguments>
<option name="outputFile" value="$MODULE_DIR$/build/js/packages/komp-jsLegacy/kotlin/komp-jsLegacy.js" /> <option name="outputFile" value="$MODULE_DIR$/build/js/packages/komp-js-legacy/kotlin/komp-js-legacy.js" />
<option name="noStdlib" value="true" /> <option name="noStdlib" value="true" />
<option name="sourceMap" value="true" /> <option name="sourceMap" value="true" />
<option name="metaInfo" value="true" /> <option name="metaInfo" value="true" />
<option name="target" value="v5" /> <option name="target" value="v5" />
<option name="moduleKind" value="umd" /> <option name="moduleKind" value="umd" />
<option name="main" value="call" /> <option name="main" value="call" />
<option name="languageVersion" value="1.4" /> <option name="languageVersion" value="1.5" />
<option name="apiVersion" value="1.4" /> <option name="apiVersion" value="1.5" />
<option name="pluginOptions"> <option name="pluginOptions">
<array /> <array />
</option> </option>
<option name="pluginClasspaths"> <option name="pluginClasspaths">
<array> <array>
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.30/b9c2a1fab9217623fc0fbadf6190e77eed6f054d/kotlin-script-runtime-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.21/96d49e89873fde985750af354b6eabb60cfa999b/kotlin-script-runtime-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.30/c7896c5c6b504f44e7cf9f5719d4393e20680666/kotlin-scripting-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.5.21/5d271f9e7e7191902f8c0d45c600f5b57a284036/kotlin-scripting-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.30/7d0085e5781847da84580d16239c1c4e0980bdb0/kotlin-scripting-jvm-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.5.21/8143908a15163e634fecb87013ed4a139170b032/kotlin-scripting-jvm-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/bb9a3173350f55732416ee27956ea8f9b81f4dbb/kotlin-stdlib-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.30/d10d1e10f47006ee08162dde039e38ac487de4ac/kotlin-stdlib-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.21/2f537cad7e9eeb9da73738c8812e1e4cf9b62e4e/kotlin-stdlib-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" />
</array> </array>
@@ -42,18 +42,18 @@
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/build/js/packages/komp-jsLegacy/kotlin" /> <output url="file://$MODULE_DIR$/build/js/packages/komp-js-legacy/kotlin" />
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$/build/externals/komp-jsIr/src" /> <content url="file://$MODULE_DIR$/build/externals/komp-js-ir/src" />
<content url="file://$MODULE_DIR$/build/externals/komp-jsLegacy/src" /> <content url="file://$MODULE_DIR$/build/externals/komp-js-legacy/src" />
<content url="file://$MODULE_DIR$/src/jsMain"> <content url="file://$MODULE_DIR$/src/jsMain">
<sourceFolder url="file://$MODULE_DIR$/src/jsMain/kotlin" type="kotlin-source" /> <sourceFolder url="file://$MODULE_DIR$/src/jsMain/kotlin" type="kotlin-source" />
</content> </content>
<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.commonMain" /> <orderEntry type="module" module-name="komp.commonMain" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.2" level="project" /> <orderEntry type="library" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.3" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.4.30" level="project" /> <orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.30" level="project" /> <orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.5.21" level="project" />
</component> </component>
</module> </module>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="komp:jsTest" 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.type="sourceSet" external.system.module.version="0.2.4-SNAPSHOT" type="JAVA_MODULE" version="4"> <module external.linked.project.id="komp:jsTest" 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.type="sourceSet" external.system.module.version="0.5.6-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false" isTestModule="true" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-jsLegacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-jsIr/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin;/home/rnentjes/Development/komp/komp/src/commonMain/kotlin"> <configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false" isTestModule="true" externalProjectId="komp" pureKotlinSourceFolders="$MODULE_DIR$/src/jsMain/kotlin;/home/rnentjes/Development/komp/komp/build/externals/komp-js-legacy/src;/home/rnentjes/Development/komp/komp/build/externals/komp-js-ir/src;/home/rnentjes/Development/komp/komp/src/jsTest/kotlin">
<dependsOnModuleNames>komp:commonTest</dependsOnModuleNames> <dependsOnModuleNames>komp:commonTest</dependsOnModuleNames>
<sourceSets> <sourceSets>
<sourceSet>komp.jsMain</sourceSet>
<sourceSet>komp.commonTest</sourceSet> <sourceSet>komp.commonTest</sourceSet>
<sourceSet>komp.jsMain</sourceSet>
<sourceSet>komp.commonMain</sourceSet> <sourceSet>komp.commonMain</sourceSet>
</sourceSets> </sourceSets>
<newMppModelJpsModuleKind>COMPILATION_AND_SOURCE_SET_HOLDER</newMppModelJpsModuleKind> <newMppModelJpsModuleKind>COMPILATION_AND_SOURCE_SET_HOLDER</newMppModelJpsModuleKind>
@@ -15,25 +15,25 @@
</externalSystemTestTasks> </externalSystemTestTasks>
<compilerSettings /> <compilerSettings />
<compilerArguments> <compilerArguments>
<option name="outputFile" value="$MODULE_DIR$/build/js/packages/komp-jsLegacy-test/kotlin/komp-jsLegacy-test.js" /> <option name="outputFile" value="$MODULE_DIR$/build/js/packages/komp-js-legacy-test/kotlin/komp-js-legacy-test.js" />
<option name="noStdlib" value="true" /> <option name="noStdlib" value="true" />
<option name="sourceMap" value="true" /> <option name="sourceMap" value="true" />
<option name="metaInfo" value="true" /> <option name="metaInfo" value="true" />
<option name="target" value="v5" /> <option name="target" value="v5" />
<option name="moduleKind" value="umd" /> <option name="moduleKind" value="umd" />
<option name="main" value="call" /> <option name="main" value="call" />
<option name="languageVersion" value="1.4" /> <option name="languageVersion" value="1.5" />
<option name="apiVersion" value="1.4" /> <option name="apiVersion" value="1.5" />
<option name="pluginOptions"> <option name="pluginOptions">
<array /> <array />
</option> </option>
<option name="pluginClasspaths"> <option name="pluginClasspaths">
<array> <array>
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.4.30/b9c2a1fab9217623fc0fbadf6190e77eed6f054d/kotlin-script-runtime-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.21/96d49e89873fde985750af354b6eabb60cfa999b/kotlin-script-runtime-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.4.30/c7896c5c6b504f44e7cf9f5719d4393e20680666/kotlin-scripting-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/1.5.21/5d271f9e7e7191902f8c0d45c600f5b57a284036/kotlin-scripting-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.4.30/7d0085e5781847da84580d16239c1c4e0980bdb0/kotlin-scripting-jvm-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/1.5.21/8143908a15163e634fecb87013ed4a139170b032/kotlin-scripting-jvm-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.30/bb9a3173350f55732416ee27956ea8f9b81f4dbb/kotlin-stdlib-common-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.30/d10d1e10f47006ee08162dde039e38ac487de4ac/kotlin-stdlib-1.4.30.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.21/2f537cad7e9eeb9da73738c8812e1e4cf9b62e4e/kotlin-stdlib-1.5.21.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.3.8/f62be6d4cbf27781c2969867b4ed952f38378492/kotlinx-coroutines-core-1.3.8.jar" />
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" /> <option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar" />
</array> </array>
@@ -47,7 +47,7 @@
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<output-test url="file://$MODULE_DIR$/build/js/packages/komp-jsLegacy-test/kotlin" /> <output-test url="file://$MODULE_DIR$/build/js/packages/komp-js-legacy-test/kotlin" />
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$/src/jsTest"> <content url="file://$MODULE_DIR$/src/jsTest">
<sourceFolder url="file://$MODULE_DIR$/src/jsTest/kotlin" type="kotlin-test" /> <sourceFolder url="file://$MODULE_DIR$/src/jsTest/kotlin" type="kotlin-test" />
@@ -58,13 +58,29 @@
<orderEntry type="module" module-name="komp.commonTest" scope="TEST" production-on-test="" /> <orderEntry type="module" module-name="komp.commonTest" scope="TEST" production-on-test="" />
<orderEntry type="module" module-name="komp.jsMain" scope="TEST" /> <orderEntry type="module" module-name="komp.jsMain" scope="TEST" />
<orderEntry type="module" module-name="komp.jsMain" scope="RUNTIME" /> <orderEntry type="module" module-name="komp.jsMain" scope="RUNTIME" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.2" level="project" /> <orderEntry type="module-library" scope="PROVIDED">
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-test-js:1.4.30" level="project" /> <library name="Gradle: nl.astraeus:komp">
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.4.30" level="project" /> <CLASSES>
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.2" level="project" /> <root url="file://$MODULE_DIR$/build/classes/kotlin/jsIr/main" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.4.30" level="project" /> </CLASSES>
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-test-common:1.4.30" level="project" /> <JAVADOC />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-test-annotations-common:1.4.30" level="project" /> <SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" scope="RUNTIME">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/build/processedResources/jsIr/main" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.7.3" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-test-js:1.5.21" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.7.3" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.5.21" level="project" />
</component> </component>
<component name="TestModuleProperties" production-module="komp.jsMain" /> <component name="TestModuleProperties" production-module="komp.jsMain" />
</module> </module>

View File

@@ -12,5 +12,3 @@ pluginManagement {
} }
rootProject.name = "komp" rootProject.name = "komp"
enableFeaturePreview("GRADLE_METADATA")

View File

@@ -1,368 +0,0 @@
package nl.astraeus.komp
import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.Node
import org.w3c.dom.NodeList
import org.w3c.dom.events.Event
import org.w3c.dom.get
const val HASH_VALUE = "komp-hash-value"
//const val HASH_ATTRIBUTE = "data-komp-hash"
const val EVENT_ATTRIBUTE = "data-komp-events"
fun Node.getKompHash(): Int = this.asDynamic()[HASH_VALUE] as? Int? ?: -1
fun Node.setKompHash(hash: Int) {
this.asDynamic()[HASH_VALUE] = hash
}
private fun NodeList.findNodeHashIndex(hash: Int): Int {
for (index in 0..this.length) {
val node = this[index]
if (node is HTMLElement && node.getKompHash() == hash) {
return index
}
}
return -1
}
object DiffPatch {
fun hashesMatch(oldNode: Node, newNode: Node): Boolean {
return (
oldNode is HTMLElement &&
newNode is HTMLElement &&
oldNode.nodeName == newNode.nodeName &&
oldNode.getKompHash() == newNode.getKompHash()
)
}
private fun updateKomponentOnNode(oldNode: Node, newNode: Node) {
val komponent = newNode.asDynamic()[KOMP_KOMPONENT] as? Komponent
if (komponent != null) {
if (Komponent.logReplaceEvent) {
console.log("Keeping oldNode, set oldNode element on Komponent", oldNode, komponent)
}
komponent.element = oldNode
}
}
fun updateNode(oldNode: Node, newNode: Node): Node {
if (hashesMatch(oldNode, newNode)) {
if (Komponent.logReplaceEvent) {
console.log("Hashes match", oldNode, newNode, oldNode.getKompHash(), newNode.getKompHash())
}
updateKomponentOnNode(oldNode, newNode)
return oldNode
}
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
}
updateKomponentOnNode(oldNode, newNode)
return oldNode
}
if (oldNode is HTMLElement && newNode is HTMLElement) {
if (oldNode.nodeName == newNode.nodeName) {
if (Komponent.logReplaceEvent) {
console.log("Update attributes", oldNode.nodeName, newNode.nodeName)
}
updateAttributes(oldNode, newNode);
if (Komponent.logReplaceEvent) {
console.log("Update events", oldNode.nodeName, newNode.nodeName)
}
updateEvents(oldNode, newNode)
if (Komponent.logReplaceEvent) {
console.log("Update children", oldNode.nodeName, newNode.nodeName)
}
updateChildren(oldNode, newNode)
oldNode.setKompHash(newNode.getKompHash())
updateKomponentOnNode(oldNode, newNode)
return oldNode
}
}
if (Komponent.logReplaceEvent) {
console.log("Replace node (type)", oldNode.nodeType, oldNode, newNode)
}
oldNode.parentNode?.replaceChild(newNode, oldNode)
//replaceNode(oldNode, newNode)
return newNode
}
private fun updateAttributes(oldNode: HTMLElement, newNode: HTMLElement) {
// removed attributes
for (name in oldNode.getAttributeNames()) {
val attr = oldNode.attributes[name]
if (attr != null && newNode.getAttribute(name) == null) {
oldNode.removeAttribute(name)
}
}
for (name in newNode.getAttributeNames()) {
val value = newNode.getAttribute(name)
val oldValue = oldNode.getAttribute(name)
if (value != oldValue) {
if (value != null) {
oldNode.setAttribute(name, value)
}else {
oldNode.removeAttribute(name)
}
}
}
if (newNode is HTMLInputElement && oldNode is HTMLInputElement) {
oldNode.value = newNode.value
}
/*
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) {
var oldIndex = 0
var newIndex = 0
if (Komponent.logReplaceEvent) {
console.log(
"updateChildren HTML old(${oldNode.childNodes.length})",
oldNode.innerHTML
)
console.log(
"updateChildren HTML new(${newNode.childNodes.length})",
newNode.innerHTML
)
}
while (newIndex < newNode.childNodes.length) {
if (Komponent.logReplaceEvent) {
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(">>> updateChildren old/new", oldChildNode, newChildNode)
}
*/
if (Komponent.logReplaceEvent) {
console.log("Update node Old/new", oldChildNode, newChildNode)
}
if (!hashesMatch(oldChildNode, newChildNode) && newChildNode is HTMLElement && oldChildNode is HTMLElement) {
if (Komponent.logReplaceEvent) {
console.log("Hashes don't match")
}
val oldHash = oldChildNode.getKompHash()
val newHash = newChildNode.getKompHash()
if (newHash >= 0) {
val oldNodeWithNewHashIndex = oldNode.childNodes.findNodeHashIndex(newHash)
if (Komponent.logReplaceEvent) {
console.log("oldNodeWithNewHashIndex", newHash, oldNodeWithNewHashIndex)
}
if (oldNodeWithNewHashIndex > oldIndex) {
if (oldHash >= 0) {
val newNodeWithOldHashIndex = newNode.childNodes.findNodeHashIndex(oldHash)
// remove i.o. swap
if (newNodeWithOldHashIndex == -1) {
if (Komponent.logReplaceEvent) {
console.log("Old node missing in new tree, remove node", oldChildNode)
}
oldNode.removeChild(oldChildNode)
continue
}
}
val nodeWithHash = oldNode.childNodes[oldNodeWithNewHashIndex]
if (Komponent.logReplaceEvent) {
console.log("nodeWithHash", nodeWithHash)
}
if (nodeWithHash != null) {
if (Komponent.logReplaceEvent) {
console.log(">-> swap nodes", oldNode)
}
oldNode.insertBefore(nodeWithHash, oldNode.childNodes[oldIndex])
if (Komponent.logReplaceEvent) {
console.log(">-> swapped nodes", oldNode)
}
newIndex++
oldIndex++
continue
}
} else if (oldHash >= 0 && newNode.childNodes.findNodeHashIndex(oldHash) > newIndex) {
if (Komponent.logReplaceEvent) {
console.log("newNodeWithOldHashIndex", oldHash, newNode.childNodes.findNodeHashIndex(oldHash))
}
oldNode.insertBefore(newChildNode, oldChildNode)
oldIndex++
continue
}
}
}
val updatedNode = updateNode(oldChildNode, newChildNode)
if (updatedNode == newChildNode) {
if (oldChildNode is HTMLElement && newChildNode is HTMLElement) {
updateEvents(oldChildNode, newChildNode)
}
oldIndex++
continue
}
} else {
if (Komponent.logReplaceEvent) {
console.log("Null node", oldChildNode, newChildNode)
}
}
oldIndex++
newIndex++
} else {
if (Komponent.logReplaceEvent) {
console.log("Append Old/new/node", oldIndex, newIndex, newChildNode)
}
oldNode.append(newChildNode)
oldIndex++
}
/*
if (Komponent.logReplaceEvent) {
console.log("<<< Updated Old/new", oldNode.innerHTML, newNode.innerHTML)
}
*/
}
while (oldIndex < oldNode.childNodes.length) {
oldNode.childNodes[oldIndex]?.also {
if (Komponent.logReplaceEvent) {
console.log("Remove old node", it)
}
oldNode.removeChild(it)
}
}
}
private fun updateEvents(oldNode: HTMLElement, newNode: HTMLElement) {
val oldEvents = mutableListOf<String>()
oldEvents.addAll((oldNode.getAttribute(EVENT_ATTRIBUTE) ?: "").split(","))
val newEvents = (newNode.getAttribute(EVENT_ATTRIBUTE) ?: "").split(",")
if (Komponent.logReplaceEvent) {
console.log("Update events", oldNode.getAttribute(EVENT_ATTRIBUTE), newNode.getAttribute(EVENT_ATTRIBUTE))
}
for (event in newEvents) {
if (event.isNotBlank()) {
val oldNodeEvent = oldNode.asDynamic()["event-$event"]
val newNodeEvent = newNode.asDynamic()["event-$event"]
if (oldNodeEvent != null) {
if (Komponent.logReplaceEvent) {
console.log("Remove old event $event")
}
oldNode.removeEventListener(event, oldNodeEvent as ((Event) -> Unit), null)
}
if (newNodeEvent != null) {
if (Komponent.logReplaceEvent) {
console.log("Set event $event on", oldNode)
}
oldNode.setEvent(event, newNodeEvent as ((Event) -> Unit))
}
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(EVENT_ATTRIBUTE)?.also {
oldNode.setAttribute(EVENT_ATTRIBUTE, it)
}
}
private fun replaceNode(oldNode: Node, newNode: Node) {
oldNode.parentNode?.also { parent ->
val clone = newNode.cloneNode(true)
cloneEvents(clone, newNode)
parent.replaceChild(clone, oldNode)
}
}
private fun cloneEvents(destination: Node, source: Node) {
if (source is HTMLElement && destination is HTMLElement) {
val events = (source.getAttribute(EVENT_ATTRIBUTE) ?: "").split(",")
for (event in events) {
if (event.isNotBlank()) {
if (Komponent.logReplaceEvent) {
console.log("Clone event $event on", source)
}
val foundEvent = source.asDynamic()["event-$event"]
if (foundEvent != null) {
if (Komponent.logReplaceEvent) {
console.log("Clone add eventlistener", foundEvent)
}
destination.setEvent(event, foundEvent as ((Event) -> Unit))
} else {
if (Komponent.logReplaceEvent) {
console.log("Event not found $event", source)
}
}
}
}
}
for (index in 0 until source.childNodes.length) {
destination.childNodes[index]?.also { destinationChild ->
source.childNodes[index]?.also { sourceChild ->
cloneEvents(destinationChild, sourceChild)
}
}
}
}
}

View File

@@ -1,229 +1,521 @@
package nl.astraeus.komp package nl.astraeus.komp
import org.w3c.dom.*
import org.w3c.dom.css.CSSStyleDeclaration
import org.w3c.dom.events.Event
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.html.* import kotlinx.html.DefaultUnsafe
import kotlinx.html.Entities
import kotlinx.html.FlowOrMetaDataOrPhrasingContent
import kotlinx.html.Tag
import kotlinx.html.TagConsumer
import kotlinx.html.Unsafe
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSpanElement
import org.w3c.dom.Node
import org.w3c.dom.asList
import org.w3c.dom.events.Event
import org.w3c.dom.get
@Suppress("NOTHING_TO_INLINE") private var currentElement: Element? = null
inline fun HTMLElement.setEvent(name: String, noinline callback: (Event) -> Unit) {
val eventName = if (name.startsWith("on")) { interface HtmlConsumer : TagConsumer<Element> {
fun append(node: Element)
fun include(komponent: Komponent)
fun debug(block: HtmlConsumer.() -> Unit)
}
fun Int.asSpaces(): String {
val result = StringBuilder()
repeat(this) {
result.append(" ")
}
return result.toString()
}
fun FlowOrMetaDataOrPhrasingContent.currentElement(): Element =
currentElement ?: error("No current element defined!")
fun Element.printTree(indent: Int = 0): String {
val result = StringBuilder()
result.append(indent.asSpaces())
result.append(tagName)
if (this.namespaceURI != "http://www.w3.org/1999/xhtml") {
result.append(" [")
result.append(namespaceURI)
result.append("]")
}
result.append(" (")
var first = true
if (hasAttributes()) {
for (index in 0 until attributes.length) {
if (!first) {
result.append(", ")
} else {
first = false
}
result.append(attributes[index]?.localName)
result.append("=")
result.append(attributes[index]?.value)
}
}
result.append(") {")
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) {
childNodes[index]?.let {
if (it is Element) {
result.append(it.printTree(indent + 2))
} else {
result.append((indent + 2).asSpaces())
result.append(it.textContent)
result.append("\n")
}
}
}
result.append(indent.asSpaces())
result.append("}\n")
return result.toString()
}
private fun Element.clearKompAttributes() {
val attributes = this.asDynamic()["komp-attributes"] as MutableSet<String>?
if (attributes == null) {
this.asDynamic()["komp-attributes"] = mutableSetOf<String>()
} else {
attributes.clear()
}
if (this is HTMLInputElement) {
this.checked = false
}
}
private fun Element.getKompAttributes(): MutableSet<String> {
var result: MutableSet<String>? = this.asDynamic()["komp-attributes"] as MutableSet<String>?
if (result == null) {
result = mutableSetOf()
this.asDynamic()["komp-attributes"] = result
}
return result
}
private fun Element.setKompAttribute(name: String, value: String) {
val setAttrs: MutableSet<String> = getKompAttributes()
setAttrs.add(name)
if (this is HTMLInputElement) {
when (name) {
"checked" -> {
this.checked = value == "checked"
}
"value" -> {
this.value = value
}
else -> {
setAttribute(name, value)
}
}
} else if (this.getAttribute(name) != value) {
setAttribute(name, value)
}
}
private fun Element.clearKompEvents() {
for ((name, event) in getKompEvents()) {
currentElement?.removeEventListener(name, event)
}
val events = this.asDynamic()["komp-events"] as MutableMap<String, (Event) -> Unit>?
if (events == null) {
this.asDynamic()["komp-events"] = mutableMapOf<String, (Event) -> Unit>()
} else {
events.clear()
}
}
private fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
val eventName: String = if (name.startsWith("on")) {
name.substring(2) name.substring(2)
} else { } else {
name name
} }
addEventListener(eventName, callback, null)
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
//asDynamic()[name] = callback
val events = getAttribute(EVENT_ATTRIBUTE) ?: ""
setAttribute( val events: MutableMap<String, (Event) -> Unit> = getKompEvents()
EVENT_ATTRIBUTE,
if (events.isBlank()) { events[eventName]?.let {
eventName println("Warn event already defined!")
} else { currentElement?.removeEventListener(eventName, it)
"$events,$eventName" }
}
) events[eventName] = event
asDynamic()["event-$eventName"] = callback
this.asDynamic()["komp-events"] = events
this.addEventListener(eventName, event)
}
private fun Element.getKompEvents(): MutableMap<String, (Event) -> Unit> {
return this.asDynamic()["komp-events"] ?: mutableMapOf()
}
private data class ElementIndex(
val parent: Node,
var childIndex: Int
)
private fun ArrayList<ElementIndex>.currentParent(): Node {
this.lastOrNull()?.let {
return it.parent
}
throw IllegalStateException("currentParent should never be null!")
}
private fun ArrayList<ElementIndex>.currentElement(): Node? {
this.lastOrNull()?.let {
return it.parent.childNodes[it.childIndex]
}
return null
}
private fun ArrayList<ElementIndex>.nextElement() {
this.lastOrNull()?.let {
it.childIndex++
} }
} }
interface HtmlConsumer : TagConsumer<HTMLElement> { private fun ArrayList<ElementIndex>.pop() {
fun append(node: Node) this.removeLast()
} }
fun HTMLElement.setStyles(cssStyle: CSSStyleDeclaration) { private fun ArrayList<ElementIndex>.push(element: Node) {
for (index in 0 until cssStyle.length) { this.add(ElementIndex(element, 0))
val propertyName = cssStyle.item(index) }
style.setProperty(propertyName, cssStyle.getPropertyValue(propertyName)) private fun ArrayList<ElementIndex>.replace(new: Node) {
if (this.currentElement() != null) {
this.currentElement()?.parentElement?.replaceChild(new, this.currentElement()!!)
} else {
this.last().parent.appendChild(new)
} }
} }
private fun Node.asElement() = this as? HTMLElement
class HtmlBuilder( class HtmlBuilder(
val komponent: Komponent, val parent: Element,
val document: Document var childIndex: Int = 0
) : HtmlConsumer { ) : HtmlConsumer {
private val path = arrayListOf<HTMLElement>() private var currentPosition = arrayListOf<ElementIndex>()
private var lastLeaved: HTMLElement? = null private var inDebug = false
var currentNode: Node? = null
var root: Element? = null
val currentAttributes: MutableMap<String, String> = mutableMapOf()
init {
currentPosition.add(ElementIndex(parent, childIndex))
}
override fun include(komponent: Komponent) {
if (
komponent.element != null &&
!komponent.memoizeChanged()
) {
currentPosition.replace(komponent.element!!)
if (Komponent.logRenderEvent) {
console.log("Skipped include $komponent, memoize hasn't changed")
}
} else {
komponent.create(
currentPosition.last().parent as Element,
currentPosition.last().childIndex
)
}
currentPosition.nextElement()
}
override fun append(node: Element) {
currentPosition.replace(node)
currentPosition.nextElement()
}
override fun debug(block: HtmlConsumer.() -> Unit) {
inDebug = true
try {
block.invoke(this)
} finally {
inDebug = false
}
}
fun logReplace(msg: String) {
if (Komponent.logReplaceEvent && inDebug) {
console.log(msg)
}
}
override fun onTagStart(tag: Tag) { override fun onTagStart(tag: Tag) {
val element: HTMLElement = when { //logReplace"onTagStart, [${tag.tagName}, ${tag.namespace}], currentPosition: $currentPosition")
tag.namespace != null -> document.createElementNS(tag.namespace!!, tag.tagName).asDynamic() currentNode = currentPosition.currentElement()
else -> document.createElement(tag.tagName) as HTMLElement
if (currentNode == null) {
//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")
currentPosition.currentParent().appendChild(currentNode!!)
} else if (
!currentNode?.asElement()?.tagName.equals(tag.tagName, true) ||
(
tag.namespace != null &&
!currentNode?.asElement()?.namespaceURI.equals(tag.namespace, true)
)
) {
//logReplace"onTagStart, currentElement, namespace: ${currentNode?.asElement()?.namespaceURI} -> ${tag.namespace}")
//logReplace"onTagStart, currentElement, replace: ${currentNode?.asElement()?.tagName} -> ${tag.tagName}")
currentNode = if (tag.namespace != null) {
document.createElementNS(tag.namespace, tag.tagName)
} else {
document.createElement(tag.tagName)
}
currentPosition.replace(currentNode!!)
} else {
//logReplace"onTagStart, same node type")
} }
if (path.isNotEmpty()) { currentElement = currentNode as? Element ?: currentElement
path.last().appendChild(element)
if (currentNode is Element) {
if (root == null) {
//logReplace"Setting root: $currentNode")
root = currentNode as Element
}
currentElement?.clearKompAttributes()
currentElement?.clearKompEvents()
for (entry in tag.attributesEntries) {
currentElement!!.setKompAttribute(entry.key.lowercase(), entry.value)
}
if (tag.namespace != null) {
//logReplace"onTagStart, same node type")
(currentNode as? Element)?.innerHTML = ""
}
} }
path.add(element) //logReplace"onTagStart, currentElement2: $currentNode")
currentPosition.push(currentNode!!)
}
private fun checkTag(tag: Tag) {
check(currentElement != null) {
js("debugger")
"No current tag"
}
check(currentElement?.tagName.equals(tag.tagName, ignoreCase = true)) {
js("debugger")
"Wrong current tag"
}
} }
override fun onTagAttributeChange(tag: Tag, attribute: String, value: String?) { override fun onTagAttributeChange(tag: Tag, attribute: String, value: String?) {
when { logReplace("onTagAttributeChange, ${tag.tagName} [$attribute, $value]")
path.isEmpty() -> throw IllegalStateException("No current tag")
path.last().tagName.toLowerCase() != tag.tagName.toLowerCase() -> throw IllegalStateException("Wrong current tag") checkTag(tag)
else -> path.last().let { node ->
if (value == null) { if (value == null) {
node.removeAttribute(attribute) currentElement?.removeAttribute(attribute.lowercase())
} else { } else {
node.setAttribute(attribute, value) currentElement?.setKompAttribute(attribute.lowercase(), value)
}
}
} }
} }
override fun onTagEvent(tag: Tag, event: String, value: (Event) -> Unit) { override fun onTagEvent(tag: Tag, event: String, value: (Event) -> Unit) {
when { //logReplace"onTagEvent, ${tag.tagName} [$event, $value]")
path.isEmpty() -> throw IllegalStateException("No current tag")
path.last().tagName.toLowerCase() != tag.tagName.toLowerCase() -> throw IllegalStateException("Wrong current tag") checkTag(tag)
else -> path.last().setEvent(event, value)
} currentElement?.setKompEvent(event.lowercase(), value)
} }
override fun onTagEnd(tag: Tag) { override fun onTagEnd(tag: Tag) {
var hash = 0 while (currentPosition.currentElement() != null) {
if (path.isEmpty() || path.last().tagName.toLowerCase() != tag.tagName.toLowerCase()) { currentPosition.currentElement()?.let {
throw IllegalStateException("We haven't entered tag ${tag.tagName} but trying to leave") it.parentElement?.removeChild(it)
}
val element = path.last()
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
for (index in 0 until element.childNodes.length) {
val child = element.childNodes[index]
if (child is HTMLElement) {
hash = hash * 37 + child.getKompHash()
} else {
hash = hash * 37 + (child?.textContent?.hashCode() ?: 0)
}
} }
} }
for ((key, value) in tag.attributesEntries) { checkTag(tag)
if (key == "class") {
val classes = value.split(Regex("\\s+"))
val classNames = StringBuilder()
for (cls in classes) { currentPosition.pop()
val cssStyle = komponent.declaredStyles[cls]
if (cssStyle != null) { val setAttrs: List<String> = currentElement.asDynamic()["komp-attributes"] ?: listOf()
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
hash = hash * 37 + cssStyle.hashCode()
}
if (cls.endsWith(":hover")) { // remove attributes that where not set
val oldOnMouseOver = element.onmouseover val element = currentElement
val oldOnMouseOut = element.onmouseout if (element?.hasAttributes() == true) {
for (index in 0 until element.attributes.length) {
val attr = element.attributes[index]
if (attr != null) {
element.onmouseover = { if (element is HTMLElement && attr.name == "data-has-focus" && "true" == attr.value) {
element.setStyles(cssStyle) element.focus()
}
oldOnMouseOver?.invoke(it) if (!setAttrs.contains(attr.name)) {
} if (element is HTMLInputElement) {
element.onmouseout = { if (attr.name == "checkbox") {
cls.split(':').firstOrNull()?.let { element.checked = false
komponent.declaredStyles[it]?.let { cssStyle -> } else if (attr.name == "value") {
element.setStyles(cssStyle) element.value = ""
}
}
oldOnMouseOut?.invoke(it)
} }
} else { } else {
element.setStyles(cssStyle) if (Komponent.logReplaceEvent) {
console.log("Clear attribute [${attr.name}] on $element)")
}
element.removeAttribute(attr.name)
} }
} else {
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
hash = hash * 37 + cls.hashCode()
}
classNames.append(cls)
classNames.append(" ")
} }
} }
element.className = classNames.toString()
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
val key_value = "${key}-${classNames}"
hash = hash * 37 + key_value.hashCode()
}
} else {
element.setAttribute(key, value)
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) {
val key_value = "${key}-${value}"
hash = hash * 37 + key_value.hashCode()
}
} }
} }
if (Komponent.updateStrategy == UpdateStrategy.DOM_DIFF) { currentPosition.nextElement()
element.setKompHash(hash)
//element.setAttribute(DiffPatch.HASH_ATTRIBUTE, hash.toString(16)) currentElement = currentElement?.parentElement as? HTMLElement
}
lastLeaved = path.removeAt(path.lastIndex) //logReplace"onTagEnd, popped: $currentElement")
} }
override fun onTagContent(content: CharSequence) { override fun onTagContent(content: CharSequence) {
if (path.isEmpty()) { //logReplace"onTagContent, [$content]")
throw IllegalStateException("No current DOM node")
check(currentElement != null) {
"No current DOM node"
} }
path.last().appendChild(document.createTextNode(content.toString())) //logReplace"Tag content: $content")
if (
currentElement?.nodeType != Node.TEXT_NODE ||
currentElement?.textContent != content.toString()
) {
currentElement?.textContent = content.toString()
}
currentPosition.nextElement()
} }
override fun onTagContentEntity(entity: Entities) { override fun onTagContentEntity(entity: Entities) {
if (path.isEmpty()) { //logReplace"onTagContentEntity, [${entity.text}]")
throw IllegalStateException("No current DOM node")
check(currentElement != null) {
"No current DOM node"
} }
// stupid hack as browsers don't support createEntityReference val s = document.createElement("span") as HTMLSpanElement
val s = document.createElement("span") as HTMLElement
s.innerHTML = entity.text s.innerHTML = entity.text
path.last().appendChild(s.childNodes.asList().first { it.nodeType == Node.TEXT_NODE }) currentPosition.replace(
s.childNodes.asList().firstOrNull() ?: document.createTextNode(entity.text)
// other solution would be )
// pathLast().innerHTML += entity.text currentPosition.nextElement()
}
override fun append(node: Node) {
path.last().appendChild(node)
} }
override fun onTagContentUnsafe(block: Unsafe.() -> Unit) { override fun onTagContentUnsafe(block: Unsafe.() -> Unit) {
with(DefaultUnsafe()) { with(DefaultUnsafe()) {
block() block()
path.last().innerHTML += toString() val textContent = toString()
//logReplace"onTagContentUnsafe, [$textContent]")
var namespace: String? = null
if (currentPosition.currentParent().nodeType == 1.toShort()) {
val element = currentPosition.currentParent() as Element
namespace = when (Komponent.unsafeMode) {
UnsafeMode.UNSAFE_ALLOWED -> {
element.namespaceURI
}
UnsafeMode.UNSAFE_SVG_ONLY -> {
if (element.namespaceURI == "http://www.w3.org/2000/svg") {
element.namespaceURI
} else {
null
}
}
else -> {
null
}
}
}
//logReplace"onTagContentUnsafe, namespace: [$namespace]")
if (Komponent.unsafeMode == UnsafeMode.UNSAFE_ALLOWED ||
(Komponent.unsafeMode == UnsafeMode.UNSAFE_SVG_ONLY && namespace == "http://www.w3.org/2000/svg")
) {
if (currentElement?.innerHTML != textContent) {
currentElement?.innerHTML += textContent
}
} else if (currentElement?.textContent != textContent) {
currentElement?.textContent = textContent
}
currentPosition.nextElement()
} }
} }
override fun onTagComment(content: CharSequence) { override fun onTagComment(content: CharSequence) {
if (path.isEmpty()) { //logReplace"onTagComment, [$content]")
throw IllegalStateException("No current DOM node")
}
path.last().appendChild(document.createComment(content.toString())) check(currentElement != null) {
"No current DOM node"
}
currentElement?.appendChild(
document.createComment(content.toString())
)
currentPosition.nextElement()
} }
override fun finalize(): HTMLElement = lastLeaved?.asR() ?: throw IllegalStateException("We can't finalize as there was no tags") override fun finalize(): Element {
//logReplace"finalize, currentPosition: $currentPosition")
@Suppress("UNCHECKED_CAST") return root ?: throw IllegalStateException("We can't finalize as there was no tags")
private fun HTMLElement.asR(): HTMLElement = this.asDynamic() }
companion object { companion object {
fun create(content: HtmlBuilder.() -> Unit): HTMLElement { fun create(content: HtmlBuilder.() -> Unit): Element {
val consumer = HtmlBuilder(DummyKomponent(), document) val container = document.createElement("div") as HTMLElement
val consumer = HtmlBuilder(container, 0)
content.invoke(consumer) content.invoke(consumer)
return consumer.finalize() return consumer.root ?: error("error")
} }
} }
} }

View File

@@ -1,18 +1,13 @@
package nl.astraeus.komp package nl.astraeus.komp
import org.w3c.dom.HTMLDivElement import kotlinx.browser.window
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.Node import org.w3c.dom.Node
import org.w3c.dom.css.CSSStyleDeclaration import org.w3c.dom.css.CSSStyleDeclaration
import kotlinx.browser.document import org.w3c.dom.get
import kotlinx.browser.window
import kotlinx.html.div
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
const val KOMP_KOMPONENT = "komp-komponent"
typealias CssStyle = CSSStyleDeclaration.() -> Unit
class StateDelegate<T>( class StateDelegate<T>(
val komponent: Komponent, val komponent: Komponent,
initialValue: T initialValue: T
@@ -33,138 +28,126 @@ class StateDelegate<T>(
inline fun <reified T> Komponent.state(initialValue: T): StateDelegate<T> = StateDelegate(this, initialValue) inline fun <reified T> Komponent.state(initialValue: T): StateDelegate<T> = StateDelegate(this, initialValue)
fun HtmlConsumer.include(component: Komponent) { enum class UnsafeMode {
if (Komponent.updateStrategy == UpdateStrategy.REPLACE) { UNSAFE_ALLOWED,
if (component.element != null) { UNSAFE_DISABLED,
component.update() UNSAFE_SVG_ONLY
} else {
component.refresh()
}
component.element?.also {
append(it)
}
} else {
append(component.create())
}
}
class DummyKomponent: Komponent() {
override fun HtmlBuilder.render() {
div {
+ "dummy"
}
}
}
enum class UpdateStrategy {
REPLACE,
DOM_DIFF
} }
abstract class Komponent { abstract class Komponent {
private var createIndex = getNextCreateIndex() val createIndex = getNextCreateIndex()
private var dirty: Boolean = true private var dirty: Boolean = true
private var lastMemoizeHash: Int? = null
var element: Node? = null var element: Node? = null
val declaredStyles: MutableMap<String, CSSStyleDeclaration> = HashMap() val declaredStyles: MutableMap<String, CSSStyleDeclaration> = HashMap()
open fun create(): HTMLElement { open fun create(parent: Element, childIndex: Int? = null) {
val consumer = HtmlBuilder(this, document) onBeforeUpdate()
consumer.render() val builder = HtmlBuilder(
val result = consumer.finalize() parent,
childIndex ?: parent.childElementCount
)
if (result.id.isBlank()) { builder.render()
result.id = "komp_${createIndex}" element = builder.root
} lastMemoizeHash = generateMemoizeHash()
onAfterUpdate()
element = result
element.asDynamic()[KOMP_KOMPONENT] = this
dirty = false
return result
} }
fun memoizeChanged() = lastMemoizeHash != null && lastMemoizeHash != generateMemoizeHash()
abstract fun HtmlBuilder.render() abstract fun HtmlBuilder.render()
/**
* This method is called after the Komponent is updated
*
* note: it's also called at first render
*/
open fun onAfterUpdate() {}
/**
* This method is called before the Komponent is updated
* and before memoizeHash is checked
*
* note: it's also called at first render
*/
open fun onBeforeUpdate() {}
fun requestUpdate() { fun requestUpdate() {
dirty = true dirty = true
scheduleForUpdate(this) scheduleForUpdate(this)
} }
open fun style(className: String, vararg imports: CssStyle, block: CssStyle = {}) { /**
val style = (document.createElement("div") as HTMLDivElement).style * Request an immediate update of this Komponent
for (imp in imports) { *
imp(style) * This will run immediately, make sure Komponents are not rendered multiple times
} * Any scheduled updates will be run as well
block(style) */
declaredStyles[className] = style fun requestImmediateUpdate() {
dirty = true
runUpdateImmediately(this)
} }
/**
* This function can be overwritten if you know how to update the Komponent yourself
*
* HTMLBuilder.render() is called 1st time the component is rendered, after that this
* method will be called
*/
open fun update() { open fun update() {
refresh() refresh()
} }
/**
* If this function returns a value it will be stored and on the next render it will be compared.
*
* The render will only happen if the hash is not null and has changed
*/
open fun generateMemoizeHash(): Int? = null
internal fun refresh() { internal fun refresh() {
val oldElement = element val currentElement = element
if (logRenderEvent) { check(currentElement != null) {
console.log("Rendering", this) error("element is null")
} }
val newElement = create()
if (oldElement != null) { val parent = currentElement.parentElement as? HTMLElement ?: error("parent is null!?")
element = if (updateStrategy == UpdateStrategy.REPLACE) { var childIndex = 0
if (logReplaceEvent) { for (index in 0 until parent.children.length) {
console.log("Replacing", oldElement, newElement) if (parent.children[index] == currentElement) {
} childIndex = index
oldElement.parentNode?.replaceChild(newElement, oldElement)
newElement
} else {
if (logReplaceEvent) {
console.log("DomDiffing", oldElement, newElement)
}
DiffPatch.updateNode(oldElement, newElement)
} }
} }
val consumer = HtmlBuilder(parent, childIndex)
consumer.root = null
consumer.render()
element = consumer.root
dirty = false dirty = false
} }
@JsName("remove") override fun toString(): String {
fun remove() { return "${this::class.simpleName}"
check(updateStrategy == UpdateStrategy.REPLACE) {
"remote only works with UpdateStrategy.REPLACE"
}
element?.let {
val parent = it.parentElement ?: throw IllegalArgumentException("Element has no parent!?")
if (logReplaceEvent) {
console.log("Remove", it)
}
parent.removeChild(it)
}
} }
companion object { companion object {
private var nextCreateIndex: Int = 1 private var nextCreateIndex: Int = 1
private var updateCallback: Int? = null private var updateCallback: Int? = null
private var scheduledForUpdate = mutableSetOf<Komponent>() private var scheduledForUpdate = mutableSetOf<Komponent>()
private var interceptor: (Komponent, () -> Unit) -> Unit = { _, block -> block() }
var logRenderEvent = false var logRenderEvent = false
var logReplaceEvent = false var logReplaceEvent = false
var updateStrategy = UpdateStrategy.DOM_DIFF var unsafeMode = UnsafeMode.UNSAFE_DISABLED
fun create(parent: HTMLElement, component: Komponent, insertAsFirst: Boolean = false) { fun create(parent: HTMLElement, component: Komponent, insertAsFirst: Boolean = false) {
val element = component.create() component.create(parent)
}
if (insertAsFirst && parent.childElementCount > 0) { fun setUpdateInterceptor(block: (Komponent, () -> Unit) -> Unit) {
parent.insertBefore(element, parent.firstChild) interceptor = block
} else {
parent.appendChild(element)
}
} }
private fun getNextCreateIndex() = nextCreateIndex++ private fun getNextCreateIndex() = nextCreateIndex++
@@ -179,6 +162,11 @@ abstract class Komponent {
} }
} }
private fun runUpdateImmediately(komponent: Komponent) {
scheduledForUpdate.add(komponent)
runUpdate()
}
private fun runUpdate() { private fun runUpdate() {
val todo = scheduledForUpdate.sortedBy { komponent -> komponent.createIndex } val todo = scheduledForUpdate.sortedBy { komponent -> komponent.createIndex }
@@ -187,21 +175,31 @@ abstract class Komponent {
} }
todo.forEach { next -> todo.forEach { next ->
val element = next.element interceptor(next) {
console.log("update element", element) val element = next.element
if (element is HTMLElement) {
console.log("by id", document.getElementById(element.id)) if (element is HTMLElement) {
if (document.getElementById(element.id) != null) {
if (next.dirty) { if (next.dirty) {
if (logRenderEvent) { if (logRenderEvent) {
console.log("Update dirty ${next.createIndex}") console.log("Update dirty ${next.createIndex}")
} }
next.update() val memoizeHash = next.generateMemoizeHash()
if (memoizeHash == null || next.lastMemoizeHash != memoizeHash) {
next.onBeforeUpdate()
next.update()
next.lastMemoizeHash = memoizeHash
next.onAfterUpdate()
} else if (logRenderEvent) {
console.log("Skipped render, memoizeHash is equal $next-[$memoizeHash]")
}
} else { } else {
if (logRenderEvent) { if (logRenderEvent) {
console.log("Skip ${next.createIndex}") console.log("Skip ${next.createIndex}")
} }
} }
} else {
console.log("Komponent element is null", next, element)
} }
} }
} }

View File

@@ -1,132 +1,238 @@
package nl.astraeus.komp package nl.astraeus.komp
import kotlinx.html.* import kotlinx.browser.document
import kotlinx.html.div
import kotlinx.html.i
import kotlinx.html.id
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import org.w3c.dom.HTMLElement import kotlinx.html.p
import org.w3c.dom.Node import kotlinx.html.span
import org.w3c.dom.get import kotlinx.html.svg
import kotlinx.html.table
import kotlinx.html.td
import kotlinx.html.tr
import kotlinx.html.unsafe
import org.w3c.dom.Element
import org.w3c.dom.HTMLDivElement
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue
fun nodesEqual(node1: Node, node2: Node): Boolean { class TestKomponent : Komponent() {
if (node1.childNodes.length != node1.childNodes.length) { override fun HtmlBuilder.render() {
return false div {
+"Test"
}
} }
if (node1 is HTMLElement && node2 is HTMLElement) { }
if (node1.attributes.length != node2.attributes.length) {
return false
}
for (index in 0 until node1.attributes.length) {
node1.attributes[index]?.also { attr1 ->
val attr2 = node2.getAttribute(attr1.name)
if (attr1.value != attr2) { class Child1 : Komponent() {
return false override fun HtmlBuilder.render() {
} div {
} +"Child 1"
} }
for (index in 0 until node1.childNodes.length) { }
node1.childNodes[index]?.also { child1 -> }
node2.childNodes[index]?.also { child2 ->
if (!nodesEqual(child1, child2)) { class Child2 : Komponent() {
return false override fun HtmlBuilder.render() {
div {
+"Child 2"
}
}
}
class SimpleKomponent : Komponent() {
var hello = true
var append = HtmlBuilder.create {
p {
+"Appended"
}
}
override fun HtmlBuilder.render() {
div("div_class") {
span {
svg {
unsafe {
+"""
<p bla>
""".trimIndent()
}
}
if (hello) {
div {
+"Hello"
}
} else {
span {
+"Good bye"
} }
} }
} }
div {
if (hello) {
id = "123"
+"div text"
} else {
+"div text goodbye"
}
onClickFunction = if (hello) {
{
println("onClick")
}
} else {
{
println("onClick 2")
}
}
}
if (hello) {
span {
+"2nd span"
}
}
//append(append)
if (hello) {
include(Child1())
} else {
include(Child2())
}
//append(append)
}
}
}
class IncludeKomponent(
var text: String = "My Text"
) : Komponent() {
override fun generateMemoizeHash(): Int = text.hashCode()
override fun HtmlBuilder.render() {
span {
+text
}
}
}
class ReplaceKomponent : Komponent() {
val includeKomponent = IncludeKomponent()
var includeSpan = true
override fun generateMemoizeHash(): Int = includeSpan.hashCode() * 7 + includeKomponent.generateMemoizeHash()
override fun HtmlBuilder.render() {
div {
+"Child 2"
div {
if (includeSpan) {
span {
i("fas fa-eye") {
+"span1"
}
}
span {
i("fas fa-eye") {
+"span2"
}
}
span {
i("fas fa-eye") {
+"span3"
}
}
}
include(includeKomponent)
}
} }
} }
return true
} }
class TestUpdate { class TestUpdate {
@Test @Test
fun testCompare1() { fun testUpdateWithEmpty() {
val dom1 = HtmlBuilder.create { val div = document.createElement("div") as HTMLDivElement
div { val rk = ReplaceKomponent()
div(classes = "bla") {
span {
+" Some Text "
}
table {
tr {
td {
+"Table column"
}
}
}
}
}
}
val dom2 = HtmlBuilder.create { Komponent.logRenderEvent = true
div {
span {
id = "123"
+"New dom!" Komponent.create(div, rk)
}
input {
value = "bla"
}
}
}
DiffPatch.updateNode(dom1, dom2) println("ReplaceKomponent: ${div.printTree()}")
assertTrue(nodesEqual(dom1, dom2), "Updated dom not equal to original") rk.requestImmediateUpdate()
println("ReplaceKomponent: ${div.printTree()}")
rk.requestImmediateUpdate()
println("ReplaceKomponent: ${div.printTree()}")
rk.includeSpan = false
rk.requestImmediateUpdate()
println("ReplaceKomponent: ${div.printTree()}")
rk.includeSpan = true
rk.includeKomponent.text = "New Text"
rk.requestImmediateUpdate()
println("ReplaceKomponent: ${div.printTree()}")
} }
@Test @Test
fun testCompare2() { fun testSimpleKomponent() {
val dom1 = HtmlBuilder.create { val sk = SimpleKomponent()
div { val div = document.createElement("div") as HTMLDivElement
div(classes = "bla") {
span { Komponent.create(div, sk)
+" Some Text "
} println("SimpleKomponent: ${div.printTree()}")
table {
tr { sk.hello = false
th { sk.requestImmediateUpdate()
+ "Header"
} println("SimpleKomponent updated: ${div.printTree()}")
}
@Test
fun testCreate() {
var elemTest: Element? = null
val element = HtmlBuilder.create {
div("div_class") {
id = "123"
+"Test"
span("span_class") {
+"Span"
elemTest = currentElement()
}
table {
tr {
td {
+"column 1"
} }
tr { td {
td { +"column 2"
+"Table column"
}
} }
} }
} }
} }
} }
val dom2 = HtmlBuilder.create { println("Element: ${element.printTree()}")
div { println("divTst: ${elemTest?.printTree()}")
div { println("span class: ${
span { elemTest?.getAttributeNames()?.joinToString
+ "Other text" { "," }
} }"
} )
span {
id = "123"
+"New dom!"
}
input {
value = "bla"
onClickFunction = {
println("Clickerdyclick!")
}
}
}
}
Komponent.logReplaceEvent = true
DiffPatch.updateNode(dom1, dom2)
assertTrue(nodesEqual(dom1, dom2), "Updated dom not equal to original")
} }
} }