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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
|
|
3
|
+
import scheduleNextTick from './scheduleNextTick';
|
|
4
|
+
|
|
5
|
+
// The original author of `scroll-behavior` package wrote:
|
|
6
|
+
//
|
|
7
|
+
// "Updating the window scroll position is really flaky.
|
|
8
|
+
// Just trying to scroll it isn't enough.
|
|
9
|
+
// Instead, try to scroll a few times until it works."
|
|
10
|
+
//
|
|
11
|
+
// What it does here is it scrolls two times:
|
|
12
|
+
// * First time at the moment of calling the `.set()` method.
|
|
13
|
+
// * Second time after a momentary delay.
|
|
14
|
+
//
|
|
15
|
+
export default class PageScrollPositionSetter {
|
|
16
|
+
// Sets page scroll position either at an "anchor" or at given coordinates.
|
|
17
|
+
_setPageScrollPositionTo(scrollPositionOrAnchor, environmentScrollPosition) {
|
|
18
|
+
if (typeof scrollPositionOrAnchor === 'string') {
|
|
19
|
+
// Scrolls page to an "ahcnor".
|
|
20
|
+
environmentScrollPosition.setPageScrollPositionAtAnchor(
|
|
21
|
+
scrollPositionOrAnchor,
|
|
22
|
+
);
|
|
23
|
+
} else {
|
|
24
|
+
// Scrolls page to given coordinates.
|
|
25
|
+
environmentScrollPosition.setPageScrollPosition(scrollPositionOrAnchor);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_setPageScrollPosition(environmentScrollPosition) {
|
|
30
|
+
const isDelayedCall = Boolean(this._cancelDelayedSetPageScrollPosition);
|
|
31
|
+
|
|
32
|
+
// If this function was triggered in a delayed fashion,
|
|
33
|
+
// clear the reference to the "cancel" function because it's no longer of use.
|
|
34
|
+
if (isDelayedCall) {
|
|
35
|
+
this._cancelDelayedSetPageScrollPosition = null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// It's not really possible for `this._pageScrollPositionOrAnchorToSet` to be `null` or `undefined` at this point.
|
|
39
|
+
// Still, this `if` condition acts as a "foolproof" redundant check.
|
|
40
|
+
/* istanbul ignore if: paranoid guard */
|
|
41
|
+
if (!this._pageScrollPositionOrAnchorToSet) {
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The original author of `scroll-behavior` package wrote:
|
|
46
|
+
//
|
|
47
|
+
// "Updating the window scroll position is really flaky.
|
|
48
|
+
// Just trying to scroll it isn't enough.
|
|
49
|
+
// Instead, try to scroll a few times until it works."
|
|
50
|
+
//
|
|
51
|
+
this._setPageScrollPositionTo(
|
|
52
|
+
this._pageScrollPositionOrAnchorToSet,
|
|
53
|
+
environmentScrollPosition,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// If it was a delayed call, stop.
|
|
57
|
+
if (isDelayedCall) {
|
|
58
|
+
this._resetScrollPositionOrAnchorToSet();
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Repeat the attempt to set scroll position after a momentary delay.
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
this._cancelDelayedSetPageScrollPosition = scheduleNextTick(() =>
|
|
65
|
+
resolve(this._setPageScrollPosition(environmentScrollPosition)),
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Sets scroll position at an anchor or at given coordinates.
|
|
71
|
+
set(
|
|
72
|
+
scrollableContainer,
|
|
73
|
+
pageScrollPositionOrAnchor,
|
|
74
|
+
environmentScrollPosition,
|
|
75
|
+
) {
|
|
76
|
+
// Prevents empty string anchor.
|
|
77
|
+
if (!pageScrollPositionOrAnchor) {
|
|
78
|
+
throw new Error('Argument is required');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Validate that no `scrollableContainer` is passed.
|
|
82
|
+
if (scrollableContainer) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
'`scrollableContainer` argument should not be provided because `PageScrollPositionSetter` was only designed to set scroll position of a page',
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.cancel();
|
|
89
|
+
|
|
90
|
+
this._pageScrollPositionOrAnchorToSet = pageScrollPositionOrAnchor;
|
|
91
|
+
|
|
92
|
+
return this._setPageScrollPosition(environmentScrollPosition);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// This function should be "idempotent", i.e. be able to be called multiple times.
|
|
96
|
+
cancel() {
|
|
97
|
+
if (this._pageScrollPositionOrAnchorToSet) {
|
|
98
|
+
this._resetScrollPositionOrAnchorToSet();
|
|
99
|
+
|
|
100
|
+
if (this._cancelDelayedSetPageScrollPosition) {
|
|
101
|
+
this._cancelDelayedSetPageScrollPosition();
|
|
102
|
+
this._cancelDelayedSetPageScrollPosition = undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_resetScrollPositionOrAnchorToSet() {
|
|
108
|
+
this._pageScrollPositionOrAnchorToSet = undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
|
|
3
|
+
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
4
|
+
import scheduleNextTick from './scheduleNextTick';
|
|
5
|
+
import debug from '../debug';
|
|
6
|
+
|
|
7
|
+
export default class ScrollPositionAutoSaver {
|
|
8
|
+
constructor({
|
|
9
|
+
scrollPosition,
|
|
10
|
+
scrollPositionSaver,
|
|
11
|
+
getScrollableContainers,
|
|
12
|
+
shouldSaveScrollPosition,
|
|
13
|
+
}) {
|
|
14
|
+
this._scrollPosition = scrollPosition;
|
|
15
|
+
this._scrollPositionSaver = scrollPositionSaver;
|
|
16
|
+
this._shouldSaveScrollPosition = shouldSaveScrollPosition;
|
|
17
|
+
|
|
18
|
+
this._getScrollableContainers = getScrollableContainers;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Starts auto-saving of scroll positions.
|
|
22
|
+
start() {
|
|
23
|
+
// Get scrollable containers.
|
|
24
|
+
const scrollableContainers = this._getScrollableContainers();
|
|
25
|
+
|
|
26
|
+
// Set up scroll listeners on scrollable containers.
|
|
27
|
+
for (const scrollableContainerKey of Object.keys(scrollableContainers)) {
|
|
28
|
+
if (scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
29
|
+
this.addPageScrollListener();
|
|
30
|
+
} else {
|
|
31
|
+
this.addScrollableContainerScrollListener(scrollableContainerKey);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Stops auto-saving of scroll positions.
|
|
37
|
+
stop() {
|
|
38
|
+
// Get scrollable containers.
|
|
39
|
+
const scrollableContainers = this._getScrollableContainers();
|
|
40
|
+
|
|
41
|
+
// Remove scroll listeners on scrollable containers.
|
|
42
|
+
for (const scrollableContainerKey of Object.keys(scrollableContainers)) {
|
|
43
|
+
if (scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
44
|
+
// If there's any scheduled saving of page scroll position, cancel it.
|
|
45
|
+
this.cancelSavePageScrollPosition();
|
|
46
|
+
// Remove scroll listener on the page.
|
|
47
|
+
this.removePageScrollListener();
|
|
48
|
+
} else {
|
|
49
|
+
this.cancelSaveScrollableContainerScrollPosition(
|
|
50
|
+
scrollableContainerKey,
|
|
51
|
+
);
|
|
52
|
+
this.removeScrollableContainerScrollListener(scrollableContainerKey);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cancelScheduledAutoSave() {
|
|
58
|
+
for (const scrollableContainerKey of Object.keys(
|
|
59
|
+
this._getScrollableContainers(),
|
|
60
|
+
)) {
|
|
61
|
+
if (scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
62
|
+
this.cancelSavePageScrollPosition();
|
|
63
|
+
} else {
|
|
64
|
+
this.cancelSaveScrollableContainerScrollPosition(
|
|
65
|
+
scrollableContainerKey,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
cancelSavePageScrollPosition(hasRun) {
|
|
72
|
+
if (this._cancelSavePageScrollPosition) {
|
|
73
|
+
if (!hasRun) {
|
|
74
|
+
debug(
|
|
75
|
+
'cancel delayed save scroll position',
|
|
76
|
+
PAGE_SCROLLABLE_CONTAINER_KEY,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
this._cancelSavePageScrollPosition();
|
|
80
|
+
this._cancelSavePageScrollPosition = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
cancelSaveScrollableContainerScrollPosition(scrollableContainerKey, hasRun) {
|
|
85
|
+
const scrollableContainerEntry =
|
|
86
|
+
this._getScrollableContainers()[scrollableContainerKey];
|
|
87
|
+
if (scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
88
|
+
if (!hasRun) {
|
|
89
|
+
debug('cancel delayed save scroll position', scrollableContainerKey);
|
|
90
|
+
}
|
|
91
|
+
scrollableContainerEntry.cancelSaveScrollPosition();
|
|
92
|
+
scrollableContainerEntry.cancelSaveScrollPosition = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
removePageScrollListener() {
|
|
97
|
+
// Remove scroll listener on the page.
|
|
98
|
+
if (this._removePageScrollListener) {
|
|
99
|
+
this._removePageScrollListener();
|
|
100
|
+
this._removePageScrollListener = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
removeScrollableContainerScrollListener(scrollableContainerKey) {
|
|
105
|
+
const scrollableContainerEntry =
|
|
106
|
+
this._getScrollableContainers()[scrollableContainerKey];
|
|
107
|
+
if (scrollableContainerEntry.removeScrollListener) {
|
|
108
|
+
scrollableContainerEntry.removeScrollListener();
|
|
109
|
+
scrollableContainerEntry.removeScrollListener = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
addScrollableContainerScrollListener(scrollableContainerKey) {
|
|
114
|
+
const scrollableContainerEntry =
|
|
115
|
+
this._getScrollableContainers()[scrollableContainerKey];
|
|
116
|
+
|
|
117
|
+
scrollableContainerEntry.removeScrollListener =
|
|
118
|
+
this._scrollPosition.addScrollableContainerScrollListener(
|
|
119
|
+
scrollableContainerEntry.scrollableContainer,
|
|
120
|
+
() => {
|
|
121
|
+
// This flag is not used in real life and is only used in tests (for some reason).
|
|
122
|
+
if (!this._shouldSaveScrollPosition()) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Use `scheduleNextTick()` function to "throttle" incoming scroll events.
|
|
126
|
+
// There would be no use in reacting to every incoming scroll event
|
|
127
|
+
// because there might be too many in a given short period of time
|
|
128
|
+
// which could affect the performance of the application.
|
|
129
|
+
if (!scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
130
|
+
debug('scroll detected', scrollableContainerKey);
|
|
131
|
+
scrollableContainerEntry.cancelSaveScrollPosition =
|
|
132
|
+
scheduleNextTick(() => {
|
|
133
|
+
debug(
|
|
134
|
+
'auto-save scroll position after scroll',
|
|
135
|
+
scrollableContainerKey,
|
|
136
|
+
);
|
|
137
|
+
this._scrollPositionSaver.saveScrollableContainerScrollPosition(
|
|
138
|
+
scrollableContainerKey,
|
|
139
|
+
scrollableContainerEntry.scrollableContainer,
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
addPageScrollListener() {
|
|
148
|
+
// Set up scroll listener on the page.
|
|
149
|
+
this._removePageScrollListener =
|
|
150
|
+
this._scrollPosition.addPageScrollListener(() => {
|
|
151
|
+
debug('scroll detected', PAGE_SCROLLABLE_CONTAINER_KEY);
|
|
152
|
+
|
|
153
|
+
// This flag is not used in real life and is only used in tests (for some reason).
|
|
154
|
+
if (!this._shouldSaveScrollPosition()) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Use `scheduleNextTick()` function to "throttle" incoming scroll events.
|
|
158
|
+
// There would be no use in reacting to every incoming scroll event
|
|
159
|
+
// because there might be too many in a given short period of time
|
|
160
|
+
// which could affect the performance of the application.
|
|
161
|
+
if (!this._cancelSavePageScrollPosition) {
|
|
162
|
+
this._cancelSavePageScrollPosition = scheduleNextTick(() => {
|
|
163
|
+
this._scrollPositionSaver.savePageScrollPosition();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|