.github/ workflows | 2 years ago | ||
gradle/ wrapper | 1 year ago | ||
src/ jsMain | 3 months ago | ||
.gitignore | 3 months ago | ||
build.gradle.kts | 3 months ago | ||
gradlew | 7 years ago | ||
gradlew.bat | 7 years ago | ||
komp-todo.iml | 4 years ago | ||
komp-todo.ipr | 6 years ago | ||
readme.md | 3 months ago | ||
settings.gradle.kts | 1 year ago |
An example on how to build a single page app with Kotlin (javascript) using static html builders.
Runing example: komp-todo
Compare it with other js frameworks: https://github.com/tastejs/todomvc/
You can also find an example of a complete application here: simple-password-manager
Dependencies:
This is the complete source:
package nl.astraeus.komp.todo import kotlinx.browser.document import kotlinx.html.* import kotlinx.html.js.onClickFunction import kotlinx.html.js.onDoubleClickFunction import kotlinx.html.js.onKeyPressFunction import nl.astraeus.komp.HtmlBuilder import nl.astraeus.komp.Komponent import org.w3c.dom.HTMLInputElement import org.w3c.dom.events.Event import org.w3c.dom.events.KeyboardEvent import kotlin.js.Date /** * see: https://github.com/tastejs/todomvc/ */ data class Todo( val dataId: String, var title: String, var completed: Boolean = false, var editing: Boolean = false ) enum class Selection(val title: String) { ALL("All"), ACTIVE("Active"), COMPLETED("Completed") } class TodoKomponent( val app: TodoApp, val todo: Todo ) : Komponent() { 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 = classes + "completed" } 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) } } button(classes = "destroy") { onClickFunction = { app.destroyTodo(todo) } } } } } } } class TodoApp : Komponent() { val todoList: MutableList<Todo> = ArrayList() var selected: Selection = Selection.ALL fun addTodo(e: Event) { val target = e.target if (target is HTMLInputElement) { todoList.add(Todo("${Date().getTime()}", target.value)) this@TodoApp.requestUpdate() } } fun editTodo(e: Event, todo: Todo) { val target = e.target if (target is HTMLInputElement) { todo.title = target.value todo.editing = false requestUpdate() } } fun destroyTodo(todo: Todo) { todoList.remove(todo) requestUpdate() } fun selectSelection(selection: Selection) { selected = selection requestUpdate() } fun clearCompleted(e: Event) { for (todo in ArrayList(todoList)) { if (todo.completed) { todoList.remove(todo) } } requestUpdate() } fun todoClicked(todo: Todo) { todo.completed = !todo.completed requestUpdate() } private fun getItemsLeft(): Int = todoList.count { todo -> !todo.completed } fun setEditing(editTodo: Todo) { for (todo in todoList) { todo.editing = todo == editTodo } requestUpdate() } 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() 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)) { include(TodoKomponent(this@TodoApp, todo)) } } } } footer(classes = "footer") { span(classes = "todo-count") { when(getItemsLeft()) { 0 -> { + "No items" } 1 -> { + "1 item left" } else -> + "${getItemsLeft()} items 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 } } } } } fun main() { Komponent.create(document.body!!, TodoApp()) }