UNPKG

2.84 kBPlain TextView Raw
1/**
2@license
3Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9*/
10
11/**
12 Basic router that calls a callback whenever the location is updated.
13
14 Example:
15
16 import { installRouter } from 'pwa-helpers/router.js';
17
18 installRouter((location) => handleNavigation(location));
19
20 For example, if you're using this router in a Redux-connected component,
21 you could dispatch an action in the callback:
22
23 import { installRouter } from 'pwa-helpers/router.js';
24 import { navigate } from '../actions/app.js';
25
26 installRouter((location) => store.dispatch(navigate(location)))
27
28 If you need to force a navigation to a new location programmatically, you can
29 do so by pushing a new state using the History API, and then manually
30 calling the callback with the new location:
31
32 window.history.pushState({}, '', '/new-route');
33 handleNavigation(window.location);
34
35 Optionally, you can use the second argument to read the event that caused the
36 navigation. For example, you may want to scroll to top only after a link click.
37
38 installRouter((location, event) => {
39 // Only scroll to top on link clicks, not popstate events.
40 if (event && event.type === 'click') {
41 window.scrollTo(0, 0);
42 }
43 handleNavigation(location);
44 });
45*/
46export const installRouter = (locationUpdatedCallback: (location:Location, event: Event|null) => void) => {
47 document.body.addEventListener('click', e => {
48 if (e.defaultPrevented || e.button !== 0 ||
49 e.metaKey || e.ctrlKey || e.shiftKey) return;
50
51 const anchor = e.composedPath().filter(
52 n => (n as HTMLElement).tagName === 'A'
53 )[0] as HTMLAnchorElement | undefined;
54 if (!anchor || anchor.target ||
55 anchor.hasAttribute('download') ||
56 anchor.getAttribute('rel') === 'external') return;
57
58 const href = anchor.href;
59 if (!href || href.indexOf('mailto:') !== -1) return;
60
61 const location = window.location;
62 const origin = location.origin || location.protocol + '//' + location.host;
63 if (href.indexOf(origin) !== 0) return;
64
65 e.preventDefault();
66 if (href !== location.href) {
67 window.history.pushState({}, '', href);
68 locationUpdatedCallback(location, e);
69 }
70 });
71
72 window.addEventListener('popstate', e => locationUpdatedCallback(window.location, e));
73 locationUpdatedCallback(window.location, null /* event */);
74};