A prototype for context receivers

This commit is contained in:
Alexander Nozik 2022-04-15 12:46:05 +03:00
parent 3198bad094
commit 212d729afb
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
2 changed files with 97 additions and 1 deletions

View File

@ -22,7 +22,7 @@ internal const val RENDER_FUNCTION_NAME = "renderAllVisionsById"
/**
* Render a fragment in the given consumer and return a map of extracted visions
* @param manager a VisionManager used for serialization
* @param context a context 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 fetchUpdatesUrl receive push updates from the server at given url

View File

@ -0,0 +1,96 @@
package space.kscience.visionforge.html
import kotlinx.html.*
import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.isEmpty
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.dataforge.names.parseAsName
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.setAsRoot
import space.kscience.visionforge.visionManager
/**
* Rendering context for visions in HTML
*/
public interface HtmlVisionContext : ContextAware {
/**
* Generate div id for vision div tag
*/
public fun generateId(name: Name): String = "vision[$name]"
/**
* Render vision at given [DIV]
*/
public fun DIV.renderVision(name: Name, vision: Vision, outputMeta: Meta)
}
public typealias HtmlVisionContextFragment = context(HtmlVisionContext) TagConsumer<*>.() -> Unit
context(HtmlVisionContext)
public fun HtmlVisionContextFragment(content: TagConsumer<*>.() -> Unit): HtmlVisionFragment = content
context(HtmlVisionContext)
private fun <T> TagConsumer<T>.vision(
visionManager: VisionManager,
name: Name,
vision: Vision,
outputMeta: Meta = Meta.EMPTY,
): T = div {
id = generateId(name)
classes = setOf(VisionTagConsumer.OUTPUT_CLASS)
vision.setAsRoot(visionManager)
attributes[VisionTagConsumer.OUTPUT_NAME_ATTRIBUTE] = name.toString()
if (!outputMeta.isEmpty()) {
//Hard-code output configuration
script {
attributes["class"] = VisionTagConsumer.OUTPUT_META_CLASS
unsafe {
+visionManager.jsonFormat.encodeToString(MetaSerializer, outputMeta)
}
}
}
renderVision(name, vision, outputMeta)
}
context(HtmlVisionContext)
private fun <T> TagConsumer<T>.vision(
name: Name,
vision: Vision,
outputMeta: Meta = Meta.EMPTY,
): T = vision(context.visionManager, name, vision, outputMeta)
/**
* Insert a vision in this HTML.
*/
context(HtmlVisionContext)
@DFExperimental
@VisionDSL
public fun <T> TagConsumer<T>.vision(
name: Name? = null,
visionProvider: VisionOutput.() -> Vision,
): T {
val output = VisionOutput(context, name)
val vision = output.visionProvider()
val actualName =
name ?: NameToken(VisionTagConsumer.DEFAULT_VISION_NAME, vision.hashCode().toUInt().toString()).asName()
return vision(output.buildVisionManager(), actualName, vision, output.meta)
}
/**
* Insert a vision in this HTML.
*/
context(HtmlVisionContext)
@DFExperimental
@VisionDSL
public fun <T> TagConsumer<T>.vision(
name: String?,
visionProvider: VisionOutput.() -> Vision,
): T = vision(name?.parseAsName(), visionProvider)