navigation-stack 0.5.2 → 0.6.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 +16 -0
- package/README.md +144 -282
- package/karma.conf.cjs +1 -1
- package/lib/cjs/NavigationStack.js +138 -49
- package/lib/cjs/data-storage/DataStorage.js +7 -6
- package/lib/cjs/environment/InMemoryEnvironment.js +6 -0
- package/lib/cjs/{session/ServerSideRenderSession.js → environment/ServerSideRenderEnvironment.js} +5 -6
- package/lib/cjs/environment/WebBrowserEnvironment.js +6 -0
- package/lib/cjs/environment/log/InMemoryLog.js +23 -0
- package/lib/cjs/environment/log/WebBrowserLog.js +22 -0
- package/lib/cjs/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/lib/cjs/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/lib/cjs/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/lib/cjs/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +2 -2
- package/lib/cjs/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/lib/cjs/getLocationBaseFromLocation.js +14 -0
- package/lib/cjs/getLocationUrl.js +3 -5
- package/lib/cjs/index.js +10 -16
- package/lib/cjs/navigationBlockers.js +34 -32
- package/lib/cjs/navigationBlockersEvaluation.js +150 -0
- package/lib/cjs/parseInputLocation.js +10 -3
- package/lib/cjs/parseQueryFromSearch.js +3 -6
- package/lib/cjs/parseQueryString.js +77 -0
- package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +7 -6
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +31 -27
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +6 -4
- package/lib/cjs/session/Session.js +61 -26
- package/lib/cjs/session/subscription/Subscription.js +36 -18
- package/lib/cjs/stringifyQuery.js +66 -0
- package/lib/cjs/stringifyQueryAsSearch.js +14 -0
- package/lib/esm/NavigationStack.js +138 -49
- package/lib/esm/data-storage/DataStorage.js +7 -6
- package/lib/esm/environment/InMemoryEnvironment.js +6 -0
- package/lib/esm/environment/ServerSideRenderEnvironment.js +10 -0
- package/lib/esm/environment/WebBrowserEnvironment.js +6 -0
- package/lib/esm/environment/log/InMemoryLog.js +17 -0
- package/lib/esm/environment/log/WebBrowserLog.js +16 -0
- package/lib/esm/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/lib/esm/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/lib/esm/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/lib/esm/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +1 -1
- package/lib/esm/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/lib/esm/getLocationBaseFromLocation.js +9 -0
- package/lib/esm/getLocationUrl.js +2 -5
- package/lib/esm/index.js +5 -8
- package/lib/esm/navigationBlockers.js +34 -32
- package/lib/esm/navigationBlockersEvaluation.js +145 -0
- package/lib/esm/parseInputLocation.js +9 -3
- package/lib/esm/parseQueryFromSearch.js +2 -6
- package/lib/esm/parseQueryString.js +72 -0
- package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +7 -6
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +31 -27
- package/lib/esm/scroll-position/ScrollPositionSaver.js +6 -4
- package/lib/esm/session/Session.js +61 -26
- package/lib/esm/session/subscription/Subscription.js +36 -18
- package/lib/esm/stringifyQuery.js +61 -0
- package/lib/esm/stringifyQueryAsSearch.js +8 -0
- package/lib/index.d.ts +180 -34
- package/package.json +4 -7
- package/src/NavigationStack.js +166 -56
- package/src/data-storage/DataStorage.js +9 -6
- package/src/environment/InMemoryEnvironment.js +6 -0
- package/src/environment/ServerSideRenderEnvironment.js +10 -0
- package/src/environment/WebBrowserEnvironment.js +6 -0
- package/src/environment/log/InMemoryLog.js +20 -0
- package/src/environment/log/WebBrowserLog.js +18 -0
- package/src/{session → environment}/navigation/InMemoryNavigation.js +16 -5
- package/src/{session → environment}/navigation/ServerSideNavigation.js +16 -7
- package/src/{session → environment}/navigation/WebBrowserNavigation.js +48 -8
- package/src/{session/navigation/error/ServerSideNavigationError.js → environment/navigation/error/ServerSideRedirectError.js} +1 -1
- package/src/environment/scroll-position/WebBrowserScrollPosition.js +15 -0
- package/src/getLocationBaseFromLocation.js +7 -0
- package/src/getLocationUrl.js +2 -5
- package/src/index.js +10 -13
- package/src/navigationBlockers.js +55 -34
- package/src/navigationBlockersEvaluation.js +161 -0
- package/src/parseInputLocation.js +10 -3
- package/src/parseQueryFromSearch.js +2 -6
- package/src/parseQueryString.js +81 -0
- package/src/scroll-position/ScrollPositionAutoSaver.js +10 -6
- package/src/scroll-position/ScrollPositionRestoration.js +36 -30
- package/src/scroll-position/ScrollPositionSaver.js +6 -4
- package/src/scroll-position/index.js +1 -1
- package/src/session/Session.js +68 -24
- package/src/session/subscription/Subscription.js +36 -11
- package/src/stringifyQuery.js +71 -0
- package/src/stringifyQueryAsSearch.js +9 -0
- package/test/NavigationStack.addBasePath.test.js +50 -0
- package/test/{redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js → NavigationStack.blockNonProgrammaticNavigationIfRequired.test.js} +51 -63
- package/test/{redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js → NavigationStack.blockProgrammaticNavigationIfRequired.test.js} +98 -78
- package/test/NavigationStack.general.test.js +68 -0
- package/test/NavigationStack.parseInputLocation.test.js +52 -0
- package/test/NavigationStack.removeBasePath.test.js +69 -0
- package/test/NavigationStack.test.js +97 -29
- package/test/data-storage/LocationDataStorage.test.js +3 -2
- package/test/index.js +7 -31
- package/test/index.test.js +4 -5
- package/test/parseQueryFromSearch.test.js +19 -0
- package/test/parseQueryString.test.js +18 -0
- package/test/scroll-position/ScrollPositionRestoration.test.js +34 -13
- package/test/scroll-position/createApp.js +8 -8
- package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +4 -4
- package/test/session/{InMemorySession.test.js → Session.InMemoryEnvironment.test.js} +10 -9
- package/test/session/{ServerSession.test.js → Session.ServerSideRenderEnvironment.test.js} +5 -4
- package/test/session/{WebBrowserSession.test.js → Session.WebBrowserEnvironment.test.js} +63 -13
- package/test/shouldWarn.js +44 -0
- package/test/stringifyQuery.test.js +65 -0
- package/types/index.d.ts +180 -34
- package/types/tsconfig.json +0 -1
- package/data-storage/package.json +0 -7
- package/lib/cjs/createSearchFromQuery.js +0 -13
- package/lib/cjs/debug.js +0 -12
- package/lib/cjs/redux/ActionTypes.js +0 -14
- package/lib/cjs/redux/ActionTypesInternal.js +0 -8
- package/lib/cjs/redux/Actions.js +0 -28
- package/lib/cjs/redux/createMiddlewares.js +0 -60
- package/lib/cjs/redux/index.js +0 -13
- package/lib/cjs/redux/internalLocationReducer.js +0 -14
- package/lib/cjs/redux/locationReducer.js +0 -13
- package/lib/cjs/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -32
- package/lib/cjs/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -113
- package/lib/cjs/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -94
- package/lib/cjs/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -30
- package/lib/cjs/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -73
- package/lib/cjs/redux/middleware/navigationOperationMiddleware.js +0 -40
- package/lib/cjs/redux/middleware/parseInputLocationMiddleware.js +0 -29
- package/lib/cjs/redux/middleware/updateLocationMiddleware.js +0 -34
- package/lib/cjs/session/InMemorySession.js +0 -22
- package/lib/cjs/session/WebBrowserSession.js +0 -20
- package/lib/data-storage/index.d.ts +0 -35
- package/lib/esm/createSearchFromQuery.js +0 -8
- package/lib/esm/debug.js +0 -7
- package/lib/esm/redux/ActionTypes.js +0 -9
- package/lib/esm/redux/ActionTypesInternal.js +0 -3
- package/lib/esm/redux/Actions.js +0 -22
- package/lib/esm/redux/createMiddlewares.js +0 -54
- package/lib/esm/redux/index.js +0 -4
- package/lib/esm/redux/internalLocationReducer.js +0 -8
- package/lib/esm/redux/locationReducer.js +0 -7
- package/lib/esm/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -27
- package/lib/esm/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -108
- package/lib/esm/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -88
- package/lib/esm/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -25
- package/lib/esm/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -68
- package/lib/esm/redux/middleware/navigationOperationMiddleware.js +0 -35
- package/lib/esm/redux/middleware/parseInputLocationMiddleware.js +0 -24
- package/lib/esm/redux/middleware/updateLocationMiddleware.js +0 -28
- package/lib/esm/session/InMemorySession.js +0 -15
- package/lib/esm/session/ServerSideRenderSession.js +0 -11
- package/lib/esm/session/WebBrowserSession.js +0 -13
- package/lib/redux/index.d.ts +0 -90
- package/lib/scroll-position/index.d.ts +0 -107
- package/redux/package.json +0 -7
- package/scroll-position/package.json +0 -7
- package/src/createSearchFromQuery.js +0 -9
- package/src/debug.js +0 -8
- package/src/redux/ActionTypes.js +0 -9
- package/src/redux/ActionTypesInternal.js +0 -3
- package/src/redux/Actions.js +0 -27
- package/src/redux/createMiddlewares.js +0 -65
- package/src/redux/index.js +0 -4
- package/src/redux/internalLocationReducer.js +0 -9
- package/src/redux/locationReducer.js +0 -8
- package/src/redux/middleware/createAddInputLocationBasePathMiddleware.js +0 -27
- package/src/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.js +0 -119
- package/src/redux/middleware/createProgrammaticNavigationBlockerMiddleware.js +0 -94
- package/src/redux/middleware/createRemoveOutputLocationBasePathMiddleware.js +0 -26
- package/src/redux/middleware/createUpdateInternalLocationMiddleware.js +0 -72
- package/src/redux/middleware/navigationOperationMiddleware.js +0 -34
- package/src/redux/middleware/parseInputLocationMiddleware.js +0 -23
- package/src/redux/middleware/updateLocationMiddleware.js +0 -28
- package/src/session/InMemorySession.js +0 -13
- package/src/session/ServerSideRenderSession.js +0 -9
- package/src/session/WebBrowserSession.js +0 -13
- package/test/middlewareTestUtil.js +0 -31
- package/test/redux/Action.test.js +0 -73
- package/test/redux/ActionTypes.test.js +0 -13
- package/test/redux/createMiddlewares.test.js +0 -96
- package/test/redux/index.test.js +0 -10
- package/test/redux/locationReducer.test.js +0 -39
- package/test/redux/middleware/createAddInputLocationBasePathMiddleware.test.js +0 -40
- package/test/redux/middleware/createRemoveOutputLocationBasePathMiddleware.test.js +0 -51
- package/test/redux/middleware/navigationOperationMiddleware.test.js +0 -78
- package/test/redux/middleware/parseInputLocationMiddleware.test.js +0 -62
- package/test/testUtil.js +0 -3
- package/types/data-storage/index.d.ts +0 -35
- package/types/redux/index.d.ts +0 -90
- package/types/scroll-position/index.d.ts +0 -107
- /package/lib/cjs/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/lib/cjs/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/lib/cjs/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/lib/cjs/{session → environment}/navigation/operation/operations.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/lib/esm/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/lib/esm/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/lib/esm/{session → environment}/navigation/operation/operations.js +0 -0
- /package/src/{session → environment}/lifecycle/InMemorySessionLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/WebBrowserSessionLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/PageLifecycle.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/PageLifecycleInstance.js +0 -0
- /package/src/{session → environment}/lifecycle/page-lifecycle/supportsConstructableEventTarget.js +0 -0
- /package/src/{session → environment}/navigation/error/NavigationOutOfBoundsError.js +0 -0
- /package/src/{session → environment}/navigation/operation/operations.js +0 -0
- /package/test/{parseInputLocationMiddleware.test.js → parseInputLocation.test.js} +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import getLocationBaseFromLocation from './getLocationBaseFromLocation';
|
|
2
|
+
import getLocationFromInternalLocation from './getLocationFromInternalLocation';
|
|
3
|
+
import isPromise from './isPromise';
|
|
4
|
+
import {
|
|
5
|
+
getNavigationBlockers,
|
|
6
|
+
runNavigationBlockers,
|
|
7
|
+
} from './navigationBlockers';
|
|
8
|
+
|
|
9
|
+
// Creates "navigation blockers evaluation" status object.
|
|
10
|
+
// It tracks the "cancelled" status of the evaluation:
|
|
11
|
+
// when next navigation happens, the previous one is no longer relevant
|
|
12
|
+
// so the evaluation of navigation blockers for it can be cancelled.
|
|
13
|
+
function createNavigationBlockersEvaluationStatus(container) {
|
|
14
|
+
/* eslint-disable no-underscore-dangle */
|
|
15
|
+
if (container._navigationBlockersEvaluationStatus) {
|
|
16
|
+
container._navigationBlockersEvaluationStatus.cancelled = true;
|
|
17
|
+
}
|
|
18
|
+
container._navigationBlockersEvaluationStatus = { cancelled: false };
|
|
19
|
+
return container._navigationBlockersEvaluationStatus;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Prevents or allows navigation that was initiated by the application code
|
|
23
|
+
// by making a `.push()` or `.replace()` method call.
|
|
24
|
+
//
|
|
25
|
+
// It doesn't handle `.shift()` method calls because it doesn't yet know
|
|
26
|
+
// the `location` that it's gonna `shift` to. Instead, it waits for the web browser
|
|
27
|
+
// to "shift" to that `location` and then reads the `location` from the address bar
|
|
28
|
+
// and, if such "shift" should've been blocked, it "rewinds" the address bar back
|
|
29
|
+
// to the previous location. This part is handled by another function.
|
|
30
|
+
//
|
|
31
|
+
// Such type of "shifting" and then rewinding the "shift" doesn't really matter to the application code at all.
|
|
32
|
+
// From the application code's point of view, all web browser's address bar doesn't matter and even doesn't exist.
|
|
33
|
+
// All that exists from the application code's point of view is the `location` object in the `NavigationStack`'s state.
|
|
34
|
+
// Until the `location` object in the `NavigationStack`'s state is updated, the "old" page is still rendered.
|
|
35
|
+
// The appliation is only concerned with the updates of the `location` object in the `NavigationStack`'s state
|
|
36
|
+
// and completely ignores any updates to the URL in the web browser's address bar.
|
|
37
|
+
//
|
|
38
|
+
export function blockProgrammaticNavigationIfRequired(
|
|
39
|
+
toLocationBase, // `location` of type `LocationBase`
|
|
40
|
+
session,
|
|
41
|
+
) {
|
|
42
|
+
// `resultValue` variable name works around a stupid javascript error:
|
|
43
|
+
// "Cannot redeclare block-scoped variable 'result'".
|
|
44
|
+
const result = runNavigationBlockers(
|
|
45
|
+
getNavigationBlockers(session),
|
|
46
|
+
// Here `payload.location` is `LocationBase`.
|
|
47
|
+
toLocationBase,
|
|
48
|
+
session.environment,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (isPromise(result)) {
|
|
52
|
+
const evaluationStatus = createNavigationBlockersEvaluationStatus(session);
|
|
53
|
+
// eslint-disable-next-line consistent-return
|
|
54
|
+
return result.then((promiseResult) => {
|
|
55
|
+
if (evaluationStatus.cancelled) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return promiseResult;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Runs navigation blockers on internal location update and "undoes" the location update
|
|
65
|
+
// if it should've been blocked.
|
|
66
|
+
//
|
|
67
|
+
// One could ask: Why the hassle of running navigation blockers on internal location update
|
|
68
|
+
// and then rewinding back if the location change should've been blocked?
|
|
69
|
+
// Why not just run navigation blockers on `.push()`/`.replace()`/`.shift()`?
|
|
70
|
+
//
|
|
71
|
+
// The reason why it runs on internal location update here is because
|
|
72
|
+
// aside from programmatic `.shift()` that can be initiated from the application code,
|
|
73
|
+
// there's non-programmatic "shift" navigation when the user manually clicks "Back" or "Forward" button
|
|
74
|
+
// in a web browser. And even if a "shift" navigation is initiated programmatically in the application code,
|
|
75
|
+
// it still doesn't know yet what the new location is gonna be cause it only knows the numeric `delta`.
|
|
76
|
+
// Such cases could only be handled by reacting to internal location updates which,
|
|
77
|
+
// in case of "Back"/"Forward", only happen after the URL in the browser's address bar has changed.
|
|
78
|
+
//
|
|
79
|
+
// There's no real drawback in reacting to an internal location update "post factum" because
|
|
80
|
+
// from the application code's point of view, web browser's address bar doesn't matter and even doesn't exist.
|
|
81
|
+
// All that exists from the application code's point of view is the `navigationStack.current` location
|
|
82
|
+
// returned from the `NavigationStack`. Until that location is updated, the "old" page is still rendered.
|
|
83
|
+
// The appliation is only concerned with the updates of the internal `location` object in the `NavigationStack``
|
|
84
|
+
// and completely ignores any updates to the URL in the web browser's address bar.
|
|
85
|
+
//
|
|
86
|
+
// So here, the code attempts to prevent or allow navigation that has already happened
|
|
87
|
+
// in the web browser's address bar but hasn't yet happened in the `NavigationStack`'s state.
|
|
88
|
+
// For example, it could be a user clicking a "Back"/"Forward" button in a web browser.
|
|
89
|
+
// If such navigation should've been blocked, it will simply not update the `location` object
|
|
90
|
+
// in the `NavigationStack`'s state, and it will also "rewind" the change of the URL in the web browser's
|
|
91
|
+
// address bar so that it's consistent with the `location` in the `NavigationStack`'s state.
|
|
92
|
+
//
|
|
93
|
+
// Returns either a `boolean` value or a `Promise` that resolves to a `boolean` value:
|
|
94
|
+
// * `false` when navigation should not have been blocked and therefore was not "rewinded".
|
|
95
|
+
// * `true` when navigation should have been blocked and therefore was "rewinded".
|
|
96
|
+
// * `true` when it "rewinded" the navigation "just in case" and then started evaluating async blockers,
|
|
97
|
+
// but while doing that, next navigation already happened so this one is no longer relevant.
|
|
98
|
+
//
|
|
99
|
+
export function blockNonProgrammaticNavigationIfRequired(
|
|
100
|
+
toLocationInternal, // `location` of type `LocationInternal`
|
|
101
|
+
session,
|
|
102
|
+
doAndIgnoreLocationUpdates,
|
|
103
|
+
) {
|
|
104
|
+
// If there're no navigation blockers to run, don't do anything.
|
|
105
|
+
if (getNavigationBlockers(session).length === 0) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If it was the initial page load or a redirect,
|
|
110
|
+
// it's not really a navigation that could be rolled back.
|
|
111
|
+
if (toLocationInternal.delta === 0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const result = runNavigationBlockers(
|
|
116
|
+
getNavigationBlockers(session),
|
|
117
|
+
getLocationBaseFromLocation(
|
|
118
|
+
getLocationFromInternalLocation(toLocationInternal),
|
|
119
|
+
),
|
|
120
|
+
session.environment,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// If some navigation blocker returned a `Promise`.
|
|
124
|
+
if (isPromise(result)) {
|
|
125
|
+
const evaluationStatus = createNavigationBlockersEvaluationStatus(session);
|
|
126
|
+
|
|
127
|
+
// While location blockers are running, rewind to the previous location.
|
|
128
|
+
doAndIgnoreLocationUpdates(() => {
|
|
129
|
+
session.shift(-toLocationInternal.delta);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return result.then((promiseResult) => {
|
|
133
|
+
if (evaluationStatus.cancelled) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
if (promiseResult) {
|
|
137
|
+
// Navigation blocked.
|
|
138
|
+
// Already rewound to a previous location.
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
// Navigation not blocked.
|
|
142
|
+
// Rewind back to the new location.
|
|
143
|
+
doAndIgnoreLocationUpdates(() => {
|
|
144
|
+
session.shift(toLocationInternal.delta);
|
|
145
|
+
});
|
|
146
|
+
// Update the location.
|
|
147
|
+
return false;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Navigation blockers did not return a `Promise`.
|
|
152
|
+
if (result) {
|
|
153
|
+
// Prevent the navigation: rewind to the previous location.
|
|
154
|
+
doAndIgnoreLocationUpdates(() => {
|
|
155
|
+
session.shift(-toLocationInternal.delta);
|
|
156
|
+
});
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
// Update the location.
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import createSearchFromQuery from './createSearchFromQuery';
|
|
2
1
|
import parseLocationUrl from './parseLocationUrl';
|
|
3
2
|
import parseQueryFromSearch from './parseQueryFromSearch';
|
|
3
|
+
import stringifyQueryAsSearch from './stringifyQueryAsSearch';
|
|
4
|
+
|
|
5
|
+
function stringifyQueryParameterValue(value) {
|
|
6
|
+
if (value === null || value === undefined) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
return String(value);
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
// * If `location` is a string, it parses it into a `LocationBase`.
|
|
6
13
|
// * If `location` is an object, it ensures that `search` and `hash` properties aren't `undefined`,
|
|
@@ -18,7 +25,7 @@ export default function parseInputLocation(location) {
|
|
|
18
25
|
...location,
|
|
19
26
|
query: {
|
|
20
27
|
...location.query,
|
|
21
|
-
[key]:
|
|
28
|
+
[key]: stringifyQueryParameterValue(location.query[key]),
|
|
22
29
|
},
|
|
23
30
|
};
|
|
24
31
|
}
|
|
@@ -38,7 +45,7 @@ export default function parseInputLocation(location) {
|
|
|
38
45
|
if (location.query && !location.search) {
|
|
39
46
|
location = {
|
|
40
47
|
...location,
|
|
41
|
-
search:
|
|
48
|
+
search: stringifyQueryAsSearch(location.query),
|
|
42
49
|
};
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import parseQueryString from './parseQueryString';
|
|
2
2
|
|
|
3
3
|
export default function parseQueryFromSearch(search) {
|
|
4
4
|
if (search.length > '?'.length) {
|
|
5
|
-
|
|
6
|
-
return parseQuery(search.slice(1));
|
|
7
|
-
} catch (error) {
|
|
8
|
-
// Ignore any query parsing errors.
|
|
9
|
-
}
|
|
5
|
+
return parseQueryString(search.slice('?'.length));
|
|
10
6
|
}
|
|
11
7
|
return {};
|
|
12
8
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
function splitAtFirstOccurence(string, separator) {
|
|
2
|
+
const separatorIndex = string.indexOf(separator);
|
|
3
|
+
if (separatorIndex === -1) {
|
|
4
|
+
return [string, ''];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
return [
|
|
8
|
+
string.slice(0, separatorIndex),
|
|
9
|
+
string.slice(separatorIndex + separator.length),
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function decode(value) {
|
|
14
|
+
// There's a convention that a space character could be encoded
|
|
15
|
+
// either as "%20" or as "+". Both of them are valid.
|
|
16
|
+
// The "+" character is unusally preferred because it results in a more
|
|
17
|
+
// human-readable URL.
|
|
18
|
+
//
|
|
19
|
+
// https://dev.to/lico/understanding-how-spaces-are-encoded-20-with-encodeuri-vs-with-url-2d6c
|
|
20
|
+
// https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding
|
|
21
|
+
//
|
|
22
|
+
// Those "+" characters don't get transformed to spaces by `decodeURIComponent()` function.
|
|
23
|
+
// This means that they should be transformed to spaces manually.
|
|
24
|
+
//
|
|
25
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#decoding_query_parameters_from_a_url
|
|
26
|
+
//
|
|
27
|
+
value = value.replaceAll('+', ' ');
|
|
28
|
+
|
|
29
|
+
// `decodeURIComponent()` could throw an error of class `URIError`.
|
|
30
|
+
//
|
|
31
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError
|
|
32
|
+
//
|
|
33
|
+
// Example: "URIError: malformed URI sequence".
|
|
34
|
+
try {
|
|
35
|
+
return decodeURIComponent(value);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.error(error);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function parseQueryString(queryString) {
|
|
44
|
+
// Create an object with no prototype
|
|
45
|
+
const query = Object.create(null);
|
|
46
|
+
|
|
47
|
+
// query parameter parsing is described in the specification:
|
|
48
|
+
// https://url.spec.whatwg.org/#urlencoded-parsing
|
|
49
|
+
for (const keyValuePair of queryString.split('&')) {
|
|
50
|
+
if (!keyValuePair) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let [key, value] = splitAtFirstOccurence(keyValuePair, '=');
|
|
55
|
+
|
|
56
|
+
// If `key` is empty, the specification considers this a valid case with `key: null`.
|
|
57
|
+
// But, there seems to be no practical use for a query parameter with `key: null`.
|
|
58
|
+
// So just skip it.
|
|
59
|
+
if (!key) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
key = decode(key);
|
|
64
|
+
|
|
65
|
+
// According to the specification, missing `=` should be treated as `value: null`.
|
|
66
|
+
if (value === '') {
|
|
67
|
+
value = null;
|
|
68
|
+
} else {
|
|
69
|
+
value = decode(value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// The handling of duplicate URL query parameters is not explicitly defined by a single,
|
|
73
|
+
// universally enforced specification. Hence, we just assume such query parameters invalid
|
|
74
|
+
// and only include the first occurrence of the query parameter in the query string.
|
|
75
|
+
if (query[key] === undefined) {
|
|
76
|
+
query[key] = value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return query;
|
|
81
|
+
}
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
4
4
|
import scheduleNextTick from './scheduleNextTick';
|
|
5
|
-
import debug from '../debug';
|
|
6
5
|
|
|
7
6
|
export default class ScrollPositionAutoSaver {
|
|
8
7
|
constructor({
|
|
8
|
+
log,
|
|
9
9
|
scrollPosition,
|
|
10
10
|
scrollPositionSaver,
|
|
11
11
|
getScrollableContainers,
|
|
12
12
|
shouldSaveScrollPosition,
|
|
13
13
|
}) {
|
|
14
|
+
this._log = log;
|
|
14
15
|
this._scrollPosition = scrollPosition;
|
|
15
16
|
this._scrollPositionSaver = scrollPositionSaver;
|
|
16
17
|
this._shouldSaveScrollPosition = shouldSaveScrollPosition;
|
|
@@ -71,7 +72,7 @@ export default class ScrollPositionAutoSaver {
|
|
|
71
72
|
cancelSavePageScrollPosition(hasRun) {
|
|
72
73
|
if (this._cancelSavePageScrollPosition) {
|
|
73
74
|
if (!hasRun) {
|
|
74
|
-
debug(
|
|
75
|
+
this._log.debug(
|
|
75
76
|
'cancel delayed save scroll position',
|
|
76
77
|
PAGE_SCROLLABLE_CONTAINER_KEY,
|
|
77
78
|
);
|
|
@@ -86,7 +87,10 @@ export default class ScrollPositionAutoSaver {
|
|
|
86
87
|
this._getScrollableContainers()[scrollableContainerKey];
|
|
87
88
|
if (scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
88
89
|
if (!hasRun) {
|
|
89
|
-
debug(
|
|
90
|
+
this._log.debug(
|
|
91
|
+
'cancel delayed save scroll position',
|
|
92
|
+
scrollableContainerKey,
|
|
93
|
+
);
|
|
90
94
|
}
|
|
91
95
|
scrollableContainerEntry.cancelSaveScrollPosition();
|
|
92
96
|
scrollableContainerEntry.cancelSaveScrollPosition = null;
|
|
@@ -127,10 +131,10 @@ export default class ScrollPositionAutoSaver {
|
|
|
127
131
|
// because there might be too many in a given short period of time
|
|
128
132
|
// which could affect the performance of the application.
|
|
129
133
|
if (!scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
130
|
-
debug('scroll detected', scrollableContainerKey);
|
|
134
|
+
this._log.debug('scroll detected', scrollableContainerKey);
|
|
131
135
|
scrollableContainerEntry.cancelSaveScrollPosition =
|
|
132
136
|
scheduleNextTick(() => {
|
|
133
|
-
debug(
|
|
137
|
+
this._log.debug(
|
|
134
138
|
'auto-save scroll position after scroll',
|
|
135
139
|
scrollableContainerKey,
|
|
136
140
|
);
|
|
@@ -148,7 +152,7 @@ export default class ScrollPositionAutoSaver {
|
|
|
148
152
|
// Set up scroll listener on the page.
|
|
149
153
|
this._removePageScrollListener =
|
|
150
154
|
this._scrollPosition.addPageScrollListener(() => {
|
|
151
|
-
debug('scroll detected', PAGE_SCROLLABLE_CONTAINER_KEY);
|
|
155
|
+
this._log.debug('scroll detected', PAGE_SCROLLABLE_CONTAINER_KEY);
|
|
152
156
|
|
|
153
157
|
// This flag is not used in real life and is only used in tests (for some reason).
|
|
154
158
|
if (!this._shouldSaveScrollPosition()) {
|
|
@@ -5,7 +5,6 @@ import ScrollPositionSaver from './ScrollPositionSaver';
|
|
|
5
5
|
import ScrollPositionSetter from './ScrollPositionSetter';
|
|
6
6
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
7
7
|
import LocationDataStorage from '../data-storage/LocationDataStorage';
|
|
8
|
-
import debug from '../debug';
|
|
9
8
|
|
|
10
9
|
function areEqualScrollPositions(scrollPosition1, scrollPosition2) {
|
|
11
10
|
let i = 0;
|
|
@@ -19,16 +18,22 @@ function areEqualScrollPositions(scrollPosition1, scrollPosition2) {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export default class ScrollPositionRestoration {
|
|
22
|
-
constructor(session,
|
|
21
|
+
constructor(session, options) {
|
|
22
|
+
this._log = session.environment.log;
|
|
23
|
+
|
|
23
24
|
this._scrollPosition = session.environment.scrollPosition;
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
// Custom `ScrollPositionSetter`.
|
|
27
|
+
this._scrollPositionSetter = options.scrollPositionSetter;
|
|
28
|
+
|
|
29
|
+
this._sessionLifecycle = session.environment.lifecycle;
|
|
26
30
|
|
|
27
31
|
this._locationDataStorage = new LocationDataStorage(session, {
|
|
28
|
-
namespace: 'navigation-stack
|
|
32
|
+
namespace: 'navigation-stack-scroll-position',
|
|
29
33
|
});
|
|
30
34
|
|
|
31
35
|
this._scrollPositionSaver = new ScrollPositionSaver({
|
|
36
|
+
log: this._log,
|
|
32
37
|
scrollPosition: this._scrollPosition,
|
|
33
38
|
saveScrollPositionForLocation: this._saveScrollPositionForLocation,
|
|
34
39
|
getScrollableContainers: () => this._scrollableContainers,
|
|
@@ -52,28 +57,30 @@ export default class ScrollPositionRestoration {
|
|
|
52
57
|
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
53
58
|
// This could be part of the public API if anyone provided a sensible real-world use case for it.
|
|
54
59
|
scrollPositionSetter:
|
|
55
|
-
(
|
|
56
|
-
//
|
|
60
|
+
(options && options._pageScrollPositionSetter) ||
|
|
61
|
+
// eslint-disable-next-line new-cap
|
|
62
|
+
(this._scrollPositionSetter && new this._scrollPositionSetter()) ||
|
|
63
|
+
// A default `ScrollPositionSetter` for a page (sets page scroll position twice with a momentary delay).
|
|
57
64
|
new PageScrollPositionSetter(),
|
|
58
65
|
|
|
59
66
|
// This function is only used in tests.
|
|
60
67
|
// There seems to be no use of it in real life, hence it's not public API.
|
|
61
68
|
// It's only used in tests.
|
|
62
69
|
_getSavedScrollPositionOnLocationChange:
|
|
63
|
-
|
|
70
|
+
options && options._getSavedPageScrollPositionOnLocationChange,
|
|
64
71
|
|
|
65
72
|
// This function is only used in tests.
|
|
66
73
|
// There seems to be no use of it in real life, hence it's not public API.
|
|
67
74
|
// It's only used in tests.
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
shouldChangeScrollPositionOnLocationChange:
|
|
76
|
+
options && options.shouldChangePageScrollPositionOnLocationChange,
|
|
70
77
|
};
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
addScrollableContainer(
|
|
74
81
|
scrollableContainerKey,
|
|
75
82
|
scrollableContainer,
|
|
76
|
-
|
|
83
|
+
options,
|
|
77
84
|
) {
|
|
78
85
|
// Originally, `scrollableContainerKey` was auto-generated,
|
|
79
86
|
// but then it didn't work with the concept of dynamically adding or removing
|
|
@@ -96,7 +103,7 @@ export default class ScrollPositionRestoration {
|
|
|
96
103
|
);
|
|
97
104
|
}
|
|
98
105
|
|
|
99
|
-
debug('add scrollable container', scrollableContainerKey);
|
|
106
|
+
this._log.debug('add scrollable container', scrollableContainerKey);
|
|
100
107
|
|
|
101
108
|
// Add scrollable container entry.
|
|
102
109
|
this._scrollableContainers[scrollableContainerKey] = {
|
|
@@ -107,21 +114,22 @@ export default class ScrollPositionRestoration {
|
|
|
107
114
|
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
108
115
|
// This could be part of the public API if anyone provided a sensible real-world use case for it.
|
|
109
116
|
scrollPositionSetter:
|
|
110
|
-
(
|
|
117
|
+
(options && options._scrollPositionSetter) ||
|
|
118
|
+
(this._scrollPositionSetter && new this._scrollPositionSetter()) ||
|
|
111
119
|
// The default basic "immediate" scroll position setter.
|
|
112
120
|
new ScrollPositionSetter(),
|
|
113
121
|
|
|
114
122
|
// This function is only used in tests.
|
|
115
123
|
// There seems to be no use of it in real life, hence it's not public API.
|
|
116
124
|
// It's only used in tests.
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
shouldChangeScrollPositionOnLocationChange:
|
|
126
|
+
options && options.shouldChangeScrollPositionOnLocationChange,
|
|
119
127
|
|
|
120
128
|
// This function is only used in tests.
|
|
121
129
|
// There seems to be no use of it in real life, hence it's not public API.
|
|
122
130
|
// It's only used in tests.
|
|
123
131
|
_getSavedScrollPositionOnLocationChange:
|
|
124
|
-
|
|
132
|
+
options && options._getSavedScrollPositionOnLocationChange,
|
|
125
133
|
};
|
|
126
134
|
|
|
127
135
|
// Scrollable containers could be added at any time, including page mount.
|
|
@@ -137,7 +145,7 @@ export default class ScrollPositionRestoration {
|
|
|
137
145
|
scrollableContainerKey,
|
|
138
146
|
);
|
|
139
147
|
if (previouslySavedScrollPosition) {
|
|
140
|
-
debug(
|
|
148
|
+
this._log.debug(
|
|
141
149
|
'restore scroll position on add scrollable container',
|
|
142
150
|
this._location.pathname,
|
|
143
151
|
scrollableContainerKey,
|
|
@@ -148,7 +156,7 @@ export default class ScrollPositionRestoration {
|
|
|
148
156
|
previouslySavedScrollPosition,
|
|
149
157
|
);
|
|
150
158
|
} else {
|
|
151
|
-
debug(
|
|
159
|
+
this._log.debug(
|
|
152
160
|
'save scroll position on add scrollable container',
|
|
153
161
|
this._location.pathname,
|
|
154
162
|
scrollableContainerKey,
|
|
@@ -168,7 +176,7 @@ export default class ScrollPositionRestoration {
|
|
|
168
176
|
|
|
169
177
|
// Removes the scrollable container.
|
|
170
178
|
return () => {
|
|
171
|
-
debug('remove scrollable container', scrollableContainerKey);
|
|
179
|
+
this._log.debug('remove scrollable container', scrollableContainerKey);
|
|
172
180
|
|
|
173
181
|
this._scrollPositionSaver._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(
|
|
174
182
|
scrollableContainerKey,
|
|
@@ -257,10 +265,10 @@ export default class ScrollPositionRestoration {
|
|
|
257
265
|
//
|
|
258
266
|
_sessionExecutionStatusListener = ({ running }) => {
|
|
259
267
|
if (running) {
|
|
260
|
-
debug('▶ running');
|
|
268
|
+
this._log.debug('▶ running');
|
|
261
269
|
this._disableAutomaticScrollRestoration();
|
|
262
270
|
} else {
|
|
263
|
-
debug('⏹ not running');
|
|
271
|
+
this._log.debug('⏹ not running');
|
|
264
272
|
this._enableAutomaticScrollRestoration();
|
|
265
273
|
|
|
266
274
|
// There might be previous scroll position already saved in the data storage.
|
|
@@ -308,7 +316,7 @@ export default class ScrollPositionRestoration {
|
|
|
308
316
|
throw new Error('`location` must have a `key`');
|
|
309
317
|
}
|
|
310
318
|
|
|
311
|
-
debug('rendered location', location.pathname);
|
|
319
|
+
this._log.debug('rendered location', location.pathname);
|
|
312
320
|
|
|
313
321
|
this._prevLocation = this._location;
|
|
314
322
|
this._location = location;
|
|
@@ -391,12 +399,12 @@ export default class ScrollPositionRestoration {
|
|
|
391
399
|
// There seems to be no use of it in real life, hence it's not public API.
|
|
392
400
|
// It's only used in tests.
|
|
393
401
|
if (
|
|
394
|
-
scrollableContainerEntry.
|
|
402
|
+
scrollableContainerEntry.shouldChangeScrollPositionOnLocationChange
|
|
395
403
|
) {
|
|
396
404
|
if (
|
|
397
|
-
!scrollableContainerEntry.
|
|
398
|
-
this._location,
|
|
405
|
+
!scrollableContainerEntry.shouldChangeScrollPositionOnLocationChange(
|
|
399
406
|
this._prevLocation,
|
|
407
|
+
this._location,
|
|
400
408
|
)
|
|
401
409
|
) {
|
|
402
410
|
return Promise.resolve();
|
|
@@ -412,8 +420,8 @@ export default class ScrollPositionRestoration {
|
|
|
412
420
|
if (scrollableContainerEntry._getSavedScrollPositionOnLocationChange) {
|
|
413
421
|
scrollPositionOrAnchorToSet =
|
|
414
422
|
scrollableContainerEntry._getSavedScrollPositionOnLocationChange(
|
|
415
|
-
this._location,
|
|
416
423
|
this._prevLocation,
|
|
424
|
+
this._location,
|
|
417
425
|
);
|
|
418
426
|
}
|
|
419
427
|
|
|
@@ -428,7 +436,7 @@ export default class ScrollPositionRestoration {
|
|
|
428
436
|
);
|
|
429
437
|
}
|
|
430
438
|
|
|
431
|
-
debug(
|
|
439
|
+
this._log.debug(
|
|
432
440
|
'restore scroll position',
|
|
433
441
|
this._location.pathname,
|
|
434
442
|
scrollableContainerKey,
|
|
@@ -462,8 +470,7 @@ export default class ScrollPositionRestoration {
|
|
|
462
470
|
try {
|
|
463
471
|
this._scrollPosition.disableAutomaticScrollRestoration();
|
|
464
472
|
} catch (error) {
|
|
465
|
-
|
|
466
|
-
console.error(
|
|
473
|
+
this._log.error(
|
|
467
474
|
'[navigation-stack] could not disable default scroll restoration mode',
|
|
468
475
|
);
|
|
469
476
|
}
|
|
@@ -473,8 +480,7 @@ export default class ScrollPositionRestoration {
|
|
|
473
480
|
try {
|
|
474
481
|
this._scrollPosition.enableAutomaticScrollRestoration();
|
|
475
482
|
} catch (error) {
|
|
476
|
-
|
|
477
|
-
console.error(
|
|
483
|
+
this._log.error(
|
|
478
484
|
'[navigation-stack] could not enable default scroll restoration mode',
|
|
479
485
|
);
|
|
480
486
|
}
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import ScrollPositionAutoSaver from './ScrollPositionAutoSaver';
|
|
4
4
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
5
|
-
import debug from '../debug';
|
|
6
5
|
|
|
7
6
|
export default class ScrollPositionSaver {
|
|
8
7
|
constructor({
|
|
8
|
+
log,
|
|
9
9
|
scrollPosition,
|
|
10
10
|
getLocation,
|
|
11
11
|
saveScrollPositionForLocation,
|
|
12
12
|
getScrollableContainers,
|
|
13
13
|
shouldSaveScrollPosition,
|
|
14
14
|
}) {
|
|
15
|
+
this._log = log;
|
|
15
16
|
this._scrollPosition = scrollPosition;
|
|
16
17
|
this._getLocation = getLocation;
|
|
17
18
|
this._saveScrollPositionForLocation = saveScrollPositionForLocation;
|
|
@@ -19,6 +20,7 @@ export default class ScrollPositionSaver {
|
|
|
19
20
|
this._shouldSaveScrollPosition = shouldSaveScrollPosition;
|
|
20
21
|
|
|
21
22
|
this._scrollPositionAutoSaver = new ScrollPositionAutoSaver({
|
|
23
|
+
log: this._log,
|
|
22
24
|
scrollPosition: this._scrollPosition,
|
|
23
25
|
scrollPositionSaver: this,
|
|
24
26
|
getScrollableContainers,
|
|
@@ -44,7 +46,7 @@ export default class ScrollPositionSaver {
|
|
|
44
46
|
return;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
debug('save scroll position', this._getLocation().pathname);
|
|
49
|
+
this._log.debug('save scroll position', this._getLocation().pathname);
|
|
48
50
|
|
|
49
51
|
// Get scrollable containers.
|
|
50
52
|
const scrollableContainers = this._getScrollableContainers();
|
|
@@ -63,7 +65,7 @@ export default class ScrollPositionSaver {
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
savePageScrollPosition() {
|
|
66
|
-
debug(
|
|
68
|
+
this._log.debug(
|
|
67
69
|
'save scroll position',
|
|
68
70
|
this._getLocation().pathname,
|
|
69
71
|
PAGE_SCROLLABLE_CONTAINER_KEY,
|
|
@@ -89,7 +91,7 @@ export default class ScrollPositionSaver {
|
|
|
89
91
|
scrollableContainerKey,
|
|
90
92
|
scrollableContainer,
|
|
91
93
|
) {
|
|
92
|
-
debug(
|
|
94
|
+
this._log.debug(
|
|
93
95
|
'save scroll position',
|
|
94
96
|
this._getLocation().pathname,
|
|
95
97
|
scrollableContainerKey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export ScrollPositionRestoration from './ScrollPositionRestoration';
|
|
1
|
+
export { default as ScrollPositionRestoration } from './ScrollPositionRestoration';
|