diff --git a/demo/playground/src/jvmMain/kotlin/VisionForgePlayGroundForJupyter.kt b/demo/playground/src/jvmMain/kotlin/VisionForgePlayGroundForJupyter.kt index 212d906e..0b87e06d 100644 --- a/demo/playground/src/jvmMain/kotlin/VisionForgePlayGroundForJupyter.kt +++ b/demo/playground/src/jvmMain/kotlin/VisionForgePlayGroundForJupyter.kt @@ -10,13 +10,14 @@ import space.kscience.visionforge.jupyter.VFIntegrationBase import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.asVision import space.kscience.visionforge.solid.Solids +import space.kscience.visionforge.visionManager @DFExperimental internal class VisionForgePlayGroundForJupyter : VFIntegrationBase( Context("VisionForge") { plugin(Solids) plugin(PlotlyPlugin) - } + }.visionManager ) { override fun Builder.afterLoaded() { diff --git a/demo/playground/src/jvmMain/kotlin/formServer.kt b/demo/playground/src/jvmMain/kotlin/formServer.kt index 9e635dc9..cef13f0b 100644 --- a/demo/playground/src/jvmMain/kotlin/formServer.kt +++ b/demo/playground/src/jvmMain/kotlin/formServer.kt @@ -8,8 +8,9 @@ import kotlinx.html.* import space.kscience.dataforge.context.Global import space.kscience.dataforge.context.fetch import space.kscience.visionforge.VisionManager +import space.kscience.visionforge.html.VisionOfHtmlForm import space.kscience.visionforge.html.VisionPage -import space.kscience.visionforge.html.formFragment +import space.kscience.visionforge.html.bindForm import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.server.EngineConnectorConfig import space.kscience.visionforge.server.close @@ -28,8 +29,18 @@ fun main() { resources() } - visionPage(connector, visionManager, VisionPage.scriptHeader("js/visionforge-playground.js")) { - val form = formFragment("form") { + val form = VisionOfHtmlForm("form").apply { + onPropertyChange(visionManager.context) { + println(this) + } + } + + visionPage( + connector, + visionManager, + VisionPage.scriptHeader("js/visionforge-playground.js"), + ) { + bindForm(form) { label { htmlFor = "fname" +"First name:" @@ -61,10 +72,7 @@ fun main() { } } - vision("form") { form } - form.onPropertyChange { - println(this) - } + vision(form) } }.start(false) diff --git a/demo/playground/src/jvmMain/kotlin/serverExtensions.kt b/demo/playground/src/jvmMain/kotlin/serverExtensions.kt index a3bde8d6..b22c6514 100644 --- a/demo/playground/src/jvmMain/kotlin/serverExtensions.kt +++ b/demo/playground/src/jvmMain/kotlin/serverExtensions.kt @@ -1,11 +1,7 @@ package space.kscience.visionforge.examples import space.kscience.dataforge.context.Global -import space.kscience.visionforge.html.HtmlVisionFragment -import space.kscience.visionforge.html.ResourceLocation -import space.kscience.visionforge.html.VisionPage -import space.kscience.visionforge.html.importScriptHeader -import space.kscience.visionforge.makeFile +import space.kscience.visionforge.html.* import space.kscience.visionforge.visionManager import java.awt.Desktop import java.nio.file.Path diff --git a/jupyter/src/jvmMain/kotlin/VFForNotebook.kt b/jupyter/src/jvmMain/kotlin/VFForNotebook.kt index 1d6a430c..eb61f889 100644 --- a/jupyter/src/jvmMain/kotlin/VFForNotebook.kt +++ b/jupyter/src/jvmMain/kotlin/VFForNotebook.kt @@ -20,10 +20,10 @@ import space.kscience.dataforge.context.logger import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.string +import space.kscience.dataforge.names.Name +import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionManager -import space.kscience.visionforge.html.HtmlFormFragment import space.kscience.visionforge.html.HtmlVisionFragment -import space.kscience.visionforge.html.VisionCollector import space.kscience.visionforge.html.visionFragment import space.kscience.visionforge.server.EngineConnectorConfig import space.kscience.visionforge.server.VisionRoute @@ -107,7 +107,7 @@ public class VFForNotebook(override val context: Context) : ContextAware, Corout //server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment) val cellRoute = "content-${counter++}" - val collector: VisionCollector = mutableMapOf() + val collector: MutableMap = mutableMapOf() val url = engine.environment.connectors.first().let { url { @@ -121,15 +121,15 @@ public class VFForNotebook(override val context: Context) : ContextAware, Corout engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector) visionFragment( - context, + visionManager, embedData = true, updatesUrl = url, - collector = collector, + onVisionRendered = { name, vision -> collector[name] = vision }, fragment = fragment ) } else { //if not, use static rendering - visionFragment(context, fragment = fragment) + visionFragment(visionManager, fragment = fragment) } } renderScriptForId(id) diff --git a/jupyter/src/jvmMain/kotlin/VFIntegrationBase.kt b/jupyter/src/jvmMain/kotlin/VFIntegrationBase.kt index 8aa9348a..bf6322e9 100644 --- a/jupyter/src/jvmMain/kotlin/VFIntegrationBase.kt +++ b/jupyter/src/jvmMain/kotlin/VFIntegrationBase.kt @@ -9,6 +9,7 @@ import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.ContextAware import space.kscience.dataforge.misc.DFExperimental import space.kscience.visionforge.Vision +import space.kscience.visionforge.VisionManager import space.kscience.visionforge.html.* import kotlin.random.Random import kotlin.random.nextUInt @@ -17,9 +18,12 @@ import kotlin.random.nextUInt * A base class for different Jupyter VF integrations */ @DFExperimental -public abstract class VFIntegrationBase(final override val context: Context) : JupyterIntegration(), ContextAware { +public abstract class VFIntegrationBase( + public val visionManager: VisionManager, +) : JupyterIntegration(), ContextAware { - protected val handler: VFForNotebook = VFForNotebook(context) + override val context: Context get() = visionManager.context + protected val handler: VFForNotebook = VFForNotebook(visionManager.context) protected abstract fun Builder.afterLoaded() @@ -67,7 +71,7 @@ public abstract class VFIntegrationBase(final override val context: Context) : J val id = "fragment[${page.hashCode()}/${Random.nextUInt()}]" div { this.id = id - visionFragment(context, fragment = page.content) + visionFragment(visionManager, fragment = page.content) } renderScriptForId(id) } diff --git a/jupyter/src/jvmMain/kotlin/forms.kt b/jupyter/src/jvmMain/kotlin/forms.kt new file mode 100644 index 00000000..bccce2e7 --- /dev/null +++ b/jupyter/src/jvmMain/kotlin/forms.kt @@ -0,0 +1,27 @@ +package space.kscience.visionforge.jupyter + +import kotlinx.html.FORM +import kotlinx.html.form +import kotlinx.html.id +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.get +import space.kscience.visionforge.html.HtmlFragment +import space.kscience.visionforge.html.VisionOfHtmlForm + +public class HtmlFormFragment internal constructor( + public val vision: VisionOfHtmlForm, + public val formBody: HtmlFragment, +){ + public val values: Meta? get() = vision.values + public operator fun get(valueName: String): Meta? = values?.get(valueName) +} + +public fun HtmlFormFragment(id: String? = null, builder: FORM.() -> Unit): HtmlFormFragment { + val realId = id ?: "form[${builder.hashCode().toUInt()}]" + return HtmlFormFragment(VisionOfHtmlForm(realId)) { + form { + this.id = realId + builder() + } + } +} \ No newline at end of file diff --git a/jupyter/visionforge-jupyter-gdml/src/jvmMain/kotlin/GdmlForJupyter.kt b/jupyter/visionforge-jupyter-gdml/src/jvmMain/kotlin/GdmlForJupyter.kt index 0f430053..0d55be2e 100644 --- a/jupyter/visionforge-jupyter-gdml/src/jvmMain/kotlin/GdmlForJupyter.kt +++ b/jupyter/visionforge-jupyter-gdml/src/jvmMain/kotlin/GdmlForJupyter.kt @@ -7,12 +7,13 @@ import space.kscience.gdml.Gdml import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.jupyter.VFIntegrationBase import space.kscience.visionforge.solid.Solids +import space.kscience.visionforge.visionManager @DFExperimental internal class GdmlForJupyter : VFIntegrationBase( Context("GDML") { plugin(Solids) - } + }.visionManager ) { override fun Builder.afterLoaded() { diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeWithControlsPlugin.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeWithControlsPlugin.kt index 191742ca..03cbb722 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeWithControlsPlugin.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeWithControlsPlugin.kt @@ -25,7 +25,7 @@ public class ThreeWithControlsPlugin : AbstractPlugin(), ElementVisionRenderer { override fun rateVision(vision: Vision): Int = if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING - override fun render(element: Element, vision: Vision, meta: Meta) { + override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { createRoot(element).render { child(ThreeCanvasWithControls) { attrs { diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt index 341c38ab..d3c2427f 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionRenderer.kt @@ -1,7 +1,6 @@ package space.kscience.visionforge.html import kotlinx.html.* -import space.kscience.dataforge.context.Context import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name @@ -15,8 +14,6 @@ public typealias HtmlVisionFragment = VisionTagConsumer<*>.() -> Unit @DFExperimental public fun HtmlVisionFragment(content: VisionTagConsumer<*>.() -> Unit): HtmlVisionFragment = content -public typealias VisionCollector = MutableMap> - /** * Render a fragment in the given consumer and return a map of extracted visions @@ -27,15 +24,18 @@ public typealias VisionCollector = MutableMap> * @param idPrefix a prefix to be used before vision ids */ public fun TagConsumer<*>.visionFragment( - context: Context, + visionManager: VisionManager, embedData: Boolean = true, fetchDataUrl: String? = null, updatesUrl: String? = null, idPrefix: String? = null, - collector: VisionCollector = mutableMapOf(), + onVisionRendered: (Name, Vision) -> Unit = { _, _ -> }, fragment: HtmlVisionFragment, ) { - val consumer = object : VisionTagConsumer(this@visionFragment, context, idPrefix) { + + val collector: MutableMap> = mutableMapOf() + + val consumer = object : VisionTagConsumer(this@visionFragment, visionManager, idPrefix) { override fun TagConsumer.vision(name: Name?, buildOutput: VisionOutput.() -> Vision): T { //Avoid re-creating cached visions @@ -47,6 +47,7 @@ public fun TagConsumer<*>.visionFragment( val (output, vision) = collector.getOrPut(actualName) { val output = VisionOutput(context, actualName) val vision = output.buildOutput() + onVisionRendered(actualName, vision) output to vision } @@ -54,8 +55,15 @@ public fun TagConsumer<*>.visionFragment( } override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) { - // Toggle update mode + val (_, actualVision) = collector.getOrPut(name) { + val output = VisionOutput(context, name) + onVisionRendered(name, vision) + output to vision + } + + + // Toggle update mode updatesUrl?.let { attributes[OUTPUT_CONNECT_ATTRIBUTE] = it } @@ -69,7 +77,7 @@ public fun TagConsumer<*>.visionFragment( type = "text/json" attributes["class"] = OUTPUT_DATA_CLASS unsafe { - +"\n${manager.encodeToString(vision)}\n" + +"\n${manager.encodeToString(actualVision)}\n" } } } @@ -80,19 +88,20 @@ public fun TagConsumer<*>.visionFragment( } public fun FlowContent.visionFragment( - context: Context, + visionManager: VisionManager, embedData: Boolean = true, fetchDataUrl: String? = null, updatesUrl: String? = null, + onVisionRendered: (Name, Vision) -> Unit = { _, _ -> }, idPrefix: String? = null, - visionCache: VisionCollector = mutableMapOf(), + fragment: HtmlVisionFragment, ): Unit = consumer.visionFragment( - context, - embedData, - fetchDataUrl, - updatesUrl, - idPrefix, - visionCache, + visionManager = visionManager, + embedData = embedData, + fetchDataUrl = fetchDataUrl, + updatesUrl = updatesUrl, + idPrefix = idPrefix, + onVisionRendered = onVisionRendered, fragment = fragment ) \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt index 4315066a..d9c0347d 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionOfHtmlForm.kt @@ -7,7 +7,6 @@ import kotlinx.html.id import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.node @Serializable @@ -18,29 +17,10 @@ public class VisionOfHtmlForm( public var values: Meta? by mutableProperties.node() } -public class HtmlFormFragment internal constructor( - public val vision: VisionOfHtmlForm, - public val formBody: HtmlFragment, -){ - public val values: Meta? get() = vision.values - public operator fun get(valueName: String): Meta? = values?.get(valueName) -} - -public fun HtmlFormFragment(id: String? = null, builder: FORM.() -> Unit): HtmlFormFragment { - val realId = id ?: "form[${builder.hashCode().toUInt()}]" - return HtmlFormFragment(VisionOfHtmlForm(realId)) { - form { - this.id = realId - builder() - } - } -} - -public fun TagConsumer.formFragment( - id: String? = null, +public fun TagConsumer.bindForm( + visionOfForm: VisionOfHtmlForm, builder: FORM.() -> Unit, -): VisionOfHtmlForm { - val formFragment = HtmlFormFragment(id, builder) - fragment(formFragment.formBody) - return formFragment.vision +): R = form { + this.id = visionOfForm.formId + builder() } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt index 6fc915ef..80a7be7e 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionTagConsumer.kt @@ -2,6 +2,7 @@ package space.kscience.visionforge.html import kotlinx.html.* import space.kscience.dataforge.context.Context +import space.kscience.dataforge.context.ContextAware import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MetaSerializer @@ -56,9 +57,11 @@ public class VisionOutput @PublishedApi internal constructor(public val context: @VisionDSL public abstract class VisionTagConsumer( private val root: TagConsumer, - public val context: Context, + public val visionManager: VisionManager, private val idPrefix: String? = null, -) : TagConsumer by root { +) : TagConsumer by root, ContextAware { + + override val context: Context get() = visionManager.context public open fun resolveId(name: Name): String = (idPrefix ?: "output") + "[$name]" diff --git a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt index 670f2018..efc7cfd0 100644 --- a/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt +++ b/visionforge-core/src/commonTest/kotlin/space/kscience/visionforge/html/HtmlTagTest.kt @@ -18,7 +18,7 @@ fun FlowContent.renderVisionFragment( fragment: HtmlVisionFragment, ): Map { val visionMap = HashMap() - val consumer = object : VisionTagConsumer(consumer, Global, idPrefix) { + val consumer = object : VisionTagConsumer(consumer, Global.visionManager, idPrefix) { override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) { visionMap[name] = vision renderer(name, vision, outputMeta) diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt index efb8a9fe..9a6547ce 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt @@ -4,6 +4,7 @@ import kotlinx.browser.document import kotlinx.browser.window import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import org.w3c.dom.* import org.w3c.dom.url.URL @@ -68,18 +69,6 @@ public class VisionClient : AbstractPlugin() { changeCollector.propertyChanged(visionName, propertyName, item) } - public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Boolean) { - visionPropertyChanged(visionName, propertyName, Meta(item)) - } - - public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: String) { - visionPropertyChanged(visionName, propertyName, Meta(item)) - } - - public fun visionPropertyChanged(visionName: Name, propertyName: Name, item: Number) { - visionPropertyChanged(visionName, propertyName, Meta(item)) - } - public fun visionChanged(name: Name?, child: Vision?) { changeCollector.setChild(name, child) } @@ -139,10 +128,12 @@ public class VisionClient : AbstractPlugin() { onopen = { feedbackJob = visionManager.context.launch { - delay(feedbackAggregationTime.milliseconds) - if (!changeCollector.isEmpty()) { - send(visionManager.encodeToString(changeCollector.deepCopy(visionManager))) - changeCollector.reset() + while (isActive) { + delay(feedbackAggregationTime.milliseconds) + if (!changeCollector.isEmpty()) { + send(visionManager.encodeToString(changeCollector.deepCopy(visionManager))) + changeCollector.reset() + } } } logger.info { "WebSocket update channel established for output '$name'" } @@ -247,6 +238,21 @@ public class VisionClient : AbstractPlugin() { } } +public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Meta?) { + visionPropertyChanged(visionName, propertyName.parseAsName(true), item) +} + +public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Number) { + visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: String) { + visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} + +public fun VisionClient.visionPropertyChanged(visionName: Name, propertyName: String, item: Boolean) { + visionPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item)) +} private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { if (document.body != null) { diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt index 86324d89..390058ea 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/inputRenderers.kt @@ -9,8 +9,11 @@ import org.w3c.dom.HTMLFormElement import org.w3c.dom.HTMLInputElement import org.w3c.dom.get import org.w3c.xhr.FormData +import space.kscience.dataforge.context.debug +import space.kscience.dataforge.context.logger import space.kscience.dataforge.meta.DynamicMeta import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.toMap import space.kscience.dataforge.meta.valueSequence import space.kscience.visionforge.html.VisionOfHtmlForm import space.kscience.visionforge.html.VisionOfNumberField @@ -33,7 +36,7 @@ internal fun textVisionRenderer( value = it ?: "" } onChangeFunction = { -// client.visionPropertyChanged(name, VisionOfTextField::text.name.pa, value) + client.visionPropertyChanged(name, VisionOfTextField::text.name, value) } } } @@ -55,7 +58,7 @@ internal fun numberVisionRenderer( value = it?.toDouble() ?: 0.0 } onChangeFunction = { -// vision.value = value.toDoubleOrNull() + client.visionPropertyChanged(name, VisionOfNumberField::value.name, value) } } } @@ -90,9 +93,10 @@ internal fun formVisionRenderer( val form = document.getElementById(vision.formId) as? HTMLFormElement ?: error("An element with id = '${vision.formId} is not a form") - console.info("Adding hooks to form '$form'") + client.logger.debug{"Adding hooks to form with id = '$vision.formId'"} vision.useProperty(VisionOfHtmlForm::values) { values -> + client.logger.debug{"Updating form '${vision.formId}' with values $values"} val inputs = form.getElementsByTagName("input") values?.valueSequence()?.forEach { (token, value) -> (inputs[token.toString()] as? HTMLInputElement)?.value = value.toString() @@ -102,8 +106,8 @@ internal fun formVisionRenderer( form.onsubmit = { event -> event.preventDefault() val formData = FormData(form).toMeta() - //console.log(formData.toString()) - //vision.values = formData + client.visionPropertyChanged(name, VisionOfHtmlForm::values.name, formData) + console.info("Sent: ${formData.toMap()}") false } } \ No newline at end of file diff --git a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/htmlExport.kt b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/htmlExport.kt index cba1ee31..ff0c3eee 100644 --- a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/htmlExport.kt +++ b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/htmlExport.kt @@ -1,4 +1,4 @@ -package space.kscience.visionforge +package space.kscience.visionforge.html import kotlinx.html.body import kotlinx.html.head @@ -6,10 +6,7 @@ import kotlinx.html.meta import kotlinx.html.stream.createHTML import space.kscience.dataforge.context.Global import space.kscience.dataforge.misc.DFExperimental -import space.kscience.visionforge.html.HtmlFragment -import space.kscience.visionforge.html.VisionPage -import space.kscience.visionforge.html.fragment -import space.kscience.visionforge.html.visionFragment +import space.kscience.visionforge.visionManager import java.awt.Desktop import java.nio.file.Files import java.nio.file.Path @@ -87,7 +84,7 @@ public fun VisionPage.makeFile( } } body { - visionFragment(Global, fragment = content) + visionFragment(Global.visionManager, fragment = content) } }.finalize() diff --git a/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt b/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt index d3b8473e..8344e52e 100644 --- a/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt +++ b/visionforge-plotly/src/jsMain/kotlin/space/kscience/visionforge/plotly/plotlyJs.kt @@ -28,7 +28,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer { else -> ElementVisionRenderer.ZERO_RATING } - override fun render(element: Element, vision: Vision, meta: Meta) { + override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found") val config = PlotlyConfig.read(meta) element.plot(plot, config) diff --git a/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt b/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt index 957936a3..42f02e75 100644 --- a/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt +++ b/visionforge-server/src/main/kotlin/space/kscience/visionforge/server/VisionServer.kt @@ -15,7 +15,6 @@ import io.ktor.server.util.* import io.ktor.server.websocket.* import io.ktor.util.pipeline.* import io.ktor.websocket.* -import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -97,8 +96,8 @@ public fun Application.serveVisionData( val vision: Vision = resolveVision(Name.parse(name)) ?: error("Plot with id='$name' not registered") launch { - incoming.consumeEach { - val data = it.data.decodeToString() + for(frame in incoming) { + val data = frame.data.decodeToString() application.log.debug("Received update: \n$data") val change = configuration.visionManager.jsonFormat.decodeFromString( VisionChange.serializer(), data @@ -143,8 +142,8 @@ public fun Application.serveVisionData( public fun Application.serveVisionData( configuration: VisionRoute, - cache: VisionCollector, -): Unit = serveVisionData(configuration) { cache[it]?.second } + data: Map, +): Unit = serveVisionData(configuration) { data[it] } // ///** @@ -179,7 +178,7 @@ public fun Application.visionPage( ) { require(WebSockets) - val collector: VisionCollector = mutableMapOf() + val collector: MutableMap = mutableMapOf() val html = createHTML().apply { head { @@ -193,7 +192,7 @@ public fun Application.visionPage( body { //Load the fragment and remember all loaded visions visionFragment( - context = configuration.context, + visionManager = configuration.visionManager, embedData = configuration.dataMode == VisionRoute.Mode.EMBED, fetchDataUrl = if (configuration.dataMode != VisionRoute.Mode.EMBED) { url { @@ -210,7 +209,7 @@ public fun Application.visionPage( path(route, "ws") } } else null, - visionCache = collector, + onVisionRendered = { name, vision -> collector[name] = vision }, fragment = visionFragment ) } diff --git a/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt b/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt index 28ad7327..dcf7ce4f 100644 --- a/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt +++ b/visionforge-tables/src/jsMain/kotlin/space/kscience/visionforge/tables/TableVisionJsPlugin.kt @@ -35,7 +35,7 @@ public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer { else -> ElementVisionRenderer.ZERO_RATING } - override fun render(element: Element, vision: Vision, meta: Meta) { + override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { val table: VisionOfTable = (vision as? VisionOfTable) ?: error("VisionOfTable expected but ${vision::class} found") diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt index bae26853..5aacba18 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt @@ -86,7 +86,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { }.launchIn(context) vision.children.changes.onEach { childName -> - if(childName.isEmpty()) return@onEach + if (childName.isEmpty()) return@onEach val child = vision.children.getChild(childName) @@ -147,7 +147,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { render(vision) } - override fun render(element: Element, vision: Vision, meta: Meta) { + override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { renderSolid( element, vision as? Solid ?: error("Solid expected but ${vision::class} found"), diff --git a/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/serverExtensions.kt b/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/serverExtensions.kt index 8f52ccf1..ba533979 100644 --- a/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/serverExtensions.kt +++ b/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/serverExtensions.kt @@ -3,7 +3,6 @@ package space.kscience.visionforge.three import space.kscience.dataforge.context.Global import space.kscience.dataforge.misc.DFExperimental import space.kscience.visionforge.html.* -import space.kscience.visionforge.makeFile import space.kscience.visionforge.visionManager import java.awt.Desktop import java.nio.file.Path