/
electric_goog_history.cljc
84 lines (72 loc) · 2.72 KB
/
electric_goog_history.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
(ns contrib.electric-goog-history
#?(:cljs
(:import goog.history.Html5History
goog.history.Html5History.TokenTransformer
goog.history.EventType))
(:require [contrib.cljs-target :refer [do-browser]]
#?(:cljs goog.events)
[hyperfiddle.electric :as e]
[hyperfiddle.electric-dom2 :as dom]
[hyperfiddle.rcf :refer [tests tap % with]]
[missionary.core :as m]))
#?(:cljs
(do-browser
(defn new-goog-history
([] (new-goog-history (fn [path-prefix location]
(str (.-pathname location)
(.-search location)
(.-hash location)))))
([retrieve-fn]
(let [transformer (TokenTransformer.)]
(set! (.. transformer -retrieveToken) retrieve-fn)
(set! (.. transformer -createUrl) (fn [token path-prefix location] (str path-prefix token)))
(doto (Html5History. js/window transformer)
(.setUseFragment false)
(.setPathPrefix "")
(.setEnabled true)))))
(defn path> [^js h]
(m/observe (fn mount [!]
(let [k (goog.events/listen h EventType.NAVIGATE (fn [^js e] (! (.-token e))))]
(! (.getToken h))
(fn unmount []
(goog.events/unlistenByKey k))))))
;; Usage from Missionary
(tests "goog-history-router"
(.isSupported Html5History js/window) := true
(def h (new-goog-history))
(def >x (m/cp (tap (m/?< (m/relieve {} (path> h))))))
(def it (>x #(tap ::notify) #(tap ::terminate)))
% := ::notify
@it
% := "/"
(.setToken h "/a")
% := ::notify
@it
% := "/a"
(.setToken h "/b")
% := ::notify
(.setToken h "/")
@it
% := "/"
(it))
))
;; Usage from Electric
(e/def !history (e/client (new-goog-history)))
(e/def path (e/client (new (m/relieve {} (path> !history)))))
; hack Cannot infer target type in expression, todo Electric compiler not propagating hint
#?(:cljs (defn -historySetToken [^js !history href] (.setToken !history href)))
(e/defn Link [href label]
(e/client
(dom/a {::dom/href href}
(dom/on "click" (e/fn [e]
(-historySetToken !history href)
(.preventDefault e)))
(dom/text label))))
(defn parse-route [path] path)
(e/defn DemoGoogHistory []
(e/client
(let [route (parse-route path)]
(case route
"/" (do (dom/h1 (dom/text "Home")) (Link. "/a" (dom/text "a")))
"/a" (do (dom/h1 (dom/text "A")) (Link. "/" (dom/text "home")))
(dom/h1 (dom/text "no matching route: " (pr-str path)))))))