Skip to content

Commit

Permalink
feat: some TODO implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
programadorthi committed Feb 3, 2024
1 parent b4dc27d commit e5e1372
Show file tree
Hide file tree
Showing 14 changed files with 1,077 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.programadorthi.routing.callloging

// TODO: Do I need MDC in a context like JS and others?
public expect object MDC {
public fun clear()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package dev.programadorthi.routing.callloging

public actual object MDC {
// TODO: Is javascript multi thread? I don't know
private val current = mutableMapOf<String, String>()

public actual fun clear() {
current.clear()
}

public actual fun getCopyOfContextMap(): Map<String, String>? {
return current
return current.toMap()
}

public actual fun remove(key: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ class EventResourcesRoutingTest {
}

// WHEN
// TODO: For now, typed event is not supported by parent looking for child. We need to use path based
parent.emitEvent(name = "/child/event_child")
advanceTimeBy(99)

Expand Down
1 change: 0 additions & 1 deletion integration/compose-animation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ configureCommon()
configureJvm()
setupJvmToolchain()

// TODO: org.jetbrains.compose.animation has targets limitation. That is the reason to duplicate configs below
kotlin {
explicitApi()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package dev.programadorthi.routing.javascript

import dev.programadorthi.routing.core.RouteMethod
import dev.programadorthi.routing.core.Routing
import dev.programadorthi.routing.core.application
import dev.programadorthi.routing.core.application.ApplicationCall
import io.ktor.http.parametersOf
import kotlinx.browser.window
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.dom.clear
Expand All @@ -27,24 +23,5 @@ public fun render(
}
}

// First time or page refresh we try continue from last state
routing.tryNotifyTheRoute(state = window.history.state)

window.onpopstate = { event ->
routing.tryNotifyTheRoute(state = event.state)
}
}

private fun Routing.tryNotifyTheRoute(state: Any?) {
val javascriptState = state.deserialize() ?: return
val call =
ApplicationCall(
application = application,
name = javascriptState.name,
uri = javascriptState.uri,
routeMethod = RouteMethod.parse(javascriptState.routeMethod),
parameters = parametersOf(javascriptState.parameters),
)
call.neglect = true
execute(call)
JavascriptRoutingStateManager.init(routing)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import dev.programadorthi.routing.core.RouteMethod
import dev.programadorthi.routing.core.application.ApplicationCall
import dev.programadorthi.routing.core.application.application
import dev.programadorthi.routing.core.application.call
import dev.programadorthi.routing.core.asRouting
import dev.programadorthi.routing.core.route
import io.ktor.util.pipeline.PipelineContext
import io.ktor.utils.io.KtorDsl
Expand All @@ -28,6 +29,8 @@ public fun Route.jsRoute(

@KtorDsl
public fun Route.jsRoute(body: PipelineContext<Unit, ApplicationCall>.() -> Element) {
val routing = asRouting ?: error("A route must be a Routing child")

handle {
application.routingFlow.emit(body(this))

Expand All @@ -50,7 +53,7 @@ public fun Route.jsRoute(body: PipelineContext<Unit, ApplicationCall>.() -> Elem
data = call.serialize(),
)

// TODO: Add support to replace all route method
RouteMethod.ReplaceAll -> JavascriptRoutingStateManager.replaceAll(call, routing)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ internal fun ApplicationCall.serialize(): String {

internal fun Any?.deserialize(): JavascriptRoutingState? =
when (this) {
is String -> Json.decodeFromString(this)
is String -> toState()
else -> null
}

private fun String.toState(): JavascriptRoutingState? =
runCatching {
Json.decodeFromString<JavascriptRoutingState>(this)
}.getOrNull()
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package dev.programadorthi.routing.javascript

import dev.programadorthi.routing.core.RouteMethod
import dev.programadorthi.routing.core.Routing
import dev.programadorthi.routing.core.application
import dev.programadorthi.routing.core.application.ApplicationCall
import io.ktor.http.parametersOf
import kotlinx.browser.window
import kotlinx.coroutines.withTimeout
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

internal object JavascriptRoutingStateManager {
fun init(routing: Routing) {
// First time or page refresh we try continue from last state
routing.tryNotifyTheRoute(state = window.history.state)

resetOnPopStateEvent(routing)
}

suspend fun replaceAll(
call: ApplicationCall,
routing: Routing,
) {
while (true) {
window.history.replaceState(
title = "",
url = null,
data = null,
)
window.history.go(-1)
val forceBreak =
runCatching {
withTimeout(1_000) {
suspendCoroutine { continuation ->
window.onpopstate = { event ->
val state = event.state.deserialize()
continuation.resume(state == null)
}
}
}
}.getOrDefault(true)
if (forceBreak) {
break
}
}

window.history.replaceState(
title = "routing",
url = call.uri,
data = call.serialize(),
)

resetOnPopStateEvent(routing)
}

private fun resetOnPopStateEvent(routing: Routing) {
window.onpopstate = { event ->
routing.tryNotifyTheRoute(state = event.state)
}
}

private fun Routing.tryNotifyTheRoute(state: Any?) {
val javascriptState = state.deserialize() ?: return
val call =
ApplicationCall(
application = application,
name = javascriptState.name,
uri = javascriptState.uri,
routeMethod = RouteMethod.parse(javascriptState.routeMethod),
parameters = parametersOf(javascriptState.parameters),
)
call.neglect = true
execute(call)
}
}
1 change: 0 additions & 1 deletion integration/voyager/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ configureCommon()
configureJvm()
setupJvmToolchain()

// TODO: Voyager has targets limitation. That is the reason to duplicate configs below
kotlin {
explicitApi()

Expand Down
Loading

0 comments on commit e5e1372

Please sign in to comment.