mirror of
https://github.com/metosin/reitit.git
synced 2026-02-19 09:15:54 +00:00
Merge pull request #259 from metosin/ignore-anchor-click-fn
Ignore anchor click fn
This commit is contained in:
commit
500d5d6540
2 changed files with 74 additions and 32 deletions
|
|
@ -18,6 +18,31 @@ request to the server. This means the URL will look normal, but the downside is
|
||||||
that the server must respond to all routes with correct file (`index.html`).
|
that the server must respond to all routes with correct file (`index.html`).
|
||||||
Check examples for simple Ring handler example.
|
Check examples for simple Ring handler example.
|
||||||
|
|
||||||
|
### Anchor click handling
|
||||||
|
|
||||||
|
HTML5 History router will handle click events on anchors where the href
|
||||||
|
matches the route tree (and other [rules](../../modules/reitit-frontend/src/reitit/frontend/history.cljs#L84-L98)).
|
||||||
|
If you have need to control this logic, for example to handle some
|
||||||
|
anchor clicks where the href matches route tree normally (i.e. browser load)
|
||||||
|
you can provide `:ignore-anchor-click?` function to add your own logic to
|
||||||
|
event handling:
|
||||||
|
|
||||||
|
```clj
|
||||||
|
(rfe/start!
|
||||||
|
router
|
||||||
|
{:use-fragment false
|
||||||
|
:ignore-anchor-click? (fn [router e el uri]
|
||||||
|
;; Add additional check on top of the default checks
|
||||||
|
(and (rfh/ignore-anchor-click? router e el uri)
|
||||||
|
(not= "false" (gobj/get (.-dataset el) "reititHandleClick"))))})
|
||||||
|
|
||||||
|
;; Use data-reitit-handle-click to disable Reitit anchor handling
|
||||||
|
[:a
|
||||||
|
{:href (rfe/href ::about)
|
||||||
|
:data-reitit-handle-click false}
|
||||||
|
"About"]
|
||||||
|
```
|
||||||
|
|
||||||
## Easy
|
## Easy
|
||||||
|
|
||||||
Reitit frontend routers require storing the state somewhere and passing it to
|
Reitit frontend routers require storing the state somewhere and passing it to
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,29 @@
|
||||||
(first (.composedPath original-event))
|
(first (.composedPath original-event))
|
||||||
(.-target event))))
|
(.-target event))))
|
||||||
|
|
||||||
|
(defn ignore-anchor-click?
|
||||||
|
"Precicate to check if the anchor click event default action
|
||||||
|
should be ignored. This logic will ignore the event
|
||||||
|
if anchor href matches the route tree, and in this case
|
||||||
|
the page location is updated using History API."
|
||||||
|
[router e el uri]
|
||||||
|
(let [current-domain (if (exists? js/location)
|
||||||
|
(.getDomain (.parse Uri js/location)))]
|
||||||
|
(and (or (and (not (.hasScheme uri)) (not (.hasDomain uri)))
|
||||||
|
(= current-domain (.getDomain uri)))
|
||||||
|
(not (.-altKey e))
|
||||||
|
(not (.-ctrlKey e))
|
||||||
|
(not (.-metaKey e))
|
||||||
|
(not (.-shiftKey e))
|
||||||
|
(or (not (.hasAttribute el "target"))
|
||||||
|
(contains? #{"" "_self"} (.getAttribute el "target")))
|
||||||
|
;; Left button
|
||||||
|
(= 0 (.-button e))
|
||||||
|
;; isContentEditable property is inherited from parents,
|
||||||
|
;; so if the anchor is inside contenteditable div, the property will be true.
|
||||||
|
(not (.-isContentEditable el))
|
||||||
|
(reitit/match-by-path router (.getPath uri)))))
|
||||||
|
|
||||||
(defrecord Html5History [on-navigate router listen-key click-listen-key]
|
(defrecord Html5History [on-navigate router listen-key click-listen-key]
|
||||||
History
|
History
|
||||||
(-init [this]
|
(-init [this]
|
||||||
|
|
@ -74,37 +97,22 @@
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(-on-navigate this (-get-path this)))
|
(-on-navigate this (-get-path this)))
|
||||||
|
|
||||||
current-domain
|
ignore-anchor-click-predicate (or (:ignore-anchor-click? this)
|
||||||
(if (exists? js/location)
|
ignore-anchor-click?)
|
||||||
(.getDomain (.parse Uri js/location)))
|
|
||||||
|
|
||||||
;; Prevent document load when clicking a elements, if the href points to URL that is part
|
;; Prevent document load when clicking a elements, if the href points to URL that is part
|
||||||
;; of the routing tree."
|
;; of the routing tree."
|
||||||
ignore-anchor-click
|
ignore-anchor-click (fn [e]
|
||||||
(fn ignore-anchor-click
|
;; Returns the next matching ancestor of event target
|
||||||
[e]
|
(when-let [el (closest-by-tag (event-target e) "a")]
|
||||||
;; Returns the next matching ancestor of event target
|
(let [uri (.parse Uri (.-href el))]
|
||||||
(when-let [el (closest-by-tag (event-target e) "a")]
|
(when (ignore-anchor-click-predicate router e el uri)
|
||||||
(let [uri (.parse Uri (.-href el))]
|
(.preventDefault e)
|
||||||
(when (and (or (and (not (.hasScheme uri)) (not (.hasDomain uri)))
|
(let [path (str (.getPath uri)
|
||||||
(= current-domain (.getDomain uri)))
|
(if (seq (.getQuery uri))
|
||||||
(not (.-altKey e))
|
(str "?" (.getQuery uri))))]
|
||||||
(not (.-ctrlKey e))
|
(.pushState js/window.history nil "" path)
|
||||||
(not (.-metaKey e))
|
(-on-navigate this path))))))]
|
||||||
(not (.-shiftKey e))
|
|
||||||
(not (contains? #{"_blank" "self"} (.getAttribute el "target")))
|
|
||||||
;; Left button
|
|
||||||
(= 0 (.-button e))
|
|
||||||
;; isContentEditable property is inherited from parents,
|
|
||||||
;; so if the anchor is inside contenteditable div, the property will be true.
|
|
||||||
(not (.-isContentEditable el))
|
|
||||||
(reitit/match-by-path router (.getPath uri)))
|
|
||||||
(.preventDefault e)
|
|
||||||
(let [path (str (.getPath uri)
|
|
||||||
(if (seq (.getQuery uri))
|
|
||||||
(str "?" (.getQuery uri))))]
|
|
||||||
(.pushState js/window.history nil "" path)
|
|
||||||
(-on-navigate this path))))))]
|
|
||||||
(-on-navigate this (-get-path this))
|
(-on-navigate this (-get-path this))
|
||||||
(assoc this
|
(assoc this
|
||||||
:listen-key (gevents/listen js/window goog.events.EventType.POPSTATE handler false)
|
:listen-key (gevents/listen js/window goog.events.EventType.POPSTATE handler false)
|
||||||
|
|
@ -133,15 +141,24 @@
|
||||||
- on-navigate Function to be called when route changes. Takes two parameters, ´match´ and ´history´ object.
|
- on-navigate Function to be called when route changes. Takes two parameters, ´match´ and ´history´ object.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
- :use-fragment (default true) If true, onhashchange and location hash are used to store current route."
|
- :use-fragment (default true) If true, onhashchange and location hash are used to store current route.
|
||||||
|
|
||||||
|
Options (Html5History):
|
||||||
|
- :ignore-anchor-click? Function (router, event, anchor element, uri) which will be called to
|
||||||
|
check if the anchor click event should be ignored.
|
||||||
|
To extend built-in check, you can call `reitit.frontend.history/ignore-anchor-click?`
|
||||||
|
function, which will ignore clicks if the href matches route tree."
|
||||||
([router on-navigate]
|
([router on-navigate]
|
||||||
(start! router on-navigate nil))
|
(start! router on-navigate nil))
|
||||||
([router
|
([router
|
||||||
on-navigate
|
on-navigate
|
||||||
{:keys [use-fragment]
|
{:keys [use-fragment]
|
||||||
:or {use-fragment true}}]
|
:or {use-fragment true}
|
||||||
(let [opts {:router router
|
:as opts}]
|
||||||
:on-navigate on-navigate}]
|
(let [opts (-> opts
|
||||||
|
(dissoc :use-fragment)
|
||||||
|
(assoc :router router
|
||||||
|
:on-navigate on-navigate))]
|
||||||
(-init (if use-fragment
|
(-init (if use-fragment
|
||||||
(map->FragmentHistory opts)
|
(map->FragmentHistory opts)
|
||||||
(map->Html5History opts))))))
|
(map->Html5History opts))))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue