navigation-stack 0.4.0 → 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 +20 -12
- package/lib/cjs/NavigationStack.js +17 -2
- package/lib/cjs/debug.js +12 -0
- package/lib/cjs/getLocationFromInternalLocation.js +2 -2
- package/lib/cjs/navigationBlockers.js +3 -0
- package/lib/cjs/scroll-position/ScrollPositionAutoSaver.js +13 -2
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +29 -5
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +8 -2
- package/lib/cjs/session/Session.js +6 -0
- package/lib/cjs/session/navigation/operation/operations.js +4 -4
- package/lib/esm/NavigationStack.js +17 -2
- package/lib/esm/debug.js +7 -0
- package/lib/esm/getLocationFromInternalLocation.js +2 -2
- package/lib/esm/navigationBlockers.js +3 -0
- package/lib/esm/scroll-position/ScrollPositionAutoSaver.js +13 -2
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +29 -5
- package/lib/esm/scroll-position/ScrollPositionSaver.js +8 -2
- package/lib/esm/session/Session.js +6 -0
- package/lib/esm/session/navigation/operation/operations.js +4 -4
- package/lib/index.d.ts +10 -9
- package/lib/scroll-position/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/NavigationStack.js +18 -2
- package/src/debug.js +8 -0
- package/src/getLocationFromInternalLocation.js +2 -2
- package/src/navigationBlockers.js +3 -0
- package/src/scroll-position/ScrollPositionAutoSaver.js +19 -2
- package/src/scroll-position/ScrollPositionRestoration.js +92 -47
- package/src/scroll-position/ScrollPositionSaver.js +21 -1
- package/src/session/Session.js +22 -0
- package/src/session/navigation/operation/operations.js +4 -4
- package/test/NavigationStack.test.js +14 -14
- package/test/middlewareTestUtil.js +1 -1
- package/test/redux/locationReducer.test.js +1 -1
- package/test/redux/middleware/createNonProgrammaticNavigationBlockerMiddleware.test.js +5 -5
- package/test/redux/middleware/createProgrammaticNavigationBlockerMiddleware.test.js +2 -2
- package/test/redux/middleware/navigationOperationMiddleware.test.js +2 -2
- package/test/scroll-position/ScrollPositionRestoration.test.js +73 -56
- package/test/scroll-position/addScrollableContainer.js +5 -2
- package/test/scroll-position/{addScrollableContainerWithHyperlink.js → addScrollableContainerWithAnchors.js} +8 -2
- package/test/scroll-position/createApp.js +20 -0
- package/test/scroll-position/withScrollableContainerAtIndexPageWithDisabledAutomaticScrollPositionRestoration.js +72 -0
- package/test/session/InMemorySession.test.js +28 -28
- package/test/session/ServerSession.test.js +1 -1
- package/test/session/WebBrowserSession.test.js +17 -17
- package/types/index.d.ts +10 -9
- package/types/scroll-position/index.d.ts +3 -3
- package/test/scroll-position/withScrollableContainerAtIndexPage.js +0 -62
|
@@ -5,6 +5,7 @@ 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';
|
|
8
9
|
function areEqualScrollPositions(scrollPosition1, scrollPosition2) {
|
|
9
10
|
let i = 0;
|
|
10
11
|
while (i < scrollPosition1.length) {
|
|
@@ -48,8 +49,10 @@ export default class ScrollPositionRestoration {
|
|
|
48
49
|
running
|
|
49
50
|
}) => {
|
|
50
51
|
if (running) {
|
|
52
|
+
debug('▶ running');
|
|
51
53
|
this._disableAutomaticScrollRestoration();
|
|
52
54
|
} else {
|
|
55
|
+
debug('⏹ not running');
|
|
53
56
|
this._enableAutomaticScrollRestoration();
|
|
54
57
|
|
|
55
58
|
// There might be previous scroll position already saved in the data storage.
|
|
@@ -140,10 +143,17 @@ export default class ScrollPositionRestoration {
|
|
|
140
143
|
// this._scrollableContainerKeyCounter++;
|
|
141
144
|
// const scrollableContainerKey = String(this._scrollableContainerKeyCounter);
|
|
142
145
|
|
|
146
|
+
// Validate `scrollableContainerKey`.
|
|
143
147
|
if (scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
144
148
|
throw new Error(`Scrollable container key "${scrollableContainerKey}" is not allowed`);
|
|
145
149
|
}
|
|
146
150
|
|
|
151
|
+
// Check that it hasn't already been added.
|
|
152
|
+
if (this._scrollableContainers[scrollableContainerKey]) {
|
|
153
|
+
throw new Error(`Scrollable container key "${scrollableContainerKey}" is already added`);
|
|
154
|
+
}
|
|
155
|
+
debug('add scrollable container', scrollableContainerKey);
|
|
156
|
+
|
|
147
157
|
// Add scrollable container entry.
|
|
148
158
|
this._scrollableContainers[scrollableContainerKey] = {
|
|
149
159
|
// Scrollable container element.
|
|
@@ -173,8 +183,10 @@ export default class ScrollPositionRestoration {
|
|
|
173
183
|
if (this._location) {
|
|
174
184
|
const previouslySavedScrollPosition = this._getSavedScrollPositionForLocation(this._location, scrollableContainerKey);
|
|
175
185
|
if (previouslySavedScrollPosition) {
|
|
186
|
+
debug('restore scroll position on add scrollable container', this._location.pathname, scrollableContainerKey, previouslySavedScrollPosition);
|
|
176
187
|
this._scrollPosition.setScrollableContainerScrollPosition(scrollableContainer, previouslySavedScrollPosition);
|
|
177
188
|
} else {
|
|
189
|
+
debug('save scroll position on add scrollable container', this._location.pathname, scrollableContainerKey);
|
|
178
190
|
this._scrollPositionSaver.saveScrollableContainerScrollPosition(scrollableContainerKey, scrollableContainer);
|
|
179
191
|
}
|
|
180
192
|
}
|
|
@@ -184,6 +196,7 @@ export default class ScrollPositionRestoration {
|
|
|
184
196
|
|
|
185
197
|
// Removes the scrollable container.
|
|
186
198
|
return () => {
|
|
199
|
+
debug('remove scrollable container', scrollableContainerKey);
|
|
187
200
|
this._scrollPositionSaver._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(scrollableContainerKey);
|
|
188
201
|
this._scrollPositionSaver._scrollPositionAutoSaver.removeScrollableContainerScrollListener(scrollableContainerKey);
|
|
189
202
|
delete this._scrollableContainers[scrollableContainerKey];
|
|
@@ -242,14 +255,20 @@ export default class ScrollPositionRestoration {
|
|
|
242
255
|
//
|
|
243
256
|
// // Save the current scroll position on the current page while it's still rendered.
|
|
244
257
|
// // This saved scroll position could later be restored in case of returing to this page.
|
|
258
|
+
// // Even if the current scroll position is a default one (scrolled to top), it should still
|
|
259
|
+
// // be saved in order to overwrite any potential previously-saved non-default scroll position.
|
|
245
260
|
// this._scrollPositionSaver.saveScrollPosition();
|
|
246
261
|
// };
|
|
247
262
|
|
|
263
|
+
// Should be called whenever a different location has been rendered (i.e. immediately after).
|
|
264
|
+
// Returns a Promise that resolves when finished restoring scroll position.
|
|
265
|
+
// There's no need to await for that Promise. It's just there because it exists.
|
|
248
266
|
locationRendered(location) {
|
|
249
267
|
// Validate that `location` has a `key`.
|
|
250
268
|
if (!location.key) {
|
|
251
269
|
throw new Error('`location` must have a `key`');
|
|
252
270
|
}
|
|
271
|
+
debug('rendered location', location.pathname);
|
|
253
272
|
this._prevLocation = this._location;
|
|
254
273
|
this._location = location;
|
|
255
274
|
this._scrollPosition.init();
|
|
@@ -280,7 +299,7 @@ export default class ScrollPositionRestoration {
|
|
|
280
299
|
|
|
281
300
|
// Set the scroll position for the new page:
|
|
282
301
|
// either restore a previously-saved one or set it to a default scroll position.
|
|
283
|
-
this._setScrollPosition();
|
|
302
|
+
return this._setScrollPosition();
|
|
284
303
|
}
|
|
285
304
|
|
|
286
305
|
// Tells if the current scroll position is the default one.
|
|
@@ -299,8 +318,12 @@ export default class ScrollPositionRestoration {
|
|
|
299
318
|
}
|
|
300
319
|
return true;
|
|
301
320
|
}
|
|
321
|
+
|
|
322
|
+
// Restores scroll position.
|
|
323
|
+
// Returns a Promise that resolves when finished setting scroll position.
|
|
324
|
+
// There's no need to await for this Promise. It just exists.
|
|
302
325
|
_setScrollPosition() {
|
|
303
|
-
|
|
326
|
+
return Promise.all(Object.keys(this._scrollableContainers).map(scrollableContainerKey => {
|
|
304
327
|
const scrollableContainerEntry = this._scrollableContainers[scrollableContainerKey];
|
|
305
328
|
|
|
306
329
|
// This function is only used in tests.
|
|
@@ -308,7 +331,7 @@ export default class ScrollPositionRestoration {
|
|
|
308
331
|
// It's only used in tests.
|
|
309
332
|
if (scrollableContainerEntry._shouldUpdateScrollPositionForLocation) {
|
|
310
333
|
if (!scrollableContainerEntry._shouldUpdateScrollPositionForLocation(this._location, this._prevLocation)) {
|
|
311
|
-
|
|
334
|
+
return Promise.resolve();
|
|
312
335
|
}
|
|
313
336
|
}
|
|
314
337
|
|
|
@@ -326,10 +349,11 @@ export default class ScrollPositionRestoration {
|
|
|
326
349
|
if (!scrollPositionOrAnchorToSet) {
|
|
327
350
|
scrollPositionOrAnchorToSet = scrollableContainerKey === PAGE_SCROLLABLE_CONTAINER_KEY ? this._getPageScrollPositionOrAnchorToSet(this._location) : this._getScrollableContainerScrollPositionToSet(this._location, scrollableContainerKey);
|
|
328
351
|
}
|
|
352
|
+
debug('restore scroll position', this._location.pathname, scrollableContainerKey, scrollPositionOrAnchorToSet);
|
|
329
353
|
|
|
330
354
|
// Set scroll position of scrollable container.
|
|
331
|
-
scrollableContainerEntry.scrollPositionSetter.set(scrollableContainerEntry.scrollableContainer, scrollPositionOrAnchorToSet, this._scrollPosition);
|
|
332
|
-
}
|
|
355
|
+
return scrollableContainerEntry.scrollPositionSetter.set(scrollableContainerEntry.scrollableContainer, scrollPositionOrAnchorToSet, this._scrollPosition);
|
|
356
|
+
}));
|
|
333
357
|
}
|
|
334
358
|
_getSavedScrollPositionForLocation(location, scrollableContainerKey = PAGE_SCROLLABLE_CONTAINER_KEY) {
|
|
335
359
|
return this._locationDataStorage.get(location, scrollableContainerKey);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import ScrollPositionAutoSaver from './ScrollPositionAutoSaver';
|
|
4
4
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
5
|
+
import debug from '../debug';
|
|
5
6
|
export default class ScrollPositionSaver {
|
|
6
7
|
constructor({
|
|
7
8
|
scrollPosition,
|
|
@@ -36,6 +37,7 @@ export default class ScrollPositionSaver {
|
|
|
36
37
|
if (!this._shouldSaveScrollPosition()) {
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
40
|
+
debug('save scroll position', this._getLocation().pathname);
|
|
39
41
|
|
|
40
42
|
// Get scrollable containers.
|
|
41
43
|
const scrollableContainers = this._getScrollableContainers();
|
|
@@ -50,23 +52,27 @@ export default class ScrollPositionSaver {
|
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
savePageScrollPosition() {
|
|
55
|
+
debug('save scroll position', this._getLocation().pathname, PAGE_SCROLLABLE_CONTAINER_KEY, this._scrollPosition.getPageScrollPosition());
|
|
56
|
+
|
|
53
57
|
// * If this is not a scheduled "auto-save" of scroll position
|
|
54
58
|
// and there already exists any scheduled "auto-save" of scroll position,
|
|
55
59
|
// cancel it and save scroll position right now instead.
|
|
56
60
|
// * If this is a scheduled "auto-save" of scroll position,
|
|
57
61
|
// clear the "cancel" function because it's no longer of use.
|
|
58
|
-
this._scrollPositionAutoSaver.cancelSavePageScrollPosition();
|
|
62
|
+
this._scrollPositionAutoSaver.cancelSavePageScrollPosition(true);
|
|
59
63
|
|
|
60
64
|
// Save scroll position.
|
|
61
65
|
this._saveScrollPositionForLocation(this._getLocation(), undefined, this._scrollPosition.getPageScrollPosition());
|
|
62
66
|
}
|
|
63
67
|
saveScrollableContainerScrollPosition(scrollableContainerKey, scrollableContainer) {
|
|
68
|
+
debug('save scroll position', this._getLocation().pathname, scrollableContainerKey, this._scrollPosition.getScrollableContainerScrollPosition(scrollableContainer));
|
|
69
|
+
|
|
64
70
|
// * If this is not a scheduled "auto-save" of scroll position
|
|
65
71
|
// and there already exists any scheduled "auto-save" of scroll position,
|
|
66
72
|
// cancel it and save scroll position right now instead.
|
|
67
73
|
// * If this is a scheduled "auto-save" of scroll position,
|
|
68
74
|
// clear the "cancel" function because it's no longer of use.
|
|
69
|
-
this._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(scrollableContainerKey);
|
|
75
|
+
this._scrollPositionAutoSaver.cancelSaveScrollableContainerScrollPosition(scrollableContainerKey, true);
|
|
70
76
|
|
|
71
77
|
// Save scroll position.
|
|
72
78
|
this._saveScrollPositionForLocation(this._getLocation(), scrollableContainerKey, this._scrollPosition.getScrollableContainerScrollPosition(scrollableContainer));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import debug from '../debug';
|
|
1
2
|
import parseInputLocation from '../parseInputLocation';
|
|
2
3
|
import createSessionKey from './key/createSessionKey';
|
|
3
4
|
import NavigationOutOfBoundsError from './navigation/error/NavigationOutOfBoundsError';
|
|
@@ -51,6 +52,7 @@ export default class Session {
|
|
|
51
52
|
// but if it was possible, this call would be required. It would also be required
|
|
52
53
|
// by `navigation` to call `session.getNextKey()` function to increment `locationKeyIndex`.
|
|
53
54
|
this._updateTerminalLocationIndex(location);
|
|
55
|
+
debug('current location', location.pathname, 'index', this._currentLocationIndex);
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -90,6 +92,7 @@ export default class Session {
|
|
|
90
92
|
if (this._currentLocationIndex !== INITIAL_INDEX) {
|
|
91
93
|
throw new Error('Already started');
|
|
92
94
|
}
|
|
95
|
+
debug('▶ start session', initialLocation.pathname);
|
|
93
96
|
this._started = true;
|
|
94
97
|
const key = this._getNextLocationKey();
|
|
95
98
|
const index = INITIAL_INDEX + 1;
|
|
@@ -108,6 +111,7 @@ export default class Session {
|
|
|
108
111
|
if (this._stopped) {
|
|
109
112
|
throw Error('Already stopped');
|
|
110
113
|
}
|
|
114
|
+
debug('⏹ stop session');
|
|
111
115
|
|
|
112
116
|
// Once stopped, it won't be able to be restarted.
|
|
113
117
|
this._stopped = true;
|
|
@@ -133,6 +137,7 @@ export default class Session {
|
|
|
133
137
|
});
|
|
134
138
|
const key = this._getNextLocationKey();
|
|
135
139
|
const index = this._currentLocationIndex + delta;
|
|
140
|
+
debug(operation === NavigationOperations.PUSH ? '↓' : '⇅', operation, location.pathname, 'index', index);
|
|
136
141
|
|
|
137
142
|
// Navigate to the location.
|
|
138
143
|
const locationResult = this._navigation.navigate(location, {
|
|
@@ -155,6 +160,7 @@ export default class Session {
|
|
|
155
160
|
return;
|
|
156
161
|
}
|
|
157
162
|
const index = this._currentLocationIndex + delta;
|
|
163
|
+
debug(delta > 0 ? '→' : '←', 'shift', delta, 'index', index);
|
|
158
164
|
|
|
159
165
|
// Validate that the new `index` is not out of bounds.
|
|
160
166
|
if (index < 0 || index > this._terminalLocationIndex) {
|
package/lib/index.d.ts
CHANGED
|
@@ -35,22 +35,23 @@ export interface Location extends LocationBase {
|
|
|
35
35
|
* a unique key identifying the current history entry
|
|
36
36
|
*/
|
|
37
37
|
key: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* the current index of the history entry, starting at 0 for the initial
|
|
41
|
+
* entry; this increments on `.push()` but not on `.replace()`
|
|
42
|
+
*/
|
|
43
|
+
index: number;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
type PushOrReplaceOperation = '
|
|
46
|
+
type PushOrReplaceOperation = 'push' | 'replace';
|
|
41
47
|
|
|
42
48
|
export interface LocationInternal extends Location {
|
|
43
49
|
/**
|
|
44
50
|
* `navigation-stack` operation.
|
|
45
51
|
*/
|
|
46
|
-
operation: PushOrReplaceOperation | '
|
|
47
|
-
/**
|
|
48
|
-
* the current index of the history entry, starting at 0 for the initial
|
|
49
|
-
* entry; this increments on `.push()` but not on `.replace()`
|
|
50
|
-
*/
|
|
51
|
-
index: number;
|
|
52
|
+
operation: PushOrReplaceOperation | 'shift' | 'init';
|
|
52
53
|
/**
|
|
53
|
-
* the difference between the current
|
|
54
|
+
* the difference between the index of the current location and the index of the previous location.
|
|
54
55
|
*/
|
|
55
56
|
delta: number;
|
|
56
57
|
}
|
|
@@ -155,7 +156,7 @@ export class NavigationStack<ScrollableContainer = any, Anchor = any> {
|
|
|
155
156
|
|
|
156
157
|
shift(delta: number): void;
|
|
157
158
|
|
|
158
|
-
locationRendered(): void
|
|
159
|
+
locationRendered(): Promise<void>;
|
|
159
160
|
|
|
160
161
|
stop(): void;
|
|
161
162
|
}
|
|
@@ -29,7 +29,7 @@ export class ScrollPositionRestoration<
|
|
|
29
29
|
_getPageScrollPositionForLocation?: (
|
|
30
30
|
location: Location,
|
|
31
31
|
prevLocation: Location | undefined,
|
|
32
|
-
) =>
|
|
32
|
+
) => [number, number] | undefined;
|
|
33
33
|
|
|
34
34
|
// Using this option, a developer could theoretically provide their own implementation
|
|
35
35
|
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
@@ -61,7 +61,7 @@ export class ScrollPositionRestoration<
|
|
|
61
61
|
_getScrollPositionForLocation?: (
|
|
62
62
|
location: Location,
|
|
63
63
|
prevLocation: Location | undefined,
|
|
64
|
-
) =>
|
|
64
|
+
) => [number, number] | undefined;
|
|
65
65
|
|
|
66
66
|
// Using this option, a developer could theoretically provide their own implementation
|
|
67
67
|
// of setting a scroll position. For example, it could use "smooth" (animated) scrolling, etc.
|
|
@@ -70,7 +70,7 @@ export class ScrollPositionRestoration<
|
|
|
70
70
|
},
|
|
71
71
|
): () => void;
|
|
72
72
|
|
|
73
|
-
locationRendered: (location: Location) => void
|
|
73
|
+
locationRendered: (location: Location) => Promise<void>;
|
|
74
74
|
|
|
75
75
|
stop(): void;
|
|
76
76
|
|
package/package.json
CHANGED
package/src/NavigationStack.js
CHANGED
|
@@ -5,6 +5,15 @@ import createMiddlewares from './redux/createMiddlewares';
|
|
|
5
5
|
import locationReducer from './redux/locationReducer';
|
|
6
6
|
import ScrollPositionRestoration from './scroll-position/ScrollPositionRestoration';
|
|
7
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
|
+
|
|
8
17
|
export default class NavigationStack {
|
|
9
18
|
constructor(session, options) {
|
|
10
19
|
this._session = session;
|
|
@@ -12,7 +21,9 @@ export default class NavigationStack {
|
|
|
12
21
|
// Create a Redux store.
|
|
13
22
|
this._store = createStore(
|
|
14
23
|
locationReducer,
|
|
15
|
-
applyMiddleware(
|
|
24
|
+
applyMiddleware(
|
|
25
|
+
...createMiddlewares(session, getCreateMiddlewaresOptions(options)),
|
|
26
|
+
),
|
|
16
27
|
);
|
|
17
28
|
|
|
18
29
|
// Create `ScrollPositionRestoration`.
|
|
@@ -78,7 +89,12 @@ export default class NavigationStack {
|
|
|
78
89
|
|
|
79
90
|
locationRendered() {
|
|
80
91
|
if (this._scrollPositionRestoration) {
|
|
81
|
-
this.
|
|
92
|
+
const location = this.current();
|
|
93
|
+
if (!location) {
|
|
94
|
+
throw new Error('Not initialized');
|
|
95
|
+
}
|
|
96
|
+
return this._scrollPositionRestoration.locationRendered(location);
|
|
82
97
|
}
|
|
98
|
+
return Promise.resolve();
|
|
83
99
|
}
|
|
84
100
|
}
|
package/src/debug.js
ADDED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Converts `LocationInternal` object to a publicly-visible `Location` object.
|
|
2
|
-
// It hides non-essential properties of location such as `operation
|
|
2
|
+
// It hides non-essential properties of location such as `operation` and `delta`.
|
|
3
3
|
export default function getLocationFromInternalLocation(internalLocation) {
|
|
4
4
|
// eslint-disable-next-line no-unused-vars
|
|
5
|
-
const { operation,
|
|
5
|
+
const { operation, delta, ...location } = internalLocation;
|
|
6
6
|
return location;
|
|
7
7
|
}
|
|
@@ -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) {
|
|
@@ -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,6 +95,7 @@ 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();
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { PAGE_SCROLLABLE_CONTAINER_KEY } from './constants';
|
|
4
4
|
import scheduleNextTick from './scheduleNextTick';
|
|
5
|
+
import debug from '../debug';
|
|
5
6
|
|
|
6
7
|
export default class ScrollPositionAutoSaver {
|
|
7
8
|
constructor({
|
|
@@ -67,17 +68,26 @@ export default class ScrollPositionAutoSaver {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
cancelSavePageScrollPosition() {
|
|
71
|
+
cancelSavePageScrollPosition(hasRun) {
|
|
71
72
|
if (this._cancelSavePageScrollPosition) {
|
|
73
|
+
if (!hasRun) {
|
|
74
|
+
debug(
|
|
75
|
+
'cancel delayed save scroll position',
|
|
76
|
+
PAGE_SCROLLABLE_CONTAINER_KEY,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
72
79
|
this._cancelSavePageScrollPosition();
|
|
73
80
|
this._cancelSavePageScrollPosition = null;
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
cancelSaveScrollableContainerScrollPosition(scrollableContainerKey) {
|
|
84
|
+
cancelSaveScrollableContainerScrollPosition(scrollableContainerKey, hasRun) {
|
|
78
85
|
const scrollableContainerEntry =
|
|
79
86
|
this._getScrollableContainers()[scrollableContainerKey];
|
|
80
87
|
if (scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
88
|
+
if (!hasRun) {
|
|
89
|
+
debug('cancel delayed save scroll position', scrollableContainerKey);
|
|
90
|
+
}
|
|
81
91
|
scrollableContainerEntry.cancelSaveScrollPosition();
|
|
82
92
|
scrollableContainerEntry.cancelSaveScrollPosition = null;
|
|
83
93
|
}
|
|
@@ -117,8 +127,13 @@ export default class ScrollPositionAutoSaver {
|
|
|
117
127
|
// because there might be too many in a given short period of time
|
|
118
128
|
// which could affect the performance of the application.
|
|
119
129
|
if (!scrollableContainerEntry.cancelSaveScrollPosition) {
|
|
130
|
+
debug('scroll detected', scrollableContainerKey);
|
|
120
131
|
scrollableContainerEntry.cancelSaveScrollPosition =
|
|
121
132
|
scheduleNextTick(() => {
|
|
133
|
+
debug(
|
|
134
|
+
'auto-save scroll position after scroll',
|
|
135
|
+
scrollableContainerKey,
|
|
136
|
+
);
|
|
122
137
|
this._scrollPositionSaver.saveScrollableContainerScrollPosition(
|
|
123
138
|
scrollableContainerKey,
|
|
124
139
|
scrollableContainerEntry.scrollableContainer,
|
|
@@ -133,6 +148,8 @@ export default class ScrollPositionAutoSaver {
|
|
|
133
148
|
// Set up scroll listener on the page.
|
|
134
149
|
this._removePageScrollListener =
|
|
135
150
|
this._scrollPosition.addPageScrollListener(() => {
|
|
151
|
+
debug('scroll detected', PAGE_SCROLLABLE_CONTAINER_KEY);
|
|
152
|
+
|
|
136
153
|
// This flag is not used in real life and is only used in tests (for some reason).
|
|
137
154
|
if (!this._shouldSaveScrollPosition()) {
|
|
138
155
|
return;
|