UNPKG

7.07 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6
7var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
8
9exports.addRoutes = addRoutes;
10exports.removeRoute = removeRoute;
11exports.match = match;
12exports.navigate = navigate;
13exports.navigatorFor = navigatorFor;
14exports.register = register;
15exports.getLocation = getLocation;
16
17function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18
19var _urlPattern = require('url-pattern');
20
21var _urlPattern2 = _interopRequireDefault(_urlPattern);
22
23var window = global.window;
24var history = global.history;
25
26var hasHistoryApi = window !== undefined && history !== undefined && typeof history.pushState === 'function';
27
28var locationChangeCallbacks = [];
29
30var onLocationChange = function onLocationChange(location) {
31 return locationChangeCallbacks.forEach(function (cb) {
32 return cb(location);
33 });
34};
35
36var routes = [];
37
38function addRoutes(newRoutes) {
39 if (!(routes instanceof Array)) throw typeError(routes, 'lucid-router expects to be passed a routing array as its first parameter');
40 for (var routeIdx in newRoutes) {
41 var route = newRoutes[routeIdx];
42 if (!(route instanceof Object)) throw typeError(routes, 'lucid-router expects each route definition to be an object');
43 route.path = route.path || null;
44 route.name = route.name || null;
45 route.external = typeof route.external === 'function' ? route.external : !!route.external;
46 try {
47 route.pattern = new _urlPattern2['default'](route.path);
48 } catch (err) {
49 throw typeError(route.path, 'lucid-router expects route paths to be a string or regex expression');
50 }
51 routes.push(route);
52 }
53}
54
55function removeRoute(name) {
56 if (!name) return;
57 var idx = -1;
58 for (var routeIdx in routes) {
59 if (routes[routeIdx].name === name) {
60 idx = routeIdx;
61 break;
62 }
63 }
64 ~idx && routes.splice(idx, 1);
65}
66
67function parseQuery(query) {
68 var queryArgs = {};
69 if (query) {
70 query.split('&').filter(function (keyValStr) {
71 return !!keyValStr;
72 }).map(function (keyValStr) {
73 return keyValStr.split('=').map(function (encoded) {
74 return decodeURIComponent(encoded);
75 });
76 }).forEach(function (_ref) {
77 var _ref2 = _slicedToArray(_ref, 2);
78
79 var key = _ref2[0];
80 var val = _ref2[1];
81 return key && (queryArgs[key] = val);
82 });
83 }
84 return queryArgs;
85}
86
87function match(path) {
88 var _path$split = path.split('#');
89
90 var _path$split2 = _slicedToArray(_path$split, 2);
91
92 var pathnameAndQuery = _path$split2[0];
93 var hashAndHashQuery = _path$split2[1];
94
95 var _pathnameAndQuery$split = pathnameAndQuery.split('?');
96
97 var _pathnameAndQuery$split2 = _slicedToArray(_pathnameAndQuery$split, 2);
98
99 var pathname = _pathnameAndQuery$split2[0];
100 var search = _pathnameAndQuery$split2[1];
101
102 var _ref3 = hashAndHashQuery ? hashAndHashQuery.split('?') : [];
103
104 var _ref32 = _slicedToArray(_ref3, 2);
105
106 var hash = _ref32[0];
107 var hashSearch = _ref32[1];
108
109 var state = parseQuery([search, hashSearch].join('&'));
110
111 var _loop = function (routeIdx) {
112 var route = routes[routeIdx];
113 var m = route.pattern.match(pathname);
114 if (!m) return 'continue';
115 Object.keys(m).forEach(function (key) {
116 return state[key] = m[key];
117 });
118 return {
119 v: {
120 route: route,
121 pathname: pathname,
122 search: search ? '?'.concat(search) : '',
123 hash: hash ? '#'.concat(hash) : '',
124 hashSearch: hashSearch ? '?'.concat(hashSearch) : '',
125 state: state }
126 };
127 };
128
129 for (var routeIdx in routes) {
130 var _ret = _loop(routeIdx);
131
132 switch (_ret) {
133 case 'continue':
134 continue;
135
136 default:
137 if (typeof _ret === 'object') return _ret.v;
138 }
139 }
140 return null;
141}
142
143function navigate(path, e, replace) {
144 if (e && e.defaultPrevented) return;
145 if (e && e.preventDefault && e.stopPropagation) {
146 e.preventDefault();
147 e.stopPropagation();
148 }
149 path = getFullPath(path);
150 if (hasHistoryApi) {
151 if (typeof path !== 'string' || !path) throw typeError(path, 'lucid-router.navigate expected a non empty string as its first parameter');
152 var m = match(path);
153 if (m && notExternal(m)) {
154 var _location = matchAndPathToLocation(m, path);
155 if (replace) {
156 history.replaceState(null, '', path);
157 } else {
158 history.pushState(null, '', path);
159 }
160 onLocationChange(_location);
161 return;
162 }
163 }
164 if (window) {
165 window.location = path;
166 }
167}
168
169function navigatorFor(path, replace) {
170 return function (e) {
171 return navigate(path, e, replace);
172 };
173}
174
175function register(callback) {
176 if (typeof callback !== 'function') throw typeError(callback, 'lucid-router.register expects to be passed a callback function');
177 locationChangeCallbacks.push(callback);
178 return function unregister() {
179 var idx = locationChangeCallbacks.indexOf(callback);
180 ~idx && locationChangeCallbacks.splice(idx, 1);
181 };
182}
183
184function getFullPath(path) {
185 if (window) {
186 var a = window.document.createElement('a');
187 a.href = path;
188 if (!a.host) a.href = a.href; /* IE hack */
189 if (a.hostname === window.location.hostname) {
190 path = a.pathname + a.search + a.hash;
191 } else {
192 path = a.href;
193 }
194 }
195 return path;
196}
197
198function getWindowPathAndQuery() {
199 var location = window.location;
200
201 if (!location) return null;
202 return location.pathname + location.search + location.hash;
203}
204
205function getLocation(path) {
206 path = path || getWindowPathAndQuery();
207 var m = match(path);
208 var location = matchAndPathToLocation(m, path);
209 onLocationChange(location);
210 return location;
211}
212
213function matchAndPathToLocation(m, p) {
214 return !m ? null : {
215 path: p,
216 name: m.route.name,
217 pathname: m.pathname,
218 search: m.search,
219 hash: m.hash,
220 hashSearch: m.hashSearch,
221 state: m.state
222 };
223}
224
225function notExternal(m) {
226 var external = m.route.external;
227
228 if (typeof external === 'function') {
229 return !external(m);
230 } else return !external;
231}
232
233if (hasHistoryApi && window) {
234 window.addEventListener('popstate', function (e) {
235 var path = getWindowPathAndQuery();
236 var m = match(path);
237 if (m && notExternal(m)) {
238 var _location2 = matchAndPathToLocation(m, path);
239 onLocationChange(_location2);
240 return;
241 }
242 }, false);
243}
244
245function typeError(type, msg) {
246 return new TypeError(msg + ' but got type `' + typeof type + '`!');
247}