fix bugs in page
This commit is contained in:
1 parent
6ed638a1cc
commit
e654fdfea6
387 files changed
+13618
-88879
No files matched your search
@@ -0,0 +1,155 @@
|
||||
(ns accountant.core
|
||||
"The only namespace in this library."
|
||||
(:require [clojure.string :as str]
|
||||
[goog.events :as events]
|
||||
[goog.history.EventType :as EventType])
|
||||
(:import goog.history.Event
|
||||
goog.history.Html5History
|
||||
goog.Uri))
|
||||
|
||||
(defn- transformer-create-url
|
||||
[token path-prefix location]
|
||||
(str path-prefix token))
|
||||
|
||||
(defn- transformer-retrieve-token
|
||||
[path-prefix location]
|
||||
(str (.-pathname location) (.-search location) (.-hash location)))
|
||||
|
||||
(defonce history (let [transformer (goog.history.Html5History.TokenTransformer.)]
|
||||
(set! (.. transformer -retrieveToken) transformer-retrieve-token)
|
||||
(set! (.. transformer -createUrl) transformer-create-url)
|
||||
(Html5History. js/window transformer)))
|
||||
|
||||
(defn- dispatch-on-navigate
|
||||
[history nav-handler]
|
||||
(events/listen
|
||||
history
|
||||
EventType/NAVIGATE
|
||||
(fn [e]
|
||||
(let [token (.-token e)]
|
||||
(nav-handler token)))))
|
||||
|
||||
(defn- get-href-attribute
|
||||
"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 href content, if
|
||||
it does not have an explicit `data-trigger` attribute to signify a non-navigational
|
||||
link element."
|
||||
[e]
|
||||
(let [href (get-href-attribute e)
|
||||
attrs (.-attributes e)
|
||||
navigation-link? (and href attrs (-> attrs (aget "data-trigger") not))]
|
||||
(if navigation-link?
|
||||
e
|
||||
(when-let [parent (.-parentNode e)]
|
||||
(recur parent)))))
|
||||
|
||||
(defn- uri->query [uri]
|
||||
(let [query (.getQuery uri)]
|
||||
(when-not (empty? query)
|
||||
(str "?" query))))
|
||||
|
||||
(defn- uri->fragment [uri]
|
||||
(let [fragment (.getFragment uri)]
|
||||
(when-not (empty? fragment)
|
||||
(str "#" fragment))))
|
||||
|
||||
(defn- prevent-reload-on-known-path
|
||||
"Create a click handler that blocks page reloads for known routes"
|
||||
[history path-exists?]
|
||||
(events/listen
|
||||
js/document
|
||||
"click"
|
||||
(fn [e]
|
||||
(let [target (.-target e)
|
||||
button (.-button e)
|
||||
meta-key (.-metaKey e)
|
||||
alt-key (.-altKey e)
|
||||
ctrl-key (.-ctrlKey e)
|
||||
shift-key (.-shiftKey e)
|
||||
any-key (or meta-key alt-key ctrl-key shift-key)
|
||||
href-node (find-href-node target)
|
||||
href (when href-node (.-href href-node))
|
||||
link-target (when href-node (.-target href-node))
|
||||
uri (.parse Uri href)
|
||||
path (.getPath uri)
|
||||
query (uri->query uri)
|
||||
fragment (uri->fragment uri)
|
||||
relative-href (str path query fragment)
|
||||
title (.-title target)
|
||||
host (.getDomain uri)
|
||||
port (.getPort uri)
|
||||
current-host js/window.location.hostname
|
||||
current-port js/window.location.port
|
||||
loc js/window.location
|
||||
current-relative-href (str (.-pathname loc) (.-query loc) (.-hash loc))]
|
||||
(when (and (not any-key)
|
||||
(#{"" "_self"} link-target)
|
||||
(= button 0)
|
||||
(= host current-host)
|
||||
(or (not port)
|
||||
(= (str port) (str current-port)))
|
||||
(path-exists? path))
|
||||
(when (not= current-relative-href relative-href) ;; do not add duplicate html5 history state
|
||||
(. history (setToken relative-href title)))
|
||||
(.preventDefault e))))))
|
||||
|
||||
(defonce nav-handler nil)
|
||||
(defonce path-exists? nil)
|
||||
|
||||
(defn configure-navigation!
|
||||
"Create and configure HTML5 history navigation.
|
||||
|
||||
nav-handler: a fn of one argument, a path. Called when we've decided
|
||||
to navigate to another page. You'll want to make your app draw the
|
||||
new page here.
|
||||
|
||||
path-exists?: a fn of one argument, a path. Return truthy if this path is handled by the SPA"
|
||||
[{:keys [nav-handler path-exists?]}]
|
||||
(.setUseFragment history false)
|
||||
(.setPathPrefix history "")
|
||||
(.setEnabled history true)
|
||||
(set! accountant.core/nav-handler nav-handler)
|
||||
(set! accountant.core/path-exists? path-exists?)
|
||||
(dispatch-on-navigate history nav-handler)
|
||||
(prevent-reload-on-known-path history path-exists?))
|
||||
|
||||
(defn map->params [query]
|
||||
(let [params (map #(name %) (keys query))
|
||||
values (vals query)
|
||||
pairs (partition 2 (interleave params values))]
|
||||
(str/join "&" (map #(str/join "=" %) pairs))))
|
||||
|
||||
(defn navigate!
|
||||
"add a browser history entry. updates window/location"
|
||||
([route] (navigate! route {}))
|
||||
([route query]
|
||||
(if nav-handler
|
||||
(let [token (.getToken history)
|
||||
old-route (first (str/split token "?"))
|
||||
query-string (map->params (reduce-kv (fn [valid k v]
|
||||
(if v
|
||||
(assoc valid k v)
|
||||
valid)) {} query))
|
||||
with-params (if (empty? query-string)
|
||||
route
|
||||
(str route "?" query-string))]
|
||||
(if (= old-route route)
|
||||
(. history (replaceToken with-params))
|
||||
(. history (setToken with-params))))
|
||||
(js/console.error "can't navigate! until configure-navigation! called"))))
|
||||
|
||||
(defn dispatch-current! []
|
||||
"Dispatch current URI path."
|
||||
(let [path (-> js/window .-location .-pathname)
|
||||
query (-> js/window .-location .-search)
|
||||
hash (-> js/window .-location .-hash)]
|
||||
(if nav-handler
|
||||
(nav-handler (str path query hash))
|
||||
(js/console.error "can't dispatch-current until configure-navigation! called"))))
|
||||
@@ -0,0 +1,306 @@
|
||||
// Compiled by ClojureScript 1.9.946 {:static-fns true, :optimize-constants true}
|
||||
goog.provide('accountant.core');
|
||||
goog.require('cljs.core');
|
||||
goog.require('cljs.core.constants');
|
||||
goog.require('clojure.string');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.history.EventType');
|
||||
goog.require('goog.history.Event');
|
||||
goog.require('goog.history.Html5History');
|
||||
goog.require('goog.Uri');
|
||||
accountant.core.transformer_create_url = (function accountant$core$transformer_create_url(token,path_prefix,location){
|
||||
return [cljs.core.str.cljs$core$IFn$_invoke$arity$1(path_prefix),cljs.core.str.cljs$core$IFn$_invoke$arity$1(token)].join('');
|
||||
});
|
||||
accountant.core.transformer_retrieve_token = (function accountant$core$transformer_retrieve_token(path_prefix,location){
|
||||
return [cljs.core.str.cljs$core$IFn$_invoke$arity$1(location.pathname),cljs.core.str.cljs$core$IFn$_invoke$arity$1(location.search),cljs.core.str.cljs$core$IFn$_invoke$arity$1(location.hash)].join('');
|
||||
});
|
||||
if(typeof accountant.core.history !== 'undefined'){
|
||||
} else {
|
||||
accountant.core.history = (function (){var transformer = (new goog.history.Html5History.TokenTransformer());
|
||||
transformer.retrieveToken = accountant.core.transformer_retrieve_token;
|
||||
|
||||
transformer.createUrl = accountant.core.transformer_create_url;
|
||||
|
||||
return (new goog.history.Html5History(window,transformer));
|
||||
})();
|
||||
}
|
||||
accountant.core.dispatch_on_navigate = (function accountant$core$dispatch_on_navigate(history,nav_handler){
|
||||
var G__14984 = history;
|
||||
var G__14985 = goog.history.EventType.NAVIGATE;
|
||||
var G__14986 = ((function (G__14984,G__14985){
|
||||
return (function (e){
|
||||
var token = e.token;
|
||||
return (nav_handler.cljs$core$IFn$_invoke$arity$1 ? nav_handler.cljs$core$IFn$_invoke$arity$1(token) : nav_handler.call(null,token));
|
||||
});})(G__14984,G__14985))
|
||||
;
|
||||
return goog.events.listen(G__14984,G__14985,G__14986);
|
||||
});
|
||||
/**
|
||||
* Given a DOM node, if it is an element node, return its href attribute.
|
||||
* Otherwise, return nil.
|
||||
*/
|
||||
accountant.core.get_href_attribute = (function accountant$core$get_href_attribute(node){
|
||||
if(cljs.core.truth_((function (){var and__8770__auto__ = node;
|
||||
if(cljs.core.truth_(and__8770__auto__)){
|
||||
return cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(node.nodeType,Node.ELEMENT_NODE);
|
||||
} else {
|
||||
return and__8770__auto__;
|
||||
}
|
||||
})())){
|
||||
return node.getAttribute("href");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 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, if
|
||||
* it does not have an explicit `data-trigger` attribute to signify a non-navigational
|
||||
* link element.
|
||||
*/
|
||||
accountant.core.find_href_node = (function accountant$core$find_href_node(e){
|
||||
while(true){
|
||||
var href = accountant.core.get_href_attribute(e);
|
||||
var attrs = e.attributes;
|
||||
var navigation_link_QMARK_ = (function (){var and__8770__auto__ = href;
|
||||
if(cljs.core.truth_(and__8770__auto__)){
|
||||
var and__8770__auto____$1 = attrs;
|
||||
if(cljs.core.truth_(and__8770__auto____$1)){
|
||||
return cljs.core.not((attrs["data-trigger"]));
|
||||
} else {
|
||||
return and__8770__auto____$1;
|
||||
}
|
||||
} else {
|
||||
return and__8770__auto__;
|
||||
}
|
||||
})();
|
||||
if(cljs.core.truth_(navigation_link_QMARK_)){
|
||||
return e;
|
||||
} else {
|
||||
var temp__5457__auto__ = e.parentNode;
|
||||
if(cljs.core.truth_(temp__5457__auto__)){
|
||||
var parent = temp__5457__auto__;
|
||||
var G__14987 = parent;
|
||||
e = G__14987;
|
||||
continue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
accountant.core.uri__GT_query = (function accountant$core$uri__GT_query(uri){
|
||||
var query = uri.getQuery();
|
||||
if(cljs.core.empty_QMARK_(query)){
|
||||
return null;
|
||||
} else {
|
||||
return ["?",cljs.core.str.cljs$core$IFn$_invoke$arity$1(query)].join('');
|
||||
}
|
||||
});
|
||||
accountant.core.uri__GT_fragment = (function accountant$core$uri__GT_fragment(uri){
|
||||
var fragment = uri.getFragment();
|
||||
if(cljs.core.empty_QMARK_(fragment)){
|
||||
return null;
|
||||
} else {
|
||||
return ["#",cljs.core.str.cljs$core$IFn$_invoke$arity$1(fragment)].join('');
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Create a click handler that blocks page reloads for known routes
|
||||
*/
|
||||
accountant.core.prevent_reload_on_known_path = (function accountant$core$prevent_reload_on_known_path(history,path_exists_QMARK_){
|
||||
var G__14988 = document;
|
||||
var G__14989 = "click";
|
||||
var G__14990 = ((function (G__14988,G__14989){
|
||||
return (function (e){
|
||||
var target = e.target;
|
||||
var button = e.button;
|
||||
var meta_key = e.metaKey;
|
||||
var alt_key = e.altKey;
|
||||
var ctrl_key = e.ctrlKey;
|
||||
var shift_key = e.shiftKey;
|
||||
var any_key = (function (){var or__8782__auto__ = meta_key;
|
||||
if(cljs.core.truth_(or__8782__auto__)){
|
||||
return or__8782__auto__;
|
||||
} else {
|
||||
var or__8782__auto____$1 = alt_key;
|
||||
if(cljs.core.truth_(or__8782__auto____$1)){
|
||||
return or__8782__auto____$1;
|
||||
} else {
|
||||
var or__8782__auto____$2 = ctrl_key;
|
||||
if(cljs.core.truth_(or__8782__auto____$2)){
|
||||
return or__8782__auto____$2;
|
||||
} else {
|
||||
return shift_key;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
var href_node = accountant.core.find_href_node(target);
|
||||
var href = (cljs.core.truth_(href_node)?href_node.href:null);
|
||||
var link_target = (cljs.core.truth_(href_node)?href_node.target:null);
|
||||
var uri = goog.Uri.parse(href);
|
||||
var path = uri.getPath();
|
||||
var query = accountant.core.uri__GT_query(uri);
|
||||
var fragment = accountant.core.uri__GT_fragment(uri);
|
||||
var relative_href = [cljs.core.str.cljs$core$IFn$_invoke$arity$1(path),cljs.core.str.cljs$core$IFn$_invoke$arity$1(query),cljs.core.str.cljs$core$IFn$_invoke$arity$1(fragment)].join('');
|
||||
var title = target.title;
|
||||
var host = uri.getDomain();
|
||||
var port = uri.getPort();
|
||||
var current_host = window.location.hostname;
|
||||
var current_port = window.location.port;
|
||||
var loc = window.location;
|
||||
var current_relative_href = [cljs.core.str.cljs$core$IFn$_invoke$arity$1(loc.pathname),cljs.core.str.cljs$core$IFn$_invoke$arity$1(loc.query),cljs.core.str.cljs$core$IFn$_invoke$arity$1(loc.hash)].join('');
|
||||
if(cljs.core.truth_((function (){var and__8770__auto__ = cljs.core.not(any_key);
|
||||
if(and__8770__auto__){
|
||||
var and__8770__auto____$1 = (function (){var fexpr__14993 = new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, 2, ["",null,"_self",null], null), null);
|
||||
return (fexpr__14993.cljs$core$IFn$_invoke$arity$1 ? fexpr__14993.cljs$core$IFn$_invoke$arity$1(link_target) : fexpr__14993.call(null,link_target));
|
||||
})();
|
||||
if(cljs.core.truth_(and__8770__auto____$1)){
|
||||
var and__8770__auto____$2 = cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(button,(0));
|
||||
if(and__8770__auto____$2){
|
||||
var and__8770__auto____$3 = cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(host,current_host);
|
||||
if(and__8770__auto____$3){
|
||||
var and__8770__auto____$4 = (cljs.core.not(port)) || (cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2([cljs.core.str.cljs$core$IFn$_invoke$arity$1(port)].join(''),[cljs.core.str.cljs$core$IFn$_invoke$arity$1(current_port)].join('')));
|
||||
if(and__8770__auto____$4){
|
||||
return (path_exists_QMARK_.cljs$core$IFn$_invoke$arity$1 ? path_exists_QMARK_.cljs$core$IFn$_invoke$arity$1(path) : path_exists_QMARK_.call(null,path));
|
||||
} else {
|
||||
return and__8770__auto____$4;
|
||||
}
|
||||
} else {
|
||||
return and__8770__auto____$3;
|
||||
}
|
||||
} else {
|
||||
return and__8770__auto____$2;
|
||||
}
|
||||
} else {
|
||||
return and__8770__auto____$1;
|
||||
}
|
||||
} else {
|
||||
return and__8770__auto__;
|
||||
}
|
||||
})())){
|
||||
if(cljs.core.not_EQ_.cljs$core$IFn$_invoke$arity$2(current_relative_href,relative_href)){
|
||||
history.setToken(relative_href,title);
|
||||
} else {
|
||||
}
|
||||
|
||||
return e.preventDefault();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});})(G__14988,G__14989))
|
||||
;
|
||||
return goog.events.listen(G__14988,G__14989,G__14990);
|
||||
});
|
||||
if(typeof accountant.core.nav_handler !== 'undefined'){
|
||||
} else {
|
||||
accountant.core.nav_handler = null;
|
||||
}
|
||||
if(typeof accountant.core.path_exists_QMARK_ !== 'undefined'){
|
||||
} else {
|
||||
accountant.core.path_exists_QMARK_ = null;
|
||||
}
|
||||
/**
|
||||
* Create and configure HTML5 history navigation.
|
||||
*
|
||||
* nav-handler: a fn of one argument, a path. Called when we've decided
|
||||
* to navigate to another page. You'll want to make your app draw the
|
||||
* new page here.
|
||||
*
|
||||
* path-exists?: a fn of one argument, a path. Return truthy if this path is handled by the SPA
|
||||
*/
|
||||
accountant.core.configure_navigation_BANG_ = (function accountant$core$configure_navigation_BANG_(p__14994){
|
||||
var map__14995 = p__14994;
|
||||
var map__14995__$1 = ((((!((map__14995 == null)))?((((map__14995.cljs$lang$protocol_mask$partition0$ & (64))) || ((cljs.core.PROTOCOL_SENTINEL === map__14995.cljs$core$ISeq$)))?true:false):false))?cljs.core.apply.cljs$core$IFn$_invoke$arity$2(cljs.core.hash_map,map__14995):map__14995);
|
||||
var nav_handler = cljs.core.get.cljs$core$IFn$_invoke$arity$2(map__14995__$1,cljs.core.cst$kw$nav_DASH_handler);
|
||||
var path_exists_QMARK_ = cljs.core.get.cljs$core$IFn$_invoke$arity$2(map__14995__$1,cljs.core.cst$kw$path_DASH_exists_QMARK_);
|
||||
accountant.core.history.setUseFragment(false);
|
||||
|
||||
accountant.core.history.setPathPrefix("");
|
||||
|
||||
accountant.core.history.setEnabled(true);
|
||||
|
||||
accountant.core.nav_handler = nav_handler;
|
||||
|
||||
accountant.core.path_exists_QMARK_ = path_exists_QMARK_;
|
||||
|
||||
accountant.core.dispatch_on_navigate(accountant.core.history,nav_handler);
|
||||
|
||||
return accountant.core.prevent_reload_on_known_path(accountant.core.history,path_exists_QMARK_);
|
||||
});
|
||||
accountant.core.map__GT_params = (function accountant$core$map__GT_params(query){
|
||||
var params = cljs.core.map.cljs$core$IFn$_invoke$arity$2((function (p1__14997_SHARP_){
|
||||
return cljs.core.name(p1__14997_SHARP_);
|
||||
}),cljs.core.keys(query));
|
||||
var values = cljs.core.vals(query);
|
||||
var pairs = cljs.core.partition.cljs$core$IFn$_invoke$arity$2((2),cljs.core.interleave.cljs$core$IFn$_invoke$arity$2(params,values));
|
||||
return clojure.string.join.cljs$core$IFn$_invoke$arity$2("&",cljs.core.map.cljs$core$IFn$_invoke$arity$2(((function (params,values,pairs){
|
||||
return (function (p1__14998_SHARP_){
|
||||
return clojure.string.join.cljs$core$IFn$_invoke$arity$2("=",p1__14998_SHARP_);
|
||||
});})(params,values,pairs))
|
||||
,pairs));
|
||||
});
|
||||
/**
|
||||
* add a browser history entry. updates window/location
|
||||
*/
|
||||
accountant.core.navigate_BANG_ = (function accountant$core$navigate_BANG_(var_args){
|
||||
var G__15000 = arguments.length;
|
||||
switch (G__15000) {
|
||||
case 1:
|
||||
return accountant.core.navigate_BANG_.cljs$core$IFn$_invoke$arity$1((arguments[(0)]));
|
||||
|
||||
break;
|
||||
case 2:
|
||||
return accountant.core.navigate_BANG_.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)]));
|
||||
|
||||
break;
|
||||
default:
|
||||
throw (new Error(["Invalid arity: ",cljs.core.str.cljs$core$IFn$_invoke$arity$1(arguments.length)].join('')));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
accountant.core.navigate_BANG_.cljs$core$IFn$_invoke$arity$1 = (function (route){
|
||||
return accountant.core.navigate_BANG_.cljs$core$IFn$_invoke$arity$2(route,cljs.core.PersistentArrayMap.EMPTY);
|
||||
});
|
||||
|
||||
accountant.core.navigate_BANG_.cljs$core$IFn$_invoke$arity$2 = (function (route,query){
|
||||
if(cljs.core.truth_(accountant.core.nav_handler)){
|
||||
var token = accountant.core.history.getToken();
|
||||
var old_route = cljs.core.first(clojure.string.split.cljs$core$IFn$_invoke$arity$2(token,"?"));
|
||||
var query_string = accountant.core.map__GT_params(cljs.core.reduce_kv(((function (token,old_route){
|
||||
return (function (valid,k,v){
|
||||
if(cljs.core.truth_(v)){
|
||||
return cljs.core.assoc.cljs$core$IFn$_invoke$arity$3(valid,k,v);
|
||||
} else {
|
||||
return valid;
|
||||
}
|
||||
});})(token,old_route))
|
||||
,cljs.core.PersistentArrayMap.EMPTY,query));
|
||||
var with_params = ((cljs.core.empty_QMARK_(query_string))?route:[cljs.core.str.cljs$core$IFn$_invoke$arity$1(route),"?",cljs.core.str.cljs$core$IFn$_invoke$arity$1(query_string)].join(''));
|
||||
if(cljs.core._EQ_.cljs$core$IFn$_invoke$arity$2(old_route,route)){
|
||||
return accountant.core.history.replaceToken(with_params);
|
||||
} else {
|
||||
return accountant.core.history.setToken(with_params);
|
||||
}
|
||||
} else {
|
||||
return console.error("can't navigate! until configure-navigation! called");
|
||||
}
|
||||
});
|
||||
|
||||
accountant.core.navigate_BANG_.cljs$lang$maxFixedArity = 2;
|
||||
|
||||
accountant.core.dispatch_current_BANG_ = (function accountant$core$dispatch_current_BANG_(){
|
||||
|
||||
var path = window.location.pathname;
|
||||
var query = window.location.search;
|
||||
var hash = window.location.hash;
|
||||
if(cljs.core.truth_(accountant.core.nav_handler)){
|
||||
var G__15002 = [cljs.core.str.cljs$core$IFn$_invoke$arity$1(path),cljs.core.str.cljs$core$IFn$_invoke$arity$1(query),cljs.core.str.cljs$core$IFn$_invoke$arity$1(hash)].join('');
|
||||
return (accountant.core.nav_handler.cljs$core$IFn$_invoke$arity$1 ? accountant.core.nav_handler.cljs$core$IFn$_invoke$arity$1(G__15002) : accountant.core.nav_handler.call(null,G__15002));
|
||||
} else {
|
||||
return console.error("can't dispatch-current until configure-navigation! called");
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user