@ktjs/router 0.14.3 → 0.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/index.iife.js +139 -27
- package/dist/index.legacy.js +147 -34
- package/dist/index.mjs +139 -27
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -124,6 +124,10 @@ interface RouterConfig {
|
|
|
124
124
|
* Default is `true`
|
|
125
125
|
*/
|
|
126
126
|
asyncGuards?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Router mode: 'history' uses HTML5 history API, 'hash' uses URL hash. Default is 'hash'.
|
|
129
|
+
*/
|
|
130
|
+
mode?: 'history' | 'hash';
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
/**
|
|
@@ -153,6 +157,8 @@ interface Router {
|
|
|
153
157
|
|
|
154
158
|
/** Navigate forward in history */
|
|
155
159
|
forward(): void;
|
|
160
|
+
|
|
161
|
+
initCurrentRoute(): void;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
interface RouteMatch {
|
package/dist/index.iife.js
CHANGED
|
@@ -169,6 +169,8 @@ var __ktjs_router__ = (function (exports) {
|
|
|
169
169
|
const onNotFound = config.onNotFound ?? defaultHook;
|
|
170
170
|
const onError = config.onError ?? defaultHook;
|
|
171
171
|
const asyncGuards = config.asyncGuards ?? true;
|
|
172
|
+
// default to 'hash' mode
|
|
173
|
+
const mode = config.mode ?? 'hash';
|
|
172
174
|
const baseUrl = config.baseUrl ?? '';
|
|
173
175
|
// # private values
|
|
174
176
|
const routes = [];
|
|
@@ -199,29 +201,47 @@ var __ktjs_router__ = (function (exports) {
|
|
|
199
201
|
* Initialize current route from URL
|
|
200
202
|
*/
|
|
201
203
|
const initCurrentRoute = () => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
204
|
+
if (mode === 'hash') {
|
|
205
|
+
const hash = window.location.hash.slice(1); // Remove '#'
|
|
206
|
+
if (!hash) {
|
|
207
|
+
return (current = null);
|
|
208
|
+
}
|
|
209
|
+
// Parse path and query
|
|
210
|
+
const [path, queryString] = hash.split('?');
|
|
211
|
+
const normalizedPath = normalizePath(path);
|
|
212
|
+
// Match route
|
|
213
|
+
const matched = match(normalizedPath);
|
|
214
|
+
if (!matched) {
|
|
215
|
+
return (current = null);
|
|
216
|
+
}
|
|
217
|
+
// Build route context
|
|
218
|
+
return (current = {
|
|
219
|
+
path: normalizedPath,
|
|
220
|
+
name: matched.route.name,
|
|
221
|
+
params: matched.params,
|
|
222
|
+
query: queryString ? parseQuery(queryString) : {},
|
|
223
|
+
meta: matched.route.meta ?? {},
|
|
224
|
+
matched: matched.result,
|
|
225
|
+
});
|
|
205
226
|
}
|
|
206
|
-
//
|
|
207
|
-
const
|
|
227
|
+
// history mode
|
|
228
|
+
const pathWithQuery = window.location.pathname + window.location.search;
|
|
229
|
+
const [path, queryString] = pathWithQuery.split('?');
|
|
208
230
|
const normalizedPath = normalizePath(path);
|
|
209
|
-
// Match route
|
|
210
231
|
const matched = match(normalizedPath);
|
|
211
232
|
if (!matched) {
|
|
212
|
-
return null;
|
|
233
|
+
return (current = null);
|
|
213
234
|
}
|
|
214
|
-
|
|
215
|
-
return {
|
|
235
|
+
return (current = {
|
|
216
236
|
path: normalizedPath,
|
|
217
237
|
name: matched.route.name,
|
|
218
238
|
params: matched.params,
|
|
219
239
|
query: queryString ? parseQuery(queryString) : {},
|
|
220
240
|
meta: matched.route.meta ?? {},
|
|
221
241
|
matched: matched.result,
|
|
222
|
-
};
|
|
242
|
+
});
|
|
223
243
|
};
|
|
224
|
-
let current =
|
|
244
|
+
let current = null;
|
|
225
245
|
const history = current ? [current] : [];
|
|
226
246
|
// # methods
|
|
227
247
|
const executeGuardsSync = (to, from, guardLevel) => {
|
|
@@ -365,17 +385,38 @@ var __ktjs_router__ = (function (exports) {
|
|
|
365
385
|
}
|
|
366
386
|
return false;
|
|
367
387
|
}
|
|
368
|
-
// Update browser history
|
|
388
|
+
// Update browser history depending on mode
|
|
369
389
|
const url = fullPath;
|
|
370
|
-
if (
|
|
371
|
-
|
|
390
|
+
if (mode === 'history') {
|
|
391
|
+
if (replace) {
|
|
392
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
396
|
+
}
|
|
372
397
|
}
|
|
373
398
|
else {
|
|
374
|
-
|
|
399
|
+
const hashUrl = '#' + fullPath;
|
|
400
|
+
if (replace) {
|
|
401
|
+
window.location.replace(hashUrl);
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
window.location.hash = fullPath;
|
|
405
|
+
}
|
|
375
406
|
}
|
|
376
|
-
// Update current route
|
|
407
|
+
// Update current route in memory
|
|
377
408
|
current = to;
|
|
378
|
-
|
|
409
|
+
if (replace) {
|
|
410
|
+
if (history.length > 0) {
|
|
411
|
+
history[history.length - 1] = to;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
history.push(to);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
history.push(to);
|
|
419
|
+
}
|
|
379
420
|
// Render component if routerView exists
|
|
380
421
|
if (routerView && to.matched.length > 0) {
|
|
381
422
|
const route = to.matched[to.matched.length - 1];
|
|
@@ -424,14 +465,35 @@ var __ktjs_router__ = (function (exports) {
|
|
|
424
465
|
}
|
|
425
466
|
// ---- Guards passed ----
|
|
426
467
|
const url = fullPath;
|
|
427
|
-
if (
|
|
428
|
-
|
|
468
|
+
if (mode === 'history') {
|
|
469
|
+
if (replace) {
|
|
470
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
474
|
+
}
|
|
429
475
|
}
|
|
430
476
|
else {
|
|
431
|
-
|
|
477
|
+
const hashUrl = '#' + fullPath;
|
|
478
|
+
if (replace) {
|
|
479
|
+
window.location.replace(hashUrl);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
window.location.hash = fullPath;
|
|
483
|
+
}
|
|
432
484
|
}
|
|
433
485
|
current = to;
|
|
434
|
-
|
|
486
|
+
if (replace) {
|
|
487
|
+
if (history.length > 0) {
|
|
488
|
+
history[history.length - 1] = to;
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
history.push(to);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
history.push(to);
|
|
496
|
+
}
|
|
435
497
|
// Render component if routerView exists
|
|
436
498
|
if (routerView && to.matched.length > 0) {
|
|
437
499
|
const route = to.matched[to.matched.length - 1];
|
|
@@ -475,12 +537,61 @@ var __ktjs_router__ = (function (exports) {
|
|
|
475
537
|
return loc;
|
|
476
538
|
};
|
|
477
539
|
// # register events
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
540
|
+
if (mode === 'history') {
|
|
541
|
+
// Listen to browser back/forward for history mode
|
|
542
|
+
window.addEventListener('popstate', (event) => {
|
|
543
|
+
if (event.state?.path) {
|
|
544
|
+
// navigate without pushing new history entry
|
|
545
|
+
navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
// hash mode: listen to hashchange
|
|
551
|
+
window.addEventListener('hashchange', () => {
|
|
552
|
+
const hash = window.location.hash.slice(1);
|
|
553
|
+
const [path] = hash.split('?');
|
|
554
|
+
const normalizedPath = normalizePath(path);
|
|
555
|
+
if (current && current.path === normalizedPath) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
// render route for new hash without adding extra history entry
|
|
559
|
+
const matched = match(normalizedPath);
|
|
560
|
+
if (!matched) {
|
|
561
|
+
onNotFound(normalizedPath);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const queryString = window.location.hash.slice(1).split('?')[1];
|
|
565
|
+
const to = {
|
|
566
|
+
path: normalizedPath,
|
|
567
|
+
name: matched.route.name,
|
|
568
|
+
params: matched.params,
|
|
569
|
+
query: queryString ? parseQuery(queryString) : {},
|
|
570
|
+
meta: matched.route.meta ?? {},
|
|
571
|
+
matched: matched.result,
|
|
572
|
+
};
|
|
573
|
+
// apply without modifying browser history
|
|
574
|
+
current = to;
|
|
575
|
+
history.push(to);
|
|
576
|
+
if (routerView && to.matched.length > 0) {
|
|
577
|
+
const route = to.matched[to.matched.length - 1];
|
|
578
|
+
if (route.component) {
|
|
579
|
+
const element = route.component();
|
|
580
|
+
if (element instanceof Promise) {
|
|
581
|
+
element.then((el) => {
|
|
582
|
+
routerView.innerHTML = '';
|
|
583
|
+
routerView.appendChild(el);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
routerView.innerHTML = '';
|
|
588
|
+
routerView.appendChild(element);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
executeAfterHooksSync(to, history[history.length - 2] ?? null);
|
|
593
|
+
});
|
|
594
|
+
}
|
|
484
595
|
// Router instance
|
|
485
596
|
return {
|
|
486
597
|
get current() {
|
|
@@ -510,6 +621,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
510
621
|
forward() {
|
|
511
622
|
window.history.forward();
|
|
512
623
|
},
|
|
624
|
+
initCurrentRoute,
|
|
513
625
|
};
|
|
514
626
|
};
|
|
515
627
|
|
package/dist/index.legacy.js
CHANGED
|
@@ -253,14 +253,16 @@ var __ktjs_router__ = (function (exports) {
|
|
|
253
253
|
* Create a new router instance
|
|
254
254
|
*/
|
|
255
255
|
var createRouter = function (config) {
|
|
256
|
-
var _a, _b, _c, _d, _e, _f;
|
|
256
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
257
257
|
// # default configs
|
|
258
258
|
var beforeEach = (_a = config.beforeEach) !== null && _a !== void 0 ? _a : defaultHook;
|
|
259
259
|
var afterEach = (_b = config.afterEach) !== null && _b !== void 0 ? _b : defaultHook;
|
|
260
260
|
var onNotFound = (_c = config.onNotFound) !== null && _c !== void 0 ? _c : defaultHook;
|
|
261
261
|
var onError = (_d = config.onError) !== null && _d !== void 0 ? _d : defaultHook;
|
|
262
262
|
var asyncGuards = (_e = config.asyncGuards) !== null && _e !== void 0 ? _e : true;
|
|
263
|
-
|
|
263
|
+
// default to 'hash' mode
|
|
264
|
+
var mode = (_f = config.mode) !== null && _f !== void 0 ? _f : 'hash';
|
|
265
|
+
var baseUrl = (_g = config.baseUrl) !== null && _g !== void 0 ? _g : '';
|
|
264
266
|
// # private values
|
|
265
267
|
var routes = [];
|
|
266
268
|
var routerView = null;
|
|
@@ -288,35 +290,53 @@ var __ktjs_router__ = (function (exports) {
|
|
|
288
290
|
};
|
|
289
291
|
// Normalize routes with default guards
|
|
290
292
|
normalize(config.routes, '/');
|
|
291
|
-
var
|
|
293
|
+
var _h = createMatcher(routes), findByName = _h.findByName, match = _h.match;
|
|
292
294
|
/**
|
|
293
295
|
* Initialize current route from URL
|
|
294
296
|
*/
|
|
295
297
|
var initCurrentRoute = function () {
|
|
296
|
-
var _a;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
var _a, _b;
|
|
299
|
+
if (mode === 'hash') {
|
|
300
|
+
var hash = window.location.hash.slice(1); // Remove '#'
|
|
301
|
+
if (!hash) {
|
|
302
|
+
return (current = null);
|
|
303
|
+
}
|
|
304
|
+
// Parse path and query
|
|
305
|
+
var _c = hash.split('?'), path_1 = _c[0], queryString_1 = _c[1];
|
|
306
|
+
var normalizedPath_1 = normalizePath(path_1);
|
|
307
|
+
// Match route
|
|
308
|
+
var matched_1 = match(normalizedPath_1);
|
|
309
|
+
if (!matched_1) {
|
|
310
|
+
return (current = null);
|
|
311
|
+
}
|
|
312
|
+
// Build route context
|
|
313
|
+
return (current = {
|
|
314
|
+
path: normalizedPath_1,
|
|
315
|
+
name: matched_1.route.name,
|
|
316
|
+
params: matched_1.params,
|
|
317
|
+
query: queryString_1 ? parseQuery(queryString_1) : {},
|
|
318
|
+
meta: (_a = matched_1.route.meta) !== null && _a !== void 0 ? _a : {},
|
|
319
|
+
matched: matched_1.result,
|
|
320
|
+
});
|
|
300
321
|
}
|
|
301
|
-
//
|
|
302
|
-
var
|
|
322
|
+
// history mode
|
|
323
|
+
var pathWithQuery = window.location.pathname + window.location.search;
|
|
324
|
+
var _d = pathWithQuery.split('?'), path = _d[0], queryString = _d[1];
|
|
303
325
|
var normalizedPath = normalizePath(path);
|
|
304
|
-
// Match route
|
|
305
326
|
var matched = match(normalizedPath);
|
|
306
327
|
if (!matched) {
|
|
307
|
-
return null;
|
|
328
|
+
return (current = null);
|
|
308
329
|
}
|
|
309
|
-
|
|
310
|
-
return {
|
|
330
|
+
return (current = {
|
|
311
331
|
path: normalizedPath,
|
|
312
332
|
name: matched.route.name,
|
|
313
333
|
params: matched.params,
|
|
314
334
|
query: queryString ? parseQuery(queryString) : {},
|
|
315
|
-
meta: (
|
|
335
|
+
meta: (_b = matched.route.meta) !== null && _b !== void 0 ? _b : {},
|
|
316
336
|
matched: matched.result,
|
|
317
|
-
};
|
|
337
|
+
});
|
|
318
338
|
};
|
|
319
|
-
var current =
|
|
339
|
+
var current = null;
|
|
320
340
|
var history = current ? [current] : [];
|
|
321
341
|
// # methods
|
|
322
342
|
var executeGuardsSync = function (to, from, guardLevel) {
|
|
@@ -474,17 +494,38 @@ var __ktjs_router__ = (function (exports) {
|
|
|
474
494
|
}
|
|
475
495
|
return false;
|
|
476
496
|
}
|
|
477
|
-
// Update browser history
|
|
497
|
+
// Update browser history depending on mode
|
|
478
498
|
var url = fullPath;
|
|
479
|
-
if (
|
|
480
|
-
|
|
499
|
+
if (mode === 'history') {
|
|
500
|
+
if (replace) {
|
|
501
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
505
|
+
}
|
|
481
506
|
}
|
|
482
507
|
else {
|
|
483
|
-
|
|
508
|
+
var hashUrl = '#' + fullPath;
|
|
509
|
+
if (replace) {
|
|
510
|
+
window.location.replace(hashUrl);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
window.location.hash = fullPath;
|
|
514
|
+
}
|
|
484
515
|
}
|
|
485
|
-
// Update current route
|
|
516
|
+
// Update current route in memory
|
|
486
517
|
current = to;
|
|
487
|
-
|
|
518
|
+
if (replace) {
|
|
519
|
+
if (history.length > 0) {
|
|
520
|
+
history[history.length - 1] = to;
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
history.push(to);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
history.push(to);
|
|
528
|
+
}
|
|
488
529
|
// Render component if routerView exists
|
|
489
530
|
if (routerView && to.matched.length > 0) {
|
|
490
531
|
var route = to.matched[to.matched.length - 1];
|
|
@@ -517,7 +558,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
517
558
|
args_1[_i - 1] = arguments[_i];
|
|
518
559
|
}
|
|
519
560
|
return __awaiter(void 0, __spreadArray([options_1], args_1, true), void 0, function (options, redirectCount) {
|
|
520
|
-
var prep, guardLevel, replace, to, fullPath, guardResult, url, route, element, error_2;
|
|
561
|
+
var prep, guardLevel, replace, to, fullPath, guardResult, url, hashUrl, route, element, error_2;
|
|
521
562
|
var _a;
|
|
522
563
|
if (redirectCount === void 0) { redirectCount = 0; }
|
|
523
564
|
return __generator(this, function (_b) {
|
|
@@ -545,14 +586,35 @@ var __ktjs_router__ = (function (exports) {
|
|
|
545
586
|
return [2 /*return*/, false];
|
|
546
587
|
}
|
|
547
588
|
url = fullPath;
|
|
548
|
-
if (
|
|
549
|
-
|
|
589
|
+
if (mode === 'history') {
|
|
590
|
+
if (replace) {
|
|
591
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
595
|
+
}
|
|
550
596
|
}
|
|
551
597
|
else {
|
|
552
|
-
|
|
598
|
+
hashUrl = '#' + fullPath;
|
|
599
|
+
if (replace) {
|
|
600
|
+
window.location.replace(hashUrl);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
window.location.hash = fullPath;
|
|
604
|
+
}
|
|
553
605
|
}
|
|
554
606
|
current = to;
|
|
555
|
-
|
|
607
|
+
if (replace) {
|
|
608
|
+
if (history.length > 0) {
|
|
609
|
+
history[history.length - 1] = to;
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
history.push(to);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
history.push(to);
|
|
617
|
+
}
|
|
556
618
|
if (!(routerView && to.matched.length > 0)) return [3 /*break*/, 3];
|
|
557
619
|
route = to.matched[to.matched.length - 1];
|
|
558
620
|
if (!route.component) return [3 /*break*/, 3];
|
|
@@ -611,13 +673,63 @@ var __ktjs_router__ = (function (exports) {
|
|
|
611
673
|
return loc;
|
|
612
674
|
};
|
|
613
675
|
// # register events
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
676
|
+
if (mode === 'history') {
|
|
677
|
+
// Listen to browser back/forward for history mode
|
|
678
|
+
window.addEventListener('popstate', function (event) {
|
|
679
|
+
var _a;
|
|
680
|
+
if ((_a = event.state) === null || _a === void 0 ? void 0 : _a.path) {
|
|
681
|
+
// navigate without pushing new history entry
|
|
682
|
+
navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
// hash mode: listen to hashchange
|
|
688
|
+
window.addEventListener('hashchange', function () {
|
|
689
|
+
var _a, _b;
|
|
690
|
+
var hash = window.location.hash.slice(1);
|
|
691
|
+
var path = hash.split('?')[0];
|
|
692
|
+
var normalizedPath = normalizePath(path);
|
|
693
|
+
if (current && current.path === normalizedPath) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
// render route for new hash without adding extra history entry
|
|
697
|
+
var matched = match(normalizedPath);
|
|
698
|
+
if (!matched) {
|
|
699
|
+
onNotFound(normalizedPath);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
var queryString = window.location.hash.slice(1).split('?')[1];
|
|
703
|
+
var to = {
|
|
704
|
+
path: normalizedPath,
|
|
705
|
+
name: matched.route.name,
|
|
706
|
+
params: matched.params,
|
|
707
|
+
query: queryString ? parseQuery(queryString) : {},
|
|
708
|
+
meta: (_a = matched.route.meta) !== null && _a !== void 0 ? _a : {},
|
|
709
|
+
matched: matched.result,
|
|
710
|
+
};
|
|
711
|
+
// apply without modifying browser history
|
|
712
|
+
current = to;
|
|
713
|
+
history.push(to);
|
|
714
|
+
if (routerView && to.matched.length > 0) {
|
|
715
|
+
var route = to.matched[to.matched.length - 1];
|
|
716
|
+
if (route.component) {
|
|
717
|
+
var element = route.component();
|
|
718
|
+
if (element instanceof Promise) {
|
|
719
|
+
element.then(function (el) {
|
|
720
|
+
routerView.innerHTML = '';
|
|
721
|
+
routerView.appendChild(el);
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
routerView.innerHTML = '';
|
|
726
|
+
routerView.appendChild(element);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
executeAfterHooksSync(to, (_b = history[history.length - 2]) !== null && _b !== void 0 ? _b : null);
|
|
731
|
+
});
|
|
732
|
+
}
|
|
621
733
|
// Router instance
|
|
622
734
|
return {
|
|
623
735
|
get current() {
|
|
@@ -647,6 +759,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
647
759
|
forward: function () {
|
|
648
760
|
window.history.forward();
|
|
649
761
|
},
|
|
762
|
+
initCurrentRoute: initCurrentRoute,
|
|
650
763
|
};
|
|
651
764
|
};
|
|
652
765
|
|
package/dist/index.mjs
CHANGED
|
@@ -166,6 +166,8 @@ const createRouter = (config) => {
|
|
|
166
166
|
const onNotFound = config.onNotFound ?? defaultHook;
|
|
167
167
|
const onError = config.onError ?? defaultHook;
|
|
168
168
|
const asyncGuards = config.asyncGuards ?? true;
|
|
169
|
+
// default to 'hash' mode
|
|
170
|
+
const mode = config.mode ?? 'hash';
|
|
169
171
|
const baseUrl = config.baseUrl ?? '';
|
|
170
172
|
// # private values
|
|
171
173
|
const routes = [];
|
|
@@ -196,29 +198,47 @@ const createRouter = (config) => {
|
|
|
196
198
|
* Initialize current route from URL
|
|
197
199
|
*/
|
|
198
200
|
const initCurrentRoute = () => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
if (mode === 'hash') {
|
|
202
|
+
const hash = window.location.hash.slice(1); // Remove '#'
|
|
203
|
+
if (!hash) {
|
|
204
|
+
return (current = null);
|
|
205
|
+
}
|
|
206
|
+
// Parse path and query
|
|
207
|
+
const [path, queryString] = hash.split('?');
|
|
208
|
+
const normalizedPath = normalizePath(path);
|
|
209
|
+
// Match route
|
|
210
|
+
const matched = match(normalizedPath);
|
|
211
|
+
if (!matched) {
|
|
212
|
+
return (current = null);
|
|
213
|
+
}
|
|
214
|
+
// Build route context
|
|
215
|
+
return (current = {
|
|
216
|
+
path: normalizedPath,
|
|
217
|
+
name: matched.route.name,
|
|
218
|
+
params: matched.params,
|
|
219
|
+
query: queryString ? parseQuery(queryString) : {},
|
|
220
|
+
meta: matched.route.meta ?? {},
|
|
221
|
+
matched: matched.result,
|
|
222
|
+
});
|
|
202
223
|
}
|
|
203
|
-
//
|
|
204
|
-
const
|
|
224
|
+
// history mode
|
|
225
|
+
const pathWithQuery = window.location.pathname + window.location.search;
|
|
226
|
+
const [path, queryString] = pathWithQuery.split('?');
|
|
205
227
|
const normalizedPath = normalizePath(path);
|
|
206
|
-
// Match route
|
|
207
228
|
const matched = match(normalizedPath);
|
|
208
229
|
if (!matched) {
|
|
209
|
-
return null;
|
|
230
|
+
return (current = null);
|
|
210
231
|
}
|
|
211
|
-
|
|
212
|
-
return {
|
|
232
|
+
return (current = {
|
|
213
233
|
path: normalizedPath,
|
|
214
234
|
name: matched.route.name,
|
|
215
235
|
params: matched.params,
|
|
216
236
|
query: queryString ? parseQuery(queryString) : {},
|
|
217
237
|
meta: matched.route.meta ?? {},
|
|
218
238
|
matched: matched.result,
|
|
219
|
-
};
|
|
239
|
+
});
|
|
220
240
|
};
|
|
221
|
-
let current =
|
|
241
|
+
let current = null;
|
|
222
242
|
const history = current ? [current] : [];
|
|
223
243
|
// # methods
|
|
224
244
|
const executeGuardsSync = (to, from, guardLevel) => {
|
|
@@ -362,17 +382,38 @@ const createRouter = (config) => {
|
|
|
362
382
|
}
|
|
363
383
|
return false;
|
|
364
384
|
}
|
|
365
|
-
// Update browser history
|
|
385
|
+
// Update browser history depending on mode
|
|
366
386
|
const url = fullPath;
|
|
367
|
-
if (
|
|
368
|
-
|
|
387
|
+
if (mode === 'history') {
|
|
388
|
+
if (replace) {
|
|
389
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
393
|
+
}
|
|
369
394
|
}
|
|
370
395
|
else {
|
|
371
|
-
|
|
396
|
+
const hashUrl = '#' + fullPath;
|
|
397
|
+
if (replace) {
|
|
398
|
+
window.location.replace(hashUrl);
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
window.location.hash = fullPath;
|
|
402
|
+
}
|
|
372
403
|
}
|
|
373
|
-
// Update current route
|
|
404
|
+
// Update current route in memory
|
|
374
405
|
current = to;
|
|
375
|
-
|
|
406
|
+
if (replace) {
|
|
407
|
+
if (history.length > 0) {
|
|
408
|
+
history[history.length - 1] = to;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
history.push(to);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
history.push(to);
|
|
416
|
+
}
|
|
376
417
|
// Render component if routerView exists
|
|
377
418
|
if (routerView && to.matched.length > 0) {
|
|
378
419
|
const route = to.matched[to.matched.length - 1];
|
|
@@ -421,14 +462,35 @@ const createRouter = (config) => {
|
|
|
421
462
|
}
|
|
422
463
|
// ---- Guards passed ----
|
|
423
464
|
const url = fullPath;
|
|
424
|
-
if (
|
|
425
|
-
|
|
465
|
+
if (mode === 'history') {
|
|
466
|
+
if (replace) {
|
|
467
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
471
|
+
}
|
|
426
472
|
}
|
|
427
473
|
else {
|
|
428
|
-
|
|
474
|
+
const hashUrl = '#' + fullPath;
|
|
475
|
+
if (replace) {
|
|
476
|
+
window.location.replace(hashUrl);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
window.location.hash = fullPath;
|
|
480
|
+
}
|
|
429
481
|
}
|
|
430
482
|
current = to;
|
|
431
|
-
|
|
483
|
+
if (replace) {
|
|
484
|
+
if (history.length > 0) {
|
|
485
|
+
history[history.length - 1] = to;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
history.push(to);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
history.push(to);
|
|
493
|
+
}
|
|
432
494
|
// Render component if routerView exists
|
|
433
495
|
if (routerView && to.matched.length > 0) {
|
|
434
496
|
const route = to.matched[to.matched.length - 1];
|
|
@@ -472,12 +534,61 @@ const createRouter = (config) => {
|
|
|
472
534
|
return loc;
|
|
473
535
|
};
|
|
474
536
|
// # register events
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
537
|
+
if (mode === 'history') {
|
|
538
|
+
// Listen to browser back/forward for history mode
|
|
539
|
+
window.addEventListener('popstate', (event) => {
|
|
540
|
+
if (event.state?.path) {
|
|
541
|
+
// navigate without pushing new history entry
|
|
542
|
+
navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
// hash mode: listen to hashchange
|
|
548
|
+
window.addEventListener('hashchange', () => {
|
|
549
|
+
const hash = window.location.hash.slice(1);
|
|
550
|
+
const [path] = hash.split('?');
|
|
551
|
+
const normalizedPath = normalizePath(path);
|
|
552
|
+
if (current && current.path === normalizedPath) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
// render route for new hash without adding extra history entry
|
|
556
|
+
const matched = match(normalizedPath);
|
|
557
|
+
if (!matched) {
|
|
558
|
+
onNotFound(normalizedPath);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const queryString = window.location.hash.slice(1).split('?')[1];
|
|
562
|
+
const to = {
|
|
563
|
+
path: normalizedPath,
|
|
564
|
+
name: matched.route.name,
|
|
565
|
+
params: matched.params,
|
|
566
|
+
query: queryString ? parseQuery(queryString) : {},
|
|
567
|
+
meta: matched.route.meta ?? {},
|
|
568
|
+
matched: matched.result,
|
|
569
|
+
};
|
|
570
|
+
// apply without modifying browser history
|
|
571
|
+
current = to;
|
|
572
|
+
history.push(to);
|
|
573
|
+
if (routerView && to.matched.length > 0) {
|
|
574
|
+
const route = to.matched[to.matched.length - 1];
|
|
575
|
+
if (route.component) {
|
|
576
|
+
const element = route.component();
|
|
577
|
+
if (element instanceof Promise) {
|
|
578
|
+
element.then((el) => {
|
|
579
|
+
routerView.innerHTML = '';
|
|
580
|
+
routerView.appendChild(el);
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
routerView.innerHTML = '';
|
|
585
|
+
routerView.appendChild(element);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
executeAfterHooksSync(to, history[history.length - 2] ?? null);
|
|
590
|
+
});
|
|
591
|
+
}
|
|
481
592
|
// Router instance
|
|
482
593
|
return {
|
|
483
594
|
get current() {
|
|
@@ -507,6 +618,7 @@ const createRouter = (config) => {
|
|
|
507
618
|
forward() {
|
|
508
619
|
window.history.forward();
|
|
509
620
|
},
|
|
621
|
+
initCurrentRoute,
|
|
510
622
|
};
|
|
511
623
|
};
|
|
512
624
|
|