org.http4k.datastar.DatastarEvent.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http4k-web-datastar Show documentation
Show all versions of http4k-web-datastar Show documentation
http4k Datastar support utilities
package org.http4k.datastar
import org.http4k.datastar.Fragment.Companion.of
import org.http4k.datastar.MergeMode.morph
import org.http4k.datastar.SettleDuration.Companion.DEFAULT
import org.http4k.sse.SseMessage.Event
import java.time.Duration
sealed class DatastarEvent(val name: String, val data: List, open val id: String?) {
fun toSseEvent() = Event(name, data.joinToString("\n"), id)
/**
* The datastar-merge-fragments event is used to merge HTML fragments into the DOM. The fragments
* line should be a valid HTML fragment. The selector line should be a valid CSS selector. The mode
* line determines how the fragments are merged into the DOM. The useViewTransition line determines
* whether to use a view transition. The settleDuration line determines how long the transition
* should take.
*/
data class MergeFragments(
val fragments: List,
val mergeMode: MergeMode = morph,
val selector: Selector? = null,
val useViewTransition: Boolean = false,
val settleDuration: SettleDuration? = DEFAULT,
override val id: String? = null,
) : DatastarEvent(
"datastar-merge-fragments",
run {
val nullable = listOfNotNull(
selector?.value?.let { "selector $it" },
settleDuration?.let { "settleDuration ${it.value.toMillis()}" }
)
val other = listOf(
"mergeMode $mergeMode",
"useViewTransition $useViewTransition"
)
fragments.map { "fragments $it" } + nullable + other
},
id
) {
constructor(
vararg fragment: Fragment,
mergeMode: MergeMode = morph,
selector: Selector? = null,
useViewTransition: Boolean = false,
settleDuration: SettleDuration? = DEFAULT,
id: String? = null,
) : this(fragment.toList(), mergeMode, selector, useViewTransition, settleDuration, id)
constructor(
vararg fragment: String,
mergeMode: MergeMode = morph,
selector: Selector? = null,
useViewTransition: Boolean = false,
settleDuration: SettleDuration? = DEFAULT,
id: String? = null,
) : this(fragment.map { of(it) }.toList(), mergeMode, selector, useViewTransition, settleDuration, id)
}
/**
* The datastar-merge-signals event is used to update the store with new values. The onlyIfMissing
* line determines whether to update the store with new values only if the key does not exist. The
* signals line should be a valid data-store attribute. This will get merged into the store.
*/
data class MergeSignals(
val signals: List,
val onlyIfMissing: Boolean? = false,
override val id: String? = null,
) : DatastarEvent("datastar-merge-signals", run {
signals.map { "signals $it" } + listOfNotNull(onlyIfMissing?.let { "onlyIfMissing $it" })
}, id) {
constructor(
vararg signal: Signal,
onlyIfMissing: Boolean? = false,
id: String? = null,
) : this(signal.toList(), onlyIfMissing, id)
}
/**
* The datastar-remove-fragments event is used to remove HTML fragments that match the provided
* selector from the DOM.
*/
data class RemoveFragments(
val selector: Selector,
override val id: String? = null,
) : DatastarEvent("datastar-remove-fragments", listOf("selector $selector"), id)
/**
* The datastar-remove-signals event is used to remove signals that match the provided paths
* from the store.
*/
data class RemoveSignals(
val paths: List,
override val id: String? = null,
) : DatastarEvent("datastar-remove-signals", paths.map { "paths $it" }, id) {
constructor(
vararg path: SignalPath,
id: String? = null,
) : this(path.toList(), id)
}
/**
* The datastar-execute-script event is used to execute JavaScript in the browser.
* The autoRemove line determines whether to remove the script after execution.
* Each attributes line adds an attribute (in the format name value) to the script element.
* Each script line contains JavaScript to be executed by the browser.
*/
data class ExecuteScript(
val script: Script,
val autoRemove: Boolean = true,
val attributes: List> = emptyList(),
override val id: String? = null,
) : DatastarEvent("datastar-execute-script", run {
listOf("script $script", "autoRemove $autoRemove") + attributes.map { "attributes ${it.first} ${it.second}" }
}, id)
companion object {
/**
* Parse an event from an SSE Event.
*/
fun from(event: Event) = with(event.data.split("\n")) {
when (event.event) {
"datastar-merge-fragments" -> {
MergeFragments(
data("fragments", Fragment.Companion::of),
data("mergeMode", MergeMode::valueOf).first(),
data("selector", Selector.Companion::of).firstOrNull(),
data("useViewTransition", String::toBoolean).firstOrNull() ?: false,
data("settleDuration", { SettleDuration.of(Duration.ofMillis(it.toLong())) }).firstOrNull(),
event.id
)
}
"datastar-merge-signals" -> {
MergeSignals(
data("signals", Signal.Companion::of),
data("onlyIfMissing", String::toBoolean).firstOrNull(),
event.id
)
}
"datastar-remove-fragments" -> {
RemoveFragments(
data("selector", Selector.Companion::of).first(),
event.id
)
}
"datastar-remove-signals" -> {
RemoveSignals(
data("paths", SignalPath.Companion::of),
event.id
)
}
"datastar-execute-script" -> {
ExecuteScript(
data("script", Script.Companion::of).first(),
data("autoRemove", String::toBoolean).firstOrNull() ?: true,
data("attributes", { it: String -> it.split(" ").let { i -> i[0] to i[1] } }),
event.id
)
}
else -> error("unknown event ${event.event}")
}
}
private fun List.data(name: String, fn: (String) -> T): List =
filter { it.startsWith(name) }.map { it.removePrefix(name).trim() }.map(fn)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy