-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathnavaid-hash.js
91 lines (76 loc) · 2.19 KB
/
navaid-hash.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 NavaidHash(base, on404) {
var rgx, 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[(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.hash.replace(/^#/, '') || '/')) {
uri = uri.match(/[^\?#]*/)[0];
for (; 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 (uri && on404) on404(uri);
}
return $;
}
$.listen = function () {
wrap('push');
wrap('replace');
function run(e) {
$.run();
}
function click(e) {
var x = e.target.closest('a'), y = x && x.getAttribute('href').replace(/^#/, '');
if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.button || e.defaultPrevented) return;
if (!y || x.target || x.host !== location.host) 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();
}
return $;
}
NavaidHash.prefix = '#';
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());
fn.apply(this, arguments);
return dispatchEvent(ev);
}
}