Skip to content

Commit

Permalink
Fix vision sharing between pages
Browse files Browse the repository at this point in the history
  • Loading branch information
altavir committed Dec 24, 2023
1 parent 2e25244 commit 4fd5c63
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 84 deletions.
42 changes: 26 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
# Changelog

## [Unreleased]
## Unreleased

### Added

### Changed
- **Breaking API** Move vision cache to upper level for renderers to avoid re-creating visions for page reload.
- **Breaking API** Forms refactor

### Deprecated

### Removed

### Fixed

### Security

## 0.3.0 - 2023-12-23

### Added

- Context receivers flag
- MeshLine for thick lines
- Custom client-side events and thier processing in VisionServer

### Changed

- Color accessor property is now `colorProperty`. Color uses non-nullable `invoke` instead of `set`.
- API update for server and pages
- Edges moved to solids module for easier construction
Expand All @@ -17,17 +36,14 @@
- Naming of Canvas3D options.
- Lights are added to the scene instead of 3D options.

### Deprecated

### Removed

### Fixed

- Jupyter integration for IDEA and Jupyter lab.

### Security
## 0.2.0

## [0.2.0]
### Added

- Server module
- Change collector
- Customizable accessors for colors
Expand All @@ -38,8 +54,8 @@
- Markdown module
- Tables module


### Changed

- Vision does not implement ItemProvider anymore. Property changes are done via `getProperty`/`setProperty` and `property` delegate.
- Point3D and Point2D are made separate classes instead of expect/actual (to split up different engines.
- JavaFX support moved to a separate module
Expand All @@ -54,16 +70,10 @@
- Property listeners are not triggered if there are no changes.
- Feedback websocket connection in the client.


### Deprecated

### Removed
- Primary modules dependencies on UI

- Primary modules dependencies on UI

### Fixed
- Version conflicts


### Security

- Version conflicts
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val dataforgeVersion by extra("0.7.1")

allprojects {
group = "space.kscience"
version = "0.3.0"
version = "0.3.1"
}

subprojects {
Expand Down
3 changes: 2 additions & 1 deletion demo/js-playground/src/jsMain/kotlin/JsPlaygroundApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ringui.SmartTabs
import ringui.Tab
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request
import space.kscience.plotly.Plotly.plot
import space.kscience.plotly.models.Trace
import space.kscience.plotly.scatter
import space.kscience.visionforge.Application
Expand Down Expand Up @@ -97,7 +98,7 @@ private class JsPlaygroundApp : Application {
Tab("plotly") {
Plotly {
attrs {
plot = space.kscience.plotly.Plotly.plot {
plot = plot {
scatter {
x(1, 2, 3)
y(5, 8, 7)
Expand Down
5 changes: 4 additions & 1 deletion demo/js-playground/src/jsMain/kotlin/gravityDemo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import space.kscience.visionforge.markup.VisionOfMarkup
import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.solid
import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.solid.*
import styled.css
import styled.styledDiv
Expand All @@ -27,7 +28,9 @@ val GravityDemo = fc<DemoProps> { props ->
val energyTrace = Trace {
name = "energy"
}
val markup = VisionOfMarkup()
val markup = VisionOfMarkup().apply {
setAsRoot(props.solids.visionManager)
}

styledDiv {
css {
Expand Down
2 changes: 1 addition & 1 deletion demo/js-playground/src/jsMain/kotlin/markupComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ val Markup = fc<MarkupProps>("Markup") { props ->
css {
width = 100.pct
height = 100.pct
border= Border(2.pt, BorderStyle.solid, Color.blue)
border = Border(2.pt, BorderStyle.solid, Color.blue)
padding = Padding(left = 8.pt)
backgroundColor = Color.white
flex = Flex(1.0)
Expand Down
6 changes: 3 additions & 3 deletions demo/playground/src/jvmMain/kotlin/formServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import space.kscience.dataforge.context.request
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.html.VisionOfHtmlForm
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.html.bindToVision
import space.kscience.visionforge.html.visionOfForm
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
Expand All @@ -36,7 +36,7 @@ fun main() {
visionManager,
VisionPage.scriptHeader("js/visionforge-playground.js"),
) {
form {
visionOfForm(form) {
label {
htmlFor = "fname"
+"First name:"
Expand Down Expand Up @@ -66,8 +66,8 @@ fun main() {
type = InputType.submit
value = "Submit"
}
vision(bindToVision(form))
}
vision(form)
println(form.values)
}

Expand Down
4 changes: 3 additions & 1 deletion demo/sat-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ kscience {
// useSerialization {
// json()
// }
jvm()
jvm{
withJava()
}
jvmMain{
implementation("io.ktor:ktor-server-cio")
implementation(projects.visionforgeThreejs.visionforgeThreejsServer)
Expand Down
29 changes: 23 additions & 6 deletions visionforge-core/api/visionforge-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -750,10 +750,10 @@ public abstract interface class space/kscience/visionforge/html/HtmlVisionFragme

public final class space/kscience/visionforge/html/HtmlVisionRendererKt {
public static final fun appendTo (Lspace/kscience/visionforge/html/HtmlVisionFragment;Lspace/kscience/visionforge/html/VisionTagConsumer;)V
public static final fun visionFragment (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
public static final fun visionFragment (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
public static synthetic fun visionFragment$default (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Ljava/lang/String;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
public static synthetic fun visionFragment$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
public static final fun visionFragment (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
public static final fun visionFragment (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;)V
public static synthetic fun visionFragment$default (Lkotlinx/html/FlowContent;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
public static synthetic fun visionFragment$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/VisionManager;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lspace/kscience/visionforge/html/HtmlVisionFragment;ILjava/lang/Object;)V
}

public final class space/kscience/visionforge/html/InputFeedbackMode : java/lang/Enum {
Expand Down Expand Up @@ -782,6 +782,21 @@ public final class space/kscience/visionforge/html/ResourceLocation : java/lang/
public abstract interface annotation class space/kscience/visionforge/html/VisionDSL : java/lang/annotation/Annotation {
}

public final class space/kscience/visionforge/html/VisionDisplay {
public fun <init> (Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;)V
public final fun component1 ()Lspace/kscience/visionforge/VisionManager;
public final fun component2 ()Lspace/kscience/visionforge/Vision;
public final fun component3 ()Lspace/kscience/dataforge/meta/Meta;
public final fun copy (Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/visionforge/html/VisionDisplay;
public static synthetic fun copy$default (Lspace/kscience/visionforge/html/VisionDisplay;Lspace/kscience/visionforge/VisionManager;Lspace/kscience/visionforge/Vision;Lspace/kscience/dataforge/meta/Meta;ILjava/lang/Object;)Lspace/kscience/visionforge/html/VisionDisplay;
public fun equals (Ljava/lang/Object;)Z
public final fun getMeta ()Lspace/kscience/dataforge/meta/Meta;
public final fun getVision ()Lspace/kscience/visionforge/Vision;
public final fun getVisionManager ()Lspace/kscience/visionforge/VisionManager;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class space/kscience/visionforge/html/VisionOfCheckbox : space/kscience/visionforge/html/VisionOfHtmlInput {
public static final field Companion Lspace/kscience/visionforge/html/VisionOfCheckbox$Companion;
public fun <init> ()V
Expand Down Expand Up @@ -852,7 +867,7 @@ public final class space/kscience/visionforge/html/VisionOfHtmlControl$Companion
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

public final class space/kscience/visionforge/html/VisionOfHtmlForm : space/kscience/visionforge/html/VisionOfHtmlControl {
public final class space/kscience/visionforge/html/VisionOfHtmlForm : space/kscience/visionforge/html/VisionOfHtmlControl, space/kscience/visionforge/ClickControl {
public static final field Companion Lspace/kscience/visionforge/html/VisionOfHtmlForm$Companion;
public fun <init> (Ljava/lang/String;)V
public final fun getFormId ()Ljava/lang/String;
Expand All @@ -876,9 +891,11 @@ public final class space/kscience/visionforge/html/VisionOfHtmlForm$Companion {
}

public final class space/kscience/visionforge/html/VisionOfHtmlFormKt {
public static final fun bindForm (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun button (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
public static synthetic fun button$default (Lspace/kscience/visionforge/html/VisionOutput;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/visionforge/html/VisionOfHtmlButton;
public static final fun onSubmit (Lspace/kscience/visionforge/html/VisionOfHtmlForm;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/Job;
public static final fun visionOfForm (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Ljava/lang/String;Lkotlinx/html/FormEncType;Lkotlinx/html/FormMethod;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static synthetic fun visionOfForm$default (Lkotlinx/html/TagConsumer;Lspace/kscience/visionforge/html/VisionOfHtmlForm;Ljava/lang/String;Lkotlinx/html/FormEncType;Lkotlinx/html/FormMethod;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
}

public class space/kscience/visionforge/html/VisionOfHtmlInput : space/kscience/visionforge/html/VisionOfHtmlControl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,55 @@ import space.kscience.dataforge.names.asName
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager

public fun interface HtmlVisionFragment{
public fun interface HtmlVisionFragment {
public fun VisionTagConsumer<*>.append()
}

public fun HtmlVisionFragment.appendTo(consumer: VisionTagConsumer<*>): Unit = consumer.append()

public data class VisionDisplay(val visionManager: VisionManager, val vision: Vision, val meta: Meta)

/**
* Render a fragment in the given consumer and return a map of extracted visions
* @param context a context used to create a vision fragment
* @param visionManager a context plugin used to create a vision fragment
* @param embedData embed Vision initial state in the HTML
* @param fetchDataUrl fetch data after first render from given url
* @param updatesUrl receive push updates from the server at given url
* @param idPrefix a prefix to be used before vision ids
* @param displayCache external cache for Vision displays. It is required to avoid re-creating visions on page update
* @param fragment the fragment to render
*/
public fun TagConsumer<*>.visionFragment(
visionManager: VisionManager,
embedData: Boolean = true,
fetchDataUrl: String? = null,
updatesUrl: String? = null,
idPrefix: String? = null,
onVisionRendered: (Name, Vision) -> Unit = { _, _ -> },
displayCache: MutableMap<Name, VisionDisplay> = mutableMapOf(),
fragment: HtmlVisionFragment,
) {

val collector: MutableMap<Name, Pair<VisionOutput, Vision>> = mutableMapOf()

val consumer = object : VisionTagConsumer<Any?>(this@visionFragment, visionManager, idPrefix) {

override fun <T> TagConsumer<T>.vision(name: Name?, buildOutput: VisionOutput.() -> Vision): T {
//Avoid re-creating cached visions
val actualName = name ?: NameToken(
DEFAULT_VISION_NAME,
buildOutput.hashCode().toUInt().toString()
buildOutput.hashCode().toString(16)
).asName()

val (output, vision) = collector.getOrPut(actualName) {
val display = displayCache.getOrPut(actualName) {
val output = VisionOutput(context, actualName)
val vision = output.buildOutput()
onVisionRendered(actualName, vision)
output to vision
VisionDisplay(output.visionManager, vision, output.meta)
}

return addVision(actualName, output.visionManager, vision, output.meta)
return addVision(actualName, display.visionManager, display.vision, display.meta)
}

override fun DIV.renderVision(manager: VisionManager, name: Name, vision: Vision, outputMeta: Meta) {

val (_, actualVision) = collector.getOrPut(name) {
val output = VisionOutput(context, name)
onVisionRendered(name, vision)
output to vision
}

displayCache[name] = VisionDisplay(manager, vision, outputMeta)

// Toggle update mode
updatesUrl?.let {
Expand All @@ -76,7 +72,7 @@ public fun TagConsumer<*>.visionFragment(
type = "text/json"
attributes["class"] = OUTPUT_DATA_CLASS
unsafe {
+"\n${manager.encodeToString(actualVision)}\n"
+"\n${manager.encodeToString(vision)}\n"
}
}
}
Expand All @@ -91,15 +87,15 @@ public fun FlowContent.visionFragment(
embedData: Boolean = true,
fetchDataUrl: String? = null,
updatesUrl: String? = null,
onVisionRendered: (Name, Vision) -> Unit = { _, _ -> },
idPrefix: String? = null,
displayCache: MutableMap<Name, VisionDisplay> = mutableMapOf(),
fragment: HtmlVisionFragment,
): Unit = consumer.visionFragment(
visionManager = visionManager,
embedData = embedData,
fetchDataUrl = fetchDataUrl,
updatesUrl = updatesUrl,
idPrefix = idPrefix,
onVisionRendered = onVisionRendered,
displayCache = displayCache,
fragment = fragment
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package space.kscience.visionforge.html

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.html.FORM
import kotlinx.html.id
import kotlinx.html.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta
Expand All @@ -23,19 +22,24 @@ public class VisionOfHtmlForm(
public var values: Meta? by properties.node()
}


/**
* Create a [VisionOfHtmlForm] and bind this form to the id
*/
public fun FORM.bindToVision(id: String): VisionOfHtmlForm {
this.id = id
return VisionOfHtmlForm(id)
}

public fun FORM.bindToVision(vision: VisionOfHtmlForm): VisionOfHtmlForm {
@HtmlTagMarker
public inline fun <T, C : TagConsumer<T>> C.visionOfForm(
vision: VisionOfHtmlForm,
action: String? = null,
encType: FormEncType? = null,
method: FormMethod? = null,
classes: String? = null,
crossinline block: FORM.() -> Unit = {},
) : T = form(action, encType, method, classes){
this.id = vision.formId
return vision
block()
}


public fun VisionOfHtmlForm.onSubmit(scope: CoroutineScope, block: (Meta?) -> Unit): Job = onClick(scope) { block(payload) }


Expand Down
Loading

0 comments on commit 4fd5c63

Please sign in to comment.