UNPKG

9.65 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
8
9var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
10
11var _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"); } }; }();
12
13exports.addRoutes = addRoutes;
14exports.removeRoute = removeRoute;
15exports.match = match;
16exports.navigate = navigate;
17exports.navigatorFor = navigatorFor;
18exports.pathFor = pathFor;
19exports.navigateToRoute = navigateToRoute;
20exports.navigatorForRoute = navigatorForRoute;
21exports.register = register;
22exports.getLocation = getLocation;
23
24var _urlPattern = require('url-pattern');
25
26var _urlPattern2 = _interopRequireDefault(_urlPattern);
27
28function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
30var window = global.window;
31var history = global.history;
32
33var hasHistoryApi = window !== undefined && history !== undefined && typeof history.pushState === 'function';
34
35var locationChangeCallbacks = [];
36
37var routes = [];
38
39function addRoutes(newRoutes) {
40 if (!(newRoutes instanceof Array)) throw typeError(routes, 'lucid-router expects to be passed a routing array as its first parameter');
41 var _iteratorNormalCompletion = true;
42 var _didIteratorError = false;
43 var _iteratorError = undefined;
44
45 try {
46 for (var _iterator = newRoutes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
47 var route = _step.value;
48
49 if (route === null || !(route instanceof Object)) throw typeError(routes, 'lucid-router expects each route definition to be an object');
50 route.path = route.path || null;
51 route.name = route.name || null;
52 route.external = typeof route.external === 'function' ? route.external : !!route.external;
53 try {
54 route.pattern = new _urlPattern2.default(route.path);
55 } catch (err) {
56 throw typeError(route.path, 'lucid-router expects route paths to be a string or regex expression');
57 }
58 routes.push(route);
59 }
60 } catch (err) {
61 _didIteratorError = true;
62 _iteratorError = err;
63 } finally {
64 try {
65 if (!_iteratorNormalCompletion && _iterator.return) {
66 _iterator.return();
67 }
68 } finally {
69 if (_didIteratorError) {
70 throw _iteratorError;
71 }
72 }
73 }
74}
75
76function removeRoute(name) {
77 var idx = -1;
78 for (var i = 0, l = routes.length; i < l; i++) {
79 if (routes[i].name === name) {
80 idx = i;
81 break;
82 }
83 }
84 ~idx && routes.splice(idx, 1);
85}
86
87function parseQuery(query) {
88 var queryArgs = {};
89 if (query) {
90 query.split('&').filter(function (keyValStr) {
91 return !!keyValStr;
92 }).map(function (keyValStr) {
93 return keyValStr.split('=').map(function (encoded) {
94 return decodeURIComponent(encoded);
95 });
96 }).forEach(function (_ref) {
97 var _ref2 = _slicedToArray(_ref, 2);
98
99 var key = _ref2[0];
100 var val = _ref2[1];
101 return key && (queryArgs[key] = val);
102 });
103 }
104 return queryArgs;
105}
106
107function match(path) {
108 var _path$split = path.split('#');
109
110 var _path$split2 = _slicedToArray(_path$split, 2);
111
112 var pathnameAndQuery = _path$split2[0];
113 var hashAndHashQuery = _path$split2[1];
114
115 var _pathnameAndQuery$spl = pathnameAndQuery.split('?');
116
117 var _pathnameAndQuery$spl2 = _slicedToArray(_pathnameAndQuery$spl, 2);
118
119 var pathname = _pathnameAndQuery$spl2[0];
120 var search = _pathnameAndQuery$spl2[1];
121
122 var _ref3 = hashAndHashQuery ? hashAndHashQuery.split('?') : [];
123
124 var _ref4 = _slicedToArray(_ref3, 2);
125
126 var hash = _ref4[0];
127 var hashSearch = _ref4[1];
128
129 var queryState = parseQuery([search, hashSearch].join('&'));
130 var _iteratorNormalCompletion2 = true;
131 var _didIteratorError2 = false;
132 var _iteratorError2 = undefined;
133
134 try {
135 for (var _iterator2 = routes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
136 var route = _step2.value;
137
138 var matchState = route.pattern.match(pathname);
139 if (!matchState) continue;
140 return {
141 route: route,
142 pathname: pathname,
143 search: search ? '?'.concat(search) : '',
144 hash: hash ? '#'.concat(hash) : '',
145 hashSearch: hashSearch ? '?'.concat(hashSearch) : '',
146 state: _extends({}, queryState, matchState)
147 };
148 }
149 } catch (err) {
150 _didIteratorError2 = true;
151 _iteratorError2 = err;
152 } finally {
153 try {
154 if (!_iteratorNormalCompletion2 && _iterator2.return) {
155 _iterator2.return();
156 }
157 } finally {
158 if (_didIteratorError2) {
159 throw _iteratorError2;
160 }
161 }
162 }
163
164 return null;
165}
166
167function navigate(path, e, replace) {
168 path = getFullPath(path);
169 if (hasHistoryApi) {
170 if (typeof path !== 'string' || !path) throw typeError(path, 'lucid-router.navigate expected a non empty string as its first parameter');
171 var m = match(path);
172 if (m && notExternal(m)) {
173 var location = matchAndPathToLocation(m, path);
174 if (replace) {
175 history.replaceState(null, '', path);
176 } else {
177 history.pushState(null, '', path);
178 }
179
180 if (e && e.preventDefault) {
181 e.preventDefault();
182 }
183
184 onLocationChange(location);
185 return;
186 }
187 }
188
189 if (window && (!e || !e.target)) {
190 window.location = path;
191 }
192}
193
194function navigatorFor(path, replace) {
195 return function (e) {
196 return navigate(path, e, replace);
197 };
198}
199
200function pathFor(routeName, params) {
201 var _iteratorNormalCompletion3 = true;
202 var _didIteratorError3 = false;
203 var _iteratorError3 = undefined;
204
205 try {
206 for (var _iterator3 = routes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
207 var route = _step3.value;
208
209 if (route.name === routeName) {
210 return route.pattern.stringify(params);
211 }
212 }
213 } catch (err) {
214 _didIteratorError3 = true;
215 _iteratorError3 = err;
216 } finally {
217 try {
218 if (!_iteratorNormalCompletion3 && _iterator3.return) {
219 _iterator3.return();
220 }
221 } finally {
222 if (_didIteratorError3) {
223 throw _iteratorError3;
224 }
225 }
226 }
227
228 throw new Error('lucid-router.pathFor failed to find a route with the name \'' + routeName + '\'');
229}
230
231function navigateToRoute(routeName, params, e) {
232 navigate(pathFor(routeName, params), e);
233}
234
235function navigatorForRoute(routeName, params) {
236 return function (e) {
237 return navigateToRoute(routeName, params, e);
238 };
239}
240
241function register(callback) {
242 if (typeof callback !== 'function') throw typeError(callback, 'lucid-router.register expects to be passed a callback function');
243 locationChangeCallbacks.push(callback);
244 return function unregister() {
245 var idx = locationChangeCallbacks.indexOf(callback);
246 ~idx && locationChangeCallbacks.splice(idx, 1);
247 };
248}
249
250function onLocationChange(location) {
251 locationChangeCallbacks.forEach(function (cb) {
252 return cb(location);
253 });
254}
255
256function getFullPath(path) {
257 if (window) {
258 var a = window.document.createElement('a');
259 a.href = path;
260 if (!a.host) a.href = a.href; /* IE hack */
261 if (a.hostname === window.location.hostname) {
262 path = a.pathname + a.search + a.hash;
263 if (path[0] !== '/') {
264 /* more IE hacks */
265 path = '/' + path;
266 }
267 } else {
268 path = a.href;
269 }
270 }
271 return path;
272}
273
274function getWindowPathAndQuery() {
275 var location = window.location;
276
277 if (!location) return null;
278 return location.pathname + location.search + location.hash;
279}
280
281function getLocation(path) {
282 path = path || getWindowPathAndQuery() || '';
283 var m = match(path);
284 var location = matchAndPathToLocation(m, path);
285 onLocationChange(location);
286 return location;
287}
288
289function matchAndPathToLocation(m, p) {
290 return !m ? null : {
291 path: p,
292 name: m.route.name,
293 pathname: m.pathname,
294 search: m.search,
295 hash: m.hash,
296 hashSearch: m.hashSearch,
297 state: m.state
298 };
299}
300
301function notExternal(m) {
302 var external = m.route.external;
303
304 if (typeof external === 'function') {
305 return !external(m);
306 } else return !external;
307}
308
309if (hasHistoryApi && window) {
310 window.addEventListener('popstate', function (e) {
311 var path = getWindowPathAndQuery() || '';
312 var m = match(path);
313 if (m && notExternal(m)) {
314 var location = matchAndPathToLocation(m, path);
315 onLocationChange(location);
316 }
317 }, false);
318}
319
320function typeError(type, msg) {
321 return new TypeError(msg + ' but got type `' + (typeof type === 'undefined' ? 'undefined' : _typeof(type)) + '`!');
322}