html output

This commit is contained in:
Alexander Nozik 2019-03-18 16:55:14 +03:00
parent 875a5ecf54
commit 2aee38793c
8 changed files with 113 additions and 6 deletions

View File

@ -0,0 +1,28 @@
plugins {
kotlin("multiplatform")
}
val htmlVersion by rootProject.extra("0.6.12")
kotlin {
jvm()
js()
sourceSets {
val commonMain by getting {
dependencies {
api(project(":dataforge-output"))
api("org.jetbrains.kotlinx:kotlinx-html-common:$htmlVersion")
}
}
val jsMain by getting {
dependencies {
api("org.jetbrains.kotlinx:kotlinx-html-js:$htmlVersion")
}
}
val jvmMain by getting{
dependencies {
api("org.jetbrains.kotlinx:kotlinx-html-jvm:$htmlVersion")
}
}
}
}

View File

@ -0,0 +1,78 @@
package hep.dataforge.output.html
import hep.dataforge.context.Context
import hep.dataforge.meta.Meta
import hep.dataforge.output.Output
import hep.dataforge.output.TextRenderer
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.output.html.HtmlBuilder.Companion.HTML_CONVERTER_TYPE
import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.html.TagConsumer
import kotlinx.html.p
import kotlin.reflect.KClass
class HtmlOutput<T : Any>(override val context: Context, private val consumer: TagConsumer<*>) : Output<T> {
private val cache = HashMap<KClass<*>, HtmlBuilder<*>>()
/**
* Find the first [TextRenderer] matching the given object type.
*/
override fun render(obj: T, meta: Meta) {
val builder: HtmlBuilder<*> = if (obj is CharSequence) {
DefaultHtmlBuilder
} else {
val value = cache[obj::class]
if (value == null) {
val answer = context.provideAll(HTML_CONVERTER_TYPE).filterIsInstance<HtmlBuilder<*>>()
.filter { it.type.isInstance(obj) }.firstOrNull()
if (answer != null) {
cache[obj::class] = answer
answer
} else {
DefaultHtmlBuilder
}
} else {
value
}
}
context.launch(Dispatchers.Output) {
(builder as HtmlBuilder<T>).run { consumer.render(obj) }
}
}
}
/**
* A text or binary renderer based on [kotlinx.io.core.Output]
*/
@Type(HTML_CONVERTER_TYPE)
interface HtmlBuilder<T : Any> {
/**
* The priority of this renderer compared to other renderers
*/
val priority: Int
/**
* The type of the content served by this renderer
*/
val type: KClass<T>
suspend fun TagConsumer<*>.render(obj: T)
companion object {
const val HTML_CONVERTER_TYPE = "dataforge.htmlBuilder"
}
}
object DefaultHtmlBuilder : HtmlBuilder<Any> {
override val priority: Int = Int.MAX_VALUE
override val type: KClass<Any> = Any::class
override suspend fun TagConsumer<*>.render(obj: Any) {
p { +obj.toString() }
}
}

View File

@ -1,4 +1,4 @@
package hep.dataforge.io
package hep.dataforge.output
import hep.dataforge.context.ContextAware
import hep.dataforge.meta.EmptyMeta

View File

@ -1,4 +1,4 @@
package hep.dataforge.io
package hep.dataforge.output
import hep.dataforge.context.AbstractPlugin
import hep.dataforge.context.Context

View File

@ -1,7 +1,7 @@
package hep.dataforge.io
package hep.dataforge.output
import hep.dataforge.context.Context
import hep.dataforge.io.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.meta.Meta
import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll

View File

@ -1,4 +1,4 @@
package hep.dataforge.io
package hep.dataforge.output
import hep.dataforge.context.Context
import hep.dataforge.context.Global

View File

@ -1,4 +1,4 @@
package hep.dataforge.io
package hep.dataforge.output
import hep.dataforge.context.Global
import kotlinx.coroutines.Dispatchers

View File

@ -25,6 +25,7 @@ include(
":dataforge-context",
":dataforge-data",
":dataforge-output",
":dataforge-output:dataforge-output-html",
":dataforge-workspace",
":dataforge-scripting"
)