diff --git a/readme.md b/readme.md index 369d533..e6977d2 100644 --- a/readme.md +++ b/readme.md @@ -11,39 +11,21 @@ * [kotlinx-html-js](https://github.com/Kotlin/kotlinx.html) * [komponent](https://github.com/rnentjes/komponent) -Complete source: +This is the complete source: ```kotlin package nl.astraeus.komp.todo -import kotlinx.html.HtmlBlockTag -import kotlinx.html.InputType -import kotlinx.html.TagConsumer -import kotlinx.html.a -import kotlinx.html.button -import kotlinx.html.classes -import kotlinx.html.div -import kotlinx.html.footer -import kotlinx.html.h1 -import kotlinx.html.header -import kotlinx.html.id -import kotlinx.html.input +import kotlinx.browser.document +import kotlinx.html.* import kotlinx.html.js.onClickFunction import kotlinx.html.js.onDoubleClickFunction import kotlinx.html.js.onKeyPressFunction -import kotlinx.html.label -import kotlinx.html.li -import kotlinx.html.section -import kotlinx.html.span -import kotlinx.html.strong -import kotlinx.html.ul +import nl.astraeus.komp.HtmlBuilder import nl.astraeus.komp.Komponent -import nl.astraeus.komp.include -import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLInputElement import org.w3c.dom.events.Event import org.w3c.dom.events.KeyboardEvent -import kotlin.browser.document import kotlin.js.Date /** @@ -51,10 +33,10 @@ */ class Todo( - val dataId: String, - var title: String, - var completed: Boolean = false, - var editing: Boolean = false + val dataId: String, + var title: String, + var completed: Boolean = false, + var editing: Boolean = false ) enum class Selection(val title: String) { @@ -63,50 +45,48 @@ COMPLETED("Completed") } -fun HtmlBlockTag.todo(app: TodoApp, todo: Todo) { - this.include(TodoKomponent(app, todo)) -} - class TodoKomponent( - val app: TodoApp, - val todo: Todo + val app: TodoApp, + val todo: Todo ) : Komponent() { - override fun render(consumer: TagConsumer) = consumer.li { - if (todo.editing) { - classes += "editing" - input(classes = "edit") { - value = todo.title - onKeyPressFunction = { e -> - val target = e.target - if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { - app.editTodo(e, todo) + override fun HtmlBuilder.render() { + li { + if (todo.editing) { + classes = classes + "editing" + input(classes = "edit") { + value = todo.title + onKeyPressFunction = { e -> + val target = e.target + if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { + app.editTodo(e, todo) + } } } - } - } else { - if (todo.completed) { - classes += "completed" - } - attributes["data-id"] = todo.dataId - div(classes = "view") { - input(classes = "toggle") { - type = InputType.checkBox - checked = todo.completed - onClickFunction = { - app.todoClicked(todo) - } + } else { + if (todo.completed) { + classes = classes + "completed" } - label(classes = "todo-content") { - +todo.title + div(classes = "view") { + input(classes = "toggle") { + type = InputType.checkBox + checked = todo.completed + onClickFunction = { + app.todoClicked(todo) + it.preventDefault() + } + } + label(classes = "todo-content") { + +todo.title - onDoubleClickFunction = { - app.setEditing(todo) + onDoubleClickFunction = { + app.setEditing(todo) + } } - } - button(classes = "destroy") { - onClickFunction = { - app.destroyTodo(todo) + button(classes = "destroy") { + onClickFunction = { + app.destroyTodo(todo) + } } } } @@ -125,7 +105,7 @@ if (target is HTMLInputElement) { todoList.add(Todo("${Date().getTime()}", target.value)) - refresh() + requestUpdate() } } @@ -136,7 +116,7 @@ todo.title = target.value todo.editing = false - refresh() + requestUpdate() } } @@ -144,13 +124,13 @@ fun destroyTodo(todo: Todo) { todoList.remove(todo) - refresh() + requestUpdate() } fun selectSelection(selection: Selection) { selected = selection - refresh() + requestUpdate() } fun clearCompleted() { @@ -160,13 +140,13 @@ } } - refresh() + requestUpdate() } fun todoClicked(todo: Todo) { todo.completed = !todo.completed - refresh() + requestUpdate() } fun getItemsLeft(): Int { @@ -184,82 +164,81 @@ todo.editing = todo == editTodo } - refresh() + requestUpdate() } - override fun refresh() { - super.refresh() + override fun HtmlBuilder.render() { + section(classes = "todoapp") { + header(classes = "header") { + h1 { +"todos" } + input(classes = "new-todo") { + id = "todo_input" + placeholder = "What needs to be done?" + autoFocus = true + onKeyPressFunction = { e -> + val target = e.target + if (target is HTMLInputElement && + e is KeyboardEvent && + e.keyCode == 13 && + target.value.isNotBlank() + ) { + e.preventDefault() + e.stopPropagation() - val inputBox = document.getElementById("todo_input") + addTodo(e) - if (inputBox is HTMLInputElement) { - inputBox.focus() - } - } - - override fun render(consumer: TagConsumer) = consumer.section(classes = "todoapp") { - header(classes = "header") { - h1 { +"todos" } - input(classes = "new-todo") { - id = "todo_input" - placeholder = "What needs to be done?" - autoFocus = true - onKeyPressFunction = { e -> - val target = e.target - if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { - addTodo(e) - - target.value = "" - target.defaultValue = "" - } - } - } - } - - section(classes = "main") { - input(classes = "toggle-all") { - type = InputType.checkBox - } - label { - htmlFor = "toggle-all" - +"Mark all as complete" - } - ul(classes = "todo-list") { - for (todo in todoList) { - if (selected == Selection.ALL || - (todo.completed && selected == Selection.COMPLETED) || - (!todo.completed && selected == Selection.ACTIVE)) { - todo(this@TodoApp, todo) - } - } - } - } - - footer(classes = "footer") { - span(classes = "todo-count") { - strong { +"${getItemsLeft()}" } - +" item left" - } - ul(classes = "filters") { - for (selection in Selection.values()) { - li { - a { - if (selection == selected) { - classes += "selected" - } - href = "#" - +selection.title - onClickFunction = { - selectSelection(selection) - } + target.value = "" + target.defaultValue = "" } } } } - button(classes = "clear-completed") { - +"Clear completed" - onClickFunction = { - clearCompleted() + + section(classes = "main") { + input(classes = "toggle-all") { + type = InputType.checkBox + } + label { + htmlFor = "toggle-all" + + "Mark all as complete" + } + ul(classes = "todo-list") { + for (todo in todoList) { + if (selected == Selection.ALL || + (todo.completed && selected == Selection.COMPLETED) || + (!todo.completed && selected == Selection.ACTIVE)) { + include(TodoKomponent(this@TodoApp, todo)) + } + } + } + } + + footer(classes = "footer") { + span(classes = "todo-count") { + strong { +"${getItemsLeft()}" } + +" item left" + } + ul(classes = "filters") { + for (selection in Selection.values()) { + li { + a { + if (selection == selected) { + classes = classes + "selected" + } + href = "#" + +selection.title + onClickFunction = { + selectSelection(selection) + } + } + } + } + } + button(classes = "clear-completed") { + +"Clear completed" + onClickFunction = { + clearCompleted() + } } } } @@ -268,6 +247,6 @@ } fun main() { - Komponent.create(document.body!!, TodoApp(), true) + Komponent.create(document.body!!, TodoApp()) } ``` diff --git a/readme.md b/readme.md index 369d533..e6977d2 100644 --- a/readme.md +++ b/readme.md @@ -11,39 +11,21 @@ * [kotlinx-html-js](https://github.com/Kotlin/kotlinx.html) * [komponent](https://github.com/rnentjes/komponent) -Complete source: +This is the complete source: ```kotlin package nl.astraeus.komp.todo -import kotlinx.html.HtmlBlockTag -import kotlinx.html.InputType -import kotlinx.html.TagConsumer -import kotlinx.html.a -import kotlinx.html.button -import kotlinx.html.classes -import kotlinx.html.div -import kotlinx.html.footer -import kotlinx.html.h1 -import kotlinx.html.header -import kotlinx.html.id -import kotlinx.html.input +import kotlinx.browser.document +import kotlinx.html.* import kotlinx.html.js.onClickFunction import kotlinx.html.js.onDoubleClickFunction import kotlinx.html.js.onKeyPressFunction -import kotlinx.html.label -import kotlinx.html.li -import kotlinx.html.section -import kotlinx.html.span -import kotlinx.html.strong -import kotlinx.html.ul +import nl.astraeus.komp.HtmlBuilder import nl.astraeus.komp.Komponent -import nl.astraeus.komp.include -import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLInputElement import org.w3c.dom.events.Event import org.w3c.dom.events.KeyboardEvent -import kotlin.browser.document import kotlin.js.Date /** @@ -51,10 +33,10 @@ */ class Todo( - val dataId: String, - var title: String, - var completed: Boolean = false, - var editing: Boolean = false + val dataId: String, + var title: String, + var completed: Boolean = false, + var editing: Boolean = false ) enum class Selection(val title: String) { @@ -63,50 +45,48 @@ COMPLETED("Completed") } -fun HtmlBlockTag.todo(app: TodoApp, todo: Todo) { - this.include(TodoKomponent(app, todo)) -} - class TodoKomponent( - val app: TodoApp, - val todo: Todo + val app: TodoApp, + val todo: Todo ) : Komponent() { - override fun render(consumer: TagConsumer) = consumer.li { - if (todo.editing) { - classes += "editing" - input(classes = "edit") { - value = todo.title - onKeyPressFunction = { e -> - val target = e.target - if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { - app.editTodo(e, todo) + override fun HtmlBuilder.render() { + li { + if (todo.editing) { + classes = classes + "editing" + input(classes = "edit") { + value = todo.title + onKeyPressFunction = { e -> + val target = e.target + if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { + app.editTodo(e, todo) + } } } - } - } else { - if (todo.completed) { - classes += "completed" - } - attributes["data-id"] = todo.dataId - div(classes = "view") { - input(classes = "toggle") { - type = InputType.checkBox - checked = todo.completed - onClickFunction = { - app.todoClicked(todo) - } + } else { + if (todo.completed) { + classes = classes + "completed" } - label(classes = "todo-content") { - +todo.title + div(classes = "view") { + input(classes = "toggle") { + type = InputType.checkBox + checked = todo.completed + onClickFunction = { + app.todoClicked(todo) + it.preventDefault() + } + } + label(classes = "todo-content") { + +todo.title - onDoubleClickFunction = { - app.setEditing(todo) + onDoubleClickFunction = { + app.setEditing(todo) + } } - } - button(classes = "destroy") { - onClickFunction = { - app.destroyTodo(todo) + button(classes = "destroy") { + onClickFunction = { + app.destroyTodo(todo) + } } } } @@ -125,7 +105,7 @@ if (target is HTMLInputElement) { todoList.add(Todo("${Date().getTime()}", target.value)) - refresh() + requestUpdate() } } @@ -136,7 +116,7 @@ todo.title = target.value todo.editing = false - refresh() + requestUpdate() } } @@ -144,13 +124,13 @@ fun destroyTodo(todo: Todo) { todoList.remove(todo) - refresh() + requestUpdate() } fun selectSelection(selection: Selection) { selected = selection - refresh() + requestUpdate() } fun clearCompleted() { @@ -160,13 +140,13 @@ } } - refresh() + requestUpdate() } fun todoClicked(todo: Todo) { todo.completed = !todo.completed - refresh() + requestUpdate() } fun getItemsLeft(): Int { @@ -184,82 +164,81 @@ todo.editing = todo == editTodo } - refresh() + requestUpdate() } - override fun refresh() { - super.refresh() + override fun HtmlBuilder.render() { + section(classes = "todoapp") { + header(classes = "header") { + h1 { +"todos" } + input(classes = "new-todo") { + id = "todo_input" + placeholder = "What needs to be done?" + autoFocus = true + onKeyPressFunction = { e -> + val target = e.target + if (target is HTMLInputElement && + e is KeyboardEvent && + e.keyCode == 13 && + target.value.isNotBlank() + ) { + e.preventDefault() + e.stopPropagation() - val inputBox = document.getElementById("todo_input") + addTodo(e) - if (inputBox is HTMLInputElement) { - inputBox.focus() - } - } - - override fun render(consumer: TagConsumer) = consumer.section(classes = "todoapp") { - header(classes = "header") { - h1 { +"todos" } - input(classes = "new-todo") { - id = "todo_input" - placeholder = "What needs to be done?" - autoFocus = true - onKeyPressFunction = { e -> - val target = e.target - if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) { - addTodo(e) - - target.value = "" - target.defaultValue = "" - } - } - } - } - - section(classes = "main") { - input(classes = "toggle-all") { - type = InputType.checkBox - } - label { - htmlFor = "toggle-all" - +"Mark all as complete" - } - ul(classes = "todo-list") { - for (todo in todoList) { - if (selected == Selection.ALL || - (todo.completed && selected == Selection.COMPLETED) || - (!todo.completed && selected == Selection.ACTIVE)) { - todo(this@TodoApp, todo) - } - } - } - } - - footer(classes = "footer") { - span(classes = "todo-count") { - strong { +"${getItemsLeft()}" } - +" item left" - } - ul(classes = "filters") { - for (selection in Selection.values()) { - li { - a { - if (selection == selected) { - classes += "selected" - } - href = "#" - +selection.title - onClickFunction = { - selectSelection(selection) - } + target.value = "" + target.defaultValue = "" } } } } - button(classes = "clear-completed") { - +"Clear completed" - onClickFunction = { - clearCompleted() + + section(classes = "main") { + input(classes = "toggle-all") { + type = InputType.checkBox + } + label { + htmlFor = "toggle-all" + + "Mark all as complete" + } + ul(classes = "todo-list") { + for (todo in todoList) { + if (selected == Selection.ALL || + (todo.completed && selected == Selection.COMPLETED) || + (!todo.completed && selected == Selection.ACTIVE)) { + include(TodoKomponent(this@TodoApp, todo)) + } + } + } + } + + footer(classes = "footer") { + span(classes = "todo-count") { + strong { +"${getItemsLeft()}" } + +" item left" + } + ul(classes = "filters") { + for (selection in Selection.values()) { + li { + a { + if (selection == selected) { + classes = classes + "selected" + } + href = "#" + +selection.title + onClickFunction = { + selectSelection(selection) + } + } + } + } + } + button(classes = "clear-completed") { + +"Clear completed" + onClickFunction = { + clearCompleted() + } } } } @@ -268,6 +247,6 @@ } fun main() { - Komponent.create(document.body!!, TodoApp(), true) + Komponent.create(document.body!!, TodoApp()) } ``` diff --git a/src/jsMain/kotlin/nl/astraeus/komp/todo/Todo.kt b/src/jsMain/kotlin/nl/astraeus/komp/todo/Todo.kt index 3127cca..f98292c 100644 --- a/src/jsMain/kotlin/nl/astraeus/komp/todo/Todo.kt +++ b/src/jsMain/kotlin/nl/astraeus/komp/todo/Todo.kt @@ -231,10 +231,5 @@ } fun main() { - Komponent.logReplaceEvent = false - Komponent.logRenderEvent = false - - println("Create TodoApp()") - Komponent.create(document.body!!, TodoApp()) }