venantius / accountant Goto Github PK
View Code? Open in Web Editor NEWClojureScript navigation for single-page applications, made simple.
License: Eclipse Public License 1.0
ClojureScript navigation for single-page applications, made simple.
License: Eclipse Public License 1.0
If an a
has a child tag with its own click event handling, it is not possible to prevent accountant from handling the click.
(Reagent/Hiccup syntax)
[:a {:href "/whatever"}
[:span {:onClick #(do
(.preventDefault %)
(.stopPropagation %)
(js/console.log "Clicked span"))} "clickme"]]
Expected result: accountant's event handler will either not receive, or disregard, the click event.
Observed result: the span's click handler is called, but accountant navigates to /whatever
immediately afterwards.
It seems like core.async dependency can be trivially removed (unless I miss something, this is the only place it's used). Would you mind accepting a PR for this?
goog.Uri
does not decode values correctly and here google/closure-library#1083 (comment) it was suggested that it's almost certainly better to just use goog.url
.
Accountant uses goog.Uri.parse
that in turn uses decodeURI
, but it cannot parse data URIs that contain binary data that has not been encoded with base64
.
An example of such URI: data:audio/midi,MThd%00%00%00%06%00%01%00%02%01%e0MTrk%00%00%00%19%00%FF%51%03%05%16%15%00%FF%59%02%00%00%00%FF%58%04%04%02%18%08%00%FF%2F%00MTrk%00%00%00%10%00%C0%00%00%90%45%55%83%30%80%45%00%00%FF%2F%00
It's a perfectly fine URI, but it cannot be decoded into a text representation.
Thanks for putting together this library. Unfortunately, I wasn't able to get it to work though I'm interested in doing so.
I ran lein new reagent myproject
. I added the necessary calls to my project.clj and core.cljs. Running lein figwheel
resulted in large stack traces.
I then copied the "only namespace" ;-), and used it in my project like this:
(defn init! []
(accountant/configure-navigation!)
; (hook-browser-navigation!)
(mount-root))
but this resulted in the console error: Error: Assert failed: Invalid Hiccup form: [nil] (in myproject.core.current_page) (valid-tag? tag)
I then copied this example: https://gist.github.com/city41/aab464ae6c112acecfe1
and that worked.
A working example could demonstrate proper usage, and maybe how this library differs from the example above, and could clarify how accountant/navigate!
is meant to be used.
When i click on link defined like this [:a {:href "/page"}]
and the current page is /page
then the whole page refreshes. But when I'm switching between different pages then everything is fine. Is this a bug/intended design or I am doing something wrong? Anyone knows how to deal with that issue?
Secretary's root path function is getting executed whenever I click anywhere on the current page. This only appears to happen when have a catch-all route defined.
This was also a symptom in issue #5 but a resolution was not reported. I am also unable to navigate routes by typing the URL in the address bar.
I've slimmed down the code to where the issue is reproducible on multiple machines:
(ns acc-test.core
(:require
[secretary.core :as secretary :refer-macros [defroute]]
[accountant.core :as accountant]
))
(accountant/configure-navigation!)
(defroute home-path "/" []
(js/console.log "Home!")
)
(defroute about-path "/about" []
(aset (.getElementById js/document "root") "innerHTML" "<h1>ABOUT</h1><a href='/'>home</a>"))
(defroute "*" []
(js/console.log "Route not found."))
Is there additional configuration in Secretary or Accountant that I am missing?
I am using it together with bidi. In the main function, I am initializing it like this:
(accountant/configure-navigation!
{:nav-handler #(rf/dispatch [:app-state/changed-route %])
:path-exists? #(contains? #{:app/index :app/help}
(:handler (b/match-route routes/routes %)))
:reload-same-path? false})
I have several problems with it:
Clicking on back and forward buttons in the browser changes the URL, but does not call :app-state/changed-route event. So it is ignored by the app.
When I remove :reload-same-path?, each click on a link called :app-state/changed-route multiple times. But I want to allow reloading the same path to the user.
Sometimes :app-state/changed-route is called multiple times anyway when I reload the page.
Any idea what I could be doing wrong?
Hi,
Given find-href
(defn- find-href
"Given a DOM element that may or may not be a link, traverse up the DOM tree
to see if any of its parents are links. If so, return the href content."
[e]
((fn [e]
(if-let [href (.-href e)]
href
(when-let [parent (.-parentNode e)]
(recur parent)))) (.-target e)))
Is the fn [e] function inside the body necessary ?
I'm asking because, you don't return it, calling it immediately and it has the same signature of the find-href, even the variable name is the same.
A recur to find-href wouldn't suffice ?
Kind regards,
Geraldo
I've made a template app using "lein new reagent myproject". The template is here.
Is there a recommended of modifying accountant in the template file, so that it will be usable with a gitlab or github pages app? gitlab and github pages do not serve the app from root but instead from a directory. For example, "https://bumblehead.gitlab.io/myproject/" or "http://bumblehead.gitlab.io/myproject/".
Should I change my app routing from '/' and '/about' to '/myproject/' and '/myproject/about'?
Hi! It seems that there's a typo in prevent-reload-on-known-path
. When comparing the current URL and the one the user clicked if they are different, it calls .setToken
in the history. To build the current URL you use (str (.-pathname loc) (.-query loc) (.-hash loc))
, where loc
is js/window.location
. It should be .-search
instead of .-query
.
accountant/src/accountant/core.cljs
Lines 90 to 103 in d62f5a9
To reproduce the issue you can try going from a URL such as https://example.com?hey
to https://example.com
. Then, the path-exists?
fn gets executed, but not the nav-handler
.
For now I'll opt on calling (set! navigate-listener-key my-own-prevent-fn)
after my call to configure-navigation!
.
Guys how to get location action(POP | PUSH | REPLACE) in nav-handler?
Hi,
I'd like to add a click handler that prevents navigation when -- for example -- the user is not signed in. It seems that the on-click gets fired after the navigation occurs, so I'm wondering if there's any way to do this. Many thanks.
I know, I know, I need to deploy this to Clojars. I wrote it on a machine that doesn't have my GPG key, so this'll have to happen once I'm at that machine again.
Steps to reproduce the problem:
/a?x=1
for example, this will call the specified nav-handler as expected with the path /a?x=1
/b?y=1
; this will call the specified nav-handler as expected with the path /b?y=1
/a?x=1
, but the nav-handler will be called with the path /a
; note the missing query parametersEnvironment: tested under Mac OS with both Chrome 60 and Firefox 56 (developer edition); clojurescript "1.9.854";
Seems to be similar to #23
In google chrome at least, when no port is specified on a link:
The test for port equality fails when no port is specified for the link, preventing accountant from stepping in.
Hello,
First I'd like to say thank you for maintaining this library! I was curious if you would consider providing the ability to un-configure (probably not the best name) navigation.
For the current implementation, the series of calls from configure-navigation!
to dispatch-on-navigate
, to goog.events/listen
creates a listener that can't be released, and it'd be nice to have a way to un-register it.
My use case is that for our project using this, we create a system component, using https://github.com/stuartsierra/component, and when a user logs out, we'd like to unlisten to the NAVIGATE event in this case so that we can clean up all of the handlers that our system creates. We have a workaround, using goog.events/removeAll
, but this makes it so that we have to know more about the implementation than we'd like to, and if your library would take on the responsibility, it'd be more pleasant to use.
Thanks for your consideration!
I have an issue that I don't know if it is due to accountant or something else in my setup. When clicking links leading to anchors on the page, the browser doesn’t scroll. If the anchor is on the same page, it’s like clicking a dead link. If the anchor is on another page on the site/app then the new page is rendered, but scrolled to wherever the previous page were scrolled. Something like so:
/A
containg:
/A#a
(high up on the page)a
(farther down the page)./B#b
(far down on the page)/B
containing:
b
(high up on the page)/A
, click the link /A#a
/A
scrolls down to anchor a
/A
, click the link /B#b
/B
opens, scrolled up to anchor b
/B
opens, scroll doesn't change (so showing content somehwere far down on the page).It isn't necessarily about clicking. It behaves the same if I type the url:s in the browser's location bar, or if I enter something like accountant.core.history.setToken("/A#a")
from the dev console.
However, if I enter window.location = "/A#a"
in the dev console it does scroll to the anchor.
When I load a url, say, http://foo.bar/baz#gazonk
from scratch or click on a link /baz#gazonk
in my SPA then my :nav-handler
gets passed a path
argument including the fragment (#gazonk
), but when I navigate to the page using the browser's back button the path
argument is stripped of the fragment. Is this intentional by Accountant, a bug or something Accountant can't do anything about, or what?
Is there a way to have a link which accountant would normally preventDefault and handle instead do the default behavior? Our use case is wanting to open some content that is rendered by our SPA in a popup. accountant seems to prevent that from working.
It would be nice if we could tell accountant somehow "don't handle this one" in the <a>
element itself, or if accountant detected links w/ the target
attr set and didn't handle them.
Hi,
I ended up using accountant for a slightly different purpose. I trigger a transition animation on any link click, and once it completes I actually load that page using a call to location.replace
Accountant has been super helpful by being able to capture all the links on the page.
Unfortunately once the next page loads, the back button is broken. The browser never returns to the original page.
Is there a way to disable just the history functionality of accountant?
I have a luminus setup for various apps. On one, I now need Accountant's ability to link internally (e.g. as an event handler) without causing a browser refresh. I'm a bit lost in getting the setup working; here's a gist with my existing setup and my attempt to get accountant working. Help would be much appreciated.
https://gist.github.com/WorldsEndless/43c8efc6d4db1ff684d9260fe22ddfc7
Steps to reproduce
/some-route?foo=bar
/another-route
Expected behavior: URL will be /another-route
Observed behavior: URL will be /another-route?foo=bar
Hey, does anyone here check for pull requests? I made one 5 days ago but it still haven't received any attention.
Hi, I seem to be having difficulty setting up accountant in a way that resolves client routable URLs without sending a remote request.
I'm using bidi routes:
["/" {"" :home
"doc" :doc
"login" :login
true :not-found}]
I run this at init:
(accountant.core/configure-navigation!
{:nav-handler #(update-page-in-db (bidi/match-route app-routes %))
:path-exists? #(boolean (bidi/match-route app-routes %))})
(accountant.core/dispatch-current!)
And I can successfully navigate to pages using:
(accountant.core/navigate! "/doc")
(accountant.core/navigate! "/")
However when I manually type in the url to point to ".../doc"
, it makes a full request to the remote, which I'd like to avoid. My understanding was that if the route is navigable (via :path-exists?
), then accountant should prevent that from happening and just route client side. Unfortunately I just cannot seem to figure out how to do this when manually typing in the URL.
Am I misunderstanding something?
Hi,
did you try to migrate this to secretary 2? I did some work on this here but i'm stuck with this issue: i need to know what is the best replacement for the locate-route
function in secretary 2.
Is it ok with you if i open a PR when i'm done or you want to keep this only for secretary 1?
Great jar, thanks!
For example when the URL is /abc
and I change it in the browser to /abc#123
the nav-handler only receives "/abc"
. When clicking on a link with href /abc#123
OTOH the nav-handler gets the full URL.
Given:
<a href="/"> <!-- Given that "/" is a known route -->
<img src="logo.png"/>
</a>
If you click the image on IE11 (at least, possibly other IE versions, too), Accountant doesn't block the page reload.
This is because find-href-node
uses the href
DOM property, and on IE11, for some reason, document.querySelector("img").href
returns the value of the src
attribute of the img
element. logo.png
isn't a known route, which leads to the browser attempting to reload the page.
One possible fix would be to use .getAttribute
instead. Something like this, for example:
diff --git a/src/accountant/core.cljs b/src/accountant/core.cljs
index fcbe6e0..42a8137 100644
--- a/src/accountant/core.cljs
+++ b/src/accountant/core.cljs
@@ -18,11 +18,18 @@
(let [token (.-token e)]
(nav-handler token)))))
+(defn- get-href
+ "Given a DOM node, if it is an element node, return its href attribute.
+ Otherwise, return nil."
+ [node]
+ (when (and node (= (.-nodeType node) js/Node.ELEMENT_NODE))
+ (.getAttribute node "href")))
+
(defn- find-href-node
"Given a DOM element that may or may not be a link, traverse up the DOM tree
to see if any of its parents are links. If so, return the node."
[e]
- (if (.-href e)
+ (if (get-href e)
e
(when-let [parent (.-parentNode e)]
(recur parent))))
Steps to reproduce
/some-route
/some-route?foo=bar
Expected result: Clicking link will result in a call to pushState
, setting the URL to /some-route?foo=bar
Observed result: Click event is not handled, a full page load occurs.
Hi
It should be possible to use secretary and accountant for routing when user type url manually?
Here's a small scenario:
I have a search input. The input changes the URL in its on-change
attribute. The URL is changed from:
localhost:3449/
to localhost:3449/?q=t
But when I keep tying the word test
into the search input, the URL changes to:
localhost:3449/?q=t?q=te?q=tes?q=test
.
I have managed to track the issue down to this line in core.cljs
line 108
:
(let [token (.getToken history)])
It seems the Html5History
API from the Google Closure Library does not keep track/return the query string when calling getToken
on it, because it always returns "/"
, instead of "/?q=t"
etc.
Is there any way I can work around this for now? I don't know if the issue is in the GCL Html5History
API, or Accountant, or that I'm doing something wrong.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.