From f288c0d5f92d57fdf5242744068929e7a707604d Mon Sep 17 00:00:00 2001 From: Ian Clarke Date: Sun, 16 Apr 2017 13:04:13 -0500 Subject: [PATCH] bump to 0.2.0 for new routing/state code, still requires experimentation, fine tuning, and documentation --- build.gradle | 2 +- src/main/kotlin/io/kweb/routing/routing.kt | 59 ++++++++++++++++++---- src/main/kotlin/io/kweb/state/state.kt | 17 ++++++- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index a4d5481e84..65c2440bab 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { } group 'io.kweb' -version '0.1.4' +version '0.2.0' apply plugin: 'java' apply plugin: 'kotlin' diff --git a/src/main/kotlin/io/kweb/routing/routing.kt b/src/main/kotlin/io/kweb/routing/routing.kt index 3bd4fbf150..1887bd016e 100644 --- a/src/main/kotlin/io/kweb/routing/routing.kt +++ b/src/main/kotlin/io/kweb/routing/routing.kt @@ -2,19 +2,58 @@ package io.kweb.routing import io.kweb.WebBrowser import io.kweb.state.Observable +import io.mola.galimatias.URL +import java.net.URLDecoder + /** + * @sample route_sample + * * Created by @@jmdesprez, some modifications by @sanity */ -// TODO: Handle window.onpopstate so that handle -// TODO: Encode and decode should occur automatically using some kind of object serialization, also need to figure out -// TODO: humanization of titles -fun WebBrowser.router(fromPath : (String) -> T, toPath : (T) -> String, humanize : (T) -> String = {it.toString()}) : Observable { - val decoded = fromPath(this.httpRequestInfo.requestedUrl.path()) - val observable = Observable(decoded) - observable.addListener({ _, new -> - doc.body.execute("""window.history.pushState({}, "${humanize(new)}", "${toPath(new)}");""") - }) - return observable +// TODO: Handle window.onpopstate so that back buttons will work in a sensible way + +fun main(args: Array) { + val url = URL.parse("http://a.b.c/hello?dog=cat&mouse=pig") + println(url) +} + +val urlPathTranslator = UrlPathTranslator() + +fun WebBrowser.pushState(path: String) { + execute("""history.pushState({}, "$path", "$path");""") +} + +inline fun WebBrowser.route(receiver: (RequestURL).() -> Unit) { + val requestUrl = with(httpRequestInfo.requestedUrl) { + this.query() + RequestURL(scheme = Scheme.valueOf(scheme()), host = host().toHumanString(), port = port(), path = Observable(urlPathTranslator.parse(path())), query = Observable(query()), rawUrl = this) + } + requestUrl.path.addListener { _, new -> + pushState(urlPathTranslator.toPath(new) + requestUrl.query.value) + } + requestUrl.query.addListener { _, new -> + pushState(urlPathTranslator.toPath(requestUrl.path.value) + new) + } + receiver(requestUrl) +} + +data class RequestURL(val scheme: Scheme, val host: String, val port: Int = 80, val path: Observable, val query: Observable, val rawUrl: URL) { + private fun queryToQueryMap(query: String): Map { + val pairs = query.split("&".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() + val queryMap = HashMap() + for (pair in pairs) { + val idx = pair.indexOf("=") + queryMap.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")) + } + return queryMap + } } + +enum class Scheme { + http, https +} + +fun route_sample() { +} \ No newline at end of file diff --git a/src/main/kotlin/io/kweb/state/state.kt b/src/main/kotlin/io/kweb/state/state.kt index aaa661083b..76466559ad 100644 --- a/src/main/kotlin/io/kweb/state/state.kt +++ b/src/main/kotlin/io/kweb/state/state.kt @@ -31,8 +31,21 @@ class Observable(@Volatile private var state : T) { val value get() = state @Synchronized fun changeTo(newVal : T) { - listeners.values.forEach {it(state, newVal)} - state = newVal + if (newVal != state) { + listeners.values.forEach { it(state, newVal) } + state = newVal + } + } + + fun view(mapper : (T) -> O, unmapper : (T, O) -> T) : Observable { + val oobs = Observable(mapper(value)) + addListener { old, new -> + oobs.changeTo(mapper(new)) + } + oobs.addListener({old, new -> + changeTo(unmapper(value, new)) + }) + return oobs } }