UNPKG

3.23 kBJavaScriptView Raw
1import Router from 'abstract-nested-router';
2import { writable } from 'svelte/store';
3import queryString from 'query-string';
4
5const cache = {};
6const baseTag = document.getElementsByTagName('base');
7const basePrefix = (baseTag[0] && baseTag[0].href.replace(/\/$/, '')) || '/';
8
9export const ROOT_URL = basePrefix.replace(window.location.origin, '');
10
11export const router = writable({
12 path: '/',
13 query: {},
14 params: {},
15});
16
17export const CTX_ROUTER = {};
18export const CTX_ROUTE = {};
19
20// use location.hash on embedded pages, e.g. Svelte REPL
21export let HASHCHANGE = window.location.origin === 'null';
22
23export function hashchangeEnable(value) {
24 if (typeof value === 'boolean') {
25 HASHCHANGE = !!value;
26 }
27
28 return HASHCHANGE;
29}
30
31export function fixedLocation(path, callback, doFinally) {
32 const baseUri = hashchangeEnable() ? window.location.hash.replace('#', '') : window.location.pathname;
33
34 // this will rebase anchors to avoid location changes
35 if (path.charAt() !== '/') {
36 path = baseUri + path;
37 }
38
39 const currentURL = baseUri + window.location.hash + window.location.search;
40
41 // do not change location et all...
42 if (currentURL !== path) {
43 callback(path);
44 }
45
46 // invoke final guard regardless of previous result
47 if (typeof doFinally === 'function') {
48 doFinally();
49 }
50}
51
52export function navigateTo(path, options) {
53 const {
54 reload, replace,
55 params, queryParams,
56 } = options || {};
57
58 // If path empty or no string, throws error
59 if (!path || typeof path !== 'string' || (path[0] !== '/' && path[0] !== '#')) {
60 throw new Error(`Expecting '/${path}' or '#${path}', given '${path}'`);
61 }
62
63 if (params) {
64 path = path.replace(/:([a-zA-Z][a-zA-Z0-9_-]*)/g, (_, key) => params[key]);
65 }
66
67 // rebase active URL
68 if (ROOT_URL !== '/' && path.indexOf(ROOT_URL) !== 0) {
69 path = ROOT_URL + path;
70 }
71
72 if (queryParams) {
73 const qs = queryString.stringify(queryParams);
74
75 if (qs) {
76 path += `?${qs}`;
77 }
78 }
79
80 if (hashchangeEnable()) {
81 window.location.hash = path.replace(/^#/, '');
82 return;
83 }
84
85 // If no History API support, fallbacks to URL redirect
86 if (reload || !window.history.pushState || !window.dispatchEvent) {
87 window.location.href = path;
88 return;
89 }
90
91 // If has History API support, uses it
92 fixedLocation(path, nextURL => {
93 window.history[replace ? 'replaceState' : 'pushState'](null, '', nextURL);
94 window.dispatchEvent(new Event('popstate'));
95 });
96}
97
98export function getProps(given, required) {
99 const { props: sub, ...others } = given;
100
101 // prune all declared props from this component
102 required = !Array.isArray(required)
103 ? Object.keys(required)
104 : required;
105
106 required.forEach(k => {
107 delete others[k];
108 });
109
110 return {
111 ...sub,
112 ...others,
113 };
114}
115
116export function isActive(uri, path, exact) {
117 if (!cache[[uri, path, exact]]) {
118 if (exact !== true && path.indexOf(uri) === 0) {
119 cache[[uri, path, exact]] = /^[#/?]?$/.test(path.substr(uri.length, 1));
120 } else if (uri.includes('*') || uri.includes(':')) {
121 cache[[uri, path, exact]] = Router.matches(uri, path);
122 } else {
123 cache[[uri, path, exact]] = path === uri;
124 }
125 }
126
127 return cache[[uri, path, exact]];
128}