UNPKG

3.1 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) {
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
47export function navigateTo(path, options) {
48 const {
49 reload, replace,
50 params, queryParams,
51 } = options || {};
52
53 // If path empty or no string, throws error
54 if (!path || typeof path !== 'string' || (path[0] !== '/' && path[0] !== '#')) {
55 throw new Error(`Expecting '/${path}' or '#${path}', given '${path}'`);
56 }
57
58 if (params) {
59 path = path.replace(/:([a-zA-Z][a-zA-Z0-9_-]*)/g, (_, key) => params[key]);
60 }
61
62 // rebase active URL
63 if (ROOT_URL !== '/' && path.indexOf(ROOT_URL) !== 0) {
64 path = ROOT_URL + path;
65 }
66
67 if (queryParams) {
68 const qs = queryString.stringify(queryParams);
69
70 if (qs) {
71 path += `?${qs}`;
72 }
73 }
74
75 if (hashchangeEnable()) {
76 window.location.hash = path.replace(/^#/, '');
77 return;
78 }
79
80 // If no History API support, fallbacks to URL redirect
81 if (reload || !window.history.pushState || !window.dispatchEvent) {
82 window.location.href = path;
83 return;
84 }
85
86 // If has History API support, uses it
87 fixedLocation(path, nextURL => {
88 window.history[replace ? 'replaceState' : 'pushState'](null, '', nextURL);
89 window.dispatchEvent(new Event('popstate'));
90 });
91}
92
93export function getProps(given, required) {
94 const { props: sub, ...others } = given;
95
96 // prune all declared props from this component
97 required = !Array.isArray(required)
98 ? Object.keys(required)
99 : required;
100
101 required.forEach(k => {
102 delete others[k];
103 });
104
105 return {
106 ...sub,
107 ...others,
108 };
109}
110
111export function isActive(uri, path, exact) {
112 if (!cache[[uri, path, exact]]) {
113 if (exact !== true && path.indexOf(uri) === 0) {
114 cache[[uri, path, exact]] = /^[#/?]?$/.test(path.substr(uri.length, 1));
115 } else if (uri.includes('*') || uri.includes(':')) {
116 cache[[uri, path, exact]] = Router.matches(uri, path);
117 } else {
118 cache[[uri, path, exact]] = path === uri;
119 }
120 }
121
122 return cache[[uri, path, exact]];
123}