diff --git a/build.gradle.kts b/build.gradle.kts
index 73f03bbd..35502755 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,7 +13,7 @@ val fxVersion by extra("11")
allprojects {
group = "space.kscience"
- version = "0.3.0-dev-11"
+ version = "0.3.0-dev-12"
}
subprojects {
diff --git a/demo/playground/build.gradle.kts b/demo/playground/build.gradle.kts
index 77dd565e..36bd6b7b 100644
--- a/demo/playground/build.gradle.kts
+++ b/demo/playground/build.gradle.kts
@@ -51,7 +51,7 @@ kotlin {
implementation(projects.visionforgeMarkdown)
implementation(projects.visionforgeTables)
implementation(projects.cernRootLoader)
- implementation(projects.visionforgeJupyter.visionforgeJupyterCommon)
+ api(projects.visionforgeJupyter.visionforgeJupyterCommon)
}
}
diff --git a/demo/playground/notebooks/common-demo.ipynb b/demo/playground/notebooks/common-demo.ipynb
index 2e4b6110..78797545 100644
--- a/demo/playground/notebooks/common-demo.ipynb
+++ b/demo/playground/notebooks/common-demo.ipynb
@@ -2,77 +2,31 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"metadata": {
- "ExecuteTime": {
- "end_time": "2023-07-20T06:12:13.305060400Z",
- "start_time": "2023-07-20T06:12:13.011273800Z"
- }
+ "tags": []
},
"outputs": [],
"source": [
"@file:Repository(\"*mavenLocal\")\n",
"@file:Repository(\"https://repo.kotlin.link\")\n",
"@file:Repository(\"https://maven.pkg.jetbrains.space/spc/p/sci/dev\")\n",
- "@file:DependsOn(\"space.kscience:visionforge-jupyter-common-jvm:0.3.0-dev-11\")"
+ "@file:DependsOn(\"space.kscience:visionforge-jupyter-common-jvm:0.3.0-dev-12\")\n",
+ "//import space.kscience.visionforge.jupyter.JupyterCommonIntegration\n",
+ "//\n",
+ "//val integration = JupyterCommonIntegration()\n",
+ "//USE(integration.getDefinitions(notebook).first())"
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"metadata": {
- "collapsed": false,
- "jupyter": {
- "outputs_hidden": false
- },
- "ExecuteTime": {
- "end_time": "2023-07-20T06:12:19.603077Z",
- "start_time": "2023-07-20T06:12:19.419504300Z"
- }
+ "tags": []
},
- "outputs": [
- {
- "data": {
- "text/html": "
Starting VisionForge server on http://localhost:7777
\n"
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "vf.startServer()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {
- "collapsed": false,
- "jupyter": {
- "outputs_hidden": false
- },
- "ExecuteTime": {
- "end_time": "2023-07-20T06:12:21.490069100Z",
- "start_time": "2023-07-20T06:12:20.694188600Z"
- }
- },
- "outputs": [
- {
- "data": {
- "text/html": "\n
AAA
\n
\n \n
\n
\n \n
\n
\n\n"
- },
- "execution_count": 4,
- "metadata": {
- "text/html": {
- "isolated": true
- }
- },
- "output_type": "execute_result"
- }
- ],
- "source": [
- "vf.page {\n",
+ "vf.fragment {\n",
" h1 { +\"AAA\" }\n",
" vision {\n",
" solid {\n",
@@ -100,24 +54,27 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
- "collapsed": false,
"jupyter": {
"outputs_hidden": false
- }
+ },
+ "tags": []
},
"outputs": [],
"source": [
- "vf.stopServer()"
+ "Plotly.plot { \n",
+ " scatter{\n",
+ " x(1,2,3)\n",
+ " y(1,2,3)\n",
+ " }\n",
+ "}"
]
},
{
"cell_type": "code",
"execution_count": null,
+ "metadata": {},
"outputs": [],
- "source": [],
- "metadata": {
- "collapsed": false
- }
+ "source": []
}
],
"metadata": {
diff --git a/ui/react/src/main/kotlin/space/kscience/visionforge/react/ThreeCanvasComponent.kt b/ui/react/src/main/kotlin/space/kscience/visionforge/react/ThreeCanvasComponent.kt
index 50c8a60a..8cfa515d 100644
--- a/ui/react/src/main/kotlin/space/kscience/visionforge/react/ThreeCanvasComponent.kt
+++ b/ui/react/src/main/kotlin/space/kscience/visionforge/react/ThreeCanvasComponent.kt
@@ -2,7 +2,6 @@ package space.kscience.visionforge.react
import kotlinx.css.*
import org.w3c.dom.Element
-import org.w3c.dom.HTMLElement
import react.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
@@ -29,7 +28,7 @@ public val ThreeCanvasComponent: FC = fc("ThreeCanvasComponent
useEffect(props.solid, props.options, elementRef) {
if (canvas == null) {
- val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
+ val element = elementRef.current ?: error("Canvas element not found")
canvas = ThreeCanvas(three, element, props.options ?: Canvas3DOptions())
}
}
diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlFragment.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlFragment.kt
index b733e6a4..ec3f3605 100644
--- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlFragment.kt
+++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlFragment.kt
@@ -4,19 +4,28 @@ import kotlinx.html.FlowContent
import kotlinx.html.TagConsumer
import kotlinx.html.stream.createHTML
-public typealias HtmlFragment = TagConsumer<*>.() -> Unit
-
-public fun HtmlFragment.renderToString(): String = createHTML().apply(this).finalize()
-
-public fun TagConsumer<*>.fragment(fragment: HtmlFragment) {
- fragment()
+/**
+ * A standalone HTML fragment
+ */
+public fun interface HtmlFragment {
+ public fun TagConsumer<*>.append()
}
-public fun FlowContent.fragment(fragment: HtmlFragment) {
- fragment(consumer)
-}
+/**
+ * Convenience method to append fragment to the given [consumer]
+ */
+public fun HtmlFragment.appendTo(consumer: TagConsumer<*>): Unit = consumer.append()
-public operator fun HtmlFragment.plus(other: HtmlFragment): HtmlFragment = {
- this@plus()
- other()
+/**
+ * Create a string from this [HtmlFragment]
+ */
+public fun HtmlFragment.renderToString(): String = createHTML().apply { append() }.finalize()
+
+public fun TagConsumer<*>.appendFragment(fragment: HtmlFragment): Unit = fragment.appendTo(this)
+
+public fun FlowContent.appendFragment(fragment: HtmlFragment): Unit = fragment.appendTo(consumer)
+
+public operator fun HtmlFragment.plus(other: HtmlFragment): HtmlFragment = HtmlFragment {
+ this@plus.appendTo(this)
+ other.appendTo(this)
}
\ No newline at end of file
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 d3c2427f..c02b6e64 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
@@ -2,18 +2,17 @@ package space.kscience.visionforge.html
import kotlinx.html.*
import space.kscience.dataforge.meta.Meta
-import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager
-public typealias HtmlVisionFragment = VisionTagConsumer<*>.() -> Unit
-
-@DFExperimental
-public fun HtmlVisionFragment(content: VisionTagConsumer<*>.() -> Unit): HtmlVisionFragment = content
+public fun interface HtmlVisionFragment{
+ public fun VisionTagConsumer<*>.append()
+}
+public fun HtmlVisionFragment.appendTo(consumer: VisionTagConsumer<*>): Unit = consumer.append()
/**
* Render a fragment in the given consumer and return a map of extracted visions
@@ -84,7 +83,7 @@ public fun TagConsumer<*>.visionFragment(
}
}
- fragment(consumer)
+ fragment.appendTo(consumer)
}
public fun FlowContent.visionFragment(
diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionPage.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionPage.kt
index f92454f0..1ea216c5 100644
--- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionPage.kt
+++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/VisionPage.kt
@@ -17,7 +17,7 @@ public data class VisionPage(
/**
* Use a script with given [src] as a global header for all pages.
*/
- public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = {
+ public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = HtmlFragment{
script {
type = "text/javascript"
this.src = src
@@ -28,7 +28,7 @@ public data class VisionPage(
/**
* Use css with the given stylesheet link as a global header for all pages.
*/
- public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = {
+ public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = HtmlFragment{
link {
rel = "stylesheet"
this.href = href
@@ -36,7 +36,7 @@ public data class VisionPage(
}
}
- public fun title(title:String): HtmlFragment = {
+ public fun title(title:String): HtmlFragment = HtmlFragment{
title(title)
}
}
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 efc7cfd0..eaea0a4e 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
@@ -24,7 +24,7 @@ fun FlowContent.renderVisionFragment(
renderer(name, vision, outputMeta)
}
}
- fragment(consumer)
+ fragment.appendTo(consumer)
return visionMap
}
@@ -35,7 +35,7 @@ private fun VisionOutput.base(block: VisionGroup.() -> Unit) = context.visionMan
@DFExperimental
class HtmlTagTest {
- val fragment: HtmlVisionFragment = {
+ val fragment = HtmlVisionFragment{
div {
h1 { +"Head" }
vision("ddd") {
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 7d61ce24..c9146efd 100644
--- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt
+++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/VisionClient.kt
@@ -286,8 +286,8 @@ public fun VisionClient.renderAllVisionsIn(element: Element) {
/**
* Render all visions in an element with a given [id]
*/
-public fun VisionClient.renderAllVisionsById(id: String): Unit = whenDocumentLoaded {
- val element = getElementById(id)
+public fun VisionClient.renderAllVisionsById(document: Document, id: String): Unit {
+ val element = document.getElementById(id)
if (element != null) {
renderAllVisionsIn(element)
} else {
diff --git a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/HtmlVisionContext.kt b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/HtmlVisionContext.kt
index 7d82da49..3796d436 100644
--- a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/HtmlVisionContext.kt
+++ b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/HtmlVisionContext.kt
@@ -34,10 +34,10 @@ public interface HtmlVisionContext : ContextAware {
public typealias HtmlVisionContextFragment = context(HtmlVisionContext) TagConsumer<*>.() -> Unit
-context(HtmlVisionContext)
-public fun HtmlVisionFragment(
- content: TagConsumer<*>.() -> Unit,
-): HtmlVisionFragment = content
+//context(HtmlVisionContext)
+//public fun HtmlVisionFragment(
+// content: TagConsumer<*>.() -> Unit,
+//): HtmlVisionFragment = HtmlVisionFragment { }
context(HtmlVisionContext)
private fun TagConsumer.vision(
diff --git a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt
index 4c4ab90a..bf880e84 100644
--- a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt
+++ b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt
@@ -91,14 +91,14 @@ internal fun checkOrStoreFile(htmlPath: Path, filePath: Path, resource: String,
*/
internal fun fileScriptHeader(
path: Path,
-): HtmlFragment = {
+): HtmlFragment = HtmlFragment{
script {
type = "text/javascript"
src = path.toString()
}
}
-internal fun embedScriptHeader(resource: String, classLoader: ClassLoader): HtmlFragment = {
+internal fun embedScriptHeader(resource: String, classLoader: ClassLoader): HtmlFragment = HtmlFragment{
script {
type = "text/javascript"
unsafe {
@@ -113,7 +113,7 @@ internal fun fileCssHeader(
cssPath: Path,
resource: String,
classLoader: ClassLoader,
-): HtmlFragment = {
+): HtmlFragment = HtmlFragment{
val relativePath = checkOrStoreFile(basePath, cssPath, resource, classLoader)
link {
rel = "stylesheet"
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 ec31b7b4..e45dd9b5 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
@@ -78,7 +78,7 @@ public fun VisionPage.makeFile(
charset = "utf-8"
}
actualHeaders.values.forEach {
- fragment(it)
+ appendFragment(it)
}
}
body {
diff --git a/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt b/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt
index 24304136..84c6908b 100644
--- a/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt
+++ b/visionforge-jupyter/src/jsMain/kotlin/VFNotebookClient.kt
@@ -1,6 +1,7 @@
package space.kscience.visionforge.jupyter
import kotlinx.browser.window
+import org.w3c.dom.Document
import org.w3c.dom.Element
import space.kscience.dataforge.context.AbstractPlugin
import space.kscience.dataforge.context.Context
@@ -20,8 +21,8 @@ public class VFNotebookClient : AbstractPlugin() {
client.renderAllVisionsIn(element)
}
- public fun renderAllVisionsById(id: String) {
- client.renderAllVisionsById(id)
+ public fun renderAllVisionsById(document: Document, id: String) {
+ client.renderAllVisionsById(document, id)
}
public fun renderAllVisions() {
diff --git a/visionforge-jupyter/src/jvmMain/kotlin/VisionForge.kt b/visionforge-jupyter/src/jvmMain/kotlin/VisionForge.kt
index 0a538a3e..d2acefde 100644
--- a/visionforge-jupyter/src/jvmMain/kotlin/VisionForge.kt
+++ b/visionforge-jupyter/src/jvmMain/kotlin/VisionForge.kt
@@ -11,6 +11,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.jetbrains.kotlinx.jupyter.api.HTML
+import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextAware
@@ -20,24 +21,33 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager
-import space.kscience.visionforge.html.HtmlVisionFragment
-import space.kscience.visionforge.html.visionFragment
+import space.kscience.visionforge.html.*
import space.kscience.visionforge.server.VisionRoute
import space.kscience.visionforge.server.serveVisionData
import kotlin.coroutines.CoroutineContext
import kotlin.random.Random
import kotlin.random.nextUInt
-internal fun TagConsumer<*>.renderScriptForId(id: String) {
- script {
- type = "text/javascript"
- unsafe { +"VisionForge.renderAllVisionsById(\"$id\");" }
- }
+
+@Suppress("FunctionName")
+internal inline fun HTML(isolated: Boolean = false, block: TagConsumer<*>.() -> Unit): MimeTypedResult =
+ HTML(createHTML().apply(block).finalize(), isolated)
+
+internal fun KotlinKernelHost.displayHtml(block: TagConsumer<*>.() -> Unit) {
+ display(HTML(false, block), null)
+}
+
+public enum class VisionForgeCompatibility {
+ JUPYTER,
+ JUPYTER_LAB,
+ DATALORE,
+ IDEA
}
/**
* A handler class that includes a server and common utilities
*/
+@Suppress("ExtractKtorModule")
public class VisionForge(
public val visionManager: VisionManager,
meta: Meta = Meta.EMPTY,
@@ -51,29 +61,28 @@ public class VisionForge(
private var engine: ApplicationEngine? = null
- public var isolateFragments: Boolean = false
+ public var notebookMode: VisionForgeCompatibility = VisionForgeCompatibility.IDEA
override val coroutineContext: CoroutineContext get() = context.coroutineContext
- public fun legacyMode() {
- isolateFragments = true
- }
public fun isServerRunning(): Boolean = engine != null
- public fun html(block: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(createHTML().apply(block).finalize())
-
public fun getProperty(name: String): TypedMeta<*>? = configuration[name] ?: context.properties[name]
- public fun startServer(
+ internal fun startServer(
+ kernel: KotlinKernelHost,
host: String = getProperty("visionforge.host").string ?: "localhost",
port: Int = getProperty("visionforge.port").int ?: VisionRoute.DEFAULT_PORT,
- ): MimeTypedResult = html {
+ ) {
if (engine != null) {
- p {
- style = "color: red;"
- +"Stopping current VisionForge server"
+ kernel.displayHtml {
+ p {
+ style = "color: red;"
+ +"Stopping current VisionForge server"
+ }
}
+
}
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
@@ -83,66 +92,91 @@ public class VisionForge(
install(WebSockets)
}.start(false)
- p {
- style = "color: blue;"
- +"Starting VisionForge server on http://$host:$port"
+ kernel.displayHtml {
+ p {
+ style = "color: blue;"
+ +"Starting VisionForge server on port $port"
+ }
}
}
- public fun stopServer() {
+ internal fun stopServer(kernel: KotlinKernelHost) {
engine?.apply {
logger.info { "Stopping VisionForge server" }
stop(1000, 2000)
engine = null
}
- }
- private fun produceHtmlString(
- fragment: HtmlVisionFragment,
- ): String = createHTML().apply {
- val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
- div {
- this.id = id
- val engine = engine
- if (engine != null) {
- //if server exist, serve dynamically
- //server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
- val cellRoute = "content-${counter++}"
-
- val collector: MutableMap = mutableMapOf()
-
- val url = engine.environment.connectors.first().let {
- url {
- protocol = URLProtocol.WS
- host = it.host
- port = it.port
- pathSegments = listOf(cellRoute, "ws")
- }
- }
-
- engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
-
- visionFragment(
- visionManager,
- embedData = true,
- updatesUrl = url,
- onVisionRendered = { name, vision -> collector[name] = vision },
- fragment = fragment
- )
- } else {
- //if not, use static rendering
- visionFragment(visionManager, fragment = fragment)
+ kernel.displayHtml {
+ p {
+ style = "color: red;"
+ +"VisionForge server stopped"
}
}
- renderScriptForId(id)
- }.finalize()
+ }
- public fun produceHtml(isolated: Boolean? = null, fragment: HtmlVisionFragment): MimeTypedResult =
- HTML(produceHtmlString(fragment), isolated ?: isolateFragments)
+ internal fun TagConsumer<*>.renderScriptForId(id: String, iframeIsolation: Boolean = false) {
+ script {
+ type = "text/javascript"
+ if (iframeIsolation) {
+ //language=JavaScript
+ unsafe { +"parent.VisionForge.renderAllVisionsById(document, \"$id\");" }
+ } else {
+ //language=JavaScript
+ unsafe { +"VisionForge.renderAllVisionsById(document, \"$id\");" }
+ }
+ }
+ }
- public fun fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(fragment = body)
- public fun page(body: HtmlVisionFragment): MimeTypedResult = produceHtml(true, body)
+
+ public fun produceHtml(
+ isolated: Boolean? = null,
+ fragment: HtmlVisionFragment,
+ ): MimeTypedResult {
+ val iframeIsolation = isolated
+ ?: (notebookMode == VisionForgeCompatibility.JUPYTER || notebookMode == VisionForgeCompatibility.DATALORE)
+ return HTML(
+ iframeIsolation
+ ) {
+ val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
+ div {
+ this.id = id
+ val engine = engine
+ if (engine != null) {
+ //if server exist, serve dynamically
+ //server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
+ val cellRoute = "content-${counter++}"
+
+ val collector: MutableMap = mutableMapOf()
+
+ val url = engine.environment.connectors.first().let {
+ url {
+ protocol = URLProtocol.WS
+ host = it.host
+ port = it.port
+ pathSegments = listOf(cellRoute, "ws")
+ }
+ }
+
+ engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
+
+ visionFragment(
+ visionManager,
+ embedData = true,
+ updatesUrl = url,
+ onVisionRendered = { name, vision -> collector[name] = vision },
+ fragment = fragment
+ )
+ } else {
+ //if not, use static rendering
+ visionFragment(visionManager, fragment = fragment)
+ }
+ }
+ renderScriptForId(id, iframeIsolation = iframeIsolation)
+ }
+ }
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
HtmlFormFragment("form[${counter++}]", builder = builder)
}
+
diff --git a/visionforge-jupyter/src/jvmMain/kotlin/VisionForgeIntegration.kt b/visionforge-jupyter/src/jvmMain/kotlin/VisionForgeIntegration.kt
index 3029ef32..e7175dd0 100644
--- a/visionforge-jupyter/src/jvmMain/kotlin/VisionForgeIntegration.kt
+++ b/visionforge-jupyter/src/jvmMain/kotlin/VisionForgeIntegration.kt
@@ -1,8 +1,7 @@
package space.kscience.visionforge.jupyter
import kotlinx.html.*
-import kotlinx.html.stream.createHTML
-import org.jetbrains.kotlinx.jupyter.api.HTML
+import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import org.jetbrains.kotlinx.jupyter.api.declare
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import space.kscience.dataforge.context.Context
@@ -31,11 +30,12 @@ public abstract class VisionForgeIntegration(
onLoaded {
declare("VisionForge" to handler, "vf" to handler)
+ handler.startServer(this)
}
onShutdown {
- handler.stopServer()
+ handler.stopServer(this)
}
import(
@@ -43,14 +43,14 @@ public abstract class VisionForgeIntegration(
"space.kscience.visionforge.html.*",
"space.kscience.visionforge.jupyter.*"
)
-
- render { fragment ->
- handler.produceHtml(fragment = fragment)
- }
-
- render { fragment ->
- handler.produceHtml(fragment = fragment)
- }
+//
+// render { fragment ->
+// HTML(fragment.renderToString())
+// }
+//
+// render { fragment ->
+// handler.produceHtml(fragment = fragment)
+// }
render { vision ->
handler.produceHtml {
@@ -59,13 +59,13 @@ public abstract class VisionForgeIntegration(
}
render { page ->
- HTML(createHTML().apply {
+ HTML(true) {
head {
meta {
charset = "utf-8"
}
page.pageHeaders.values.forEach {
- fragment(it)
+ appendFragment(it)
}
}
body {
@@ -74,9 +74,11 @@ public abstract class VisionForgeIntegration(
this.id = id
visionFragment(visionManager, fragment = page.content)
}
- renderScriptForId(id)
+ with(handler) {
+ renderScriptForId(id, true)
+ }
}
- }.finalize(), true)
+ }
}
render { fragment ->
@@ -87,7 +89,7 @@ public abstract class VisionForgeIntegration(
+"The server is not running. Forms are not interactive. Start server with `VisionForge.startServer()."
}
}
- fragment(fragment.formBody)
+ appendFragment(fragment.formBody)
vision(fragment.vision)
}
}
@@ -96,10 +98,25 @@ public abstract class VisionForgeIntegration(
}
}
+
+/**
+ * Create a fragment without a head to be embedded in the page
+ */
+@Suppress("UnusedReceiverParameter")
+public fun VisionForge.html(body: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(false, body)
+
+
+/**
+ * Create a fragment without a head to be embedded in the page
+ */
+public fun VisionForge.fragment(body: VisionTagConsumer<*>.() -> Unit): MimeTypedResult = produceHtml(false, body)
+
+
/**
* Create a standalone page in the notebook
*/
public fun VisionForge.page(
pageHeaders: Map = emptyMap(),
- content: HtmlVisionFragment
-): VisionPage = VisionPage(visionManager, pageHeaders, content)
\ No newline at end of file
+ body: VisionTagConsumer<*>.() -> Unit,
+): VisionPage = VisionPage(visionManager, pageHeaders, body)
+
diff --git a/visionforge-jupyter/visionforge-jupyter-common/src/jvmMain/kotlin/JupyterCommonIntegration.kt b/visionforge-jupyter/visionforge-jupyter-common/src/jvmMain/kotlin/JupyterCommonIntegration.kt
index 54f2e266..c326a816 100644
--- a/visionforge-jupyter/visionforge-jupyter-common/src/jvmMain/kotlin/JupyterCommonIntegration.kt
+++ b/visionforge-jupyter/visionforge-jupyter-common/src/jvmMain/kotlin/JupyterCommonIntegration.kt
@@ -6,8 +6,12 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.gdml.Gdml
import space.kscience.plotly.Plot
+import space.kscience.plotly.PlotlyPage
+import space.kscience.plotly.StaticPlotlyRenderer
import space.kscience.tables.*
import space.kscience.visionforge.gdml.toVision
+import space.kscience.visionforge.html.HtmlFragment
+import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.asVision
@@ -23,7 +27,7 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
override fun Builder.afterLoaded() {
resources {
- js("three") {
+ js("visionforge-common") {
classPath("js/visionforge-jupyter-common.js")
}
}
@@ -55,6 +59,24 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
vision { plot.asVision() }
}
}
+
+
+ render { plotlyPage ->
+ val headers = plotlyPage.headers.associate { plotlyFragment ->
+ plotlyFragment.hashCode().toString(16) to HtmlFragment {
+ plotlyFragment.visit(this)
+ }
+
+ }
+ VisionPage(visionManager, headers) {
+ div{
+ p { +"Plotly page renderer is not recommended in VisionForge, use `vf.page{}`" }
+ }
+ div {
+ plotlyPage.fragment.render.invoke(this, StaticPlotlyRenderer)
+ }
+ }
+ }
}
public companion object {
diff --git a/visionforge-threejs/visionforge-threejs-server/src/jvmTest/kotlin/space/kscience/visionforge/three/TestServerExtensions.kt b/visionforge-threejs/visionforge-threejs-server/src/jvmTest/kotlin/space/kscience/visionforge/three/TestServerExtensions.kt
index ef4eb39b..95d9e6f7 100644
--- a/visionforge-threejs/visionforge-threejs-server/src/jvmTest/kotlin/space/kscience/visionforge/three/TestServerExtensions.kt
+++ b/visionforge-threejs/visionforge-threejs-server/src/jvmTest/kotlin/space/kscience/visionforge/three/TestServerExtensions.kt
@@ -3,6 +3,7 @@ package space.kscience.visionforge.three
import kotlinx.html.stream.createHTML
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.html.VisionPage
+import space.kscience.visionforge.html.appendTo
import space.kscience.visionforge.html.importScriptHeader
import kotlin.test.Test
@@ -15,7 +16,7 @@ class TestServerExtensions {
VisionPage.importScriptHeader(
"js/visionforge-three.js",
ResourceLocation.SYSTEM
- ).invoke(this)
+ ).appendTo(this)
}.finalize()