|
18 | 18 | (recur-href (.-parentNode target)))))
|
19 | 19 |
|
20 | 20 | (defn- update-history! [h]
|
21 |
| - (.setUseFragment h false) |
22 |
| - (.setPathPrefix h "") |
23 |
| - (.setEnabled h true) |
24 |
| - h) |
| 21 | + (doto h |
| 22 | + (.setUseFragment false) |
| 23 | + (.setPathPrefix "") |
| 24 | + (.setEnabled true))) |
25 | 25 |
|
26 | 26 | (defn- set-retrieve-token! [t]
|
27 | 27 | (set! (.. t -retrieveToken)
|
|
35 | 35 | (str path-prefix token)))
|
36 | 36 | t)
|
37 | 37 |
|
38 |
| -(def transformer |
39 |
| - (-> (TokenTransformer.) set-retrieve-token! set-create-url!)) |
40 |
| - |
41 |
| -(def history |
42 |
| - (-> (Html5History. js/window transformer) update-history!)) |
43 |
| - |
44 |
| -(defn set-token! |
45 |
| - "Sets the history state" |
46 |
| - ([token] |
47 |
| - (. history (setToken token))) |
48 |
| - ([token title] |
49 |
| - (. history (setToken token title)))) |
50 |
| - |
51 |
| -(defn replace-token! |
52 |
| - "Replaces the current history state without affecting the rest of the history stack" |
53 |
| - ([token] |
54 |
| - (. history (replaceToken token))) |
55 |
| - ([token title] |
56 |
| - (. history (replaceToken token title)))) |
57 |
| - |
58 |
| -(defn get-token |
59 |
| - "Returns the current token" |
60 |
| - [] |
61 |
| - (.getToken history)) |
62 |
| - |
63 |
| -(defn supported? |
64 |
| - "Returns whether Html5History is supported" |
65 |
| - [window] |
66 |
| - (.isSupported Html5History window)) |
67 |
| - |
68 |
| -(defn push-state! |
69 |
| - "Initializes push state using goog.history.Html5History |
70 |
| -
|
71 |
| - Adds an event listener to all click events and dispatches `dispatch-fn` |
72 |
| - when the target element contains a href attribute that matches |
73 |
| - any of the routes returned by `match-fn` |
74 |
| -
|
75 |
| - Takes in three functions: |
| 38 | +(defn new-history |
| 39 | + ([] |
| 40 | + (new-history (-> (TokenTransformer.) set-retrieve-token! set-create-url!))) |
| 41 | + ([transformer] |
| 42 | + (-> (Html5History. js/window transformer) update-history!))) |
| 43 | + |
| 44 | +(defprotocol IHistory |
| 45 | + (set-token! [this token] [this token title]) |
| 46 | + (replace-token! [this token] [this token title]) |
| 47 | + (get-token [this]) |
| 48 | + (start! [this]) |
| 49 | + (stop! [this])) |
| 50 | + |
| 51 | +(defn pushy |
| 52 | + "Takes in three functions: |
76 | 53 | * dispatch-fn: the function that dispatches when a match is found
|
77 | 54 | * match-fn: the function used to check if a particular route exists
|
78 | 55 | * identity-fn: (optional) extract the route from value returned by match-fn"
|
79 | 56 | ([dispatch-fn match-fn]
|
80 |
| - (push-state! dispatch-fn match-fn identity)) |
81 |
| - |
| 57 | + (pushy dispatch-fn match-fn identity)) |
82 | 58 | ([dispatch-fn match-fn identity-fn]
|
83 |
| - ;; We want to call `dispatch-fn` on any change to the location |
84 |
| - (events/listen history EventType.NAVIGATE |
85 |
| - (fn [e] |
86 |
| - (if-let [match (-> (.-token e) match-fn identity-fn)] |
87 |
| - (dispatch-fn match)))) |
88 |
| - |
89 |
| - ;; Dispatch on initialization |
90 |
| - (when-let [match (-> (get-token) match-fn identity-fn)] |
91 |
| - (dispatch-fn match)) |
| 59 | + (let [history (new-history) |
| 60 | + event-keys (atom nil)] |
| 61 | + (reify |
| 62 | + IHistory |
| 63 | + (set-token! [_ token] |
| 64 | + (. history (setToken token))) |
| 65 | + (set-token! [_ token title] |
| 66 | + (. history (setToken token title))) |
| 67 | + |
| 68 | + (replace-token! [_ token] |
| 69 | + (. history (setToken token))) |
| 70 | + (replace-token! [_ token title] |
| 71 | + (. history (setToken token title))) |
| 72 | + |
| 73 | + (get-token [_] |
| 74 | + (.getToken history)) |
| 75 | + |
| 76 | + (start! [this] |
| 77 | + (stop! this) |
| 78 | + ;; We want to call `dispatch-fn` on any change to the location |
| 79 | + (swap! event-keys conj |
| 80 | + (events/listen history EventType.NAVIGATE |
| 81 | + (fn [e] |
| 82 | + (if-let [match (-> (.-token e) match-fn identity-fn)] |
| 83 | + (dispatch-fn match))))) |
| 84 | + |
| 85 | + ;; Dispatch on initialization |
| 86 | + (when-let [match (-> (get-token this) match-fn identity-fn)] |
| 87 | + (dispatch-fn match)) |
| 88 | + |
| 89 | + (swap! event-keys conj |
| 90 | + (on-click |
| 91 | + (fn [e] |
| 92 | + (when-let [el (recur-href (-> e .-target))] |
| 93 | + (let [href (.-href el) |
| 94 | + path (->> href (.parse Uri) .getPath)] |
| 95 | + ;; Proceed if `identity-fn` returns a value and |
| 96 | + ;; the user did not trigger the event via one of the |
| 97 | + ;; keys we should bypass |
| 98 | + (when (and (identity-fn (match-fn path)) |
| 99 | + ;; Bypass dispatch if any of these keys |
| 100 | + (not (.-altKey e)) |
| 101 | + (not (.-ctrlKey e)) |
| 102 | + (not (.-metaKey e)) |
| 103 | + (not (.-shiftKey e)) |
| 104 | + ;; Bypass if target = _blank |
| 105 | + (not (= "_blank" (.getAttribute el "target"))) |
| 106 | + ;; Bypass dispatch if middle click |
| 107 | + (not= 1 (.-button e))) |
| 108 | + ;; Dispatch! |
| 109 | + (if-let [title (-> el .-title)] |
| 110 | + (set-token! this path title) |
| 111 | + (set-token! this path)) |
| 112 | + (.preventDefault e))))))) |
| 113 | + nil) |
| 114 | + |
| 115 | + (stop! [this] |
| 116 | + (doseq [key @event-keys] |
| 117 | + (events/unlistenByKey key)) |
| 118 | + (reset! event-keys nil)))))) |
92 | 119 |
|
93 |
| - ;; Setup event listener on all 'click' events |
94 |
| - (on-click |
95 |
| - (fn [e] |
96 |
| - (when-let [el (recur-href (-> e .-target))] |
97 |
| - (let [href (.-href el) |
98 |
| - path (->> href (.parse Uri) .getPath)] |
99 |
| - ;; Proceed if `identity-fn` returns a value and |
100 |
| - ;; the user did not trigger the event via one of the |
101 |
| - ;; keys we should bypass |
102 |
| - (when (and (identity-fn (match-fn path)) |
103 |
| - ;; Bypass dispatch if any of these keys |
104 |
| - (not (.-altKey e)) |
105 |
| - (not (.-ctrlKey e)) |
106 |
| - (not (.-metaKey e)) |
107 |
| - (not (.-shiftKey e)) |
108 |
| - ;; Bypass if target = _blank |
109 |
| - (not (= "_blank" (.getAttribute el "target"))) |
110 |
| - ;; Bypass dispatch if middle click |
111 |
| - (not= 1 (.-button e))) |
112 |
| - ;; Dispatch! |
113 |
| - (set-token! path (-> el .-title)) |
114 |
| - (.preventDefault e)))))))) |
115 |
| - |
116 |
| -(defn unlisten! |
117 |
| - "Closes the pushy event listeners" |
118 |
| - [push-state] |
119 |
| - (events/unlistenByKey push-state) |
120 |
| - (events/unlisten history EventType.NAVIGATE)) |
| 120 | +(defn supported? |
| 121 | + "Returns whether Html5History is supported" |
| 122 | + ([] (supported? js/window)) |
| 123 | + ([window] (.isSupported Html5History window))) |
0 commit comments