vscroll 1.4.1 → 1.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/LICENSE +1 -1
- package/README.md +17 -16
- package/dist/bundles/vscroll.esm5.js +403 -321
- package/dist/bundles/vscroll.esm5.js.map +1 -1
- package/dist/bundles/vscroll.esm5.min.js +2 -2
- package/dist/bundles/vscroll.esm5.min.js.map +1 -1
- package/dist/bundles/vscroll.esm6.js +310 -244
- package/dist/bundles/vscroll.esm6.js.map +1 -1
- package/dist/bundles/vscroll.esm6.min.js +2 -2
- package/dist/bundles/vscroll.esm6.min.js.map +1 -1
- package/dist/bundles/vscroll.umd.js +404 -322
- package/dist/bundles/vscroll.umd.js.map +1 -1
- package/dist/bundles/vscroll.umd.min.js +2 -2
- package/dist/bundles/vscroll.umd.min.js.map +1 -1
- package/dist/esm2015/classes/domRoutines.js +101 -66
- package/dist/esm2015/classes/domRoutines.js.map +1 -1
- package/dist/esm2015/classes/logger.js +2 -2
- package/dist/esm2015/classes/logger.js.map +1 -1
- package/dist/esm2015/classes/paddings.js +5 -5
- package/dist/esm2015/classes/paddings.js.map +1 -1
- package/dist/esm2015/classes/state/cycle.js +7 -6
- package/dist/esm2015/classes/state/cycle.js.map +1 -1
- package/dist/esm2015/classes/state/render.js +1 -1
- package/dist/esm2015/classes/state/render.js.map +1 -1
- package/dist/esm2015/classes/state/scroll.js +6 -6
- package/dist/esm2015/classes/state/scroll.js.map +1 -1
- package/dist/esm2015/classes/state.js +23 -15
- package/dist/esm2015/classes/state.js.map +1 -1
- package/dist/esm2015/classes/viewport.js +13 -22
- package/dist/esm2015/classes/viewport.js.map +1 -1
- package/dist/esm2015/index.js.map +1 -1
- package/dist/esm2015/interfaces/index.js.map +1 -1
- package/dist/esm2015/interfaces/routines.js +2 -0
- package/dist/esm2015/interfaces/routines.js.map +1 -0
- package/dist/esm2015/interfaces/state.js.map +1 -1
- package/dist/esm2015/interfaces/workflow.js.map +1 -1
- package/dist/esm2015/processes/adapter/reload.js +1 -1
- package/dist/esm2015/processes/adapter/reload.js.map +1 -1
- package/dist/esm2015/processes/adjust.js +44 -15
- package/dist/esm2015/processes/adjust.js.map +1 -1
- package/dist/esm2015/processes/end.js +18 -16
- package/dist/esm2015/processes/end.js.map +1 -1
- package/dist/esm2015/processes/fetch.js +3 -3
- package/dist/esm2015/processes/fetch.js.map +1 -1
- package/dist/esm2015/processes/init.js +2 -2
- package/dist/esm2015/processes/init.js.map +1 -1
- package/dist/esm2015/processes/render.js +6 -6
- package/dist/esm2015/processes/render.js.map +1 -1
- package/dist/esm2015/processes/scroll.js +21 -21
- package/dist/esm2015/processes/scroll.js.map +1 -1
- package/dist/esm2015/scroller.js +4 -4
- package/dist/esm2015/scroller.js.map +1 -1
- package/dist/esm2015/version.js +1 -1
- package/dist/esm2015/version.js.map +1 -1
- package/dist/esm2015/workflow.js +9 -8
- package/dist/esm2015/workflow.js.map +1 -1
- package/dist/esm5/classes/adapter.js +4 -4
- package/dist/esm5/classes/adapter.js.map +1 -1
- package/dist/esm5/classes/buffer/cache.js +1 -1
- package/dist/esm5/classes/buffer/cache.js.map +1 -1
- package/dist/esm5/classes/buffer/checkCall.js +4 -4
- package/dist/esm5/classes/buffer/checkCall.js.map +1 -1
- package/dist/esm5/classes/buffer.js +3 -3
- package/dist/esm5/classes/buffer.js.map +1 -1
- package/dist/esm5/classes/domRoutines.js +115 -66
- package/dist/esm5/classes/domRoutines.js.map +1 -1
- package/dist/esm5/classes/logger.js +21 -21
- package/dist/esm5/classes/logger.js.map +1 -1
- package/dist/esm5/classes/paddings.js +5 -5
- package/dist/esm5/classes/paddings.js.map +1 -1
- package/dist/esm5/classes/state/cycle.js +9 -8
- package/dist/esm5/classes/state/cycle.js.map +1 -1
- package/dist/esm5/classes/state/render.js +1 -1
- package/dist/esm5/classes/state/render.js.map +1 -1
- package/dist/esm5/classes/state/scroll.js +11 -11
- package/dist/esm5/classes/state/scroll.js.map +1 -1
- package/dist/esm5/classes/state.js +23 -15
- package/dist/esm5/classes/state.js.map +1 -1
- package/dist/esm5/classes/viewport.js +14 -23
- package/dist/esm5/classes/viewport.js.map +1 -1
- package/dist/esm5/index.js.map +1 -1
- package/dist/esm5/inputs/validation.js +4 -4
- package/dist/esm5/inputs/validation.js.map +1 -1
- package/dist/esm5/interfaces/index.js.map +1 -1
- package/dist/esm5/interfaces/routines.js +2 -0
- package/dist/esm5/interfaces/routines.js.map +1 -0
- package/dist/esm5/interfaces/state.js.map +1 -1
- package/dist/esm5/interfaces/workflow.js.map +1 -1
- package/dist/esm5/processes/adapter/reload.js +1 -1
- package/dist/esm5/processes/adapter/reload.js.map +1 -1
- package/dist/esm5/processes/adapter/remove.js +1 -1
- package/dist/esm5/processes/adapter/remove.js.map +1 -1
- package/dist/esm5/processes/adjust.js +48 -19
- package/dist/esm5/processes/adjust.js.map +1 -1
- package/dist/esm5/processes/clip.js +5 -5
- package/dist/esm5/processes/clip.js.map +1 -1
- package/dist/esm5/processes/end.js +18 -16
- package/dist/esm5/processes/end.js.map +1 -1
- package/dist/esm5/processes/fetch.js +5 -5
- package/dist/esm5/processes/fetch.js.map +1 -1
- package/dist/esm5/processes/init.js +2 -2
- package/dist/esm5/processes/init.js.map +1 -1
- package/dist/esm5/processes/misc/base.js +1 -1
- package/dist/esm5/processes/misc/base.js.map +1 -1
- package/dist/esm5/processes/preClip.js +2 -2
- package/dist/esm5/processes/preClip.js.map +1 -1
- package/dist/esm5/processes/preFetch.js +5 -5
- package/dist/esm5/processes/preFetch.js.map +1 -1
- package/dist/esm5/processes/render.js +6 -6
- package/dist/esm5/processes/render.js.map +1 -1
- package/dist/esm5/processes/scroll.js +22 -22
- package/dist/esm5/processes/scroll.js.map +1 -1
- package/dist/esm5/scroller.js +5 -5
- package/dist/esm5/scroller.js.map +1 -1
- package/dist/esm5/version.js +1 -1
- package/dist/esm5/version.js.map +1 -1
- package/dist/esm5/workflow.js +15 -12
- package/dist/esm5/workflow.js.map +1 -1
- package/dist/typings/classes/domRoutines.d.ts +23 -18
- package/dist/typings/classes/logger.d.ts +1 -1
- package/dist/typings/classes/paddings.d.ts +2 -2
- package/dist/typings/classes/state/cycle.d.ts +1 -1
- package/dist/typings/classes/state/render.d.ts +1 -1
- package/dist/typings/classes/state/scroll.d.ts +4 -4
- package/dist/typings/classes/state.d.ts +6 -3
- package/dist/typings/classes/viewport.d.ts +2 -4
- package/dist/typings/index.d.ts +2 -2
- package/dist/typings/interfaces/index.d.ts +3 -2
- package/dist/typings/interfaces/routines.d.ts +157 -0
- package/dist/typings/interfaces/state.d.ts +2 -15
- package/dist/typings/interfaces/workflow.d.ts +3 -0
- package/dist/typings/processes/adjust.d.ts +1 -0
- package/dist/typings/processes/end.d.ts +1 -2
- package/dist/typings/scroller.d.ts +1 -1
- package/dist/typings/workflow.d.ts +2 -2
- package/package.json +18 -17
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vscroll (https://github.com/dhilt/vscroll) FESM2015
|
|
3
|
-
* Version: 1.
|
|
3
|
+
* Version: 1.5.0 (2022-02-02T15:07:21.893Z)
|
|
4
4
|
* Author: Denis Hilt
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
@@ -328,7 +328,7 @@ const reactiveConfigStorage = new Map();
|
|
|
328
328
|
|
|
329
329
|
var core = {
|
|
330
330
|
name: 'vscroll',
|
|
331
|
-
version: '1.
|
|
331
|
+
version: '1.5.0'
|
|
332
332
|
};
|
|
333
333
|
|
|
334
334
|
let instanceCount$1 = 0;
|
|
@@ -1276,10 +1276,10 @@ const BaseAdapterProcessFactory = (process) => { var _a; return _a = class BaseA
|
|
|
1276
1276
|
const initProcesses = [CommonProcess.init, AdapterProcess.reset, AdapterProcess.reload];
|
|
1277
1277
|
class Init extends BaseProcessFactory(CommonProcess.init) {
|
|
1278
1278
|
static run(scroller, process) {
|
|
1279
|
-
const { state
|
|
1279
|
+
const { state, workflow } = scroller;
|
|
1280
1280
|
const isInitial = initProcesses.includes(process);
|
|
1281
1281
|
scroller.logger.logCycle(true);
|
|
1282
|
-
|
|
1282
|
+
state.startWorkflowCycle(isInitial, process);
|
|
1283
1283
|
workflow.call({
|
|
1284
1284
|
process: Init.process,
|
|
1285
1285
|
status: ProcessStatus.next
|
|
@@ -1298,15 +1298,15 @@ class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
|
|
|
1298
1298
|
Scroll.onThrottle(scroller, position, () => Scroll.onScroll(scroller, workflow));
|
|
1299
1299
|
}
|
|
1300
1300
|
static onSynthetic(scroller, position) {
|
|
1301
|
-
const {
|
|
1302
|
-
const synthPos =
|
|
1301
|
+
const { scroll } = scroller.state;
|
|
1302
|
+
const synthPos = scroll.syntheticPosition;
|
|
1303
1303
|
if (synthPos !== null) {
|
|
1304
|
-
if (
|
|
1305
|
-
|
|
1304
|
+
if (scroll.syntheticFulfill) {
|
|
1305
|
+
scroll.syntheticPosition = null;
|
|
1306
1306
|
}
|
|
1307
|
-
if (!
|
|
1307
|
+
if (!scroll.syntheticFulfill || synthPos === position) {
|
|
1308
1308
|
scroller.logger.log(() => [
|
|
1309
|
-
'skipping scroll', position, `[${
|
|
1309
|
+
'skipping scroll', position, `[${scroll.syntheticFulfill ? '' : 'pre-'}synthetic]`
|
|
1310
1310
|
]);
|
|
1311
1311
|
return true;
|
|
1312
1312
|
}
|
|
@@ -1317,13 +1317,13 @@ class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
|
|
|
1317
1317
|
return false;
|
|
1318
1318
|
}
|
|
1319
1319
|
static onThrottle(scroller, position, done) {
|
|
1320
|
-
const { state: {
|
|
1321
|
-
|
|
1322
|
-
const { direction, time } =
|
|
1323
|
-
const timeDiff =
|
|
1320
|
+
const { state: { scroll }, settings: { throttle }, logger } = scroller;
|
|
1321
|
+
scroll.current = Scroll.getScrollEvent(position, scroll.previous);
|
|
1322
|
+
const { direction, time } = scroll.current;
|
|
1323
|
+
const timeDiff = scroll.previous ? time - scroll.previous.time : Infinity;
|
|
1324
1324
|
const delta = throttle - timeDiff;
|
|
1325
1325
|
const shouldDelay = isFinite(delta) && delta > 0;
|
|
1326
|
-
const alreadyDelayed = !!
|
|
1326
|
+
const alreadyDelayed = !!scroll.scrollTimer;
|
|
1327
1327
|
logger.log(() => [
|
|
1328
1328
|
direction === Direction.backward ? '\u2934' : '\u2935',
|
|
1329
1329
|
position,
|
|
@@ -1331,17 +1331,17 @@ class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
|
|
|
1331
1331
|
shouldDelay ? (alreadyDelayed ? 'delayed' : `/ ${delta}ms delay`) : ''
|
|
1332
1332
|
]);
|
|
1333
1333
|
if (!shouldDelay) {
|
|
1334
|
-
if (
|
|
1335
|
-
clearTimeout(
|
|
1336
|
-
|
|
1334
|
+
if (scroll.scrollTimer) {
|
|
1335
|
+
clearTimeout(scroll.scrollTimer);
|
|
1336
|
+
scroll.scrollTimer = null;
|
|
1337
1337
|
}
|
|
1338
1338
|
done();
|
|
1339
1339
|
return;
|
|
1340
1340
|
}
|
|
1341
1341
|
if (!alreadyDelayed) {
|
|
1342
|
-
|
|
1342
|
+
scroll.scrollTimer = setTimeout(() => {
|
|
1343
1343
|
logger.log(() => {
|
|
1344
|
-
const curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition,
|
|
1344
|
+
const curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scroll.current);
|
|
1345
1345
|
return [
|
|
1346
1346
|
curr.direction === Direction.backward ? '\u2934' : '\u2935',
|
|
1347
1347
|
curr.position,
|
|
@@ -1350,7 +1350,7 @@ class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
|
|
|
1350
1350
|
position
|
|
1351
1351
|
];
|
|
1352
1352
|
});
|
|
1353
|
-
|
|
1353
|
+
scroll.scrollTimer = null;
|
|
1354
1354
|
done();
|
|
1355
1355
|
}, delta);
|
|
1356
1356
|
}
|
|
@@ -1369,11 +1369,11 @@ class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
|
|
|
1369
1369
|
return { position, direction, time };
|
|
1370
1370
|
}
|
|
1371
1371
|
static onScroll(scroller, workflow) {
|
|
1372
|
-
const { state: {
|
|
1373
|
-
|
|
1374
|
-
|
|
1372
|
+
const { state: { scroll, cycle } } = scroller;
|
|
1373
|
+
scroll.previous = Object.assign({}, scroll.current);
|
|
1374
|
+
scroll.current = null;
|
|
1375
1375
|
if (cycle.busy.get()) {
|
|
1376
|
-
scroller.logger.log(() => ['skipping scroll',
|
|
1376
|
+
scroller.logger.log(() => ['skipping scroll', scroll.previous.position, '[pending]']);
|
|
1377
1377
|
return;
|
|
1378
1378
|
}
|
|
1379
1379
|
workflow.call({
|
|
@@ -1424,7 +1424,7 @@ class Reload extends BaseAdapterProcessFactory(AdapterProcess.reload) {
|
|
|
1424
1424
|
viewport.reset(buffer.startIndex);
|
|
1425
1425
|
const payload = {};
|
|
1426
1426
|
if (state.cycle.busy.get()) {
|
|
1427
|
-
state.
|
|
1427
|
+
state.scroll.stop();
|
|
1428
1428
|
payload.finalize = true;
|
|
1429
1429
|
state.cycle.interrupter = Reload.process;
|
|
1430
1430
|
}
|
|
@@ -2183,9 +2183,9 @@ class Fetch extends BaseProcessFactory(CommonProcess.fetch) {
|
|
|
2183
2183
|
}
|
|
2184
2184
|
}
|
|
2185
2185
|
else {
|
|
2186
|
-
const { state: {
|
|
2187
|
-
if (
|
|
2188
|
-
|
|
2186
|
+
const { state: { scroll, fetch }, viewport } = scroller;
|
|
2187
|
+
if (scroll.positionBeforeAsync === null) {
|
|
2188
|
+
scroll.positionBeforeAsync = viewport.scrollPosition;
|
|
2189
2189
|
}
|
|
2190
2190
|
fetch.cancel = () => {
|
|
2191
2191
|
box.success = () => null;
|
|
@@ -2305,13 +2305,13 @@ class PostFetch extends BaseProcessFactory(CommonProcess.postFetch) {
|
|
|
2305
2305
|
|
|
2306
2306
|
class Render extends BaseProcessFactory(CommonProcess.render) {
|
|
2307
2307
|
static run(scroller) {
|
|
2308
|
-
const { workflow, state: { cycle, render,
|
|
2308
|
+
const { workflow, state: { cycle, render, scroll }, viewport, routines } = scroller;
|
|
2309
2309
|
scroller.logger.stat('before new items render');
|
|
2310
|
-
if (
|
|
2311
|
-
|
|
2310
|
+
if (scroll.positionBeforeAsync === null) {
|
|
2311
|
+
scroll.positionBeforeAsync = viewport.scrollPosition;
|
|
2312
2312
|
}
|
|
2313
|
-
render.
|
|
2314
|
-
render.
|
|
2313
|
+
render.cancel = routines.render(() => {
|
|
2314
|
+
render.cancel = null;
|
|
2315
2315
|
if (Render.doRender(scroller)) {
|
|
2316
2316
|
workflow.call({
|
|
2317
2317
|
process: Render.process,
|
|
@@ -2326,7 +2326,7 @@ class Render extends BaseProcessFactory(CommonProcess.render) {
|
|
|
2326
2326
|
payload: { error: 'Can\'t associate item with element' }
|
|
2327
2327
|
});
|
|
2328
2328
|
}
|
|
2329
|
-
}
|
|
2329
|
+
});
|
|
2330
2330
|
}
|
|
2331
2331
|
static doRender(scroller) {
|
|
2332
2332
|
const { state: { fetch, render }, viewport, buffer, logger } = scroller;
|
|
@@ -2357,14 +2357,79 @@ class Render extends BaseProcessFactory(CommonProcess.render) {
|
|
|
2357
2357
|
}
|
|
2358
2358
|
}
|
|
2359
2359
|
|
|
2360
|
+
const isInterrupted = ({ call }) => !!call.interrupted;
|
|
2361
|
+
class End extends BaseProcessFactory(CommonProcess.end) {
|
|
2362
|
+
static run(scroller, { error } = {}) {
|
|
2363
|
+
const { workflow, state: { cycle: { interrupter } } } = scroller;
|
|
2364
|
+
if (!error && !interrupter) {
|
|
2365
|
+
// set out params accessible via Adapter
|
|
2366
|
+
End.calculateParams(scroller, workflow);
|
|
2367
|
+
}
|
|
2368
|
+
// explicit interruption for we don't want to go through the inner loop finalizing
|
|
2369
|
+
if (isInterrupted(workflow)) {
|
|
2370
|
+
workflow.call({ process: End.process, status: ProcessStatus.done });
|
|
2371
|
+
return;
|
|
2372
|
+
}
|
|
2373
|
+
const next = End.shouldContinueRun(scroller, error);
|
|
2374
|
+
scroller.state.endInnerLoop();
|
|
2375
|
+
workflow.call({
|
|
2376
|
+
process: End.process,
|
|
2377
|
+
status: next ? ProcessStatus.next : ProcessStatus.done,
|
|
2378
|
+
payload: Object.assign({}, (interrupter ? { process: interrupter } : {}))
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
static calculateParams(scroller, workflow) {
|
|
2382
|
+
const { adapter, viewport, buffer: { items } } = scroller;
|
|
2383
|
+
if (adapter.wanted.firstVisible) {
|
|
2384
|
+
const { item } = viewport.getEdgeVisibleItem(items, Direction.backward);
|
|
2385
|
+
if (!item || item.element !== adapter.firstVisible.element) {
|
|
2386
|
+
adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
// the workflow can be interrupter on firstVisible change
|
|
2390
|
+
if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
|
|
2391
|
+
const { item } = viewport.getEdgeVisibleItem(items, Direction.forward);
|
|
2392
|
+
if (!item || item.element !== adapter.lastVisible.element) {
|
|
2393
|
+
adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
static shouldContinueRun(scroller, error) {
|
|
2398
|
+
const { cycle, fetch, render } = scroller.state;
|
|
2399
|
+
// Adapter.reload or Adapter.reset
|
|
2400
|
+
if (cycle.interrupter) {
|
|
2401
|
+
return true;
|
|
2402
|
+
}
|
|
2403
|
+
// critical error
|
|
2404
|
+
if (error) {
|
|
2405
|
+
return false;
|
|
2406
|
+
}
|
|
2407
|
+
// Adapter.check
|
|
2408
|
+
if (fetch.simulate && fetch.isCheck && !render.noSize) {
|
|
2409
|
+
return true;
|
|
2410
|
+
}
|
|
2411
|
+
// Adapter.remove or Adapter.update with clip
|
|
2412
|
+
if (fetch.simulate && fetch.doRemove) {
|
|
2413
|
+
return true;
|
|
2414
|
+
}
|
|
2415
|
+
// common inner loop (App start, scroll, Adapter.clip) with full fetch
|
|
2416
|
+
if (!fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
|
|
2417
|
+
return true;
|
|
2418
|
+
}
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2360
2423
|
class Adjust extends BaseProcessFactory(CommonProcess.adjust) {
|
|
2361
2424
|
static run(scroller) {
|
|
2362
|
-
const { workflow, viewport, state: {
|
|
2363
|
-
|
|
2425
|
+
const { workflow, viewport, state: { scroll } } = scroller;
|
|
2426
|
+
scroll.positionBeforeAdjust = viewport.scrollPosition;
|
|
2364
2427
|
Adjust.setPaddings(scroller);
|
|
2365
|
-
|
|
2428
|
+
scroll.positionAfterAdjust = viewport.scrollPosition;
|
|
2366
2429
|
// scroll position adjustments
|
|
2367
2430
|
const position = Adjust.calculatePosition(scroller);
|
|
2431
|
+
// additional adjustment if the position can't be reached during the initial cycle
|
|
2432
|
+
Adjust.setAdditionalForwardPadding(scroller, position);
|
|
2368
2433
|
// set new position using animation frame
|
|
2369
2434
|
Adjust.setPosition(scroller, position, () => workflow.call({
|
|
2370
2435
|
process: Adjust.process,
|
|
@@ -2395,7 +2460,8 @@ class Adjust extends BaseProcessFactory(CommonProcess.adjust) {
|
|
|
2395
2460
|
}
|
|
2396
2461
|
// lack of items case
|
|
2397
2462
|
const bufferSize = viewport.getScrollableSize() - forward.size - backward.size;
|
|
2398
|
-
const
|
|
2463
|
+
const scrollSize = bwdSize + bufferSize + fwdSize;
|
|
2464
|
+
const viewportSizeDiff = viewport.getSize() - scrollSize;
|
|
2399
2465
|
if (viewportSizeDiff > 0) {
|
|
2400
2466
|
if (inverse) {
|
|
2401
2467
|
bwdSize += viewportSizeDiff;
|
|
@@ -2410,7 +2476,7 @@ class Adjust extends BaseProcessFactory(CommonProcess.adjust) {
|
|
|
2410
2476
|
scroller.logger.stat('after paddings adjustments');
|
|
2411
2477
|
}
|
|
2412
2478
|
static calculatePosition(scroller) {
|
|
2413
|
-
const { viewport, buffer, state: { fetch, render,
|
|
2479
|
+
const { viewport, buffer, state: { fetch, render, scroll } } = scroller;
|
|
2414
2480
|
let position = viewport.paddings.backward.size;
|
|
2415
2481
|
// increase the position to meet the expectation of the first visible item
|
|
2416
2482
|
if (!isNaN(fetch.firstVisible.index) && !isNaN(buffer.firstIndex)) {
|
|
@@ -2433,8 +2499,8 @@ class Adjust extends BaseProcessFactory(CommonProcess.adjust) {
|
|
|
2433
2499
|
});
|
|
2434
2500
|
}
|
|
2435
2501
|
// slow fetch/render case
|
|
2436
|
-
if (
|
|
2437
|
-
const diff = render.positionBefore -
|
|
2502
|
+
if (scroll.positionBeforeAsync !== null) {
|
|
2503
|
+
const diff = render.positionBefore - scroll.positionBeforeAsync;
|
|
2438
2504
|
if (diff !== 0) {
|
|
2439
2505
|
scroller.logger.log(`shift position due to fetch-render difference (${diff})`);
|
|
2440
2506
|
position += diff;
|
|
@@ -2446,22 +2512,47 @@ class Adjust extends BaseProcessFactory(CommonProcess.adjust) {
|
|
|
2446
2512
|
}
|
|
2447
2513
|
return Math.round(position);
|
|
2448
2514
|
}
|
|
2515
|
+
static setAdditionalForwardPadding(scroller, position) {
|
|
2516
|
+
const { viewport, buffer, state: { cycle } } = scroller;
|
|
2517
|
+
if (!cycle.isInitial || !End.shouldContinueRun(scroller, null)) {
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
const diff = position - viewport.getMaxScrollPosition();
|
|
2521
|
+
if (diff <= 0) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
const last = buffer.getLastVisibleItem();
|
|
2525
|
+
if (!last) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
let size = 0;
|
|
2529
|
+
let index = last.$index + 1;
|
|
2530
|
+
while (size <= diff && index <= buffer.absMaxIndex) {
|
|
2531
|
+
size += buffer.getSizeByIndex(index++);
|
|
2532
|
+
}
|
|
2533
|
+
const shift = Math.min(size, diff);
|
|
2534
|
+
if (shift) {
|
|
2535
|
+
viewport.paddings.forward.size += shift;
|
|
2536
|
+
scroller.logger.log(`increase fwd padding due to lack of items (${diff} -> ${shift})`);
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2449
2539
|
static setPosition(scroller, position, done) {
|
|
2450
|
-
const { state: {
|
|
2451
|
-
if (!
|
|
2540
|
+
const { state: { scroll }, viewport, routines } = scroller;
|
|
2541
|
+
if (!scroll.hasPositionChanged(position)) {
|
|
2452
2542
|
return done();
|
|
2453
2543
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2544
|
+
scroll.syntheticPosition = position;
|
|
2545
|
+
scroll.syntheticFulfill = false;
|
|
2546
|
+
scroll.cancelAnimation = routines.animate(() => {
|
|
2547
|
+
scroll.cancelAnimation = null;
|
|
2548
|
+
const inertiaDiff = scroll.positionAfterAdjust - viewport.scrollPosition;
|
|
2458
2549
|
let diffLog = '';
|
|
2459
2550
|
if (inertiaDiff > 0) {
|
|
2460
2551
|
position -= inertiaDiff;
|
|
2461
|
-
|
|
2552
|
+
scroll.syntheticPosition = position;
|
|
2462
2553
|
diffLog = ` (-${inertiaDiff})`;
|
|
2463
2554
|
}
|
|
2464
|
-
|
|
2555
|
+
scroll.syntheticFulfill = true;
|
|
2465
2556
|
viewport.scrollPosition = position;
|
|
2466
2557
|
scroller.logger.stat('after scroll adjustment' + diffLog);
|
|
2467
2558
|
done();
|
|
@@ -2601,67 +2692,6 @@ class Clip extends BaseProcessFactory(CommonProcess.clip) {
|
|
|
2601
2692
|
}
|
|
2602
2693
|
}
|
|
2603
2694
|
|
|
2604
|
-
const isInterrupted = ({ call }) => !!call.interrupted;
|
|
2605
|
-
class End extends BaseProcessFactory(CommonProcess.end) {
|
|
2606
|
-
static run(scroller, { error } = {}) {
|
|
2607
|
-
const { workflow, state: { cycle: { interrupter } } } = scroller;
|
|
2608
|
-
if (!error && !interrupter) {
|
|
2609
|
-
// set out params accessible via Adapter
|
|
2610
|
-
End.calculateParams(scroller, workflow);
|
|
2611
|
-
}
|
|
2612
|
-
// explicit interruption for we don't want to go through the inner loop finalizing
|
|
2613
|
-
if (isInterrupted(workflow)) {
|
|
2614
|
-
workflow.call({ process: End.process, status: ProcessStatus.done });
|
|
2615
|
-
return;
|
|
2616
|
-
}
|
|
2617
|
-
const next = End.finalizeInnerLoop(scroller, error);
|
|
2618
|
-
workflow.call({
|
|
2619
|
-
process: End.process,
|
|
2620
|
-
status: next ? ProcessStatus.next : ProcessStatus.done,
|
|
2621
|
-
payload: Object.assign({}, (interrupter ? { process: interrupter } : {}))
|
|
2622
|
-
});
|
|
2623
|
-
}
|
|
2624
|
-
static calculateParams(scroller, workflow) {
|
|
2625
|
-
const { adapter, viewport, buffer: { items } } = scroller;
|
|
2626
|
-
if (adapter.wanted.firstVisible) {
|
|
2627
|
-
const { item } = viewport.getEdgeVisibleItem(items, Direction.backward);
|
|
2628
|
-
if (!item || item.element !== adapter.firstVisible.element) {
|
|
2629
|
-
adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
// the workflow can be interrupter on firstVisible change
|
|
2633
|
-
if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
|
|
2634
|
-
const { item } = viewport.getEdgeVisibleItem(items, Direction.forward);
|
|
2635
|
-
if (!item || item.element !== adapter.lastVisible.element) {
|
|
2636
|
-
adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
|
|
2637
|
-
}
|
|
2638
|
-
}
|
|
2639
|
-
}
|
|
2640
|
-
static finalizeInnerLoop(scroller, error) {
|
|
2641
|
-
const { state, state: { cycle, clip, fetch } } = scroller;
|
|
2642
|
-
const next = !!cycle.interrupter || (error ? false : End.getNext(scroller));
|
|
2643
|
-
cycle.innerLoop.isInitial = false;
|
|
2644
|
-
fetch.stopSimulate();
|
|
2645
|
-
clip.reset(true);
|
|
2646
|
-
state.endInnerLoop();
|
|
2647
|
-
return next;
|
|
2648
|
-
}
|
|
2649
|
-
static getNext(scroller) {
|
|
2650
|
-
const { state: { fetch, render } } = scroller;
|
|
2651
|
-
if (fetch.simulate && fetch.isCheck && !render.noSize) { // Adapter.check
|
|
2652
|
-
return true;
|
|
2653
|
-
}
|
|
2654
|
-
if (fetch.simulate && fetch.doRemove) { // Adapter.remove or Adapter.update with clip
|
|
2655
|
-
return true;
|
|
2656
|
-
}
|
|
2657
|
-
if ( // common inner loop (App start, Scroll, Adapter.clip) accompanied by fetch
|
|
2658
|
-
!fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
|
|
2659
|
-
return true;
|
|
2660
|
-
}
|
|
2661
|
-
return false;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
2695
|
class Logger {
|
|
2666
2696
|
constructor(scroller, packageInfo, adapter) {
|
|
2667
2697
|
this.logs = [];
|
|
@@ -2711,7 +2741,7 @@ class Logger {
|
|
|
2711
2741
|
this.getLoopId = () => scroller.state.cycle.loopId;
|
|
2712
2742
|
this.getLoopIdNext = () => scroller.state.cycle.loopIdNext;
|
|
2713
2743
|
this.getWorkflowCycleData = () => `${settings.instanceIndex}-${scroller.state.cycle.count}`;
|
|
2714
|
-
this.getScrollPosition = (
|
|
2744
|
+
this.getScrollPosition = () => scroller.routines.getScrollPosition();
|
|
2715
2745
|
this.log(() => 'vscroll Workflow has been started, ' +
|
|
2716
2746
|
`core: ${packageInfo.core.name} v${packageInfo.core.version}, ` +
|
|
2717
2747
|
`consumer: ${packageInfo.consumer.name} v${packageInfo.consumer.version}, ` +
|
|
@@ -2767,7 +2797,7 @@ class Logger {
|
|
|
2767
2797
|
}
|
|
2768
2798
|
prepareForLog(data) {
|
|
2769
2799
|
return data instanceof Event && data.target
|
|
2770
|
-
? this.getScrollPosition(
|
|
2800
|
+
? this.getScrollPosition()
|
|
2771
2801
|
: data;
|
|
2772
2802
|
}
|
|
2773
2803
|
logProcess(data) {
|
|
@@ -2849,64 +2879,73 @@ class Logger {
|
|
|
2849
2879
|
}
|
|
2850
2880
|
|
|
2851
2881
|
class Routines {
|
|
2852
|
-
constructor(settings) {
|
|
2853
|
-
this.
|
|
2854
|
-
this.
|
|
2855
|
-
|
|
2882
|
+
constructor(element, settings, CustomRoutines) {
|
|
2883
|
+
this.element = element;
|
|
2884
|
+
this.settings = {
|
|
2885
|
+
viewport: settings.viewport,
|
|
2886
|
+
horizontal: settings.horizontal,
|
|
2887
|
+
window: settings.windowViewport
|
|
2888
|
+
};
|
|
2889
|
+
// provide custom overrides for IRoutines methods
|
|
2890
|
+
if (CustomRoutines) {
|
|
2891
|
+
const routines = new CustomRoutines(element, this.settings);
|
|
2892
|
+
Object.getOwnPropertyNames(Object.getPrototypeOf(routines))
|
|
2893
|
+
.filter(method => method !== 'constructor' &&
|
|
2894
|
+
typeof routines[method] === 'function' &&
|
|
2895
|
+
typeof this[method] === 'function')
|
|
2896
|
+
.forEach(method => this[method] = (...args) => routines[method].apply(this, args));
|
|
2897
|
+
}
|
|
2898
|
+
// initialization
|
|
2899
|
+
this.viewport = this.getViewportElement();
|
|
2900
|
+
this.onInit(settings);
|
|
2856
2901
|
}
|
|
2857
2902
|
checkElement(element) {
|
|
2858
2903
|
if (!element) {
|
|
2859
2904
|
throw new Error('HTML element is not defined');
|
|
2860
2905
|
}
|
|
2861
2906
|
}
|
|
2862
|
-
|
|
2863
|
-
if (this.window) {
|
|
2907
|
+
getViewportElement() {
|
|
2908
|
+
if (this.settings.window) {
|
|
2864
2909
|
return document.documentElement;
|
|
2865
2910
|
}
|
|
2866
|
-
if (this.viewport) {
|
|
2867
|
-
return this.viewport;
|
|
2911
|
+
if (this.settings.viewport) {
|
|
2912
|
+
return this.settings.viewport;
|
|
2868
2913
|
}
|
|
2869
|
-
this.checkElement(element);
|
|
2870
|
-
const parent = element.parentElement;
|
|
2914
|
+
this.checkElement(this.element);
|
|
2915
|
+
const parent = this.element.parentElement;
|
|
2871
2916
|
this.checkElement(parent);
|
|
2872
2917
|
return parent;
|
|
2873
2918
|
}
|
|
2874
|
-
|
|
2875
|
-
if (
|
|
2876
|
-
|
|
2919
|
+
onInit(settings) {
|
|
2920
|
+
if (settings.windowViewport) {
|
|
2921
|
+
if ('scrollRestoration' in history) {
|
|
2922
|
+
history.scrollRestoration = 'manual';
|
|
2923
|
+
}
|
|
2877
2924
|
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
setupScrollRestoration() {
|
|
2881
|
-
if ('scrollRestoration' in history) {
|
|
2882
|
-
history.scrollRestoration = 'manual';
|
|
2925
|
+
if (settings.dismissOverflowAnchor) {
|
|
2926
|
+
this.viewport.style.overflowAnchor = 'none';
|
|
2883
2927
|
}
|
|
2884
2928
|
}
|
|
2885
|
-
dismissOverflowAnchor(element) {
|
|
2886
|
-
this.checkElement(element);
|
|
2887
|
-
element.style.overflowAnchor = 'none';
|
|
2888
|
-
}
|
|
2889
2929
|
findElementBySelector(element, selector) {
|
|
2890
2930
|
this.checkElement(element);
|
|
2891
2931
|
return element.querySelector(selector);
|
|
2892
2932
|
}
|
|
2893
|
-
findPaddingElement(
|
|
2894
|
-
return this.findElementBySelector(element, `[data-padding-${direction}]`);
|
|
2933
|
+
findPaddingElement(direction) {
|
|
2934
|
+
return this.findElementBySelector(this.element, `[data-padding-${direction}]`);
|
|
2895
2935
|
}
|
|
2896
|
-
findItemElement(
|
|
2897
|
-
return this.findElementBySelector(element, `[data-sid="${id}"]`);
|
|
2936
|
+
findItemElement(id) {
|
|
2937
|
+
return this.findElementBySelector(this.element, `[data-sid="${id}"]`);
|
|
2898
2938
|
}
|
|
2899
|
-
getScrollPosition(
|
|
2900
|
-
if (this.window) {
|
|
2901
|
-
return window.pageYOffset;
|
|
2939
|
+
getScrollPosition() {
|
|
2940
|
+
if (this.settings.window) {
|
|
2941
|
+
return this.settings.horizontal ? window.pageXOffset : window.pageYOffset;
|
|
2902
2942
|
}
|
|
2903
|
-
this.
|
|
2904
|
-
return element[this.horizontal ? 'scrollLeft' : 'scrollTop'];
|
|
2943
|
+
return this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'];
|
|
2905
2944
|
}
|
|
2906
|
-
setScrollPosition(
|
|
2945
|
+
setScrollPosition(value) {
|
|
2907
2946
|
value = Math.max(0, value);
|
|
2908
|
-
if (this.window) {
|
|
2909
|
-
if (this.horizontal) {
|
|
2947
|
+
if (this.settings.window) {
|
|
2948
|
+
if (this.settings.horizontal) {
|
|
2910
2949
|
window.scrollTo(value, window.scrollY);
|
|
2911
2950
|
}
|
|
2912
2951
|
else {
|
|
@@ -2914,49 +2953,62 @@ class Routines {
|
|
|
2914
2953
|
}
|
|
2915
2954
|
return;
|
|
2916
2955
|
}
|
|
2917
|
-
this.
|
|
2918
|
-
element[this.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
|
|
2956
|
+
this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
|
|
2919
2957
|
}
|
|
2920
|
-
|
|
2958
|
+
getElementParams(element) {
|
|
2921
2959
|
this.checkElement(element);
|
|
2922
|
-
if (this.window && doNotBind) {
|
|
2923
|
-
const { clientWidth, clientHeight, clientLeft, clientTop } = element;
|
|
2924
|
-
return {
|
|
2925
|
-
'height': clientHeight,
|
|
2926
|
-
'width': clientWidth,
|
|
2927
|
-
'top': clientTop,
|
|
2928
|
-
'bottom': clientTop + clientHeight,
|
|
2929
|
-
'left': clientLeft,
|
|
2930
|
-
'right': clientLeft + clientWidth,
|
|
2931
|
-
'x': clientLeft,
|
|
2932
|
-
'y': clientTop,
|
|
2933
|
-
'toJSON': () => null,
|
|
2934
|
-
};
|
|
2935
|
-
}
|
|
2936
2960
|
return element.getBoundingClientRect();
|
|
2937
2961
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2962
|
+
getWindowParams() {
|
|
2963
|
+
const { clientWidth, clientHeight, clientLeft, clientTop } = this.viewport;
|
|
2964
|
+
return {
|
|
2965
|
+
'height': clientHeight,
|
|
2966
|
+
'width': clientWidth,
|
|
2967
|
+
'top': clientTop,
|
|
2968
|
+
'bottom': clientTop + clientHeight,
|
|
2969
|
+
'left': clientLeft,
|
|
2970
|
+
'right': clientLeft + clientWidth,
|
|
2971
|
+
'x': clientLeft,
|
|
2972
|
+
'y': clientTop,
|
|
2973
|
+
'toJSON': () => null,
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
getSize(element) {
|
|
2977
|
+
return this.getElementParams(element)[this.settings.horizontal ? 'width' : 'height'];
|
|
2978
|
+
}
|
|
2979
|
+
getScrollerSize() {
|
|
2980
|
+
return this.getElementParams(this.element)[this.settings.horizontal ? 'width' : 'height'];
|
|
2981
|
+
}
|
|
2982
|
+
getViewportSize() {
|
|
2983
|
+
if (this.settings.window) {
|
|
2984
|
+
return this.getWindowParams()[this.settings.horizontal ? 'width' : 'height'];
|
|
2985
|
+
}
|
|
2986
|
+
return this.getSize(this.viewport);
|
|
2940
2987
|
}
|
|
2941
2988
|
getSizeStyle(element) {
|
|
2942
2989
|
this.checkElement(element);
|
|
2943
|
-
const size = element.style[this.horizontal ? 'width' : 'height'];
|
|
2990
|
+
const size = element.style[this.settings.horizontal ? 'width' : 'height'];
|
|
2944
2991
|
return parseFloat(size) || 0;
|
|
2945
2992
|
}
|
|
2946
2993
|
setSizeStyle(element, value) {
|
|
2947
2994
|
this.checkElement(element);
|
|
2948
2995
|
value = Math.max(0, Math.round(value));
|
|
2949
|
-
element.style[this.horizontal ? 'width' : 'height'] = `${value}px`;
|
|
2996
|
+
element.style[this.settings.horizontal ? 'width' : 'height'] = `${value}px`;
|
|
2950
2997
|
}
|
|
2951
|
-
getEdge(element, direction
|
|
2952
|
-
const
|
|
2998
|
+
getEdge(element, direction) {
|
|
2999
|
+
const { horizontal } = this.settings;
|
|
3000
|
+
const params = this.getElementParams(element);
|
|
2953
3001
|
const isFwd = direction === Direction.forward;
|
|
2954
|
-
return params[isFwd ? (
|
|
3002
|
+
return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
|
|
2955
3003
|
}
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
3004
|
+
getViewportEdge(direction) {
|
|
3005
|
+
const { window, horizontal } = this.settings;
|
|
3006
|
+
if (window) {
|
|
3007
|
+
const params = this.getWindowParams();
|
|
3008
|
+
const isFwd = direction === Direction.forward;
|
|
3009
|
+
return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
|
|
3010
|
+
}
|
|
3011
|
+
return this.getEdge(this.viewport, direction);
|
|
2960
3012
|
}
|
|
2961
3013
|
makeElementVisible(element) {
|
|
2962
3014
|
this.checkElement(element);
|
|
@@ -2968,19 +3020,32 @@ class Routines {
|
|
|
2968
3020
|
this.checkElement(element);
|
|
2969
3021
|
element.style.display = 'none';
|
|
2970
3022
|
}
|
|
2971
|
-
getOffset(
|
|
2972
|
-
this.
|
|
2973
|
-
return (this.
|
|
3023
|
+
getOffset() {
|
|
3024
|
+
const get = (element) => (this.settings.horizontal ? element.offsetLeft : element.offsetTop) || 0;
|
|
3025
|
+
return get(this.element) - (!this.settings.window ? get(this.viewport) : 0);
|
|
2974
3026
|
}
|
|
2975
3027
|
scrollTo(element, argument) {
|
|
2976
3028
|
this.checkElement(element);
|
|
2977
3029
|
element.scrollIntoView(argument);
|
|
2978
3030
|
}
|
|
3031
|
+
render(cb) {
|
|
3032
|
+
const timeoutId = setTimeout(() => cb());
|
|
3033
|
+
return () => clearTimeout(timeoutId);
|
|
3034
|
+
}
|
|
3035
|
+
animate(cb) {
|
|
3036
|
+
const animationFrameId = requestAnimationFrame(() => cb());
|
|
3037
|
+
return () => cancelAnimationFrame(animationFrameId);
|
|
3038
|
+
}
|
|
3039
|
+
onScroll(handler) {
|
|
3040
|
+
const eventReceiver = this.settings.window ? window : this.viewport;
|
|
3041
|
+
eventReceiver.addEventListener('scroll', handler);
|
|
3042
|
+
return () => eventReceiver.removeEventListener('scroll', handler);
|
|
3043
|
+
}
|
|
2979
3044
|
}
|
|
2980
3045
|
|
|
2981
3046
|
class Padding {
|
|
2982
|
-
constructor(
|
|
2983
|
-
const found = routines.findPaddingElement(
|
|
3047
|
+
constructor(direction, routines) {
|
|
3048
|
+
const found = routines.findPaddingElement(direction);
|
|
2984
3049
|
routines.checkElement(found);
|
|
2985
3050
|
this.element = found;
|
|
2986
3051
|
this.direction = direction;
|
|
@@ -2997,10 +3062,10 @@ class Padding {
|
|
|
2997
3062
|
}
|
|
2998
3063
|
}
|
|
2999
3064
|
class Paddings {
|
|
3000
|
-
constructor(
|
|
3065
|
+
constructor(routines, settings) {
|
|
3001
3066
|
this.settings = settings;
|
|
3002
|
-
this.forward = new Padding(
|
|
3003
|
-
this.backward = new Padding(
|
|
3067
|
+
this.forward = new Padding(Direction.forward, routines);
|
|
3068
|
+
this.backward = new Padding(Direction.backward, routines);
|
|
3004
3069
|
}
|
|
3005
3070
|
byDirection(direction, opposite) {
|
|
3006
3071
|
return direction === Direction.backward
|
|
@@ -3051,27 +3116,18 @@ class Paddings {
|
|
|
3051
3116
|
}
|
|
3052
3117
|
|
|
3053
3118
|
class Viewport {
|
|
3054
|
-
constructor(
|
|
3055
|
-
this.element = element;
|
|
3119
|
+
constructor(settings, routines, state, logger) {
|
|
3056
3120
|
this.settings = settings;
|
|
3057
3121
|
this.routines = routines;
|
|
3058
3122
|
this.state = state;
|
|
3059
3123
|
this.logger = logger;
|
|
3060
|
-
this.
|
|
3061
|
-
this.scrollEventReceiver = this.routines.getScrollEventReceiver(this.element);
|
|
3062
|
-
if (settings.windowViewport) {
|
|
3063
|
-
this.routines.setupScrollRestoration();
|
|
3064
|
-
}
|
|
3065
|
-
if (settings.dismissOverflowAnchor) {
|
|
3066
|
-
this.routines.dismissOverflowAnchor(this.hostElement);
|
|
3067
|
-
}
|
|
3068
|
-
this.paddings = new Paddings(this.element, this.routines, settings);
|
|
3124
|
+
this.paddings = new Paddings(this.routines, settings);
|
|
3069
3125
|
}
|
|
3070
3126
|
reset(startIndex) {
|
|
3071
3127
|
this.setOffset();
|
|
3072
3128
|
this.paddings.reset(this.getSize(), startIndex, this.offset);
|
|
3073
3129
|
this.scrollPosition = this.paddings.backward.size || 0;
|
|
3074
|
-
this.state.
|
|
3130
|
+
this.state.scroll.reset();
|
|
3075
3131
|
}
|
|
3076
3132
|
setPosition(value) {
|
|
3077
3133
|
const oldPosition = this.scrollPosition;
|
|
@@ -3079,7 +3135,7 @@ class Viewport {
|
|
|
3079
3135
|
this.logger.log(() => ['setting scroll position at', value, '[cancelled]']);
|
|
3080
3136
|
return value;
|
|
3081
3137
|
}
|
|
3082
|
-
this.routines.setScrollPosition(
|
|
3138
|
+
this.routines.setScrollPosition(value);
|
|
3083
3139
|
const position = this.scrollPosition;
|
|
3084
3140
|
this.logger.log(() => [
|
|
3085
3141
|
'setting scroll position at', position, ...(position !== value ? [`(${value})`] : [])
|
|
@@ -3087,31 +3143,31 @@ class Viewport {
|
|
|
3087
3143
|
return position;
|
|
3088
3144
|
}
|
|
3089
3145
|
get scrollPosition() {
|
|
3090
|
-
return this.routines.getScrollPosition(
|
|
3146
|
+
return this.routines.getScrollPosition();
|
|
3091
3147
|
}
|
|
3092
3148
|
set scrollPosition(value) {
|
|
3093
3149
|
this.setPosition(value);
|
|
3094
3150
|
}
|
|
3095
3151
|
getSize() {
|
|
3096
|
-
return this.routines.
|
|
3152
|
+
return this.routines.getViewportSize();
|
|
3097
3153
|
}
|
|
3098
3154
|
getScrollableSize() {
|
|
3099
|
-
return this.routines.
|
|
3155
|
+
return this.routines.getScrollerSize();
|
|
3156
|
+
}
|
|
3157
|
+
getMaxScrollPosition() {
|
|
3158
|
+
return this.getScrollableSize() - this.getSize();
|
|
3100
3159
|
}
|
|
3101
3160
|
getBufferPadding() {
|
|
3102
3161
|
return this.getSize() * this.settings.padding;
|
|
3103
3162
|
}
|
|
3104
3163
|
getEdge(direction) {
|
|
3105
|
-
return this.routines.
|
|
3164
|
+
return this.routines.getViewportEdge(direction);
|
|
3106
3165
|
}
|
|
3107
3166
|
setOffset() {
|
|
3108
|
-
this.offset = this.routines.getOffset(
|
|
3109
|
-
if (!this.settings.windowViewport) {
|
|
3110
|
-
this.offset -= this.routines.getOffset(this.hostElement);
|
|
3111
|
-
}
|
|
3167
|
+
this.offset = this.routines.getOffset();
|
|
3112
3168
|
}
|
|
3113
3169
|
findItemElementById(id) {
|
|
3114
|
-
return this.routines.findItemElement(
|
|
3170
|
+
return this.routines.findItemElement(id);
|
|
3115
3171
|
}
|
|
3116
3172
|
getEdgeVisibleItem(items, direction) {
|
|
3117
3173
|
const bwd = direction === Direction.backward;
|
|
@@ -3903,6 +3959,7 @@ class InnerLoopModel {
|
|
|
3903
3959
|
return this.count === 0;
|
|
3904
3960
|
}
|
|
3905
3961
|
done() {
|
|
3962
|
+
this.isInitial = false;
|
|
3906
3963
|
this.count++;
|
|
3907
3964
|
this.total++;
|
|
3908
3965
|
this.busy.set(false);
|
|
@@ -3922,7 +3979,7 @@ class WorkflowCycleModel {
|
|
|
3922
3979
|
this.innerLoop = new InnerLoopModel(loopCount);
|
|
3923
3980
|
this.interrupter = null;
|
|
3924
3981
|
this.busy = new Reactive(false);
|
|
3925
|
-
this.
|
|
3982
|
+
this.end(cycleCount);
|
|
3926
3983
|
}
|
|
3927
3984
|
get loopId() {
|
|
3928
3985
|
return `${this.instanceIndex}-${this.count}-${this.innerLoop.total}`;
|
|
@@ -3930,11 +3987,6 @@ class WorkflowCycleModel {
|
|
|
3930
3987
|
get loopIdNext() {
|
|
3931
3988
|
return `${this.instanceIndex}-${this.count}-${this.innerLoop.total + 1}`;
|
|
3932
3989
|
}
|
|
3933
|
-
done(count) {
|
|
3934
|
-
this.count = count;
|
|
3935
|
-
this.isInitial = false;
|
|
3936
|
-
this.busy.set(false);
|
|
3937
|
-
}
|
|
3938
3990
|
start(isInitial, initiator) {
|
|
3939
3991
|
this.isInitial = isInitial;
|
|
3940
3992
|
this.initiator = initiator;
|
|
@@ -3943,6 +3995,11 @@ class WorkflowCycleModel {
|
|
|
3943
3995
|
this.interrupter = null;
|
|
3944
3996
|
this.busy.set(true);
|
|
3945
3997
|
}
|
|
3998
|
+
end(count) {
|
|
3999
|
+
this.count = count;
|
|
4000
|
+
this.isInitial = false;
|
|
4001
|
+
this.busy.set(false);
|
|
4002
|
+
}
|
|
3946
4003
|
dispose(forever) {
|
|
3947
4004
|
if (forever) {
|
|
3948
4005
|
// otherwise the value will be persisted during re-instantiation
|
|
@@ -4102,11 +4159,11 @@ class RenderModel {
|
|
|
4102
4159
|
this.sizeBefore = 0;
|
|
4103
4160
|
this.sizeAfter = 0;
|
|
4104
4161
|
this.positionBefore = 0;
|
|
4105
|
-
this.
|
|
4162
|
+
this.cancel = null;
|
|
4106
4163
|
}
|
|
4107
4164
|
}
|
|
4108
4165
|
|
|
4109
|
-
class
|
|
4166
|
+
class ScrollModel {
|
|
4110
4167
|
constructor() {
|
|
4111
4168
|
this.reset();
|
|
4112
4169
|
}
|
|
@@ -4118,16 +4175,16 @@ class ScrollState {
|
|
|
4118
4175
|
this.positionBeforeAsync = null;
|
|
4119
4176
|
this.positionBeforeAdjust = null;
|
|
4120
4177
|
this.positionAfterAdjust = null;
|
|
4121
|
-
this.
|
|
4178
|
+
this.stop();
|
|
4122
4179
|
}
|
|
4123
|
-
|
|
4180
|
+
stop() {
|
|
4124
4181
|
if (this.scrollTimer) {
|
|
4125
4182
|
clearTimeout(this.scrollTimer);
|
|
4126
4183
|
this.scrollTimer = null;
|
|
4127
4184
|
}
|
|
4128
|
-
if (this.
|
|
4129
|
-
|
|
4130
|
-
this.
|
|
4185
|
+
if (this.cancelAnimation) {
|
|
4186
|
+
this.cancelAnimation();
|
|
4187
|
+
this.cancelAnimation = null;
|
|
4131
4188
|
}
|
|
4132
4189
|
}
|
|
4133
4190
|
hasPositionChanged(position) {
|
|
@@ -4146,25 +4203,19 @@ class State {
|
|
|
4146
4203
|
this.fetch = new FetchModel(settings.directionPriority);
|
|
4147
4204
|
this.clip = new ClipModel();
|
|
4148
4205
|
this.render = new RenderModel();
|
|
4149
|
-
this.
|
|
4206
|
+
this.scroll = new ScrollModel();
|
|
4150
4207
|
}
|
|
4151
4208
|
get time() {
|
|
4152
4209
|
return Number(new Date()) - this.initTime;
|
|
4153
4210
|
}
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
}
|
|
4160
|
-
if (render.renderTimer) {
|
|
4161
|
-
clearTimeout(render.renderTimer);
|
|
4162
|
-
render.renderTimer = null;
|
|
4163
|
-
}
|
|
4164
|
-
cycle.innerLoop.done();
|
|
4211
|
+
startWorkflowCycle(isInitial, initiator) {
|
|
4212
|
+
this.cycle.start(isInitial, initiator);
|
|
4213
|
+
}
|
|
4214
|
+
endWorkflowCycle(count) {
|
|
4215
|
+
this.cycle.end(count);
|
|
4165
4216
|
}
|
|
4166
4217
|
startInnerLoop() {
|
|
4167
|
-
const { cycle,
|
|
4218
|
+
const { cycle, scroll: scroll, fetch, render, clip } = this;
|
|
4168
4219
|
cycle.innerLoop.start();
|
|
4169
4220
|
scroll.positionBeforeAsync = null;
|
|
4170
4221
|
if (!fetch.simulate) {
|
|
@@ -4177,10 +4228,24 @@ class State {
|
|
|
4177
4228
|
doRender: fetch.simulate && fetch.items.length > 0
|
|
4178
4229
|
} : {}));
|
|
4179
4230
|
}
|
|
4231
|
+
endInnerLoop() {
|
|
4232
|
+
const { fetch, clip, render, cycle } = this;
|
|
4233
|
+
fetch.stopSimulate();
|
|
4234
|
+
clip.reset(true);
|
|
4235
|
+
if (fetch.cancel) {
|
|
4236
|
+
fetch.cancel();
|
|
4237
|
+
fetch.cancel = null;
|
|
4238
|
+
}
|
|
4239
|
+
if (render.cancel) {
|
|
4240
|
+
render.cancel();
|
|
4241
|
+
render.cancel = null;
|
|
4242
|
+
}
|
|
4243
|
+
cycle.innerLoop.done();
|
|
4244
|
+
}
|
|
4180
4245
|
dispose() {
|
|
4246
|
+
this.scroll.stop();
|
|
4181
4247
|
this.cycle.dispose();
|
|
4182
4248
|
this.endInnerLoop();
|
|
4183
|
-
this.scrollState.cleanupTimers();
|
|
4184
4249
|
}
|
|
4185
4250
|
}
|
|
4186
4251
|
|
|
@@ -4591,21 +4656,21 @@ class Adapter {
|
|
|
4591
4656
|
const INVALID_DATASOURCE_PREFIX = 'Invalid datasource:';
|
|
4592
4657
|
let instanceCount = 0;
|
|
4593
4658
|
class Scroller {
|
|
4594
|
-
constructor({ datasource, consumer, element, workflow, scroller }) {
|
|
4659
|
+
constructor({ datasource, consumer, element, workflow, Routines: CustomRoutines, scroller }) {
|
|
4595
4660
|
const { params: { get } } = validate(datasource, DATASOURCE);
|
|
4596
4661
|
if (!get.isValid) {
|
|
4597
4662
|
throw new Error(`${INVALID_DATASOURCE_PREFIX} ${get.errors[0]}`);
|
|
4598
4663
|
}
|
|
4599
4664
|
const packageInfo = scroller ? scroller.state.packageInfo : { consumer, core };
|
|
4600
|
-
element = scroller ? scroller.
|
|
4665
|
+
element = scroller ? scroller.routines.element : element;
|
|
4601
4666
|
workflow = scroller ? scroller.workflow : workflow;
|
|
4602
4667
|
this.workflow = workflow;
|
|
4603
4668
|
this.settings = new Settings(datasource.settings, datasource.devSettings, ++instanceCount);
|
|
4604
4669
|
this.logger = new Logger(this, packageInfo, datasource.adapter);
|
|
4605
|
-
this.routines = new Routines(this.settings);
|
|
4670
|
+
this.routines = new Routines(element, this.settings, CustomRoutines);
|
|
4606
4671
|
this.state = new State(packageInfo, this.settings, scroller ? scroller.state : void 0);
|
|
4607
4672
|
this.buffer = new Buffer(this.settings, workflow.onDataChanged, this.logger);
|
|
4608
|
-
this.viewport = new Viewport(
|
|
4673
|
+
this.viewport = new Viewport(this.settings, this.routines, this.state, this.logger);
|
|
4609
4674
|
this.logger.object('vscroll settings object', this.settings, true);
|
|
4610
4675
|
this.initDatasource(datasource, scroller);
|
|
4611
4676
|
}
|
|
@@ -4859,14 +4924,14 @@ const runStateMachine = ({ input: { process, status, payload = {} }, methods: {
|
|
|
4859
4924
|
};
|
|
4860
4925
|
|
|
4861
4926
|
class Workflow {
|
|
4862
|
-
constructor({ element, datasource, consumer, run }) {
|
|
4927
|
+
constructor({ element, datasource, consumer, run, Routines }) {
|
|
4863
4928
|
this.isInitialized = false;
|
|
4864
4929
|
this.initTimer = null;
|
|
4865
4930
|
this.adapterRun$ = new Reactive();
|
|
4866
4931
|
this.cyclesDone = 0;
|
|
4867
4932
|
this.interruptionCount = 0;
|
|
4868
4933
|
this.errors = [];
|
|
4869
|
-
this.
|
|
4934
|
+
this.offScroll = () => null;
|
|
4870
4935
|
this.propagateChanges = run;
|
|
4871
4936
|
this.stateMachineMethods = {
|
|
4872
4937
|
run: this.runProcess(),
|
|
@@ -4874,7 +4939,9 @@ class Workflow {
|
|
|
4874
4939
|
done: this.done.bind(this),
|
|
4875
4940
|
onError: this.onError.bind(this)
|
|
4876
4941
|
};
|
|
4877
|
-
this.scroller = new Scroller({
|
|
4942
|
+
this.scroller = new Scroller({
|
|
4943
|
+
element, datasource, consumer, workflow: this.getUpdater(), Routines
|
|
4944
|
+
});
|
|
4878
4945
|
if (this.scroller.settings.initializeDelay) {
|
|
4879
4946
|
this.initTimer = setTimeout(() => {
|
|
4880
4947
|
this.initTimer = null;
|
|
@@ -4894,14 +4961,13 @@ class Workflow {
|
|
|
4894
4961
|
status: ProcessStatus.start
|
|
4895
4962
|
});
|
|
4896
4963
|
// set up scroll event listener
|
|
4897
|
-
const {
|
|
4964
|
+
const { routines } = this.scroller;
|
|
4898
4965
|
const onScrollHandler = event => this.callWorkflow({
|
|
4899
4966
|
process: CommonProcess.scroll,
|
|
4900
4967
|
status: ProcessStatus.start,
|
|
4901
4968
|
payload: { event }
|
|
4902
4969
|
});
|
|
4903
|
-
|
|
4904
|
-
this.disposeScrollEventHandler = () => scrollEventReceiver.removeEventListener('scroll', onScrollHandler);
|
|
4970
|
+
this.offScroll = routines.onScroll(onScrollHandler);
|
|
4905
4971
|
}
|
|
4906
4972
|
changeItems(items) {
|
|
4907
4973
|
this.propagateChanges(items);
|
|
@@ -4987,14 +5053,14 @@ class Workflow {
|
|
|
4987
5053
|
const { state, logger } = this.scroller;
|
|
4988
5054
|
this.cyclesDone++;
|
|
4989
5055
|
logger.logCycle(false);
|
|
4990
|
-
state.
|
|
5056
|
+
state.endWorkflowCycle(this.cyclesDone + 1);
|
|
4991
5057
|
this.finalize();
|
|
4992
5058
|
}
|
|
4993
5059
|
dispose() {
|
|
4994
5060
|
if (this.initTimer) {
|
|
4995
5061
|
clearTimeout(this.initTimer);
|
|
4996
5062
|
}
|
|
4997
|
-
this.
|
|
5063
|
+
this.offScroll();
|
|
4998
5064
|
this.adapterRun$.dispose();
|
|
4999
5065
|
this.scroller.dispose(true);
|
|
5000
5066
|
Object.getOwnPropertyNames(this).forEach(prop => {
|