Add input listeners

This commit is contained in:
Alexander Nozik 2023-12-06 23:01:22 +03:00
parent bce61c0fb0
commit 05b87857f4
6 changed files with 31 additions and 18 deletions

View File

@ -13,6 +13,7 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.react.render import space.kscience.visionforge.react.render
import space.kscience.visionforge.solid.Solid import space.kscience.visionforge.solid.Solid
import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.specifications.Canvas3DOptions
@ -26,9 +27,9 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer {
override fun rateVision(vision: Vision): Int = override fun rateVision(vision: Vision): Int =
if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
if (meta["controls.enabled"].boolean == false) { if (meta["controls.enabled"].boolean == false) {
three.render(element, name, vision, meta) three.render(element, client, name, vision, meta)
} else { } else {
space.kscience.visionforge.react.createRoot(element).render { space.kscience.visionforge.react.createRoot(element).render {
child(ThreeCanvasWithControls) { child(ThreeCanvasWithControls) {

View File

@ -1,8 +1,11 @@
package space.kscience.visionforge package space.kscience.visionforge
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.coroutines.launch
import kotlinx.dom.clear
import kotlinx.html.InputType import kotlinx.html.InputType
import kotlinx.html.div import kotlinx.html.div
import kotlinx.html.dom.append
import kotlinx.html.js.input import kotlinx.html.js.input
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLFormElement import org.w3c.dom.HTMLFormElement
@ -13,6 +16,7 @@ import org.w3c.xhr.FormData
import space.kscience.dataforge.context.debug import space.kscience.dataforge.context.debug
import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.logger
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.html.* import space.kscience.visionforge.html.*
/** /**
@ -27,6 +31,12 @@ private fun HTMLElement.subscribeToVision(vision: VisionOfHtml) {
} }
private fun VisionClient.sendInputEvent(name: Name, value: Value?) {
context.launch {
sendEvent(name, VisionValueChangeEvent(value))
}
}
/** /**
* Subscribes the HTML input element to a given vision. * Subscribes the HTML input element to a given vision.
* *
@ -44,6 +54,10 @@ internal val htmlVisionRenderer: ElementVisionRenderer =
div {}.also { div -> div {}.also { div ->
div.subscribeToVision(vision) div.subscribeToVision(vision)
vision.useProperty(VisionOfPlainHtml::content) { vision.useProperty(VisionOfPlainHtml::content) {
div.clear()
div.append {
}
div.textContent = it div.textContent = it
} }
} }
@ -57,7 +71,7 @@ internal val inputVisionRenderer: ElementVisionRenderer =
type = InputType.text type = InputType.text
}.also { htmlInputElement -> }.also { htmlInputElement ->
val onEvent: (Event) -> Unit = { val onEvent: (Event) -> Unit = {
client.sendEvent(name, VisionValueChangeEvent(htmlInputElement.value.asValue())) client.sendInputEvent(name, htmlInputElement.value.asValue())
} }
@ -81,7 +95,7 @@ internal val checkboxVisionRenderer: ElementVisionRenderer =
type = InputType.checkBox type = InputType.checkBox
}.also { htmlInputElement -> }.also { htmlInputElement ->
val onEvent: (Event) -> Unit = { val onEvent: (Event) -> Unit = {
client.sendEvent(name, VisionValueChangeEvent(htmlInputElement.checked.asValue())) client.sendInputEvent(name, htmlInputElement.value.asValue())
} }
@ -105,7 +119,7 @@ internal val textVisionRenderer: ElementVisionRenderer =
type = InputType.text type = InputType.text
}.also { htmlInputElement -> }.also { htmlInputElement ->
val onEvent: (Event) -> Unit = { val onEvent: (Event) -> Unit = {
client.sendEvent(name, VisionValueChangeEvent(htmlInputElement.value.asValue())) client.sendInputEvent(name, htmlInputElement.value.asValue())
} }
@ -131,7 +145,7 @@ internal val numberVisionRenderer: ElementVisionRenderer =
val onEvent: (Event) -> Unit = { val onEvent: (Event) -> Unit = {
htmlInputElement.value.toDoubleOrNull()?.let { htmlInputElement.value.toDoubleOrNull()?.let {
client.sendEvent(name, VisionValueChangeEvent(it.asValue())) client.sendInputEvent(name, htmlInputElement.value.asValue())
} }
} }
@ -159,7 +173,7 @@ internal val rangeVisionRenderer: ElementVisionRenderer =
val onEvent: (Event) -> Unit = { val onEvent: (Event) -> Unit = {
htmlInputElement.value.toDoubleOrNull()?.let { htmlInputElement.value.toDoubleOrNull()?.let {
client.sendEvent(name, VisionValueChangeEvent(it.asValue())) client.sendInputEvent(name, htmlInputElement.value.asValue())
} }
} }
@ -200,7 +214,7 @@ internal fun FormData.toMeta(): Meta {
} }
internal val formVisionRenderer: ElementVisionRenderer = internal val formVisionRenderer: ElementVisionRenderer =
ElementVisionRenderer<VisionOfHtmlForm> { _, vision, _ -> ElementVisionRenderer<VisionOfHtmlForm> { name, client, vision, _ ->
val form = document.getElementById(vision.formId) as? HTMLFormElement val form = document.getElementById(vision.formId) as? HTMLFormElement
?: error("An element with id = '${vision.formId} is not a form") ?: error("An element with id = '${vision.formId} is not a form")
@ -220,7 +234,7 @@ internal val formVisionRenderer: ElementVisionRenderer =
form.onsubmit = { event -> form.onsubmit = { event ->
event.preventDefault() event.preventDefault()
val formData = FormData(form).toMeta() val formData = FormData(form).toMeta()
vision.values = formData client.sendMetaEvent(name, formData)
console.info("Sent: ${formData.toMap()}") console.info("Sent: ${formData.toMap()}")
false false
} }

View File

@ -27,7 +27,7 @@ public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
else -> ElementVisionRenderer.ZERO_RATING else -> ElementVisionRenderer.ZERO_RATING
} }
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
require(vision is VisionOfMarkup) { "The vision is not a markup vision" } require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
val div = document.createElement("div") val div = document.createElement("div")
val flavour = when (vision.format) { val flavour = when (vision.format) {

View File

@ -10,10 +10,7 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.plotly.PlotlyConfig import space.kscience.plotly.PlotlyConfig
import space.kscience.plotly.plot import space.kscience.plotly.plot
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.*
import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionPlugin
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer { public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
public val visionClient: JsVisionClient by require(JsVisionClient) public val visionClient: JsVisionClient by require(JsVisionClient)
@ -27,7 +24,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
else -> ElementVisionRenderer.ZERO_RATING else -> ElementVisionRenderer.ZERO_RATING
} }
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found") val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
val config = PlotlyConfig.read(meta) val config = PlotlyConfig.read(meta)
element.plot(config, plot) element.plot(config, plot)

View File

@ -14,6 +14,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.visionforge.ElementVisionRenderer import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.JsVisionClient import space.kscience.visionforge.JsVisionClient
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import tabulator.Tabulator import tabulator.Tabulator
import tabulator.TabulatorFull import tabulator.TabulatorFull
@ -34,7 +35,7 @@ public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer {
else -> ElementVisionRenderer.ZERO_RATING else -> ElementVisionRenderer.ZERO_RATING
} }
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
val table: VisionOfTable = (vision as? VisionOfTable) val table: VisionOfTable = (vision as? VisionOfTable)
?: error("VisionOfTable expected but ${vision::class} found") ?: error("VisionOfTable expected but ${vision::class} found")

View File

@ -150,7 +150,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
render(vision) render(vision)
} }
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
renderSolid( renderSolid(
element, element,
vision as? Solid ?: error("Solid expected but ${vision::class} found"), vision as? Solid ?: error("Solid expected but ${vision::class} found"),