forked from lukeed/navaid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
91 lines (77 loc) · 2.23 KB
/
index.js
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
85
86
87
88
89
90
91
import convert from 'regexparam';
export default function Navaid(base, on404) {
var rgx, curr, routes=[], $={};
var fmt = $.format = function (uri) {
if (!uri) return uri;
uri = '/' + uri.replace(/^\/|\/$/g, '');
return rgx.test(uri) && uri.replace(rgx, '/');
}
base = '/' + (base || '').replace(/^\/|\/$/g, '');
rgx = base == '/' ? /^\/+/ : new RegExp('^\\' + base + '(?=\\/|$)\\/?', 'i');
$.route = function (uri, replace) {
if (uri[0] == '/' && !rgx.test(uri)) uri = base + uri;
history[(uri === curr || replace ? 'replace' : 'push') + 'State'](uri, null, uri);
}
$.on = function (pat, fn) {
(pat = convert(pat)).fn = fn;
routes.push(pat);
return $;
}
$.run = function (uri) {
var i=0, params={}, arr, obj;
if (uri = fmt(uri || location.pathname)) {
uri = uri.match(/[^\?#]*/)[0];
for (curr = uri; i < routes.length; i++) {
if (arr = (obj=routes[i]).pattern.exec(uri)) {
for (i=0; i < obj.keys.length;) {
params[obj.keys[i]] = arr[++i] || null;
}
obj.fn(params); // todo loop?
return $;
}
}
if (on404) on404(uri);
}
return $;
}
$.listen = function (u) {
wrap('push');
wrap('replace');
function run(e) {
$.run();
}
function click(e) {
var x = e.composedPath, x = e.path || x && x() || [e.target],
x = x[0].closest('a'), y = x && x.getAttribute('href');
if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.button || e.defaultPrevented) return;
if (!y || x.target || x.host !== location.host || y[0] == '#') return;
if (y[0] != '/' || rgx.test(y)) {
e.preventDefault();
$.route(y);
}
}
addEventListener('popstate', run);
addEventListener('replacestate', run);
addEventListener('pushstate', run);
addEventListener('click', click);
$.unlisten = function () {
removeEventListener('popstate', run);
removeEventListener('replacestate', run);
removeEventListener('pushstate', run);
removeEventListener('click', click);
}
return $.run(u);
}
return $;
}
function wrap(type, fn) {
if (history[type]) return;
history[type] = type;
fn = history[type += 'State'];
history[type] = function (uri) {
var ev = new Event(type.toLowerCase());
ev.uri = uri;
fn.apply(this, arguments);
return dispatchEvent(ev);
}
}