forked from kscience/visionforge
Jupyter renderers are working for lab and Idea
This commit is contained in:
parent
a49a4f1a7f
commit
b3f68d879f
@ -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 {
|
||||
|
@ -51,7 +51,7 @@ kotlin {
|
||||
implementation(projects.visionforgeMarkdown)
|
||||
implementation(projects.visionforgeTables)
|
||||
implementation(projects.cernRootLoader)
|
||||
implementation(projects.visionforgeJupyter.visionforgeJupyterCommon)
|
||||
api(projects.visionforgeJupyter.visionforgeJupyterCommon)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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": "<p style=\"color: blue;\">Starting VisionForge server on http://localhost:7777</p>\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": "<div id=\"fragment[1645474043/2315898832]\">\n <h1>AAA</h1>\n <div id=\"output[vision[302766000]]\" class=\"visionforge-output\" data-output-name=\"vision[302766000]\" data-output-connect=\"ws://localhost:7777/content-0/ws\">\n <script type=\"text/json\" class=\"visionforge-output-data\">\n{\n \"type\": \"group.solid\",\n \"children\": {\n \"@ambientLight\": {\n \"type\": \"solid.light.ambient\"\n },\n \"@static[1326263213]\": {\n \"type\": \"solid.box\",\n \"xSize\": 100.0,\n \"ySize\": 100.0,\n \"zSize\": 200.0\n },\n \"@static[1813044036]\": {\n \"type\": \"solid.sphere\",\n \"properties\": {\n \"position\": {\n \"x\": 300\n }\n },\n \"radius\": 100.0\n }\n }\n}\n</script>\n </div>\n <div id=\"output[vision[1326029936]]\" class=\"visionforge-output\" data-output-name=\"vision[1326029936]\" data-output-connect=\"ws://localhost:7777/content-0/ws\">\n <script type=\"text/json\" class=\"visionforge-output-data\">\n{\n \"type\": \"vision.plotly\",\n \"meta\": {\n \"data\": {\n \"type\": \"scatter\",\n \"x\": [\n 1,\n 2,\n 3,\n 1\n ],\n \"y\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"@index\": \"0\"\n }\n }\n}\n</script>\n </div>\n</div>\n<script type=\"text/javascript\">VisionForge.renderAllVisionsById(\"fragment[1645474043/2315898832]\");</script>\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": {
|
||||
|
@ -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<ThreeCanvasProps> = 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())
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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(
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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") {
|
||||
|
@ -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 {
|
||||
|
@ -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 <T> TagConsumer<T>.vision(
|
||||
|
@ -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"
|
||||
|
@ -78,7 +78,7 @@ public fun VisionPage.makeFile(
|
||||
charset = "utf-8"
|
||||
}
|
||||
actualHeaders.values.forEach {
|
||||
fragment(it)
|
||||
appendFragment(it)
|
||||
}
|
||||
}
|
||||
body {
|
||||
|
@ -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() {
|
||||
|
@ -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<Name, Vision> = 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<Name, Vision> = 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)
|
||||
}
|
||||
|
||||
|
@ -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<HtmlFragment> { fragment ->
|
||||
handler.produceHtml(fragment = fragment)
|
||||
}
|
||||
|
||||
render<HtmlVisionFragment> { fragment ->
|
||||
handler.produceHtml(fragment = fragment)
|
||||
}
|
||||
//
|
||||
// render<HtmlFragment> { fragment ->
|
||||
// HTML(fragment.renderToString())
|
||||
// }
|
||||
//
|
||||
// render<HtmlVisionFragment> { fragment ->
|
||||
// handler.produceHtml(fragment = fragment)
|
||||
// }
|
||||
|
||||
render<Vision> { vision ->
|
||||
handler.produceHtml {
|
||||
@ -59,13 +59,13 @@ public abstract class VisionForgeIntegration(
|
||||
}
|
||||
|
||||
render<VisionPage> { 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<HtmlFormFragment> { 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<String, HtmlFragment> = emptyMap(),
|
||||
content: HtmlVisionFragment
|
||||
): VisionPage = VisionPage(visionManager, pageHeaders, content)
|
||||
body: VisionTagConsumer<*>.() -> Unit,
|
||||
): VisionPage = VisionPage(visionManager, pageHeaders, body)
|
||||
|
||||
|
@ -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> { 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 {
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user