diff options
11 files changed, 217 insertions, 16 deletions
diff --git a/build.gradle b/build.gradle index 8e43c79b..aeab07b8 100644 --- a/build.gradle +++ b/build.gradle @@ -54,6 +54,7 @@ kotlinFrontend { dependency("awesome-bootstrap-checkbox", "0.3.7") dependency "bootstrap-select" dependency "ajax-bootstrap-select" + dependency "trix" dependency("snabbdom", "0.6.9") dependency "snabbdom-virtualize" dependency "navigo" diff --git a/src/main/assets/css/style.css b/src/main/assets/css/style.css index 61696cb2..fbb29c37 100644 --- a/src/main/assets/css/style.css +++ b/src/main/assets/css/style.css @@ -52,3 +52,11 @@ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAICAQAAADdTl4aAAAAIElEQVQoz2MwrTD9TxFsZ7jPcV+IIsjFQAUw6hFqegQA+xzRHT2p7pEAAAAASUVORK5CYII=') center center no-repeat #cecece; cursor: row-resize; } + +.trix-control { + overflow-y: auto; +} + +trix-toolbar .trix-button-group { + margin-bottom: 3px; +} diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt index b6444720..084b60d6 100644 --- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt @@ -7,19 +7,20 @@ import pl.treksoft.kvision.data.DataComponent import pl.treksoft.kvision.data.DataContainer import pl.treksoft.kvision.dropdown.DD.* import pl.treksoft.kvision.dropdown.DropDown -import pl.treksoft.kvision.form.check.CheckBox import pl.treksoft.kvision.form.INPUTSIZE -import pl.treksoft.kvision.form.text.TEXTINPUTTYPE -import pl.treksoft.kvision.form.text.Text -import pl.treksoft.kvision.form.text.TextArea -import pl.treksoft.kvision.form.text.TextAreaInput -import pl.treksoft.kvision.form.text.TextInput +import pl.treksoft.kvision.form.check.CheckBox import pl.treksoft.kvision.form.select.AjaxOptions import pl.treksoft.kvision.form.select.SELECTWIDTHTYPE import pl.treksoft.kvision.form.select.Select import pl.treksoft.kvision.form.select.SelectInput import pl.treksoft.kvision.form.select.SelectOptGroup import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.form.text.RichText +import pl.treksoft.kvision.form.text.TEXTINPUTTYPE +import pl.treksoft.kvision.form.text.Text +import pl.treksoft.kvision.form.text.TextArea +import pl.treksoft.kvision.form.text.TextAreaInput +import pl.treksoft.kvision.form.text.TextInput import pl.treksoft.kvision.html.* import pl.treksoft.kvision.html.TAG.DIV import pl.treksoft.kvision.html.TAG.H1 @@ -217,6 +218,25 @@ class Showcase : ApplicationBase() { } root.add(mbuttons8) + val htmlArea = RichText("test<b>Boldzik</b>", "Pole html").apply { + size = INPUTSIZE.SMALL + placeholder = "Wprowadź rich text" + width = 50.perc() + inputHeight = 200.px() + } + root.add(htmlArea) + htmlArea.setEventListener<RichText> { + change = { + console.log(self.value) + } + } + val mbuttons9 = Button("Sprawdz html").setEventListener<Button> { + click = { + println(htmlArea.value) + } + } + root.add(mbuttons9) + val container = SimplePanel(setOf("abc", "def")) val h1 = Tag(H1, "To jest <i>test pisania</i> tekstu", false, null, classes = setOf("test", "test2")) container.add(h1) @@ -482,6 +502,11 @@ class Showcase : ApplicationBase() { } else { split.show() } + if (htmlArea.visible) { + htmlArea.hide() + } else { + htmlArea.show() + } } } root.add(button) diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt index 541733b3..e3c34190 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt @@ -27,6 +27,8 @@ object KVManager { private val bootstrapSelectAjaxCss = require("ajax-bootstrap-select/dist/css/ajax-bootstrap-select.min.css") private val bootstrapSelectAjax = require("ajax-bootstrap-select/dist/js/ajax-bootstrap-select.min.js") private val bootstrapSelectAjaxI18n = require("./js/ajax-bootstrap-select.pl-PL.js") + private val trixCss = require("trix/dist/trix.css") + private val trix = require("trix") private val sdPatch = Snabbdom.init(arrayOf(classModule, attributesModule, propsModule, styleModule, eventListenersModule, datasetModule)) diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt index 09d9ec50..a71a84a5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt @@ -7,17 +7,12 @@ import pl.treksoft.kvision.snabbdom.StringBoolPair import pl.treksoft.kvision.snabbdom.StringPair abstract class AbstractTextInput(value: String? = null, - classes: Set<String> = setOf()) : Widget(classes + "form-control"), StringFormField { + classes: Set<String> = setOf()) : Widget(classes), StringFormField { init { this.setInternalEventListener<AbstractTextInput> { input = { - val v = getElementJQuery()?.`val`() as String? - if (v != null && v.isNotEmpty()) { - self.value = v - } else { - self.value = null - } + self.changeValue() } } } @@ -105,9 +100,18 @@ abstract class AbstractTextInput(value: String? = null, return sn } - private fun refreshState() { + protected open fun refreshState() { value?.let { getElementJQuery()?.`val`(it) } ?: getElementJQueryD()?.`val`(null) } + + protected open fun changeValue() { + val v = getElementJQuery()?.`val`() as String? + if (v != null && v.isNotEmpty()) { + this.value = v + } else { + this.value = null + } + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt new file mode 100644 index 00000000..b963b4ea --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt @@ -0,0 +1,19 @@ +package pl.treksoft.kvision.form.text + +open class RichText(value: String? = null, + label: String? = null, rich: Boolean = false) : AbstractText(label, rich) { + + var inputHeight + get() = input.height + set(value) { + input.height = value + } + + final override val input: RichTextInput = RichTextInput(value).apply { id = idc } + + init { + @Suppress("LeakingThis") + input.eventTarget = this + this.addInternal(input) + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt new file mode 100644 index 00000000..5f791c94 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt @@ -0,0 +1,83 @@ +package pl.treksoft.kvision.form.text + +import com.github.snabbdom.VNode +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.snabbdom.StringPair +import kotlin.browser.document + +open class RichTextInput(value: String? = null, classes: Set<String> = setOf()) : + AbstractTextInput(value, classes + "form-control" + "trix-control") { + + private var trixId: String? = null + + override fun render(): VNode { + return kvh("trix-editor") + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + placeholder?.let { + sn.add("placeholder" to it) + } + name?.let { + sn.add("name" to it) + } + autofocus?.let { + if (it) { + sn.add("autofocus" to "autofocus") + } + } + if (disabled) { + sn.add("disabled" to "true") + } + return sn + } + + @Suppress("UnsafeCastFromDynamic") + override fun afterInsert(node: VNode) { + if (this.disabled || this.readonly == true) { + this.getElementJQuery()?.removeAttr("contenteditable") + } else { + this.getElementJQuery()?.on("trix-change", { _, _ -> + if (trixId != null) { + val v = document.getElementById("trix-input-" + trixId)?.let { jQuery(it).`val`() as String? } + value = if (v != null && v.isNotEmpty()) { + v + } else { + null + } + val event = org.w3c.dom.events.Event("change") + this.getElement()?.dispatchEvent(event) + } + }) + } + this.getElementJQuery()?.on("trix-initialize", { _, _ -> + trixId = this.getElementJQuery()?.attr("trix-id") + value?.let { + this.getElement().asDynamic().editor.loadHTML(it) + } + }) + this.getElementJQuery()?.on("trix-file-accept", { e, _ -> e.preventDefault() }) + } + + override fun afterDestroy() { + document.getElementById("trix-input-" + trixId)?.remove() + document.getElementById("trix-toolbar-" + trixId)?.remove() + trixId = null + } + + @Suppress("UnsafeCastFromDynamic") + override fun refreshState() { + val v = document.getElementById("trix-input-" + trixId)?.let { jQuery(it).`val`() as String? } + if (value != v) { + val editor = this.getElement().asDynamic().editor + value?.let { + editor.loadHTML(it) + } ?: editor.loadHTML("") + } + } + + override fun changeValue() { + // disabled parent class functionality + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt index e8fd9a43..2b5ff31d 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt @@ -4,7 +4,7 @@ import com.github.snabbdom.VNode import pl.treksoft.kvision.snabbdom.StringPair open class TextAreaInput(cols: Int? = null, rows: Int? = null, value: String? = null, classes: Set<String> = setOf()) : - AbstractTextInput(value, classes) { + AbstractTextInput(value, classes + "form-control") { var cols: Int? = cols set(value) { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt index 436c0fec..3cd86e04 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt @@ -9,7 +9,7 @@ enum class TEXTINPUTTYPE(val type: String) { } open class TextInput(type: TEXTINPUTTYPE = TEXTINPUTTYPE.TEXT, value: String? = null, classes: Set<String> = setOf()) : - AbstractTextInput(value, classes) { + AbstractTextInput(value, classes + "form-control") { var type: TEXTINPUTTYPE = type set(value) { diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt new file mode 100644 index 00000000..c2a3a6ee --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt @@ -0,0 +1,28 @@ +package test.pl.treksoft.kvision.form.text + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.form.text.RichTextInput +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class RichTextInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val hai = RichTextInput(value = "abc").apply { + placeholder = "place" + id = "idti" + } + root.add(hai) + val id = document.getElementById("test")?.let { jQuery(it).find("trix-editor").attr("trix-id") } ?: "0" + val content = document.getElementById("test")?.let { jQuery(it).find("trix-editor")[0]?.outerHTML } + assertEquals("<trix-editor contenteditable=\"\" class=\"form-control trix-control\" id=\"idti\" placeholder=\"place\" trix-id=\"$id\" input=\"trix-input-$id\" toolbar=\"trix-toolbar-$id\"></trix-editor>", content, "Should render correct html area field") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt new file mode 100644 index 00000000..24851007 --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt @@ -0,0 +1,31 @@ +package test.pl.treksoft.kvision.form.text + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.form.text.RichText +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class RichTextSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val hai = RichText(value = "abc", label = "Field").apply { + placeholder = "place" + id = "idti" + } + root.add(hai) + val id = document.getElementById("test")?.let { jQuery(it).find("trix-editor").attr("trix-id") } ?: "0" + val iid = hai.input.id + val content = document.getElementById("test")?.let { jQuery(it).find("trix-editor")[0]?.outerHTML } + assertEquals("<trix-editor contenteditable=\"\" class=\"form-control trix-control\" id=\"$iid\" placeholder=\"place\" trix-id=\"$id\" input=\"trix-input-$id\" toolbar=\"trix-toolbar-$id\"></trix-editor>", content, "Should render correct html area form field") + val label = document.getElementById("test")?.let { jQuery(it).find("label")[0]?.outerHTML } + assertEquals("<label for=\"$iid\">Field</label>", label, "Should render correct label for html area form field") + } + } + +}
\ No newline at end of file |