navigation-stack 0.3.1 → 0.5.0
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/CHANGELOG.md +12 -0
- package/README.md +611 -163
- package/data-storage/package.json +6 -0
- package/karma.conf.cjs +21 -4
- package/lib/cjs/NavigationStack.js +88 -0
- package/lib/cjs/data-storage/DataStorage.js +71 -0
- package/lib/cjs/data-storage/LocationDataStorage.js +29 -0
- package/lib/cjs/data-storage/index.js +9 -0
- package/lib/cjs/debug.js +12 -0
- package/lib/cjs/environment/InMemoryEnvironment.js +15 -0
- package/lib/cjs/environment/WebBrowserEnvironment.js +15 -0
- package/lib/cjs/environment/data-storage/InMemoryDataStorage.js +27 -0
- package/lib/cjs/environment/data-storage/WebBrowserDataStorage.js +21 -0
- package/lib/cjs/environment/scroll-position/InMemoryScrollPosition.js +44 -0
- package/lib/cjs/environment/scroll-position/WebBrowserScrollPosition.js +60 -0
- package/lib/cjs/getLocationFromInternalLocation.js +14 -0
- package/lib/cjs/index.js +20 -16
- package/lib/cjs/navigationBlockers.js +28 -23
- package/lib/cjs/{normalizeInputLocation.js → parseInputLocation.js} +25 -9
- package/lib/cjs/{ActionTypes.js → redux/ActionTypes.js} +1 -1
- package/lib/cjs/redux/ActionTypesInternal.js +8 -0
- package/lib/cjs/{Actions.js → redux/Actions.js} +5 -4
- package/lib/cjs/redux/createMiddlewares.js +60 -0
- package/lib/cjs/redux/index.js +13 -0
- package/lib/cjs/redux/internalLocationReducer.js +14 -0
- package/lib/cjs/redux/middleware/createAddInputLocationBasePathMiddleware.js +32 -0
- package/lib/cjs/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +113 -0
- package/lib/cjs/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +94 -0
- package/lib/cjs/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +30 -0
- package/lib/cjs/redux/middleware/createUpdateInternalLocationMiddleware.js +73 -0
- package/lib/cjs/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +11 -8
- package/lib/cjs/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +6 -4
- package/lib/cjs/redux/middleware/updateLocationMiddleware.js +34 -0
- package/lib/cjs/scroll-position/PageScrollPositionSetter.js +97 -0
- package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +141 -0
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +407 -0
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +87 -0
- package/lib/cjs/scroll-position/ScrollPositionSetter.js +16 -0
- package/lib/cjs/scroll-position/constants.js +5 -0
- package/lib/cjs/scroll-position/index.js +7 -0
- package/lib/cjs/scroll-position/scheduleNextTick.js +11 -0
- package/lib/cjs/session/InMemorySession.js +22 -0
- package/lib/cjs/session/ServerSideRenderSession.js +17 -0
- package/lib/cjs/session/Session.js +202 -0
- package/lib/cjs/session/WebBrowserSession.js +20 -0
- package/lib/cjs/session/key/createSessionKey.js +23 -0
- package/lib/cjs/session/lifecycle/InMemorySessionLifecycle.js +19 -0
- package/lib/cjs/session/lifecycle/WebBrowserSessionLifecycle.js +128 -0
- package/lib/cjs/session/lifecycle/page-lifecycle/PageLifecycle.js +269 -0
- package/lib/cjs/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +8 -0
- package/lib/cjs/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +33 -0
- package/lib/cjs/session/navigation/InMemoryNavigation.js +104 -0
- package/lib/cjs/session/navigation/ServerSideNavigation.js +61 -0
- package/lib/cjs/session/navigation/WebBrowserNavigation.js +221 -0
- package/lib/cjs/session/navigation/error/NavigationOutOfBoundsError.js +12 -0
- package/lib/cjs/session/navigation/error/ServerSideNavigationError.js +21 -0
- package/lib/cjs/session/navigation/operation/operations.js +11 -0
- package/lib/cjs/session/subscription/Subscription.js +81 -0
- package/lib/data-storage/index.d.ts +35 -0
- package/lib/esm/NavigationStack.js +81 -0
- package/lib/esm/data-storage/DataStorage.js +65 -0
- package/lib/esm/data-storage/LocationDataStorage.js +22 -0
- package/lib/esm/data-storage/index.js +2 -0
- package/lib/esm/debug.js +7 -0
- package/lib/esm/environment/InMemoryEnvironment.js +8 -0
- package/lib/esm/environment/WebBrowserEnvironment.js +8 -0
- package/lib/esm/environment/data-storage/InMemoryDataStorage.js +21 -0
- package/lib/esm/environment/data-storage/WebBrowserDataStorage.js +15 -0
- package/lib/esm/environment/scroll-position/InMemoryScrollPosition.js +38 -0
- package/lib/esm/environment/scroll-position/WebBrowserScrollPosition.js +54 -0
- package/lib/esm/getLocationFromInternalLocation.js +9 -0
- package/lib/esm/index.js +10 -8
- package/lib/esm/navigationBlockers.js +28 -23
- package/lib/esm/{normalizeInputLocation.js → parseInputLocation.js} +24 -8
- package/lib/esm/{ActionTypes.js → redux/ActionTypes.js} +1 -1
- package/lib/esm/redux/ActionTypesInternal.js +3 -0
- package/lib/esm/{Actions.js → redux/Actions.js} +5 -4
- package/lib/esm/redux/createMiddlewares.js +54 -0
- package/lib/esm/redux/index.js +4 -0
- package/lib/esm/redux/internalLocationReducer.js +8 -0
- package/lib/esm/redux/middleware/createAddInputLocationBasePathMiddleware.js +27 -0
- package/lib/esm/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +108 -0
- package/lib/esm/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +88 -0
- package/lib/esm/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +25 -0
- package/lib/esm/redux/middleware/createUpdateInternalLocationMiddleware.js +68 -0
- package/lib/esm/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +10 -7
- package/lib/esm/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +5 -3
- package/lib/esm/redux/middleware/updateLocationMiddleware.js +28 -0
- package/lib/esm/scroll-position/PageScrollPositionSetter.js +91 -0
- package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +134 -0
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +400 -0
- package/lib/esm/scroll-position/ScrollPositionSaver.js +80 -0
- package/lib/esm/scroll-position/ScrollPositionSetter.js +10 -0
- package/lib/esm/scroll-position/constants.js +1 -0
- package/lib/esm/scroll-position/index.js +1 -0
- package/lib/esm/scroll-position/scheduleNextTick.js +6 -0
- package/lib/esm/session/InMemorySession.js +15 -0
- package/lib/esm/session/ServerSideRenderSession.js +11 -0
- package/lib/esm/session/Session.js +195 -0
- package/lib/esm/session/WebBrowserSession.js +13 -0
- package/lib/esm/session/key/createSessionKey.js +18 -0
- package/lib/esm/session/lifecycle/InMemorySessionLifecycle.js +13 -0
- package/lib/esm/session/lifecycle/WebBrowserSessionLifecycle.js +120 -0
- package/lib/esm/session/lifecycle/page-lifecycle/PageLifecycle.js +263 -0
- package/lib/esm/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +2 -0
- package/lib/esm/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +30 -0
- package/lib/esm/session/navigation/InMemoryNavigation.js +97 -0
- package/lib/esm/session/navigation/ServerSideNavigation.js +54 -0
- package/lib/esm/session/navigation/WebBrowserNavigation.js +213 -0
- package/lib/esm/session/navigation/error/NavigationOutOfBoundsError.js +6 -0
- package/lib/esm/session/navigation/error/ServerSideNavigationError.js +14 -0
- package/lib/esm/session/navigation/operation/operations.js +6 -0
- package/lib/esm/session/subscription/Subscription.js +75 -0
- package/lib/index.d.ts +179 -157
- package/lib/redux/index.d.ts +90 -0
- package/lib/scroll-position/index.d.ts +107 -0
- package/package.json +9 -5
- package/redux/package.json +6 -0
- package/scroll-position/package.json +6 -0
- package/src/NavigationStack.js +100 -0
- package/src/data-storage/DataStorage.js +69 -0
- package/src/data-storage/LocationDataStorage.js +23 -0
- package/src/data-storage/index.js +2 -0
- package/src/debug.js +8 -0
- package/src/environment/InMemoryEnvironment.js +9 -0
- package/src/environment/WebBrowserEnvironment.js +9 -0
- package/src/environment/data-storage/InMemoryDataStorage.js +23 -0
- package/src/environment/data-storage/WebBrowserDataStorage.js +17 -0
- package/src/environment/scroll-position/InMemoryScrollPosition.js +45 -0
- package/src/environment/scroll-position/WebBrowserScrollPosition.js +72 -0
- package/src/getLocationFromInternalLocation.js +7 -0
- package/src/index.js +10 -8
- package/src/navigationBlockers.js +31 -27
- package/src/{normalizeInputLocation.js → parseInputLocation.js} +23 -8
- package/src/{ActionTypes.js → redux/ActionTypes.js} +1 -1
- package/src/redux/ActionTypesInternal.js +3 -0
- package/src/{Actions.js → redux/Actions.js} +4 -3
- package/src/redux/createMiddlewares.js +65 -0
- package/src/redux/index.js +4 -0
- package/src/redux/internalLocationReducer.js +9 -0
- package/src/redux/middleware/createAddInputLocationBasePathMiddleware.js +27 -0
- package/src/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +119 -0
- package/src/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +94 -0
- package/src/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +26 -0
- package/src/redux/middleware/createUpdateInternalLocationMiddleware.js +72 -0
- package/src/{middleware/navigationActionMiddleware.js → redux/middleware/navigationOperationMiddleware.js} +10 -3
- package/src/{middleware/normalizeInputLocationMiddleware.js → redux/middleware/parseInputLocationMiddleware.js} +5 -3
- package/src/redux/middleware/updateLocationMiddleware.js +28 -0
- package/src/scroll-position/PageScrollPositionSetter.js +110 -0
- package/src/scroll-position/ScrollPositionAutoSaver.js +168 -0
- package/src/scroll-position/ScrollPositionRestoration.js +551 -0
- package/src/scroll-position/ScrollPositionSaver.js +120 -0
- package/src/scroll-position/ScrollPositionSetter.js +16 -0
- package/src/scroll-position/constants.js +1 -0
- package/src/scroll-position/index.js +1 -0
- package/src/scroll-position/scheduleNextTick.js +6 -0
- package/src/session/InMemorySession.js +13 -0
- package/src/session/ServerSideRenderSession.js +9 -0
- package/src/session/Session.js +238 -0
- package/src/session/WebBrowserSession.js +13 -0
- package/src/session/key/createSessionKey.js +18 -0
- package/src/session/lifecycle/InMemorySessionLifecycle.js +13 -0
- package/src/session/lifecycle/WebBrowserSessionLifecycle.js +126 -0
- package/src/session/lifecycle/page-lifecycle/PageLifecycle.js +291 -0
- package/src/session/lifecycle/page-lifecycle/PageLifecycleInstance.js +3 -0
- package/src/session/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +32 -0
- package/src/session/navigation/InMemoryNavigation.js +78 -0
- package/src/session/navigation/ServerSideNavigation.js +43 -0
- package/src/session/navigation/WebBrowserNavigation.js +224 -0
- package/src/session/navigation/error/NavigationOutOfBoundsError.js +7 -0
- package/src/session/navigation/error/ServerSideNavigationError.js +18 -0
- package/src/session/navigation/operation/operations.js +6 -0
- package/src/session/subscription/Subscription.js +76 -0
- package/test/NavigationStack.test.js +296 -0
- package/test/{LocationDataStorage.test.js → data-storage/LocationDataStorage.test.js} +3 -3
- package/test/data-storage/index.test.js +8 -0
- package/test/index.js +12 -0
- package/test/index.test.js +8 -7
- package/test/{helpers.js → middlewareTestUtil.js} +9 -12
- package/test/{normalizeInputLocation.test.js → parseInputLocationMiddleware.test.js} +9 -9
- package/test/{Action.test.js → redux/Action.test.js} +7 -6
- package/test/{ActionTypes.test.js → redux/ActionTypes.test.js} +2 -2
- package/test/redux/createMiddlewares.test.js +96 -0
- package/test/redux/index.test.js +10 -0
- package/test/{locationReducer.test.js → redux/locationReducer.test.js} +4 -7
- package/test/redux/middleware/createAddInputLocationBasePathMiddleware.test.js +40 -0
- package/test/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js +264 -0
- package/test/redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js +312 -0
- package/test/redux/middleware/createRemoveOutputLocationBasePathMiddleware.test.js +51 -0
- package/test/{middleware/navigationActionMiddleware.test.js → redux/middleware/navigationOperationMiddleware.test.js} +16 -12
- package/test/{middleware/normalizeInputLocationMiddleware.test.js → redux/middleware/parseInputLocationMiddleware.test.js} +4 -4
- package/test/scroll-position/ScrollPositionRestoration.test.js +435 -0
- package/test/scroll-position/addScrollableContainer.js +39 -0
- package/test/scroll-position/addScrollableContainerWithAnchors.js +56 -0
- package/test/scroll-position/createApp.js +132 -0
- package/test/scroll-position/delay.js +9 -0
- package/test/scroll-position/mockPageLifecycle.js +17 -0
- package/test/scroll-position/runApp.js +24 -0
- package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +72 -0
- package/test/session/InMemorySession.test.js +348 -0
- package/test/session/ServerSession.test.js +17 -9
- package/test/session/WebBrowserSession.test.js +265 -0
- package/test/testUtil.js +3 -0
- package/types/data-storage/index.d.ts +35 -0
- package/types/index.d.ts +179 -157
- package/types/redux/index.d.ts +90 -0
- package/types/scroll-position/index.d.ts +107 -0
- package/types/tsconfig.json +1 -1
- package/lib/cjs/LocationDataStorage.js +0 -61
- package/lib/cjs/addBeforeLocationChangeListener.js +0 -7
- package/lib/cjs/beforeLocationChangeListeners.js +0 -51
- package/lib/cjs/createMiddlewares.js +0 -47
- package/lib/cjs/middleware/createBasePathMiddleware.js +0 -24
- package/lib/cjs/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -39
- package/lib/cjs/middleware/createLocationMiddleware.js +0 -56
- package/lib/cjs/middleware/createNavigationBlockerMiddleware.js +0 -161
- package/lib/cjs/middleware/createTransformLocationMiddleware.js +0 -38
- package/lib/cjs/onlyAllowedOnClientSide.js +0 -10
- package/lib/cjs/session/BrowserSession.js +0 -235
- package/lib/cjs/session/MemorySession.js +0 -223
- package/lib/cjs/session/ServerSession.js +0 -65
- package/lib/esm/LocationDataStorage.js +0 -54
- package/lib/esm/addBeforeLocationChangeListener.js +0 -2
- package/lib/esm/beforeLocationChangeListeners.js +0 -44
- package/lib/esm/createMiddlewares.js +0 -41
- package/lib/esm/middleware/createBasePathMiddleware.js +0 -19
- package/lib/esm/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -34
- package/lib/esm/middleware/createLocationMiddleware.js +0 -50
- package/lib/esm/middleware/createNavigationBlockerMiddleware.js +0 -156
- package/lib/esm/middleware/createTransformLocationMiddleware.js +0 -33
- package/lib/esm/onlyAllowedOnClientSide.js +0 -5
- package/lib/esm/session/BrowserSession.js +0 -229
- package/lib/esm/session/MemorySession.js +0 -217
- package/lib/esm/session/ServerSession.js +0 -58
- package/src/LocationDataStorage.js +0 -60
- package/src/addBeforeLocationChangeListener.js +0 -2
- package/src/beforeLocationChangeListeners.js +0 -54
- package/src/createMiddlewares.js +0 -45
- package/src/middleware/createBasePathMiddleware.js +0 -20
- package/src/middleware/createBeforeLocationChangeListenerMiddleware.js +0 -40
- package/src/middleware/createLocationMiddleware.js +0 -55
- package/src/middleware/createNavigationBlockerMiddleware.js +0 -168
- package/src/middleware/createTransformLocationMiddleware.js +0 -29
- package/src/onlyAllowedOnClientSide.js +0 -5
- package/src/session/BrowserSession.js +0 -235
- package/src/session/MemorySession.js +0 -219
- package/src/session/ServerSession.js +0 -67
- package/test/createMiddlewares.test.js +0 -62
- package/test/middleware/createBasePathMiddleware.test.js +0 -67
- package/test/middleware/createBeforeLocationChangeListenerMiddleware.test.js +0 -141
- package/test/middleware/createNavigationBlockerMiddleware.test.js +0 -471
- package/test/middleware/createTransformLocationMiddleware.test.js +0 -44
- package/test/session/BrowserSession.test.js +0 -182
- package/test/session/MemorySession.test.js +0 -244
- /package/lib/cjs/{locationReducer.js → redux/locationReducer.js} +0 -0
- /package/lib/esm/{locationReducer.js → redux/locationReducer.js} +0 -0
- /package/src/{locationReducer.js → redux/locationReducer.js} +0 -0
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
4
|
-
exports.default = void 0;
|
|
5
|
-
var _getLocationUrl = _interopRequireDefault(require("../getLocationUrl"));
|
|
6
|
-
var _parseQueryFromSearch = _interopRequireDefault(require("../parseQueryFromSearch"));
|
|
7
|
-
const _excluded = ["delta"];
|
|
8
|
-
/* eslint-disable max-classes-per-file */
|
|
9
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
11
|
-
const INITIAL_KEY_INDEX = -1;
|
|
12
|
-
const INITIAL_INDEX = -1;
|
|
13
|
-
const INIT_LOCATION_DELTA = 0;
|
|
14
|
-
|
|
15
|
-
// A web browser has a notion of a "navigation history".
|
|
16
|
-
// A "navigation history" exists within a given web browser's tab.
|
|
17
|
-
// The user can click "Back" or "Forward" buttons in the web browser and it will automatically load
|
|
18
|
-
// "previous" or "next" page from scratch.
|
|
19
|
-
//
|
|
20
|
-
// Later, web browsers added a `window.history` object that the application can,
|
|
21
|
-
// but isn't required to, interact with. That `window.history` object allows the application
|
|
22
|
-
// to programmatically control the URL in the address bar of the web browser, as well as
|
|
23
|
-
// the "navigation history" by programmatically adding new entries to it or reading the current entry,
|
|
24
|
-
// and it also allows the application to override the default web browser's behavior
|
|
25
|
-
// when the user clicks "Back" or "Forward" buttons in the web browser.
|
|
26
|
-
//
|
|
27
|
-
// Specifically, the `window.history` object has a method called `.pushState()` which programmatically adds
|
|
28
|
-
// a new entry in the "navigation history" and updates the URL in the address bar and also
|
|
29
|
-
// tells the web browser that starting from the entry before this new entry in the "navigation history",
|
|
30
|
-
// the application would prefer to manually handle any "Back"/"Forward" transition when the user clicks
|
|
31
|
-
// those "Back" or "Forward" buttons in the web browser, and this behavior should persist for any future
|
|
32
|
-
// "navigation history" entries programmatically added by the application via `window.history.pushState()`,
|
|
33
|
-
// and will only stop if the user navigates from the page by the means of conventional navigation,
|
|
34
|
-
// that is by clicking a standard hyperlink, at which point the current page gets "destroyed".
|
|
35
|
-
//
|
|
36
|
-
// So for manually "pushed" entries of the "navigation history", the web browser won't load those pages
|
|
37
|
-
// from scratch after a user-initiated "Back" or "Forward" transition. In fact, it won't do anything and
|
|
38
|
-
// it will just step aside and let the application itself do those transitions. The web browser will only
|
|
39
|
-
// update the URL in the address bar and that's it.
|
|
40
|
-
//
|
|
41
|
-
// This whole thing allows the application to:
|
|
42
|
-
//
|
|
43
|
-
// * Load the "previous" or "next" page much faster than when using the default "from scratch" approach
|
|
44
|
-
// because it doesn't have to destroy the current page, then send a new HTTP request to the server,
|
|
45
|
-
// then parse the HTML response and initialize a new page, re-download all those images, etc.
|
|
46
|
-
//
|
|
47
|
-
// * Optionally render a snapshotted verison of the "previous" page thereby "restoring" the "previous" page
|
|
48
|
-
// rather than reloading it from scratch, i.e. the state of the "previous" page could be fully restored.
|
|
49
|
-
//
|
|
50
|
-
class BrowserNavigation {
|
|
51
|
-
constructor() {
|
|
52
|
-
// `this._keyPrefix` exists to avoid `this._keyIndex` collision after a page refresh.
|
|
53
|
-
// After a page refresh, `this._keyIndex` is reset to `0` while the previous navigation history
|
|
54
|
-
// still exists because web browser navigation history survives a page reload.
|
|
55
|
-
this._keyPrefix = Date.now().toString(36);
|
|
56
|
-
// `this._keyIndex` is incremented every time the current location changes.
|
|
57
|
-
this._keyIndex = INITIAL_KEY_INDEX;
|
|
58
|
-
|
|
59
|
-
// `this._index` is the index of the top element in the navigation stack.
|
|
60
|
-
// I.e. it's the index of the "current" location in the navigation stack.
|
|
61
|
-
this._index = INITIAL_INDEX;
|
|
62
|
-
}
|
|
63
|
-
init() {
|
|
64
|
-
return this._createEntryFromCurrentLocation('INIT');
|
|
65
|
-
}
|
|
66
|
-
_createEntryFromCurrentLocation(action) {
|
|
67
|
-
const {
|
|
68
|
-
pathname,
|
|
69
|
-
search,
|
|
70
|
-
hash
|
|
71
|
-
} = window.location;
|
|
72
|
-
const isSettingInitialLocation = this._index === INITIAL_INDEX;
|
|
73
|
-
if (action === 'INIT' && !isSettingInitialLocation) {
|
|
74
|
-
throw Error('Browser session has already been initialized');
|
|
75
|
-
}
|
|
76
|
-
if (isSettingInitialLocation && action !== 'INIT') {
|
|
77
|
-
throw Error('Browser session must be initialized before reacting to location changes');
|
|
78
|
-
}
|
|
79
|
-
const {
|
|
80
|
-
key,
|
|
81
|
-
index,
|
|
82
|
-
delta,
|
|
83
|
-
state
|
|
84
|
-
} = isSettingInitialLocation ? this._createAdditionalPropertiesForNewLocation({
|
|
85
|
-
delta: 1,
|
|
86
|
-
state: undefined
|
|
87
|
-
}) : this._restoreAdditionalPropertiesForCurrentLocation();
|
|
88
|
-
return {
|
|
89
|
-
action,
|
|
90
|
-
pathname,
|
|
91
|
-
search,
|
|
92
|
-
query: (0, _parseQueryFromSearch.default)(search),
|
|
93
|
-
hash,
|
|
94
|
-
key,
|
|
95
|
-
index,
|
|
96
|
-
delta: isSettingInitialLocation ? INIT_LOCATION_DELTA : delta,
|
|
97
|
-
state
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Subscribes to changes in location,
|
|
102
|
-
// excluding ones that happened as a result of calling `.navigate()`.
|
|
103
|
-
subscribe(listener) {
|
|
104
|
-
const onPopState = () => {
|
|
105
|
-
listener(this._createEntryFromCurrentLocation('SHIFT'));
|
|
106
|
-
};
|
|
107
|
-
window.addEventListener('popstate', onPopState);
|
|
108
|
-
return () => {
|
|
109
|
-
window.removeEventListener('popstate', onPopState);
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
navigate(location) {
|
|
113
|
-
const {
|
|
114
|
-
action,
|
|
115
|
-
state
|
|
116
|
-
} = location;
|
|
117
|
-
if (action !== 'PUSH' && action !== 'REPLACE') {
|
|
118
|
-
throw Error(`Unrecognized browser session action: ${action}`);
|
|
119
|
-
}
|
|
120
|
-
if (this._index === INITIAL_INDEX) {
|
|
121
|
-
throw Error('Browser session must be initialized before navigation');
|
|
122
|
-
}
|
|
123
|
-
const delta = action === 'PUSH' ? 1 : 0;
|
|
124
|
-
const additionalProperties = this._createAdditionalPropertiesForNewLocation({
|
|
125
|
-
delta,
|
|
126
|
-
state
|
|
127
|
-
});
|
|
128
|
-
this._storeAdditionalPropertiesForLocation(location, additionalProperties);
|
|
129
|
-
return Object.assign({}, location, additionalProperties);
|
|
130
|
-
}
|
|
131
|
-
shift(delta) {
|
|
132
|
-
window.history.go(delta);
|
|
133
|
-
}
|
|
134
|
-
_createKeyForKeyIndex(keyIndex) {
|
|
135
|
-
return `${this._keyPrefix}.${keyIndex.toString(36)}`;
|
|
136
|
-
}
|
|
137
|
-
_createAdditionalPropertiesForNewLocation({
|
|
138
|
-
delta,
|
|
139
|
-
state
|
|
140
|
-
}) {
|
|
141
|
-
this._keyIndex++;
|
|
142
|
-
this._index += delta;
|
|
143
|
-
return {
|
|
144
|
-
key: this._createKeyForKeyIndex(this._keyIndex),
|
|
145
|
-
index: this._index,
|
|
146
|
-
delta,
|
|
147
|
-
state
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
_restoreAdditionalPropertiesForCurrentLocation() {
|
|
151
|
-
// Initial location doesn't have any `window.history.state` assigned to it
|
|
152
|
-
// because it wasn't navigated to via a `window.history.pushState()` method.
|
|
153
|
-
// Because of that, the additional properties for the initial location can't be read
|
|
154
|
-
// from `window.history.state` and have to be reconstructed manually.
|
|
155
|
-
const {
|
|
156
|
-
key,
|
|
157
|
-
index,
|
|
158
|
-
state
|
|
159
|
-
} = window.history.state || this._getAdditionalPropertiesForInitialLocation();
|
|
160
|
-
const delta = index - this._index;
|
|
161
|
-
this._index = index;
|
|
162
|
-
return {
|
|
163
|
-
key,
|
|
164
|
-
index,
|
|
165
|
-
delta,
|
|
166
|
-
state
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
_storeAdditionalPropertiesForLocation(location, additionalProperties) {
|
|
170
|
-
const url = (0, _getLocationUrl.default)(location);
|
|
171
|
-
// `delta` property is not stored in `window.history.state`
|
|
172
|
-
// because it is supposed to be recalculated every time when reading from `window.history.state`.
|
|
173
|
-
const {
|
|
174
|
-
delta
|
|
175
|
-
} = additionalProperties,
|
|
176
|
-
restProperties = _objectWithoutPropertiesLoose(additionalProperties, _excluded);
|
|
177
|
-
if (delta === 1) {
|
|
178
|
-
window.history.pushState(restProperties, null, url);
|
|
179
|
-
} else if (delta === 0) {
|
|
180
|
-
window.history.replaceState(restProperties, null, url);
|
|
181
|
-
} else {
|
|
182
|
-
throw new Error(`Unexpected \`delta\` when storing additional properties for location: ${delta}`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Initial location doesn't have any `window.history.state` assigned to it
|
|
187
|
-
// because it wasn't navigated to via a `window.history.pushState()` method.
|
|
188
|
-
// Because of that, the additional properties for the initial location can't be read
|
|
189
|
-
// from `window.history.state` and have to be reconstructed manually.
|
|
190
|
-
_getAdditionalPropertiesForInitialLocation() {
|
|
191
|
-
return {
|
|
192
|
-
key: this._createKeyForKeyIndex(INITIAL_KEY_INDEX + 1),
|
|
193
|
-
index: INITIAL_INDEX + 1,
|
|
194
|
-
delta: INIT_LOCATION_DELTA,
|
|
195
|
-
state: undefined
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
class BrowserDataStorage {
|
|
200
|
-
// Returns either a `string` value or `null` if the key doesn't exist.
|
|
201
|
-
get(key) {
|
|
202
|
-
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
203
|
-
return window.sessionStorage.getItem(key);
|
|
204
|
-
}
|
|
205
|
-
remove(key) {
|
|
206
|
-
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
207
|
-
window.sessionStorage.removeItem(key);
|
|
208
|
-
}
|
|
209
|
-
set(key, value) {
|
|
210
|
-
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
211
|
-
window.sessionStorage.setItem(key, value);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
class BrowserSession {
|
|
215
|
-
constructor() {
|
|
216
|
-
this.navigation = new BrowserNavigation();
|
|
217
|
-
this.dataStorage = new BrowserDataStorage();
|
|
218
|
-
}
|
|
219
|
-
addBeforeDestroyListener(onBeforeDestroy) {
|
|
220
|
-
const onBeforeUnload = event => {
|
|
221
|
-
if (onBeforeDestroy()) {
|
|
222
|
-
// Calling `event.preventDefault()` will cause a web browser
|
|
223
|
-
// to show a generic "Ok"/"Cancel" modal with some generic text:
|
|
224
|
-
// "Are you sure to leave the current page?".
|
|
225
|
-
event.preventDefault();
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
window.addEventListener('beforeunload', onBeforeUnload);
|
|
229
|
-
return () => {
|
|
230
|
-
window.removeEventListener('beforeunload', onBeforeUnload);
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
exports.default = BrowserSession;
|
|
235
|
-
module.exports = exports.default;
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
4
|
-
exports.default = void 0;
|
|
5
|
-
var _normalizeInputLocation = _interopRequireDefault(require("../normalizeInputLocation"));
|
|
6
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
-
/* eslint-disable max-classes-per-file */
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
10
|
-
function _loadState(load, isValidLoadedData) {
|
|
11
|
-
try {
|
|
12
|
-
const data = JSON.parse(load());
|
|
13
|
-
|
|
14
|
-
// Check that the stack and index at least seem reasonable before using
|
|
15
|
-
// them as state. This isn't foolproof, but it might prevent mistakes.
|
|
16
|
-
// Also perform a basic validation of `state`.
|
|
17
|
-
if (isValidLoadedData(data)) {
|
|
18
|
-
return data;
|
|
19
|
-
}
|
|
20
|
-
} catch (error) {} // eslint-disable-line no-empty
|
|
21
|
-
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
26
|
-
function _saveState(save, data) {
|
|
27
|
-
try {
|
|
28
|
-
save(JSON.stringify(data));
|
|
29
|
-
} catch (error) {} // eslint-disable-line no-empty
|
|
30
|
-
}
|
|
31
|
-
class MemoryNavigation {
|
|
32
|
-
constructor(initialLocation, {
|
|
33
|
-
save,
|
|
34
|
-
load
|
|
35
|
-
} = {}) {
|
|
36
|
-
this._save = save;
|
|
37
|
-
this._keyPrefix = Date.now().toString(36);
|
|
38
|
-
this._keyIndex = 0;
|
|
39
|
-
this._subscriptionListener = null;
|
|
40
|
-
const initialState = load ? _loadState(load, this._isValidLoadedData) : null;
|
|
41
|
-
if (initialState) {
|
|
42
|
-
this._stack = initialState.stack;
|
|
43
|
-
this._index = initialState.index;
|
|
44
|
-
} else {
|
|
45
|
-
this._stack = [Object.assign({}, (0, _normalizeInputLocation.default)(initialLocation), {
|
|
46
|
-
key: this._getNextKey()
|
|
47
|
-
})];
|
|
48
|
-
this._index = 0;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
_isValidLoadedData({
|
|
52
|
-
stack,
|
|
53
|
-
index
|
|
54
|
-
}) {
|
|
55
|
-
// Check that the `stack` and `index` at least seem reasonable before using them.
|
|
56
|
-
// This isn't foolproof, but it might prevent mistakes.
|
|
57
|
-
return Array.isArray(stack) && typeof index === 'number' && stack[index];
|
|
58
|
-
}
|
|
59
|
-
init() {
|
|
60
|
-
return this._createLocationObject({
|
|
61
|
-
action: 'INIT',
|
|
62
|
-
delta: 0
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
subscribe(listener) {
|
|
66
|
-
this._subscriptionListener = listener;
|
|
67
|
-
return () => {
|
|
68
|
-
this._subscriptionListener = null;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
navigate(location) {
|
|
72
|
-
const {
|
|
73
|
-
action,
|
|
74
|
-
pathname,
|
|
75
|
-
search,
|
|
76
|
-
query,
|
|
77
|
-
hash,
|
|
78
|
-
state
|
|
79
|
-
} = location;
|
|
80
|
-
if (action !== 'PUSH' && action !== 'REPLACE') {
|
|
81
|
-
throw Error(`Unrecognized browser session action: ${action}`);
|
|
82
|
-
}
|
|
83
|
-
const delta = action === 'PUSH' ? 1 : 0;
|
|
84
|
-
this._index += delta;
|
|
85
|
-
const key = this._getNextKey();
|
|
86
|
-
this._stack[this._index] = {
|
|
87
|
-
pathname,
|
|
88
|
-
search,
|
|
89
|
-
query,
|
|
90
|
-
hash,
|
|
91
|
-
state,
|
|
92
|
-
key
|
|
93
|
-
};
|
|
94
|
-
if (action === 'PUSH') {
|
|
95
|
-
this._stack.length = this._index + 1;
|
|
96
|
-
}
|
|
97
|
-
if (this._save) {
|
|
98
|
-
_saveState(this._save, {
|
|
99
|
-
stack: this._stack,
|
|
100
|
-
index: this._index
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
return Object.assign({}, location, {
|
|
104
|
-
key,
|
|
105
|
-
index: this._index,
|
|
106
|
-
delta
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
shift(delta) {
|
|
110
|
-
const prevIndex = this._index;
|
|
111
|
-
this._index = Math.min(Math.max(this._index + delta, 0), this._stack.length - 1);
|
|
112
|
-
if (this._index === prevIndex) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
if (this._save) {
|
|
116
|
-
_saveState(this._save, {
|
|
117
|
-
stack: this._stack,
|
|
118
|
-
index: this._index
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
if (this._subscriptionListener) {
|
|
122
|
-
this._subscriptionListener(this._createLocationObject({
|
|
123
|
-
action: 'SHIFT',
|
|
124
|
-
delta: this._index - prevIndex
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
_getNextKey() {
|
|
129
|
-
const key = `${this._keyPrefix}.${this._keyIndex.toString(36)}`;
|
|
130
|
-
this._keyIndex++;
|
|
131
|
-
return key;
|
|
132
|
-
}
|
|
133
|
-
_createLocationObject({
|
|
134
|
-
action,
|
|
135
|
-
delta
|
|
136
|
-
}) {
|
|
137
|
-
return Object.assign({}, this._stack[this._index], {
|
|
138
|
-
action,
|
|
139
|
-
index: this._index,
|
|
140
|
-
delta
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
class MemoryDataStorage {
|
|
145
|
-
constructor({
|
|
146
|
-
load,
|
|
147
|
-
save
|
|
148
|
-
} = {}) {
|
|
149
|
-
this._save = save;
|
|
150
|
-
const initialState = load ? _loadState(load, this._isValidLoadedData) : null;
|
|
151
|
-
if (initialState) {
|
|
152
|
-
this._state = initialState.state;
|
|
153
|
-
} else {
|
|
154
|
-
this._state = {};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Returns either a `string` value or `null` if the key doesn't exist.
|
|
159
|
-
get(key) {
|
|
160
|
-
if (key in this._state) {
|
|
161
|
-
return this._state[key];
|
|
162
|
-
}
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
remove(key) {
|
|
166
|
-
if (key in this._state) {
|
|
167
|
-
delete this._state[key];
|
|
168
|
-
}
|
|
169
|
-
if (this._save) {
|
|
170
|
-
_saveState(this._save, {
|
|
171
|
-
state: this._state
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
set(key, value) {
|
|
176
|
-
this._state[key] = value;
|
|
177
|
-
if (this._save) {
|
|
178
|
-
_saveState(this._save, {
|
|
179
|
-
state: this._state
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
_isValidLoadedData({
|
|
184
|
-
state
|
|
185
|
-
}) {
|
|
186
|
-
// Perform a basic validation of `state`.
|
|
187
|
-
return typeof state === 'object' && state !== null;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function createNestedStateSaveLoadFunctions({
|
|
191
|
-
save,
|
|
192
|
-
load
|
|
193
|
-
}, key) {
|
|
194
|
-
return {
|
|
195
|
-
save: save ? data => save(key, data) : undefined,
|
|
196
|
-
load: load ? () => load(key) : undefined
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
class MemorySession {
|
|
200
|
-
constructor(initialLocation, {
|
|
201
|
-
save,
|
|
202
|
-
load
|
|
203
|
-
} = {}) {
|
|
204
|
-
this.navigation = new MemoryNavigation(initialLocation, createNestedStateSaveLoadFunctions({
|
|
205
|
-
save,
|
|
206
|
-
load
|
|
207
|
-
}, 'navigation'));
|
|
208
|
-
this.dataStorage = new MemoryDataStorage(createNestedStateSaveLoadFunctions({
|
|
209
|
-
save,
|
|
210
|
-
load
|
|
211
|
-
}, 'dataStorage'));
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// "Before destroy" listeners are currently ignored.
|
|
215
|
-
// If required, one could implement a `_destroy()` method
|
|
216
|
-
// and there check that the listeners actually do get called.
|
|
217
|
-
// eslint-disable-next-line no-unused-vars
|
|
218
|
-
addBeforeDestroyListener(listener) {
|
|
219
|
-
return () => {};
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
exports.default = MemorySession;
|
|
223
|
-
module.exports = exports.default;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
4
|
-
exports.default = void 0;
|
|
5
|
-
var _normalizeInputLocation = _interopRequireDefault(require("../normalizeInputLocation"));
|
|
6
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
-
/* eslint-disable max-classes-per-file */
|
|
8
|
-
|
|
9
|
-
function noop() {}
|
|
10
|
-
function serverSideNavigationNotPossible() {
|
|
11
|
-
throw new Error('Server-side navigation is not possible');
|
|
12
|
-
}
|
|
13
|
-
class ServerNavigation {
|
|
14
|
-
constructor(initialLocation) {
|
|
15
|
-
this._location = (0, _normalizeInputLocation.default)(initialLocation);
|
|
16
|
-
}
|
|
17
|
-
init() {
|
|
18
|
-
return Object.assign({
|
|
19
|
-
action: 'INIT'
|
|
20
|
-
}, this._location, {
|
|
21
|
-
index: 0,
|
|
22
|
-
key: '0'
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
subscribe() {
|
|
26
|
-
// Server-side environment emits no location subscription events.
|
|
27
|
-
return noop;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Navigation methods are not implemented, because `ServerSession` instances
|
|
31
|
-
// cannot navigate.
|
|
32
|
-
navigate() {
|
|
33
|
-
serverSideNavigationNotPossible();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Navigation methods are not implemented, because `ServerSession` instances
|
|
37
|
-
// cannot navigate.
|
|
38
|
-
shift() {
|
|
39
|
-
serverSideNavigationNotPossible();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
class ServerDataStorage {
|
|
43
|
-
// It doesn't seem to make any sense to store anything on server side.
|
|
44
|
-
// Hence, state management methods are "no op" stubs.
|
|
45
|
-
get() {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
remove() {}
|
|
49
|
-
set() {}
|
|
50
|
-
}
|
|
51
|
-
class ServerSession {
|
|
52
|
-
constructor(initialLocation) {
|
|
53
|
-
this.navigation = new ServerNavigation(initialLocation);
|
|
54
|
-
this.dataStorage = new ServerDataStorage();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// "Before destroy" listeners are currently ignored.
|
|
58
|
-
// If required, one could implement a `_destroy()` method
|
|
59
|
-
// and there check that the listeners actually do get called.
|
|
60
|
-
addBeforeDestroyListener() {
|
|
61
|
-
return noop;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
exports.default = ServerSession;
|
|
65
|
-
module.exports = exports.default;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import getLocationUrl from './getLocationUrl';
|
|
2
|
-
export default class LocationDataStorage {
|
|
3
|
-
constructor(environment, {
|
|
4
|
-
namespace
|
|
5
|
-
}) {
|
|
6
|
-
this._environment = environment;
|
|
7
|
-
this._getFallbackLocationKey = getLocationUrl;
|
|
8
|
-
this._stateKeyPrefix = `${namespace}|`;
|
|
9
|
-
// this._stateKeyPrefix = namespace ? `${namespace}|` : '';
|
|
10
|
-
}
|
|
11
|
-
get(location, key) {
|
|
12
|
-
const stateKey = this._getStateKey(location, key);
|
|
13
|
-
try {
|
|
14
|
-
const value = this._environment.dataStorage.get(stateKey);
|
|
15
|
-
// === null is probably sufficient.
|
|
16
|
-
if (value === null) {
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// We want to catch JSON parse errors in case someone separately threw
|
|
21
|
-
// junk into sessionStorage under our namespace.
|
|
22
|
-
return JSON.parse(value);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
// Pretend that the entry doesn't exist.
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
set(location, key, value) {
|
|
29
|
-
const stateKey = this._getStateKey(location, key);
|
|
30
|
-
if (value === undefined) {
|
|
31
|
-
try {
|
|
32
|
-
this._environment.dataStorage.remove(stateKey);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
// No need to handle errors here.
|
|
35
|
-
}
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Unlike with read, we want to fail on invalid values here, since the
|
|
40
|
-
// value here is provided by the caller of this method.
|
|
41
|
-
const valueString = JSON.stringify(value);
|
|
42
|
-
try {
|
|
43
|
-
this._environment.dataStorage.set(stateKey, valueString);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
// No need to handle errors here either. If it didn't work, it didn't
|
|
46
|
-
// work. We make no guarantees about actually saving the value.
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
_getStateKey(location, key) {
|
|
50
|
-
const locationKey = location.key || this._getFallbackLocationKey(location);
|
|
51
|
-
const keyPrefix = `${this._stateKeyPrefix}${locationKey}`;
|
|
52
|
-
return `${keyPrefix}|${key}`;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-underscore-dangle */
|
|
2
|
-
|
|
3
|
-
export function getBeforeLocationChangeListeners(session) {
|
|
4
|
-
return session._beforeLocationChangeListenersList || [];
|
|
5
|
-
}
|
|
6
|
-
function addBeforeLocationChangeListenerToTheList(listener, session) {
|
|
7
|
-
if (!session._beforeLocationChangeListenersList) {
|
|
8
|
-
session._beforeLocationChangeListenersList = [];
|
|
9
|
-
}
|
|
10
|
-
session._beforeLocationChangeListenersList.push(listener);
|
|
11
|
-
}
|
|
12
|
-
function removeBeforeLocationChangeListenerFromTheList(listener, session) {
|
|
13
|
-
if (session._beforeLocationChangeListenersList) {
|
|
14
|
-
session._beforeLocationChangeListenersList = session._beforeLocationChangeListenersList.filter(_ => _ !== listener);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function removeAllBeforeLocationChangeListeners(session) {
|
|
18
|
-
session._beforeLocationChangeListenersList = [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Runs the `listener` while ignoring any errors that might be thrown by it.
|
|
22
|
-
function runBeforeLocationChangeListener(listener, location) {
|
|
23
|
-
try {
|
|
24
|
-
listener(location);
|
|
25
|
-
} catch (error) {
|
|
26
|
-
// eslint-disable-next-line no-console
|
|
27
|
-
console.warn(`Ignoring before location change listener \`${listener.name}\` that failed with \`${error}\`.`);
|
|
28
|
-
// eslint-disable-next-line no-console
|
|
29
|
-
console.error(error);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Runs all listeners in order.
|
|
34
|
-
export function runBeforeLocationChangeListeners(navigationListeners, toLocation) {
|
|
35
|
-
for (const listener of navigationListeners) {
|
|
36
|
-
runBeforeLocationChangeListener(listener, toLocation);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function addBeforeLocationChangeListener(session, listener) {
|
|
40
|
-
addBeforeLocationChangeListenerToTheList(listener, session);
|
|
41
|
-
return () => {
|
|
42
|
-
removeBeforeLocationChangeListenerFromTheList(listener, session);
|
|
43
|
-
};
|
|
44
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import createBasePathMiddleware from './middleware/createBasePathMiddleware';
|
|
2
|
-
import createBeforeLocationChangeListenerMiddleware from './middleware/createBeforeLocationChangeListenerMiddleware';
|
|
3
|
-
import createLocationMiddleware from './middleware/createLocationMiddleware';
|
|
4
|
-
import createNavigationBlockerMiddleware from './middleware/createNavigationBlockerMiddleware';
|
|
5
|
-
import navigationActionMiddleware from './middleware/navigationActionMiddleware';
|
|
6
|
-
import normalizeInputLocationMiddleware from './middleware/normalizeInputLocationMiddleware';
|
|
7
|
-
export default function createMiddlewares(session, options) {
|
|
8
|
-
// Allows temporarily ignoring location update events.
|
|
9
|
-
let shouldIgnoreLocationSubscriptionEvents = false;
|
|
10
|
-
const ignoreLocationSubscriptionEvents = func => {
|
|
11
|
-
shouldIgnoreLocationSubscriptionEvents = true;
|
|
12
|
-
func();
|
|
13
|
-
shouldIgnoreLocationSubscriptionEvents = false;
|
|
14
|
-
};
|
|
15
|
-
return [
|
|
16
|
-
// Validates that the action "payload" (input location) is a proper `NormalizedInputLocation`.
|
|
17
|
-
normalizeInputLocationMiddleware,
|
|
18
|
-
// Transforms a "PUSH" / "REPLACE" action into a "NAVIGATE" action.
|
|
19
|
-
navigationActionMiddleware,
|
|
20
|
-
// If a website is hosted under a certain path (`basePath`)
|
|
21
|
-
// then this middleware will automatically strip that starting segment from the `pathname` of `location`s.
|
|
22
|
-
createBasePathMiddleware(options && options.basePath),
|
|
23
|
-
// Allows blocking navigation.
|
|
24
|
-
// Handles `NAVIGATE` actions dispatched by the application itself.
|
|
25
|
-
createNavigationBlockerMiddleware(session, {
|
|
26
|
-
ignoreLocationSubscriptionEvents
|
|
27
|
-
}),
|
|
28
|
-
// This "middleware" performs the actual navigation according to the `session` being used.
|
|
29
|
-
// For example, when `BrowserSession` is used, it calls methods of the `history` object.
|
|
30
|
-
createLocationMiddleware(session, {
|
|
31
|
-
shouldIgnoreLocationSubscriptionEvents: () => shouldIgnoreLocationSubscriptionEvents
|
|
32
|
-
}),
|
|
33
|
-
// Allows blocking navigation.
|
|
34
|
-
// Handles location `UPDATE` actions dispatched in response to location update events.
|
|
35
|
-
createNavigationBlockerMiddleware(session, {
|
|
36
|
-
ignoreLocationSubscriptionEvents
|
|
37
|
-
}),
|
|
38
|
-
// Allows subscribing to upcoming location changes
|
|
39
|
-
// before those changes are applied in the `location` object in the state.
|
|
40
|
-
createBeforeLocationChangeListenerMiddleware(session)];
|
|
41
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { addBasePath, removeBasePath } from '../basePath';
|
|
2
|
-
import createTransformLocationMiddleware from './createTransformLocationMiddleware';
|
|
3
|
-
|
|
4
|
-
// Creates a "middleware" that, when a website is hosted under a certain path (`basePath`),
|
|
5
|
-
// automatically strips that starting segment from the `pathname` of `location`s.
|
|
6
|
-
export default function createBasePathMiddleware(basePath) {
|
|
7
|
-
return createTransformLocationMiddleware({
|
|
8
|
-
// Transforms input `Location`:
|
|
9
|
-
// prepends `basePath` to the URL.
|
|
10
|
-
transformInputLocation: location => {
|
|
11
|
-
return addBasePath(location, basePath);
|
|
12
|
-
},
|
|
13
|
-
// Transforms subscription `Location` object:
|
|
14
|
-
// removes `basePath` from the URL.
|
|
15
|
-
transformSubscriptionLocation: location => {
|
|
16
|
-
return removeBasePath(location, basePath);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
}
|