navigation-stack 0.3.0 → 0.4.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/README.md +603 -163
- package/data-storage/package.json +6 -0
- package/karma.conf.cjs +21 -4
- package/lib/cjs/NavigationStack.js +73 -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/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 +25 -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 +130 -0
- package/lib/cjs/scroll-position/ScrollPositionRestoration.js +383 -0
- package/lib/cjs/scroll-position/ScrollPositionSaver.js +81 -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 +196 -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 +66 -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/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 +25 -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 +123 -0
- package/lib/esm/scroll-position/ScrollPositionRestoration.js +376 -0
- package/lib/esm/scroll-position/ScrollPositionSaver.js +74 -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 +189 -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 +178 -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 +84 -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/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 +28 -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 +151 -0
- package/src/scroll-position/ScrollPositionRestoration.js +506 -0
- package/src/scroll-position/ScrollPositionSaver.js +100 -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 +216 -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 +418 -0
- package/test/scroll-position/addScrollableContainer.js +36 -0
- package/test/scroll-position/addScrollableContainerWithHyperlink.js +50 -0
- package/test/scroll-position/createApp.js +112 -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/withScrollableContainerAtIndexPage.js +62 -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 +178 -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 -60
- 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 -53
- 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 -59
- 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,418 @@
|
|
|
1
|
+
import { offset, scrollLeft, scrollTop } from 'dom-helpers';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
|
|
4
|
+
import addScrollableContainer from './addScrollableContainer';
|
|
5
|
+
import addScrollableContainerWithHyperlink from './addScrollableContainerWithHyperlink';
|
|
6
|
+
import createApp from './createApp';
|
|
7
|
+
import delay from './delay';
|
|
8
|
+
import { setEventListener, triggerEvent } from './mockPageLifecycle';
|
|
9
|
+
import runApp from './runApp';
|
|
10
|
+
import withScrollableContainerAtIndexPage from './withScrollableContainerAtIndexPage';
|
|
11
|
+
import PageLifecycle from '../../src/session/lifecycle/page-lifecycle/PageLifecycleInstance';
|
|
12
|
+
|
|
13
|
+
describe('ScrollPositionRestoration', () => {
|
|
14
|
+
let unlisten;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
window.history.scrollRestoration = 'auto';
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
if (unlisten) {
|
|
22
|
+
unlisten();
|
|
23
|
+
}
|
|
24
|
+
sinon.restore();
|
|
25
|
+
setEventListener();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('sets/restores/resets `window.history.scrollRestoration` on freeze/resume', (done) => {
|
|
29
|
+
sinon.replace(PageLifecycle, 'addEventListener', setEventListener);
|
|
30
|
+
const app = createApp();
|
|
31
|
+
expect(window.history.scrollRestoration).to.equal('auto');
|
|
32
|
+
unlisten = runApp(app, [
|
|
33
|
+
() => {
|
|
34
|
+
expect(window.history.scrollRestoration).to.equal('manual');
|
|
35
|
+
triggerEvent('frozen', 'hidden');
|
|
36
|
+
expect(window.history.scrollRestoration).to.equal('manual');
|
|
37
|
+
triggerEvent('hidden', 'frozen');
|
|
38
|
+
expect(window.history.scrollRestoration).to.equal('auto');
|
|
39
|
+
triggerEvent('frozen', 'hidden');
|
|
40
|
+
expect(window.history.scrollRestoration).to.equal('manual');
|
|
41
|
+
done();
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('sets/restores `window.history.scrollRestoration` on termination', (done) => {
|
|
47
|
+
sinon.replace(PageLifecycle, 'addEventListener', setEventListener);
|
|
48
|
+
expect(window.history.scrollRestoration).to.equal('auto');
|
|
49
|
+
const app = createApp();
|
|
50
|
+
unlisten = runApp(app, [
|
|
51
|
+
() => {
|
|
52
|
+
expect(window.history.scrollRestoration).to.equal('manual');
|
|
53
|
+
triggerEvent('hidden', 'terminated');
|
|
54
|
+
expect(window.history.scrollRestoration).to.equal('auto');
|
|
55
|
+
done();
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('default behavior', () => {
|
|
61
|
+
it('should emulate browser scroll behavior', (done) => {
|
|
62
|
+
const app = addScrollableContainerWithHyperlink(createApp());
|
|
63
|
+
const child1 = document.getElementById('child1');
|
|
64
|
+
const child2 = document.getElementById('child2-id');
|
|
65
|
+
|
|
66
|
+
unlisten = runApp(app, [
|
|
67
|
+
() => {
|
|
68
|
+
// This will be ignored, but will exercise the throttle logic.
|
|
69
|
+
scrollTop(window, 10000);
|
|
70
|
+
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
scrollTop(window, 15000);
|
|
73
|
+
delay(() => {
|
|
74
|
+
app.goTo('/detail');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
() => {
|
|
79
|
+
expect(scrollTop(window)).to.equal(0);
|
|
80
|
+
scrollTop(window, 5000);
|
|
81
|
+
delay(app.goBack);
|
|
82
|
+
},
|
|
83
|
+
(location) => {
|
|
84
|
+
expect(location.state).to.not.exist();
|
|
85
|
+
// Here, it said "expected 14999.8330078125 to equal 15000".
|
|
86
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
87
|
+
expect(scrollTop(window)).to.be.closeTo(15000, 0.5);
|
|
88
|
+
app.goTo('/detail#child2');
|
|
89
|
+
},
|
|
90
|
+
() => {
|
|
91
|
+
expect(scrollTop(window)).to.be.closeTo(offset(child2).top, 2);
|
|
92
|
+
app.goTo('/detail#child1');
|
|
93
|
+
},
|
|
94
|
+
() => {
|
|
95
|
+
// Here, it said "expected 7.800000190734863 to equal 7.999997138977051".
|
|
96
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
97
|
+
expect(scrollTop(window)).to.be.closeTo(offset(child1).top, 0.5);
|
|
98
|
+
app.goTo('/detail#unknown-fragment');
|
|
99
|
+
},
|
|
100
|
+
() => {
|
|
101
|
+
expect(scrollTop(window)).to.equal(0);
|
|
102
|
+
done();
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should not crash when `window.history` is not available', (done) => {
|
|
108
|
+
Object.defineProperty(window.history, 'scrollRestoration', {
|
|
109
|
+
value: 'auto',
|
|
110
|
+
// See https://github.com/taion/scroll-behavior/issues/126
|
|
111
|
+
writable: false,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const app = addScrollableContainerWithHyperlink(createApp());
|
|
117
|
+
|
|
118
|
+
unlisten = runApp(app, [
|
|
119
|
+
() => {
|
|
120
|
+
expect(scrollTop(window)).to.equal(0);
|
|
121
|
+
|
|
122
|
+
delete window.history.scrollRestoration;
|
|
123
|
+
window.history.scrollRestoration = 'auto';
|
|
124
|
+
|
|
125
|
+
done();
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('custom behavior', () => {
|
|
132
|
+
it('should allow scroll suppression', (done) => {
|
|
133
|
+
const app = addScrollableContainerWithHyperlink(
|
|
134
|
+
createApp({
|
|
135
|
+
shouldUpdatePageScrollPositionForLocation: (
|
|
136
|
+
location,
|
|
137
|
+
prevLocation,
|
|
138
|
+
) => {
|
|
139
|
+
return (
|
|
140
|
+
!prevLocation || prevLocation.pathname !== location.pathname
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
unlisten = runApp(app, [
|
|
147
|
+
() => {
|
|
148
|
+
app.goTo('/detail');
|
|
149
|
+
},
|
|
150
|
+
() => {
|
|
151
|
+
scrollTop(window, 5000);
|
|
152
|
+
delay(() => {
|
|
153
|
+
app.goTo('/detail?key=value');
|
|
154
|
+
});
|
|
155
|
+
},
|
|
156
|
+
() => {
|
|
157
|
+
// Here, it said "expected 4999.7998046875 to equal 5000".
|
|
158
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
159
|
+
expect(scrollTop(window)).to.be.closeTo(5000, 0.5);
|
|
160
|
+
app.goTo('/');
|
|
161
|
+
},
|
|
162
|
+
() => {
|
|
163
|
+
expect(scrollTop(window)).to.equal(0);
|
|
164
|
+
done();
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should ignore scroll events when `disableSavingScrollPosition()` is used', (done) => {
|
|
170
|
+
const app = addScrollableContainerWithHyperlink(createApp());
|
|
171
|
+
|
|
172
|
+
unlisten = runApp(app, [
|
|
173
|
+
() => {
|
|
174
|
+
app.disableSavingScrollPosition();
|
|
175
|
+
scrollTop(window, 5000);
|
|
176
|
+
delay(() => {
|
|
177
|
+
app.goTo('/detail');
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
() => {
|
|
181
|
+
delay(() => {
|
|
182
|
+
app.goBack();
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
() => {
|
|
186
|
+
expect(scrollTop(window)).to.equal(0);
|
|
187
|
+
app.enableSavingScrollPosition();
|
|
188
|
+
scrollTop(window, 2000);
|
|
189
|
+
delay(() => {
|
|
190
|
+
app.goTo('/detail');
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
() => {
|
|
194
|
+
delay(() => {
|
|
195
|
+
app.goBack();
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
() => {
|
|
199
|
+
// Here, it said "expected 1999.8333740234375 to equal 2000".
|
|
200
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
201
|
+
expect(scrollTop(window)).to.be.closeTo(2000, 0.5);
|
|
202
|
+
done();
|
|
203
|
+
},
|
|
204
|
+
]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should allow custom position', (done) => {
|
|
208
|
+
const app = addScrollableContainerWithHyperlink(
|
|
209
|
+
createApp({
|
|
210
|
+
getPageScrollPositionForLocation: () => [10, 20],
|
|
211
|
+
}),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
unlisten = runApp(app, [
|
|
215
|
+
() => {
|
|
216
|
+
app.goTo('/detail');
|
|
217
|
+
},
|
|
218
|
+
() => {
|
|
219
|
+
app.goTo('/');
|
|
220
|
+
},
|
|
221
|
+
() => {
|
|
222
|
+
// Here, it said "expected 9.966666221618652 to equal 10".
|
|
223
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
224
|
+
expect(scrollLeft(window)).to.be.closeTo(10, 0.5);
|
|
225
|
+
// Here, it said "19.933332443237305 to equal 20".
|
|
226
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
227
|
+
expect(scrollTop(window)).to.be.closeTo(20, 0.5);
|
|
228
|
+
done();
|
|
229
|
+
},
|
|
230
|
+
]);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should save scroll position even if no scroll events are dispatched', (done) => {
|
|
234
|
+
let customInitialPageScrollPosition;
|
|
235
|
+
|
|
236
|
+
const app = addScrollableContainerWithHyperlink(
|
|
237
|
+
createApp({
|
|
238
|
+
// eslint-disable-next-line no-unused-vars
|
|
239
|
+
getPageScrollPositionForLocation(location, prevLocation) {
|
|
240
|
+
if (customInitialPageScrollPosition) {
|
|
241
|
+
return [10, 20];
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
},
|
|
245
|
+
}),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
unlisten = runApp(app, [
|
|
249
|
+
() => {
|
|
250
|
+
app.goTo('/detail');
|
|
251
|
+
},
|
|
252
|
+
() => {
|
|
253
|
+
customInitialPageScrollPosition = [10, 20];
|
|
254
|
+
app.goTo('/');
|
|
255
|
+
},
|
|
256
|
+
() => {
|
|
257
|
+
customInitialPageScrollPosition = undefined;
|
|
258
|
+
app.goTo('/detail');
|
|
259
|
+
},
|
|
260
|
+
() => {
|
|
261
|
+
app.goBack();
|
|
262
|
+
},
|
|
263
|
+
() => {
|
|
264
|
+
// Here, it said "expected 9.966666221618652 to equal 10".
|
|
265
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
266
|
+
expect(scrollLeft(window)).to.be.closeTo(10, 0.5);
|
|
267
|
+
// Here, it said "expected 19.933332443237305 to equal 20".
|
|
268
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
269
|
+
expect(scrollTop(window)).to.be.closeTo(20, 0.5);
|
|
270
|
+
done();
|
|
271
|
+
},
|
|
272
|
+
]);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe('scrollable container', () => {
|
|
277
|
+
it('should follow browser scroll behavior', (done) => {
|
|
278
|
+
const { container, ...app } = addScrollableContainer(
|
|
279
|
+
createApp({
|
|
280
|
+
shouldUpdatePageScrollPositionForLocation: () => false,
|
|
281
|
+
}),
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
unlisten = runApp(app, [
|
|
285
|
+
() => {
|
|
286
|
+
scrollTop(container, 10000);
|
|
287
|
+
delay(() => {
|
|
288
|
+
app.goTo('/other');
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
() => {
|
|
292
|
+
expect(scrollTop(container)).to.equal(0);
|
|
293
|
+
scrollTop(container, 5000);
|
|
294
|
+
delay(() => {
|
|
295
|
+
app.goBack();
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
() => {
|
|
299
|
+
// Here, it said "expected 10000.033203125 to equal 10000".
|
|
300
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
301
|
+
expect(scrollTop(container)).to.be.closeTo(10000, 0.5);
|
|
302
|
+
app.goTo('/other');
|
|
303
|
+
},
|
|
304
|
+
() => {
|
|
305
|
+
expect(scrollTop(container)).to.equal(0);
|
|
306
|
+
done();
|
|
307
|
+
},
|
|
308
|
+
]);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should restore scroll on remount', (done) => {
|
|
312
|
+
const { container, ...app } = withScrollableContainerAtIndexPage(
|
|
313
|
+
createApp({
|
|
314
|
+
shouldUpdatePageScrollPositionForLocation: () => false,
|
|
315
|
+
}),
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
unlisten = runApp(app, [
|
|
319
|
+
() => {
|
|
320
|
+
scrollTop(container, 10000);
|
|
321
|
+
delay(() => {
|
|
322
|
+
app.goTo('/other');
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
() => {
|
|
326
|
+
expect(container.scrollHeight).to.equal(100);
|
|
327
|
+
expect(scrollTop(container)).to.equal(0);
|
|
328
|
+
scrollTop(container, 5000);
|
|
329
|
+
delay(() => {
|
|
330
|
+
app.goBack();
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
() => {
|
|
334
|
+
expect(container.scrollHeight).to.equal(20000);
|
|
335
|
+
// Here, it said "expected 10000.033203125 to equal 10000".
|
|
336
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
337
|
+
expect(scrollTop(container)).to.be.closeTo(10000, 0.5);
|
|
338
|
+
done();
|
|
339
|
+
},
|
|
340
|
+
]);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('should save element scroll position on scroll event, i.e. before navigation is even attempted', (done) => {
|
|
344
|
+
const app1 = addScrollableContainer(
|
|
345
|
+
createApp({
|
|
346
|
+
shouldUpdatePageScrollPositionForLocation: () => false,
|
|
347
|
+
}),
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const unlisten1 = runApp(app1, [
|
|
351
|
+
() => {
|
|
352
|
+
expect(scrollTop(app1.container)).to.equal(0);
|
|
353
|
+
scrollTop(app1.container, 5000);
|
|
354
|
+
|
|
355
|
+
delay(() => {
|
|
356
|
+
unlisten1();
|
|
357
|
+
|
|
358
|
+
const app2 = addScrollableContainer(
|
|
359
|
+
createApp({
|
|
360
|
+
sessionKey: app1.getSessionKey(),
|
|
361
|
+
shouldUpdatePageScrollPositionForLocation: () => false,
|
|
362
|
+
}),
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
unlisten = app2.listen(() => {
|
|
366
|
+
delay(() => {
|
|
367
|
+
// Here, it said "expected 4999.7998046875 to equal 5000".
|
|
368
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
369
|
+
expect(scrollTop(app2.container)).to.be.closeTo(5000, 0.5);
|
|
370
|
+
done();
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
},
|
|
375
|
+
]);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should ignore scroll events when `disableSavingScrollPosition` is used', (done) => {
|
|
379
|
+
const app = addScrollableContainer(
|
|
380
|
+
addScrollableContainerWithHyperlink(createApp()),
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
unlisten = runApp(app, [
|
|
384
|
+
() => {
|
|
385
|
+
app.disableSavingScrollPosition();
|
|
386
|
+
scrollTop(app.container, 5432);
|
|
387
|
+
delay(() => {
|
|
388
|
+
app.goTo('/detail');
|
|
389
|
+
});
|
|
390
|
+
},
|
|
391
|
+
() => {
|
|
392
|
+
delay(() => {
|
|
393
|
+
app.goBack();
|
|
394
|
+
});
|
|
395
|
+
},
|
|
396
|
+
() => {
|
|
397
|
+
expect(scrollTop(app.container)).to.equal(0);
|
|
398
|
+
app.enableSavingScrollPosition();
|
|
399
|
+
scrollTop(app.container, 2000);
|
|
400
|
+
delay(() => {
|
|
401
|
+
app.goTo('/detail');
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
() => {
|
|
405
|
+
delay(() => {
|
|
406
|
+
app.goBack();
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
() => {
|
|
410
|
+
// Here, it said "expected 1999.8333740234375 to equal 2000".
|
|
411
|
+
// Using `.to.be.closeTo()` here instead of `.to.equal()` to work around this browser issue.
|
|
412
|
+
expect(scrollTop(app.container)).to.be.closeTo(2000, 0.5);
|
|
413
|
+
done();
|
|
414
|
+
},
|
|
415
|
+
]);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Adds a 100x100 scrollable container on the website, with a large amount of content
|
|
2
|
+
// inside it (20000x20000 to be specific), making the container scrollable.
|
|
3
|
+
export default function addScrollableContainer(app) {
|
|
4
|
+
// Create a scrollable container.
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.style.height = '100px';
|
|
7
|
+
container.style.width = '100px';
|
|
8
|
+
container.style.overflow = 'hidden';
|
|
9
|
+
|
|
10
|
+
// Put a large amount of content in the container, making it scrollable.
|
|
11
|
+
const element = document.createElement('div');
|
|
12
|
+
element.style.height = '20000px';
|
|
13
|
+
element.style.width = '20000px';
|
|
14
|
+
container.appendChild(element);
|
|
15
|
+
|
|
16
|
+
// Add the scrollable container to the website.
|
|
17
|
+
document.body.appendChild(container);
|
|
18
|
+
|
|
19
|
+
// This function will only be called once, so no need to guard.
|
|
20
|
+
function listen(listener) {
|
|
21
|
+
const unlisten = app.listen(listener);
|
|
22
|
+
|
|
23
|
+
app.registerScrollableContainer('container', container);
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
unlisten();
|
|
27
|
+
document.body.removeChild(container);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...app,
|
|
33
|
+
container,
|
|
34
|
+
listen,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Creates a scrollable container on the website.
|
|
2
|
+
//
|
|
3
|
+
// Puts a couple of child elements inside it:
|
|
4
|
+
// * One is just a simple child element, 100px in height.
|
|
5
|
+
// * Another is a clickable hyperlink to an unspecified location, 100px in height.
|
|
6
|
+
//
|
|
7
|
+
// * When the current location is "/", the scrollable container size is 20000x20000.
|
|
8
|
+
// * At any other location, the scrollable container size is 10000x10000.
|
|
9
|
+
//
|
|
10
|
+
export default function withRoutes(app) {
|
|
11
|
+
const container = document.createElement('div');
|
|
12
|
+
document.body.appendChild(container);
|
|
13
|
+
|
|
14
|
+
const child1 = document.createElement('div');
|
|
15
|
+
child1.id = 'child1';
|
|
16
|
+
child1.style.height = '100px';
|
|
17
|
+
container.appendChild(child1);
|
|
18
|
+
|
|
19
|
+
const child2 = document.createElement('a');
|
|
20
|
+
child2.id = 'child2-id';
|
|
21
|
+
child2.name = 'child2';
|
|
22
|
+
child2.style.height = '100px';
|
|
23
|
+
child2.appendChild(document.createTextNode('link'));
|
|
24
|
+
container.appendChild(child2);
|
|
25
|
+
|
|
26
|
+
// This function will only be called once, so no need to guard.
|
|
27
|
+
function listen(listener) {
|
|
28
|
+
const unlisten = app.listen((location) => {
|
|
29
|
+
listener(location);
|
|
30
|
+
|
|
31
|
+
if (location.pathname === '/') {
|
|
32
|
+
container.style.height = '20000px';
|
|
33
|
+
container.style.width = '20000px';
|
|
34
|
+
} else {
|
|
35
|
+
container.style.height = '10000px';
|
|
36
|
+
container.style.width = '10000px';
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return () => {
|
|
41
|
+
unlisten();
|
|
42
|
+
document.body.removeChild(container);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...app,
|
|
48
|
+
listen,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import NavigationStack from '../../src/NavigationStack';
|
|
2
|
+
import ScrollPositionRestoration from '../../src/scroll-position/ScrollPositionRestoration';
|
|
3
|
+
import WebBrowserSession from '../../src/session/WebBrowserSession';
|
|
4
|
+
|
|
5
|
+
// Creates a website with `ScrollPositionRestoration`.
|
|
6
|
+
export default function createApp({
|
|
7
|
+
sessionKey,
|
|
8
|
+
shouldUpdatePageScrollPositionForLocation,
|
|
9
|
+
getPageScrollPositionForLocation,
|
|
10
|
+
} = {}) {
|
|
11
|
+
let currentLocation = null;
|
|
12
|
+
|
|
13
|
+
let listeners = [];
|
|
14
|
+
let scrollPositionRestoration = null;
|
|
15
|
+
let navigationStack = null;
|
|
16
|
+
let session = null;
|
|
17
|
+
|
|
18
|
+
function onLocationDidChange(location) {
|
|
19
|
+
// const prevLocation = currentLocation;
|
|
20
|
+
currentLocation = location;
|
|
21
|
+
|
|
22
|
+
listeners.forEach((listener) => {
|
|
23
|
+
listener(location);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
scrollPositionRestoration.locationRendered(location);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Removes a "location change" event listener.
|
|
30
|
+
let unlisten = null;
|
|
31
|
+
|
|
32
|
+
// Adds a "location change" event listener.
|
|
33
|
+
// A "location change" event happens at every navigation: `goTo()` or `goBack()`,
|
|
34
|
+
// An initial "location change" event happens at startup.
|
|
35
|
+
function listen(listener) {
|
|
36
|
+
// Create a `WebBrowserSession`, `NavigationStack` and `ScrollPositionRestoration`
|
|
37
|
+
// at the initial call of the `app.listen()` function.
|
|
38
|
+
if (listeners.length > 0) {
|
|
39
|
+
throw new Error('Only one `listener` is allowed in tests');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
session = new WebBrowserSession();
|
|
43
|
+
// There's this one test that restores data of a session of a previous app
|
|
44
|
+
// and for that the new session just has to have the same key in order to read
|
|
45
|
+
// the previous app's session data from the environment storage.
|
|
46
|
+
if (sessionKey) {
|
|
47
|
+
session.key = sessionKey;
|
|
48
|
+
}
|
|
49
|
+
navigationStack = new NavigationStack(session);
|
|
50
|
+
scrollPositionRestoration = new ScrollPositionRestoration(session, {
|
|
51
|
+
_shouldUpdatePageScrollPositionForLocation:
|
|
52
|
+
shouldUpdatePageScrollPositionForLocation,
|
|
53
|
+
_getPageScrollPositionForLocation: getPageScrollPositionForLocation,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
unlisten = navigationStack.subscribe(onLocationDidChange);
|
|
57
|
+
|
|
58
|
+
listeners.push(listener);
|
|
59
|
+
|
|
60
|
+
navigationStack.init(currentLocation);
|
|
61
|
+
|
|
62
|
+
return () => {
|
|
63
|
+
listeners = listeners.filter((item) => item !== listener);
|
|
64
|
+
|
|
65
|
+
if (listeners.length === 0) {
|
|
66
|
+
// `navigationStack.stop()` automatically calls `session.stop()`
|
|
67
|
+
// so there's no requirement to call `session.stop()` explicitly here.
|
|
68
|
+
navigationStack.stop();
|
|
69
|
+
scrollPositionRestoration.stop();
|
|
70
|
+
unlisten();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Registers a scrollable container on a page.
|
|
76
|
+
function registerScrollableContainer(key, element, options) {
|
|
77
|
+
return scrollPositionRestoration.addScrollableContainer(key, element, {
|
|
78
|
+
_shouldUpdateScrollPositionForLocation:
|
|
79
|
+
options && options.shouldUpdateScrollPositionForLocation,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function disableSavingScrollPosition() {
|
|
84
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
85
|
+
scrollPositionRestoration._disableSavingScrollPosition();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function enableSavingScrollPosition() {
|
|
89
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
90
|
+
scrollPositionRestoration._enableSavingScrollPosition();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Navigates to a new location.
|
|
94
|
+
const goTo = (location) => {
|
|
95
|
+
navigationStack.push(location);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Navigates to a previous location.
|
|
99
|
+
const goBack = () => {
|
|
100
|
+
navigationStack.shift(-1);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
goTo,
|
|
105
|
+
goBack,
|
|
106
|
+
listen,
|
|
107
|
+
registerScrollableContainer,
|
|
108
|
+
disableSavingScrollPosition,
|
|
109
|
+
enableSavingScrollPosition,
|
|
110
|
+
getSessionKey: () => session.key,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Simulates `PageLifecycle` events.
|
|
2
|
+
|
|
3
|
+
let listener;
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
export const setEventListener = (eventType, callback) => {
|
|
7
|
+
listener = callback;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const triggerEvent = (oldState, newState) => {
|
|
11
|
+
if (listener) {
|
|
12
|
+
const event = new Event('statechange');
|
|
13
|
+
event.newState = newState;
|
|
14
|
+
event.oldState = oldState;
|
|
15
|
+
listener(event);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import delay from './delay';
|
|
2
|
+
|
|
3
|
+
// Runs the website.
|
|
4
|
+
// Executes the `steps` in order.
|
|
5
|
+
// Every step, except for the last one, must end with navigation: `goTo()` or `goBack()`,
|
|
6
|
+
// otherwise the application wouldn't reach the last step and would just freeze after the incorrect step.
|
|
7
|
+
export default function runApp(app, steps) {
|
|
8
|
+
window.history.replaceState(null, null, '/');
|
|
9
|
+
|
|
10
|
+
let i = 0;
|
|
11
|
+
|
|
12
|
+
return app.listen((location) => {
|
|
13
|
+
if (i === steps.length) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Wait a extra tick for all the scroll callbacks to fire before checking
|
|
18
|
+
// position.
|
|
19
|
+
delay(() => {
|
|
20
|
+
steps[i](location);
|
|
21
|
+
i++;
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|