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
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "navigation-stack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Handles navigation in a web browser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"history",
|
|
7
7
|
"browser",
|
|
8
8
|
"navigation",
|
|
9
|
-
"router"
|
|
9
|
+
"router",
|
|
10
|
+
"routing"
|
|
10
11
|
],
|
|
11
12
|
"homepage": "https://gitlab.com/catamphetamine/navigation-stack#readme",
|
|
12
13
|
"bugs": {
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
"scripts": {
|
|
25
26
|
"build": "rimraf lib && 4c build --types false src && npm run build:pick && npm run build:types",
|
|
26
27
|
"build:pick": "cherry-pick --cjs-dir cjs --esm-dir esm --cwd lib ../src",
|
|
27
|
-
"build:types": "cpy types/*.d.ts lib",
|
|
28
|
+
"build:types": "cpy types/*.d.ts lib && cpy types/data-storage/*.d.ts lib/data-storage && cpy types/scroll-position/*.d.ts lib/scroll-position && cpy types/redux/*.d.ts lib/redux",
|
|
28
29
|
"format": "4c format --prettier-ignore .eslintignore .",
|
|
29
30
|
"lint": "4c lint --prettier-ignore .eslintignore .",
|
|
30
31
|
"prepublishOnly": "npm run build",
|
|
@@ -44,7 +45,8 @@
|
|
|
44
45
|
},
|
|
45
46
|
"prettier": "@4c/prettier-config",
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"query-string": "^5.1.1"
|
|
48
|
+
"query-string": "^5.1.1",
|
|
49
|
+
"redux": "^5.0.1"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@4c/babel-preset": "^9.1.0",
|
|
@@ -65,6 +67,7 @@
|
|
|
65
67
|
"delay": "^4.4.1",
|
|
66
68
|
"dirty-chai": "^2.0.1",
|
|
67
69
|
"doctoc": "^2.2.0",
|
|
70
|
+
"dom-helpers": "^6.0.1",
|
|
68
71
|
"eslint-config-4catalyzer": "^1.4.1",
|
|
69
72
|
"eslint-config-4catalyzer-typescript": "^3.2.1",
|
|
70
73
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -84,11 +87,12 @@
|
|
|
84
87
|
"mocha": "^9.2.2",
|
|
85
88
|
"p-defer": "^3.0.0",
|
|
86
89
|
"prettier": "^2.6.2",
|
|
90
|
+
"process": "^0.11.10",
|
|
87
91
|
"puppeteer": "^13.7.0",
|
|
88
|
-
"redux": "^4.1.2",
|
|
89
92
|
"rimraf": "^3.0.2",
|
|
90
93
|
"sinon": "^11.1.2",
|
|
91
94
|
"sinon-chai": "^3.7.0",
|
|
95
|
+
"util": "^0.12.5",
|
|
92
96
|
"webpack": "^5.72.1"
|
|
93
97
|
}
|
|
94
98
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { applyMiddleware, createStore } from 'redux';
|
|
2
|
+
|
|
3
|
+
import Actions from './redux/Actions';
|
|
4
|
+
import createMiddlewares from './redux/createMiddlewares';
|
|
5
|
+
import locationReducer from './redux/locationReducer';
|
|
6
|
+
import ScrollPositionRestoration from './scroll-position/ScrollPositionRestoration';
|
|
7
|
+
|
|
8
|
+
function getCreateMiddlewaresOptions(navigationStackOptions) {
|
|
9
|
+
if (!navigationStackOptions) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
// eslint-disable-next-line no-unused-vars
|
|
13
|
+
const { maintainScrollPosition, ...restOptions } = navigationStackOptions;
|
|
14
|
+
return restOptions;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class NavigationStack {
|
|
18
|
+
constructor(session, options) {
|
|
19
|
+
this._session = session;
|
|
20
|
+
|
|
21
|
+
// Create a Redux store.
|
|
22
|
+
this._store = createStore(
|
|
23
|
+
locationReducer,
|
|
24
|
+
applyMiddleware(
|
|
25
|
+
...createMiddlewares(session, getCreateMiddlewaresOptions(options)),
|
|
26
|
+
),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Create `ScrollPositionRestoration`.
|
|
30
|
+
if (options && options.maintainScrollPosition) {
|
|
31
|
+
this._scrollPositionRestoration = new ScrollPositionRestoration(session);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
addScrollableContainer(scrollableContainerKey, scrollableContainer) {
|
|
36
|
+
if (!this._scrollPositionRestoration) {
|
|
37
|
+
throw new Error('`maintainScrollPosition: true` option not passed');
|
|
38
|
+
}
|
|
39
|
+
return this._scrollPositionRestoration.addScrollableContainer(
|
|
40
|
+
scrollableContainerKey,
|
|
41
|
+
scrollableContainer,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
subscribe(listener) {
|
|
46
|
+
// Subscribe to any potential Redux state changes.
|
|
47
|
+
return this._store.subscribe(() => {
|
|
48
|
+
// Initially, calls the listener when setting the initial location.
|
|
49
|
+
// After that, calls it on any location change.
|
|
50
|
+
const location = this.current();
|
|
51
|
+
if (!this._latestLocation || location !== this._latestLocation) {
|
|
52
|
+
this._latestLocation = location;
|
|
53
|
+
listener(location);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
init(initialLocation) {
|
|
59
|
+
if (this._latestLocation) {
|
|
60
|
+
throw new Error('Already initialized');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this._store.dispatch(Actions.init(initialLocation));
|
|
64
|
+
this._latestLocation = this.current();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
current() {
|
|
68
|
+
return this._store.getState();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
push(location) {
|
|
72
|
+
this._store.dispatch(Actions.push(location));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
replace(location) {
|
|
76
|
+
this._store.dispatch(Actions.replace(location));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
shift(delta) {
|
|
80
|
+
this._store.dispatch(Actions.shift(delta));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
stop() {
|
|
84
|
+
if (this._scrollPositionRestoration) {
|
|
85
|
+
this._scrollPositionRestoration.stop();
|
|
86
|
+
}
|
|
87
|
+
this._store.dispatch(Actions.stop());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
locationRendered() {
|
|
91
|
+
if (this._scrollPositionRestoration) {
|
|
92
|
+
const location = this.current();
|
|
93
|
+
if (!location) {
|
|
94
|
+
throw new Error('Not initialized');
|
|
95
|
+
}
|
|
96
|
+
return this._scrollPositionRestoration.locationRendered(location);
|
|
97
|
+
}
|
|
98
|
+
return Promise.resolve();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export default class DataStorage {
|
|
2
|
+
constructor(session, { namespace }) {
|
|
3
|
+
if (!session.key) {
|
|
4
|
+
throw new Error('`DataStorage` requires a `session.key`');
|
|
5
|
+
}
|
|
6
|
+
this._sessionKey = session.key;
|
|
7
|
+
this._dataStorage = session.environment.dataStorage;
|
|
8
|
+
this._namespace = namespace;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get(key) {
|
|
12
|
+
const storageKey = this._getStorageKey(key);
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const value = this._dataStorage.get(storageKey);
|
|
16
|
+
// === null is probably sufficient.
|
|
17
|
+
if (value === null) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// We want to catch JSON parse errors in case someone separately threw
|
|
22
|
+
// junk into sessionStorage under our namespace.
|
|
23
|
+
return JSON.parse(value);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
// eslint-disable-next-line no-console
|
|
26
|
+
console.error('[navigation-stack] Could not read data from storage');
|
|
27
|
+
|
|
28
|
+
// Pretend that the entry doesn't exist.
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
set(key, value) {
|
|
34
|
+
const storageKey = this._getStorageKey(key);
|
|
35
|
+
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
try {
|
|
38
|
+
this._dataStorage.remove(storageKey);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// No need to handle errors here.
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.error('[navigation-stack] Could not delete data from storage');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Unlike with read, we want to fail on invalid values here, since the
|
|
49
|
+
// value here is provided by the caller of this method.
|
|
50
|
+
const valueString = JSON.stringify(value);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
this._dataStorage.set(storageKey, valueString);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// No need to handle errors here either. If it didn't work, it didn't
|
|
56
|
+
// work. We make no guarantees about actually saving the value.
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.error('[navigation-stack] Could not save data in storage');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// It could also implement a method that would clean up any data written so far,
|
|
63
|
+
// but so far it doesn't seem to be required by any real-world use case.
|
|
64
|
+
// cleanUp() {}
|
|
65
|
+
|
|
66
|
+
_getStorageKey(key) {
|
|
67
|
+
return `${this._sessionKey}|${this.namespace}|${key}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import DataStorage from './DataStorage';
|
|
2
|
+
import getLocationUrl from '../getLocationUrl';
|
|
3
|
+
|
|
4
|
+
export default class LocationDataStorage {
|
|
5
|
+
constructor(session, { namespace }) {
|
|
6
|
+
this._storage = new DataStorage(session, { namespace });
|
|
7
|
+
|
|
8
|
+
this._getFallbackLocationKey = getLocationUrl;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get(location, key) {
|
|
12
|
+
return this._storage.get(this._getKey(location, key));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
set(location, key, value) {
|
|
16
|
+
this._storage.set(this._getKey(location, key), value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_getKey(location, key) {
|
|
20
|
+
const locationKey = location.key || this._getFallbackLocationKey(location);
|
|
21
|
+
return `${locationKey}|${key}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/debug.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import InMemoryDataStorage from './data-storage/InMemoryDataStorage';
|
|
2
|
+
import InMemoryScrollPosition from './scroll-position/InMemoryScrollPosition';
|
|
3
|
+
|
|
4
|
+
export default class InMemoryEnvironment {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.dataStorage = new InMemoryDataStorage();
|
|
7
|
+
this.scrollPosition = new InMemoryScrollPosition();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import WebBrowserDataStorage from './data-storage/WebBrowserDataStorage';
|
|
2
|
+
import WebBrowserScrollPosition from './scroll-position/WebBrowserScrollPosition';
|
|
3
|
+
|
|
4
|
+
export default class WebBrowserEnvironment {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.dataStorage = new WebBrowserDataStorage();
|
|
7
|
+
this.scrollPosition = new WebBrowserScrollPosition();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default class InMemoryDataStorage {
|
|
2
|
+
constructor() {
|
|
3
|
+
this._state = {};
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Returns either a `string` value or `null` if the key doesn't exist.
|
|
7
|
+
get(key) {
|
|
8
|
+
if (key in this._state) {
|
|
9
|
+
return this._state[key];
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
remove(key) {
|
|
15
|
+
if (key in this._state) {
|
|
16
|
+
delete this._state[key];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
set(key, value) {
|
|
21
|
+
this._state[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default class WebBrowserDataStorage {
|
|
2
|
+
// Returns either a `string` value or `null` if the key doesn't exist.
|
|
3
|
+
get(key) {
|
|
4
|
+
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
5
|
+
return window.sessionStorage.getItem(key);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
remove(key) {
|
|
9
|
+
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
10
|
+
window.sessionStorage.removeItem(key);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
set(key, value) {
|
|
14
|
+
// `sessionStorage` persists across page reloads, and so does web browser navigation history.
|
|
15
|
+
window.sessionStorage.setItem(key, value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export default class InMemoryScrollPosition {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.init();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
getPageScrollPosition() {
|
|
7
|
+
return this._pageScrollPosition || [0, 0];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
setPageScrollPosition(scrollPosition) {
|
|
11
|
+
this._pageScrollPosition = scrollPosition;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line no-unused-vars
|
|
15
|
+
setPageScrollPositionAtAnchor(anchor) {
|
|
16
|
+
this.setPageScrollPosition([0, 0]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getScrollableContainerScrollPosition(key) {
|
|
20
|
+
return this._scrollableContainerScrollPositions[key] || [0, 0];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setScrollableContainerScrollPosition(key, scrollPosition) {
|
|
24
|
+
this._scrollableContainerScrollPositions[key] = scrollPosition;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
|
28
|
+
addPageScrollListener(listener) {
|
|
29
|
+
return () => {};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line no-unused-vars
|
|
33
|
+
addScrollableContainerScrollListener(scrollableContainerElement, listener) {
|
|
34
|
+
return () => {};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
enableAutomaticScrollRestoration() {}
|
|
38
|
+
|
|
39
|
+
disableAutomaticScrollRestoration() {}
|
|
40
|
+
|
|
41
|
+
init() {
|
|
42
|
+
this._pageScrollPosition = undefined;
|
|
43
|
+
this._scrollableContainerScrollPositions = {};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export default class WebBrowserScrollPosition {
|
|
2
|
+
getPageScrollPosition() {
|
|
3
|
+
return [window.pageXOffset, window.pageYOffset];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
setPageScrollPosition(scrollPosition) {
|
|
7
|
+
const [scrollX, scrollY] = scrollPosition;
|
|
8
|
+
window.scrollTo(scrollX, scrollY);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setPageScrollPositionAtAnchor(anchor) {
|
|
12
|
+
const anchorElement =
|
|
13
|
+
document.getElementById(anchor) || document.getElementsByName(anchor)[0];
|
|
14
|
+
if (anchorElement) {
|
|
15
|
+
// By default it scrolls the element into view
|
|
16
|
+
// so that it's visible at the top of the window.
|
|
17
|
+
anchorElement.scrollIntoView();
|
|
18
|
+
} else {
|
|
19
|
+
this.setPageScrollPosition([0, 0]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getScrollableContainerScrollPosition(scrollableContainerElement) {
|
|
24
|
+
return [
|
|
25
|
+
scrollableContainerElement.scrollLeft,
|
|
26
|
+
scrollableContainerElement.scrollTop,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setScrollableContainerScrollPosition(
|
|
31
|
+
scrollableContainerElement,
|
|
32
|
+
scrollPosition,
|
|
33
|
+
) {
|
|
34
|
+
const [scrollX, scrollY] = scrollPosition;
|
|
35
|
+
scrollableContainerElement.scrollLeft = scrollX;
|
|
36
|
+
scrollableContainerElement.scrollTop = scrollY;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
addPageScrollListener(listener) {
|
|
40
|
+
// eslint-disable-next-line no-unused-vars
|
|
41
|
+
const scrollListener = (event) => {
|
|
42
|
+
listener();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
window.addEventListener('scroll', scrollListener);
|
|
46
|
+
return () => {
|
|
47
|
+
window.removeEventListener('scroll', scrollListener);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
addScrollableContainerScrollListener(scrollableContainerElement, listener) {
|
|
52
|
+
// eslint-disable-next-line no-unused-vars
|
|
53
|
+
const scrollListener = (event) => {
|
|
54
|
+
listener();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
scrollableContainerElement.addEventListener('scroll', scrollListener);
|
|
58
|
+
return () => {
|
|
59
|
+
scrollableContainerElement.removeEventListener('scroll', scrollListener);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
enableAutomaticScrollRestoration() {
|
|
64
|
+
window.history.scrollRestoration = 'auto';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
disableAutomaticScrollRestoration() {
|
|
68
|
+
window.history.scrollRestoration = 'manual';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
init() {}
|
|
72
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Converts `LocationInternal` object to a publicly-visible `Location` object.
|
|
2
|
+
// It hides non-essential properties of location such as `operation` and `delta`.
|
|
3
|
+
export default function getLocationFromInternalLocation(internalLocation) {
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
const { operation, delta, ...location } = internalLocation;
|
|
6
|
+
return location;
|
|
7
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
export Actions from './Actions';
|
|
2
|
-
export ActionTypes from './ActionTypes';
|
|
3
1
|
export { addBasePath, removeBasePath } from './basePath';
|
|
4
2
|
export addNavigationBlocker from './addNavigationBlocker';
|
|
5
3
|
export getLocationUrl from './getLocationUrl';
|
|
6
4
|
export parseLocationUrl from './parseLocationUrl';
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
export
|
|
5
|
+
export parseInputLocation from './parseInputLocation';
|
|
6
|
+
export NavigationStack from './NavigationStack';
|
|
7
|
+
export DataStorage from './data-storage/DataStorage';
|
|
8
|
+
export LocationDataStorage from './data-storage/LocationDataStorage';
|
|
9
|
+
export Session from './session/Session';
|
|
10
|
+
export InMemorySession from './session/InMemorySession';
|
|
11
|
+
export WebBrowserSession from './session/WebBrowserSession';
|
|
12
|
+
export ServerSideRenderSession from './session/ServerSideRenderSession';
|
|
13
|
+
export ServerSideNavigationError from './session/navigation/error/ServerSideNavigationError';
|
|
14
|
+
export NavigationOutOfBoundsError from './session/navigation/error/NavigationOutOfBoundsError';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-underscore-dangle */
|
|
2
2
|
|
|
3
|
+
import debug from './debug';
|
|
3
4
|
import isPromise from './isPromise';
|
|
4
5
|
|
|
5
6
|
export function getNavigationBlockers(session) {
|
|
@@ -23,15 +24,15 @@ function removeNavigationBlockerFromTheList(blocker, session) {
|
|
|
23
24
|
|
|
24
25
|
export function removeAllNavigationBlockers(session) {
|
|
25
26
|
if (
|
|
26
|
-
getNavigationBlockers(session).some((blocker) => blocker.
|
|
27
|
+
getNavigationBlockers(session).some((blocker) => blocker.beforeTermination)
|
|
27
28
|
) {
|
|
28
|
-
if (!session.
|
|
29
|
+
if (!session._removeTerminationBlocker) {
|
|
29
30
|
throw new Error(
|
|
30
|
-
'`
|
|
31
|
+
'`_removeTerminationBlocker` property not found in the `session`',
|
|
31
32
|
);
|
|
32
33
|
}
|
|
33
|
-
session.
|
|
34
|
-
session.
|
|
34
|
+
session._removeTerminationBlocker();
|
|
35
|
+
session._removeTerminationBlocker = undefined;
|
|
35
36
|
}
|
|
36
37
|
session._navigationBlockersList = [];
|
|
37
38
|
}
|
|
@@ -86,6 +87,7 @@ export function runNavigationBlockers(navigationBlockers, toLocation) {
|
|
|
86
87
|
if (isPromise(result)) {
|
|
87
88
|
return result.then((resultValue) => {
|
|
88
89
|
if (resultValue) {
|
|
90
|
+
debug('Navigation blocked', toLocation.pathname);
|
|
89
91
|
return resultValue;
|
|
90
92
|
}
|
|
91
93
|
return next();
|
|
@@ -93,40 +95,41 @@ export function runNavigationBlockers(navigationBlockers, toLocation) {
|
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
if (result) {
|
|
98
|
+
debug('Navigation blocked', toLocation.pathname);
|
|
96
99
|
return result;
|
|
97
100
|
}
|
|
98
101
|
return next();
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
/* istanbul ignore next: not testable with Karma */
|
|
102
|
-
function
|
|
105
|
+
function terminationBlocker(session) {
|
|
103
106
|
const result = runNavigationBlockers(getNavigationBlockers(session), null);
|
|
104
107
|
|
|
105
|
-
// If no blocker returned anything, don't prevent the
|
|
108
|
+
// If no blocker returned anything, so don't prevent the navigation.
|
|
106
109
|
if (!result) {
|
|
107
110
|
return undefined;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
// Web browsers don't allow displaying a custom modal in "beforeunload" phase.
|
|
111
114
|
// They only allow displaying a standard one, with the default text.
|
|
112
|
-
// Hence, "asynchronous" blockers should be ignored.
|
|
115
|
+
// Hence, "asynchronous" blockers should be ignored because web browsers won't wait for those to finish anyway.
|
|
113
116
|
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
|
114
117
|
if (isPromise(result)) {
|
|
115
118
|
return undefined;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
|
-
//
|
|
121
|
+
// Block the navigation.
|
|
119
122
|
return true;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
export function addNavigationBlocker(session, blocker) {
|
|
123
|
-
// All navigation blockers also run on `
|
|
126
|
+
// All navigation blockers also run on `beforeTermination` event.
|
|
124
127
|
// If required, this could be a parameter of this function.
|
|
125
128
|
// The rationale could be that adding a `beforeunload` listener
|
|
126
129
|
// disables web page caching in some browsers like Firefox.
|
|
127
|
-
const
|
|
130
|
+
const beforeTermination = true;
|
|
128
131
|
|
|
129
|
-
// If it's the first "
|
|
132
|
+
// If it's the first "beforeTermination" blocker, add a `terminationBlocker`.
|
|
130
133
|
//
|
|
131
134
|
// Sidenote: Add the "beforeunload" event listener only as needed, as its presence
|
|
132
135
|
// prevents the page from being added to the page navigation cache:
|
|
@@ -137,41 +140,42 @@ export function addNavigationBlocker(session, blocker) {
|
|
|
137
140
|
//
|
|
138
141
|
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
|
139
142
|
if (
|
|
140
|
-
|
|
143
|
+
beforeTermination &&
|
|
141
144
|
!getNavigationBlockers(session).some(
|
|
142
|
-
(navigationBlocker) => navigationBlocker.
|
|
145
|
+
(navigationBlocker) => navigationBlocker.beforeTermination,
|
|
143
146
|
)
|
|
144
147
|
) {
|
|
145
|
-
if (session.
|
|
148
|
+
if (session._removeTerminationBlocker) {
|
|
146
149
|
throw new Error(
|
|
147
|
-
'Unexpected `
|
|
150
|
+
'Unexpected `_removeTerminationBlocker` property found in the `session`',
|
|
148
151
|
);
|
|
149
152
|
}
|
|
150
|
-
session.
|
|
151
|
-
() =>
|
|
152
|
-
|
|
153
|
+
session._removeTerminationBlocker =
|
|
154
|
+
session.lifecycle.addTerminationBlocker(() => {
|
|
155
|
+
return terminationBlocker(session);
|
|
156
|
+
});
|
|
153
157
|
}
|
|
154
158
|
|
|
155
|
-
const newNavigationBlocker = { blocker,
|
|
159
|
+
const newNavigationBlocker = { blocker, beforeTermination };
|
|
156
160
|
addNavigationBlockerToTheList(newNavigationBlocker, session);
|
|
157
161
|
|
|
158
162
|
return () => {
|
|
159
163
|
removeNavigationBlockerFromTheList(newNavigationBlocker, session);
|
|
160
164
|
|
|
161
|
-
// If it was the last "
|
|
165
|
+
// If it was the last "beforeTermination" blocker, remove navigation blocker.
|
|
162
166
|
if (
|
|
163
|
-
|
|
167
|
+
beforeTermination &&
|
|
164
168
|
!getNavigationBlockers(session).some(
|
|
165
|
-
(navigationBlocker) => navigationBlocker.
|
|
169
|
+
(navigationBlocker) => navigationBlocker.beforeTermination,
|
|
166
170
|
)
|
|
167
171
|
) {
|
|
168
|
-
if (!session.
|
|
172
|
+
if (!session._removeTerminationBlocker) {
|
|
169
173
|
throw new Error(
|
|
170
|
-
'`
|
|
174
|
+
'`_removeTerminationBlocker` property not found in the `session`',
|
|
171
175
|
);
|
|
172
176
|
}
|
|
173
|
-
session.
|
|
174
|
-
session.
|
|
177
|
+
session._removeTerminationBlocker();
|
|
178
|
+
session._removeTerminationBlocker = undefined;
|
|
175
179
|
}
|
|
176
180
|
};
|
|
177
181
|
}
|