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.
Files changed (136) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +17 -16
  3. package/dist/bundles/vscroll.esm5.js +403 -321
  4. package/dist/bundles/vscroll.esm5.js.map +1 -1
  5. package/dist/bundles/vscroll.esm5.min.js +2 -2
  6. package/dist/bundles/vscroll.esm5.min.js.map +1 -1
  7. package/dist/bundles/vscroll.esm6.js +310 -244
  8. package/dist/bundles/vscroll.esm6.js.map +1 -1
  9. package/dist/bundles/vscroll.esm6.min.js +2 -2
  10. package/dist/bundles/vscroll.esm6.min.js.map +1 -1
  11. package/dist/bundles/vscroll.umd.js +404 -322
  12. package/dist/bundles/vscroll.umd.js.map +1 -1
  13. package/dist/bundles/vscroll.umd.min.js +2 -2
  14. package/dist/bundles/vscroll.umd.min.js.map +1 -1
  15. package/dist/esm2015/classes/domRoutines.js +101 -66
  16. package/dist/esm2015/classes/domRoutines.js.map +1 -1
  17. package/dist/esm2015/classes/logger.js +2 -2
  18. package/dist/esm2015/classes/logger.js.map +1 -1
  19. package/dist/esm2015/classes/paddings.js +5 -5
  20. package/dist/esm2015/classes/paddings.js.map +1 -1
  21. package/dist/esm2015/classes/state/cycle.js +7 -6
  22. package/dist/esm2015/classes/state/cycle.js.map +1 -1
  23. package/dist/esm2015/classes/state/render.js +1 -1
  24. package/dist/esm2015/classes/state/render.js.map +1 -1
  25. package/dist/esm2015/classes/state/scroll.js +6 -6
  26. package/dist/esm2015/classes/state/scroll.js.map +1 -1
  27. package/dist/esm2015/classes/state.js +23 -15
  28. package/dist/esm2015/classes/state.js.map +1 -1
  29. package/dist/esm2015/classes/viewport.js +13 -22
  30. package/dist/esm2015/classes/viewport.js.map +1 -1
  31. package/dist/esm2015/index.js.map +1 -1
  32. package/dist/esm2015/interfaces/index.js.map +1 -1
  33. package/dist/esm2015/interfaces/routines.js +2 -0
  34. package/dist/esm2015/interfaces/routines.js.map +1 -0
  35. package/dist/esm2015/interfaces/state.js.map +1 -1
  36. package/dist/esm2015/interfaces/workflow.js.map +1 -1
  37. package/dist/esm2015/processes/adapter/reload.js +1 -1
  38. package/dist/esm2015/processes/adapter/reload.js.map +1 -1
  39. package/dist/esm2015/processes/adjust.js +44 -15
  40. package/dist/esm2015/processes/adjust.js.map +1 -1
  41. package/dist/esm2015/processes/end.js +18 -16
  42. package/dist/esm2015/processes/end.js.map +1 -1
  43. package/dist/esm2015/processes/fetch.js +3 -3
  44. package/dist/esm2015/processes/fetch.js.map +1 -1
  45. package/dist/esm2015/processes/init.js +2 -2
  46. package/dist/esm2015/processes/init.js.map +1 -1
  47. package/dist/esm2015/processes/render.js +6 -6
  48. package/dist/esm2015/processes/render.js.map +1 -1
  49. package/dist/esm2015/processes/scroll.js +21 -21
  50. package/dist/esm2015/processes/scroll.js.map +1 -1
  51. package/dist/esm2015/scroller.js +4 -4
  52. package/dist/esm2015/scroller.js.map +1 -1
  53. package/dist/esm2015/version.js +1 -1
  54. package/dist/esm2015/version.js.map +1 -1
  55. package/dist/esm2015/workflow.js +9 -8
  56. package/dist/esm2015/workflow.js.map +1 -1
  57. package/dist/esm5/classes/adapter.js +4 -4
  58. package/dist/esm5/classes/adapter.js.map +1 -1
  59. package/dist/esm5/classes/buffer/cache.js +1 -1
  60. package/dist/esm5/classes/buffer/cache.js.map +1 -1
  61. package/dist/esm5/classes/buffer/checkCall.js +4 -4
  62. package/dist/esm5/classes/buffer/checkCall.js.map +1 -1
  63. package/dist/esm5/classes/buffer.js +3 -3
  64. package/dist/esm5/classes/buffer.js.map +1 -1
  65. package/dist/esm5/classes/domRoutines.js +115 -66
  66. package/dist/esm5/classes/domRoutines.js.map +1 -1
  67. package/dist/esm5/classes/logger.js +21 -21
  68. package/dist/esm5/classes/logger.js.map +1 -1
  69. package/dist/esm5/classes/paddings.js +5 -5
  70. package/dist/esm5/classes/paddings.js.map +1 -1
  71. package/dist/esm5/classes/state/cycle.js +9 -8
  72. package/dist/esm5/classes/state/cycle.js.map +1 -1
  73. package/dist/esm5/classes/state/render.js +1 -1
  74. package/dist/esm5/classes/state/render.js.map +1 -1
  75. package/dist/esm5/classes/state/scroll.js +11 -11
  76. package/dist/esm5/classes/state/scroll.js.map +1 -1
  77. package/dist/esm5/classes/state.js +23 -15
  78. package/dist/esm5/classes/state.js.map +1 -1
  79. package/dist/esm5/classes/viewport.js +14 -23
  80. package/dist/esm5/classes/viewport.js.map +1 -1
  81. package/dist/esm5/index.js.map +1 -1
  82. package/dist/esm5/inputs/validation.js +4 -4
  83. package/dist/esm5/inputs/validation.js.map +1 -1
  84. package/dist/esm5/interfaces/index.js.map +1 -1
  85. package/dist/esm5/interfaces/routines.js +2 -0
  86. package/dist/esm5/interfaces/routines.js.map +1 -0
  87. package/dist/esm5/interfaces/state.js.map +1 -1
  88. package/dist/esm5/interfaces/workflow.js.map +1 -1
  89. package/dist/esm5/processes/adapter/reload.js +1 -1
  90. package/dist/esm5/processes/adapter/reload.js.map +1 -1
  91. package/dist/esm5/processes/adapter/remove.js +1 -1
  92. package/dist/esm5/processes/adapter/remove.js.map +1 -1
  93. package/dist/esm5/processes/adjust.js +48 -19
  94. package/dist/esm5/processes/adjust.js.map +1 -1
  95. package/dist/esm5/processes/clip.js +5 -5
  96. package/dist/esm5/processes/clip.js.map +1 -1
  97. package/dist/esm5/processes/end.js +18 -16
  98. package/dist/esm5/processes/end.js.map +1 -1
  99. package/dist/esm5/processes/fetch.js +5 -5
  100. package/dist/esm5/processes/fetch.js.map +1 -1
  101. package/dist/esm5/processes/init.js +2 -2
  102. package/dist/esm5/processes/init.js.map +1 -1
  103. package/dist/esm5/processes/misc/base.js +1 -1
  104. package/dist/esm5/processes/misc/base.js.map +1 -1
  105. package/dist/esm5/processes/preClip.js +2 -2
  106. package/dist/esm5/processes/preClip.js.map +1 -1
  107. package/dist/esm5/processes/preFetch.js +5 -5
  108. package/dist/esm5/processes/preFetch.js.map +1 -1
  109. package/dist/esm5/processes/render.js +6 -6
  110. package/dist/esm5/processes/render.js.map +1 -1
  111. package/dist/esm5/processes/scroll.js +22 -22
  112. package/dist/esm5/processes/scroll.js.map +1 -1
  113. package/dist/esm5/scroller.js +5 -5
  114. package/dist/esm5/scroller.js.map +1 -1
  115. package/dist/esm5/version.js +1 -1
  116. package/dist/esm5/version.js.map +1 -1
  117. package/dist/esm5/workflow.js +15 -12
  118. package/dist/esm5/workflow.js.map +1 -1
  119. package/dist/typings/classes/domRoutines.d.ts +23 -18
  120. package/dist/typings/classes/logger.d.ts +1 -1
  121. package/dist/typings/classes/paddings.d.ts +2 -2
  122. package/dist/typings/classes/state/cycle.d.ts +1 -1
  123. package/dist/typings/classes/state/render.d.ts +1 -1
  124. package/dist/typings/classes/state/scroll.d.ts +4 -4
  125. package/dist/typings/classes/state.d.ts +6 -3
  126. package/dist/typings/classes/viewport.d.ts +2 -4
  127. package/dist/typings/index.d.ts +2 -2
  128. package/dist/typings/interfaces/index.d.ts +3 -2
  129. package/dist/typings/interfaces/routines.d.ts +157 -0
  130. package/dist/typings/interfaces/state.d.ts +2 -15
  131. package/dist/typings/interfaces/workflow.d.ts +3 -0
  132. package/dist/typings/processes/adjust.d.ts +1 -0
  133. package/dist/typings/processes/end.d.ts +1 -2
  134. package/dist/typings/scroller.d.ts +1 -1
  135. package/dist/typings/workflow.d.ts +2 -2
  136. package/package.json +18 -17
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * vscroll (https://github.com/dhilt/vscroll) UMD
3
- * Version: 1.4.1 (2021-11-02T00:21:12.677Z)
3
+ * Version: 1.5.0 (2022-02-02T15:07:24.737Z)
4
4
  * Author: Denis Hilt
5
5
  * License: MIT
6
6
  */
@@ -94,7 +94,7 @@
94
94
 
95
95
  /**
96
96
  * vscroll (https://github.com/dhilt/vscroll) FESM5
97
- * Version: 1.4.1 (2021-11-02T00:21:05.317Z)
97
+ * Version: 1.5.0 (2022-02-02T15:07:19.169Z)
98
98
  * Author: Denis Hilt
99
99
  * License: MIT
100
100
  */
@@ -435,7 +435,7 @@
435
435
 
436
436
  var core = {
437
437
  name: 'vscroll',
438
- version: '1.4.1'
438
+ version: '1.5.0'
439
439
  };
440
440
 
441
441
  var instanceCount$1 = 0;
@@ -544,7 +544,7 @@
544
544
  ValidatorType["enum"] = "must belong to {arg1} list";
545
545
  })(ValidatorType || (ValidatorType = {}));
546
546
  var getError = function (msg, args) {
547
- return (args || ['']).reduce(function (acc, arg, index) { return acc.replace("{arg" + (index + 1) + "}", arg); }, msg);
547
+ return (args || ['']).reduce(function (acc, arg, index) { return acc.replace("{arg".concat(index + 1, "}"), arg); }, msg);
548
548
  };
549
549
  var getNumber = function (value) {
550
550
  return typeof value === 'number' || (typeof value === 'string' && value !== '')
@@ -709,7 +709,7 @@
709
709
  }
710
710
  var isAnotherPresent = context && Object.prototype.hasOwnProperty.call(context, token);
711
711
  if (isSet && isAnotherPresent) {
712
- errors.push(getError(err, [tokens.join('", "')]) + (" (" + token + " is present)"));
712
+ errors.push(getError(err, [tokens.join('", "')]) + " (".concat(token, " is present)"));
713
713
  break;
714
714
  }
715
715
  if (noOneIsPresent && isAnotherPresent) {
@@ -834,9 +834,9 @@
834
834
  ValidatedData.prototype.setParam = function (token, value) {
835
835
  if (!value.isValid) {
836
836
  value.errors = !value.isSet
837
- ? ["\"" + token + "\" must be set"]
837
+ ? ["\"".concat(token, "\" must be set")]
838
838
  : value.errors.map(function (err) {
839
- return "\"" + token + "\" " + err;
839
+ return "\"".concat(token, "\" ").concat(err);
840
840
  });
841
841
  }
842
842
  this.params[token] = value;
@@ -1424,7 +1424,7 @@
1424
1424
  scroller.workflow.call({
1425
1425
  process: process,
1426
1426
  status: ProcessStatus.error,
1427
- payload: { error: "Wrong argument of the \"" + process + "\" method call" }
1427
+ payload: { error: "Wrong argument of the \"".concat(process, "\" method call") }
1428
1428
  });
1429
1429
  }
1430
1430
  }
@@ -1442,10 +1442,10 @@
1442
1442
  return _super !== null && _super.apply(this, arguments) || this;
1443
1443
  }
1444
1444
  Init.run = function (scroller, process) {
1445
- var cycle = scroller.state.cycle, workflow = scroller.workflow;
1445
+ var state = scroller.state, workflow = scroller.workflow;
1446
1446
  var isInitial = initProcesses.includes(process);
1447
1447
  scroller.logger.logCycle(true);
1448
- cycle.start(isInitial, process);
1448
+ state.startWorkflowCycle(isInitial, process);
1449
1449
  workflow.call({
1450
1450
  process: Init.process,
1451
1451
  status: ProcessStatus.next
@@ -1471,16 +1471,16 @@
1471
1471
  });
1472
1472
  };
1473
1473
  Scroll.onSynthetic = function (scroller, position) {
1474
- var scrollState = scroller.state.scrollState;
1475
- var synthPos = scrollState.syntheticPosition;
1474
+ var scroll = scroller.state.scroll;
1475
+ var synthPos = scroll.syntheticPosition;
1476
1476
  if (synthPos !== null) {
1477
- if (scrollState.syntheticFulfill) {
1478
- scrollState.syntheticPosition = null;
1477
+ if (scroll.syntheticFulfill) {
1478
+ scroll.syntheticPosition = null;
1479
1479
  }
1480
- if (!scrollState.syntheticFulfill || synthPos === position) {
1480
+ if (!scroll.syntheticFulfill || synthPos === position) {
1481
1481
  scroller.logger.log(function () { return [
1482
1482
  'skipping scroll', position,
1483
- "[" + (scrollState.syntheticFulfill ? '' : 'pre-') + "synthetic]"
1483
+ "[".concat(scroll.syntheticFulfill ? '' : 'pre-', "synthetic]")
1484
1484
  ]; });
1485
1485
  return true;
1486
1486
  }
@@ -1491,31 +1491,31 @@
1491
1491
  return false;
1492
1492
  };
1493
1493
  Scroll.onThrottle = function (scroller, position, done) {
1494
- var scrollState = scroller.state.scrollState, throttle = scroller.settings.throttle, logger = scroller.logger;
1495
- scrollState.current = Scroll.getScrollEvent(position, scrollState.previous);
1496
- var _a = scrollState.current, direction = _a.direction, time = _a.time;
1497
- var timeDiff = scrollState.previous ? time - scrollState.previous.time : Infinity;
1494
+ var scroll = scroller.state.scroll, throttle = scroller.settings.throttle, logger = scroller.logger;
1495
+ scroll.current = Scroll.getScrollEvent(position, scroll.previous);
1496
+ var _a = scroll.current, direction = _a.direction, time = _a.time;
1497
+ var timeDiff = scroll.previous ? time - scroll.previous.time : Infinity;
1498
1498
  var delta = throttle - timeDiff;
1499
1499
  var shouldDelay = isFinite(delta) && delta > 0;
1500
- var alreadyDelayed = !!scrollState.scrollTimer;
1500
+ var alreadyDelayed = !!scroll.scrollTimer;
1501
1501
  logger.log(function () { return [
1502
1502
  direction === exports.Direction.backward ? '\u2934' : '\u2935',
1503
1503
  position,
1504
1504
  shouldDelay ? (timeDiff + 'ms') : '0ms',
1505
- shouldDelay ? (alreadyDelayed ? 'delayed' : "/ " + delta + "ms delay") : ''
1505
+ shouldDelay ? (alreadyDelayed ? 'delayed' : "/ ".concat(delta, "ms delay")) : ''
1506
1506
  ]; });
1507
1507
  if (!shouldDelay) {
1508
- if (scrollState.scrollTimer) {
1509
- clearTimeout(scrollState.scrollTimer);
1510
- scrollState.scrollTimer = null;
1508
+ if (scroll.scrollTimer) {
1509
+ clearTimeout(scroll.scrollTimer);
1510
+ scroll.scrollTimer = null;
1511
1511
  }
1512
1512
  done();
1513
1513
  return;
1514
1514
  }
1515
1515
  if (!alreadyDelayed) {
1516
- scrollState.scrollTimer = setTimeout(function () {
1516
+ scroll.scrollTimer = setTimeout(function () {
1517
1517
  logger.log(function () {
1518
- var curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scrollState.current);
1518
+ var curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scroll.current);
1519
1519
  return [
1520
1520
  curr.direction === exports.Direction.backward ? '\u2934' : '\u2935',
1521
1521
  curr.position,
@@ -1524,7 +1524,7 @@
1524
1524
  position
1525
1525
  ];
1526
1526
  });
1527
- scrollState.scrollTimer = null;
1527
+ scroll.scrollTimer = null;
1528
1528
  done();
1529
1529
  }, delta);
1530
1530
  }
@@ -1543,11 +1543,11 @@
1543
1543
  return { position: position, direction: direction, time: time };
1544
1544
  };
1545
1545
  Scroll.onScroll = function (scroller, workflow) {
1546
- var _a = scroller.state, scrollState = _a.scrollState, cycle = _a.cycle;
1547
- scrollState.previous = __assign({}, scrollState.current);
1548
- scrollState.current = null;
1546
+ var _a = scroller.state, scroll = _a.scroll, cycle = _a.cycle;
1547
+ scroll.previous = __assign({}, scroll.current);
1548
+ scroll.current = null;
1549
1549
  if (cycle.busy.get()) {
1550
- scroller.logger.log(function () { return ['skipping scroll', scrollState.previous.position, '[pending]']; });
1550
+ scroller.logger.log(function () { return ['skipping scroll', scroll.previous.position, '[pending]']; });
1551
1551
  return;
1552
1552
  }
1553
1553
  workflow.call({
@@ -1608,7 +1608,7 @@
1608
1608
  viewport.reset(buffer.startIndex);
1609
1609
  var payload = {};
1610
1610
  if (state.cycle.busy.get()) {
1611
- state.scrollState.cleanupTimers();
1611
+ state.scroll.stop();
1612
1612
  payload.finalize = true;
1613
1613
  state.cycle.interrupter = Reload.process;
1614
1614
  }
@@ -1998,7 +1998,7 @@
1998
1998
  }
1999
1999
  }
2000
2000
  // virtual removal
2001
- scroller.logger.log(function () { return "going to remove " + toRemove.length + " item(s) virtually"; });
2001
+ scroller.logger.log(function () { return "going to remove ".concat(toRemove.length, " item(s) virtually"); });
2002
2002
  buffer.removeVirtually(toRemove, !!increase);
2003
2003
  buffer.checkDefaultSize();
2004
2004
  Remove.shiftFirstVisibleIndex(scroller, toRemove, !!increase);
@@ -2232,8 +2232,8 @@
2232
2232
  startDelta += buffer.getSizeByIndex(index);
2233
2233
  }
2234
2234
  scroller.logger.log(function () { return __spreadArray([
2235
- "start delta is " + startDelta
2236
- ], __read((offset ? [" (+" + offset + " offset)"] : [])), false); });
2235
+ "start delta is ".concat(startDelta)
2236
+ ], __read((offset ? [" (+".concat(offset, " offset)")] : [])), false); });
2237
2237
  return startDelta;
2238
2238
  };
2239
2239
  PreFetch.setFirstIndex = function (scroller) {
@@ -2404,17 +2404,17 @@
2404
2404
  direction_1 = fetch.last.index < buffer.items[0].$index ? exports.Direction.backward : exports.Direction.forward;
2405
2405
  }
2406
2406
  fetch.direction = direction_1;
2407
- scroller.logger.log(function () { return "fetch direction is \"" + direction_1 + "\""; });
2407
+ scroller.logger.log(function () { return "fetch direction is \"".concat(direction_1, "\""); });
2408
2408
  }
2409
2409
  };
2410
2410
  PreFetch.getStatus = function (scroller) {
2411
2411
  var _a = scroller.state, cycle = _a.cycle, fetch = _a.fetch;
2412
2412
  if (cycle.initiator === AdapterProcess.clip) {
2413
- scroller.logger.log(function () { return "going to skip fetch due to \"" + AdapterProcess.clip + "\" process"; });
2413
+ scroller.logger.log(function () { return "going to skip fetch due to \"".concat(AdapterProcess.clip, "\" process"); });
2414
2414
  return ProcessStatus.next;
2415
2415
  }
2416
2416
  if (fetch.shouldFetch) {
2417
- scroller.logger.log(function () { return "going to fetch " + fetch.count + " items started from index " + fetch.index; });
2417
+ scroller.logger.log(function () { return "going to fetch ".concat(fetch.count, " items started from index ").concat(fetch.index); });
2418
2418
  return ProcessStatus.next;
2419
2419
  }
2420
2420
  return ProcessStatus.done;
@@ -2432,8 +2432,8 @@
2432
2432
  var box = {
2433
2433
  success: function (data) {
2434
2434
  scroller.logger.log(function () {
2435
- return "resolved " + data.length + " items " +
2436
- ("(index = " + scroller.state.fetch.index + ", count = " + scroller.state.fetch.count + ")");
2435
+ return "resolved ".concat(data.length, " items ") +
2436
+ "(index = ".concat(scroller.state.fetch.index, ", count = ").concat(scroller.state.fetch.count, ")");
2437
2437
  });
2438
2438
  scroller.state.fetch.newItemsData = data;
2439
2439
  workflow.call({
@@ -2463,9 +2463,9 @@
2463
2463
  }
2464
2464
  }
2465
2465
  else {
2466
- var _b = scroller.state, scrollState = _b.scrollState, fetch_1 = _b.fetch, viewport = scroller.viewport;
2467
- if (scrollState.positionBeforeAsync === null) {
2468
- scrollState.positionBeforeAsync = viewport.scrollPosition;
2466
+ var _b = scroller.state, scroll_1 = _b.scroll, fetch_1 = _b.fetch, viewport = scroller.viewport;
2467
+ if (scroll_1.positionBeforeAsync === null) {
2468
+ scroll_1.positionBeforeAsync = viewport.scrollPosition;
2469
2469
  }
2470
2470
  fetch_1.cancel = function () {
2471
2471
  box.success = function () { return null; };
@@ -2597,13 +2597,13 @@
2597
2597
  return _super !== null && _super.apply(this, arguments) || this;
2598
2598
  }
2599
2599
  Render.run = function (scroller) {
2600
- var workflow = scroller.workflow, _a = scroller.state, cycle = _a.cycle, render = _a.render, scrollState = _a.scrollState, viewport = scroller.viewport;
2600
+ var workflow = scroller.workflow, _a = scroller.state, cycle = _a.cycle, render = _a.render, scroll = _a.scroll, viewport = scroller.viewport, routines = scroller.routines;
2601
2601
  scroller.logger.stat('before new items render');
2602
- if (scrollState.positionBeforeAsync === null) {
2603
- scrollState.positionBeforeAsync = viewport.scrollPosition;
2602
+ if (scroll.positionBeforeAsync === null) {
2603
+ scroll.positionBeforeAsync = viewport.scrollPosition;
2604
2604
  }
2605
- render.renderTimer = setTimeout(function () {
2606
- render.renderTimer = null;
2605
+ render.cancel = routines.render(function () {
2606
+ render.cancel = null;
2607
2607
  if (Render.doRender(scroller)) {
2608
2608
  workflow.call({
2609
2609
  process: Render.process,
@@ -2618,7 +2618,7 @@
2618
2618
  payload: { error: 'Can\'t associate item with element' }
2619
2619
  });
2620
2620
  }
2621
- }, 0);
2621
+ });
2622
2622
  };
2623
2623
  Render.doRender = function (scroller) {
2624
2624
  var _a = scroller.state, fetch = _a.fetch, render = _a.render, viewport = scroller.viewport, buffer = scroller.buffer, logger = scroller.logger;
@@ -2652,18 +2652,92 @@
2652
2652
  return Render;
2653
2653
  }(BaseProcessFactory(CommonProcess.render)));
2654
2654
 
2655
+ var isInterrupted = function (_a) {
2656
+ var call = _a.call;
2657
+ return !!call.interrupted;
2658
+ };
2659
+ var End = /** @class */ (function (_super) {
2660
+ __extends(End, _super);
2661
+ function End() {
2662
+ return _super !== null && _super.apply(this, arguments) || this;
2663
+ }
2664
+ End.run = function (scroller, _a) {
2665
+ var _b = _a === void 0 ? {} : _a, error = _b.error;
2666
+ var workflow = scroller.workflow, interrupter = scroller.state.cycle.interrupter;
2667
+ if (!error && !interrupter) {
2668
+ // set out params accessible via Adapter
2669
+ End.calculateParams(scroller, workflow);
2670
+ }
2671
+ // explicit interruption for we don't want to go through the inner loop finalizing
2672
+ if (isInterrupted(workflow)) {
2673
+ workflow.call({ process: End.process, status: ProcessStatus.done });
2674
+ return;
2675
+ }
2676
+ var next = End.shouldContinueRun(scroller, error);
2677
+ scroller.state.endInnerLoop();
2678
+ workflow.call({
2679
+ process: End.process,
2680
+ status: next ? ProcessStatus.next : ProcessStatus.done,
2681
+ payload: __assign({}, (interrupter ? { process: interrupter } : {}))
2682
+ });
2683
+ };
2684
+ End.calculateParams = function (scroller, workflow) {
2685
+ var adapter = scroller.adapter, viewport = scroller.viewport, items = scroller.buffer.items;
2686
+ if (adapter.wanted.firstVisible) {
2687
+ var item = viewport.getEdgeVisibleItem(items, exports.Direction.backward).item;
2688
+ if (!item || item.element !== adapter.firstVisible.element) {
2689
+ adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
2690
+ }
2691
+ }
2692
+ // the workflow can be interrupter on firstVisible change
2693
+ if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
2694
+ var item = viewport.getEdgeVisibleItem(items, exports.Direction.forward).item;
2695
+ if (!item || item.element !== adapter.lastVisible.element) {
2696
+ adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
2697
+ }
2698
+ }
2699
+ };
2700
+ End.shouldContinueRun = function (scroller, error) {
2701
+ var _a = scroller.state, cycle = _a.cycle, fetch = _a.fetch, render = _a.render;
2702
+ // Adapter.reload or Adapter.reset
2703
+ if (cycle.interrupter) {
2704
+ return true;
2705
+ }
2706
+ // critical error
2707
+ if (error) {
2708
+ return false;
2709
+ }
2710
+ // Adapter.check
2711
+ if (fetch.simulate && fetch.isCheck && !render.noSize) {
2712
+ return true;
2713
+ }
2714
+ // Adapter.remove or Adapter.update with clip
2715
+ if (fetch.simulate && fetch.doRemove) {
2716
+ return true;
2717
+ }
2718
+ // common inner loop (App start, scroll, Adapter.clip) with full fetch
2719
+ if (!fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
2720
+ return true;
2721
+ }
2722
+ return false;
2723
+ };
2724
+ return End;
2725
+ }(BaseProcessFactory(CommonProcess.end)));
2726
+
2655
2727
  var Adjust = /** @class */ (function (_super) {
2656
2728
  __extends(Adjust, _super);
2657
2729
  function Adjust() {
2658
2730
  return _super !== null && _super.apply(this, arguments) || this;
2659
2731
  }
2660
2732
  Adjust.run = function (scroller) {
2661
- var workflow = scroller.workflow, viewport = scroller.viewport, scrollState = scroller.state.scrollState;
2662
- scrollState.positionBeforeAdjust = viewport.scrollPosition;
2733
+ var workflow = scroller.workflow, viewport = scroller.viewport, scroll = scroller.state.scroll;
2734
+ scroll.positionBeforeAdjust = viewport.scrollPosition;
2663
2735
  Adjust.setPaddings(scroller);
2664
- scrollState.positionAfterAdjust = viewport.scrollPosition;
2736
+ scroll.positionAfterAdjust = viewport.scrollPosition;
2665
2737
  // scroll position adjustments
2666
2738
  var position = Adjust.calculatePosition(scroller);
2739
+ // additional adjustment if the position can't be reached during the initial cycle
2740
+ Adjust.setAdditionalForwardPadding(scroller, position);
2667
2741
  // set new position using animation frame
2668
2742
  Adjust.setPosition(scroller, position, function () {
2669
2743
  return workflow.call({
@@ -2696,7 +2770,8 @@
2696
2770
  }
2697
2771
  // lack of items case
2698
2772
  var bufferSize = viewport.getScrollableSize() - forward.size - backward.size;
2699
- var viewportSizeDiff = viewport.getSize() - (bwdSize + bufferSize + fwdSize);
2773
+ var scrollSize = bwdSize + bufferSize + fwdSize;
2774
+ var viewportSizeDiff = viewport.getSize() - scrollSize;
2700
2775
  if (viewportSizeDiff > 0) {
2701
2776
  if (inverse) {
2702
2777
  bwdSize += viewportSizeDiff;
@@ -2705,7 +2780,7 @@
2705
2780
  fwdSize += viewportSizeDiff;
2706
2781
  }
2707
2782
  scroller.logger.log(function () {
2708
- return inverse ? 'backward' : 'forward' + (" padding will be increased by " + viewportSizeDiff + " to fill the viewport");
2783
+ return inverse ? 'backward' : 'forward' + " padding will be increased by ".concat(viewportSizeDiff, " to fill the viewport");
2709
2784
  });
2710
2785
  }
2711
2786
  backward.size = bwdSize;
@@ -2713,11 +2788,11 @@
2713
2788
  scroller.logger.stat('after paddings adjustments');
2714
2789
  };
2715
2790
  Adjust.calculatePosition = function (scroller) {
2716
- var viewport = scroller.viewport, buffer = scroller.buffer, _a = scroller.state, fetch = _a.fetch, render = _a.render, scrollState = _a.scrollState;
2791
+ var viewport = scroller.viewport, buffer = scroller.buffer, _a = scroller.state, fetch = _a.fetch, render = _a.render, scroll = _a.scroll;
2717
2792
  var position = viewport.paddings.backward.size;
2718
2793
  // increase the position to meet the expectation of the first visible item
2719
2794
  if (!isNaN(fetch.firstVisible.index) && !isNaN(buffer.firstIndex)) {
2720
- scroller.logger.log("first index = " + fetch.firstVisible.index + ", delta = " + fetch.firstVisible.delta);
2795
+ scroller.logger.log("first index = ".concat(fetch.firstVisible.index, ", delta = ").concat(fetch.firstVisible.delta));
2721
2796
  var shouldCheckPreSizeExpectation_1 = fetch.shouldCheckPreSizeExpectation(buffer.lastIndex);
2722
2797
  buffer.items.forEach(function (item) {
2723
2798
  // 1) shift of the buffered items before the first visible item
@@ -2736,10 +2811,10 @@
2736
2811
  });
2737
2812
  }
2738
2813
  // slow fetch/render case
2739
- if (scrollState.positionBeforeAsync !== null) {
2740
- var diff = render.positionBefore - scrollState.positionBeforeAsync;
2814
+ if (scroll.positionBeforeAsync !== null) {
2815
+ var diff = render.positionBefore - scroll.positionBeforeAsync;
2741
2816
  if (diff !== 0) {
2742
- scroller.logger.log("shift position due to fetch-render difference (" + diff + ")");
2817
+ scroller.logger.log("shift position due to fetch-render difference (".concat(diff, ")"));
2743
2818
  position += diff;
2744
2819
  }
2745
2820
  }
@@ -2749,22 +2824,47 @@
2749
2824
  }
2750
2825
  return Math.round(position);
2751
2826
  };
2827
+ Adjust.setAdditionalForwardPadding = function (scroller, position) {
2828
+ var viewport = scroller.viewport, buffer = scroller.buffer, cycle = scroller.state.cycle;
2829
+ if (!cycle.isInitial || !End.shouldContinueRun(scroller, null)) {
2830
+ return;
2831
+ }
2832
+ var diff = position - viewport.getMaxScrollPosition();
2833
+ if (diff <= 0) {
2834
+ return;
2835
+ }
2836
+ var last = buffer.getLastVisibleItem();
2837
+ if (!last) {
2838
+ return;
2839
+ }
2840
+ var size = 0;
2841
+ var index = last.$index + 1;
2842
+ while (size <= diff && index <= buffer.absMaxIndex) {
2843
+ size += buffer.getSizeByIndex(index++);
2844
+ }
2845
+ var shift = Math.min(size, diff);
2846
+ if (shift) {
2847
+ viewport.paddings.forward.size += shift;
2848
+ scroller.logger.log("increase fwd padding due to lack of items (".concat(diff, " -> ").concat(shift, ")"));
2849
+ }
2850
+ };
2752
2851
  Adjust.setPosition = function (scroller, position, done) {
2753
- var scrollState = scroller.state.scrollState, viewport = scroller.viewport;
2754
- if (!scrollState.hasPositionChanged(position)) {
2852
+ var scroll = scroller.state.scroll, viewport = scroller.viewport, routines = scroller.routines;
2853
+ if (!scroll.hasPositionChanged(position)) {
2755
2854
  return done();
2756
2855
  }
2757
- scrollState.syntheticPosition = position;
2758
- scrollState.syntheticFulfill = false;
2759
- scrollState.animationFrameId = requestAnimationFrame(function () {
2760
- var inertiaDiff = scrollState.positionAfterAdjust - viewport.scrollPosition;
2856
+ scroll.syntheticPosition = position;
2857
+ scroll.syntheticFulfill = false;
2858
+ scroll.cancelAnimation = routines.animate(function () {
2859
+ scroll.cancelAnimation = null;
2860
+ var inertiaDiff = scroll.positionAfterAdjust - viewport.scrollPosition;
2761
2861
  var diffLog = '';
2762
2862
  if (inertiaDiff > 0) {
2763
2863
  position -= inertiaDiff;
2764
- scrollState.syntheticPosition = position;
2765
- diffLog = " (-" + inertiaDiff + ")";
2864
+ scroll.syntheticPosition = position;
2865
+ diffLog = " (-".concat(inertiaDiff, ")");
2766
2866
  }
2767
- scrollState.syntheticFulfill = true;
2867
+ scroll.syntheticFulfill = true;
2768
2868
  viewport.scrollPosition = position;
2769
2869
  scroller.logger.stat('after scroll adjustment' + diffLog);
2770
2870
  done();
@@ -2796,8 +2896,8 @@
2796
2896
  var firstIndex = fetch.first.indexBuffer;
2797
2897
  var lastIndex = fetch.last.indexBuffer;
2798
2898
  scroller.logger.log(function () {
2799
- return "looking for " + (fetch.direction ? 'anti-' + fetch.direction + ' ' : '') + "items " +
2800
- ("that are out of [" + firstIndex + ".." + lastIndex + "] range");
2899
+ return "looking for ".concat(fetch.direction ? 'anti-' + fetch.direction + ' ' : '', "items ") +
2900
+ "that are out of [".concat(firstIndex, "..").concat(lastIndex, "] range");
2801
2901
  });
2802
2902
  if (PreClip.isBackward(scroller, firstIndex)) {
2803
2903
  PreClip.prepareClipByDirection(scroller, exports.Direction.backward, firstIndex);
@@ -2881,7 +2981,7 @@
2881
2981
  var _a;
2882
2982
  var buffer = scroller.buffer, paddings = scroller.viewport.paddings, clip = scroller.state.clip, logger = scroller.logger;
2883
2983
  var size = (_a = {}, _a[exports.Direction.backward] = 0, _a[exports.Direction.forward] = 0, _a);
2884
- logger.stat("before clip (" + ++clip.callCount + ")");
2984
+ logger.stat("before clip (".concat(++clip.callCount, ")"));
2885
2985
  var itemsToRemove = buffer.items.filter(function (item) {
2886
2986
  if (!item.toRemove) {
2887
2987
  return false;
@@ -2909,10 +3009,10 @@
2909
3009
  });
2910
3010
  return list.length
2911
3011
  ? [
2912
- "clipped " + list.length + " item(s) from Buffer" +
2913
- (size.backward ? ", +" + size.backward + " fwd px" : '') +
2914
- (size.forward ? ", +" + size.forward + " bwd px" : '') +
2915
- (", range: [" + list[0] + ".." + list[list.length - 1] + "]")
3012
+ "clipped ".concat(list.length, " item(s) from Buffer") +
3013
+ (size.backward ? ", +".concat(size.backward, " fwd px") : '') +
3014
+ (size.forward ? ", +".concat(size.forward, " bwd px") : '') +
3015
+ ", range: [".concat(list[0], "..").concat(list[list.length - 1], "]")
2916
3016
  ]
2917
3017
  : 'clipped 0 items from Buffer';
2918
3018
  });
@@ -2921,76 +3021,6 @@
2921
3021
  return Clip;
2922
3022
  }(BaseProcessFactory(CommonProcess.clip)));
2923
3023
 
2924
- var isInterrupted = function (_a) {
2925
- var call = _a.call;
2926
- return !!call.interrupted;
2927
- };
2928
- var End = /** @class */ (function (_super) {
2929
- __extends(End, _super);
2930
- function End() {
2931
- return _super !== null && _super.apply(this, arguments) || this;
2932
- }
2933
- End.run = function (scroller, _a) {
2934
- var _b = _a === void 0 ? {} : _a, error = _b.error;
2935
- var workflow = scroller.workflow, interrupter = scroller.state.cycle.interrupter;
2936
- if (!error && !interrupter) {
2937
- // set out params accessible via Adapter
2938
- End.calculateParams(scroller, workflow);
2939
- }
2940
- // explicit interruption for we don't want to go through the inner loop finalizing
2941
- if (isInterrupted(workflow)) {
2942
- workflow.call({ process: End.process, status: ProcessStatus.done });
2943
- return;
2944
- }
2945
- var next = End.finalizeInnerLoop(scroller, error);
2946
- workflow.call({
2947
- process: End.process,
2948
- status: next ? ProcessStatus.next : ProcessStatus.done,
2949
- payload: __assign({}, (interrupter ? { process: interrupter } : {}))
2950
- });
2951
- };
2952
- End.calculateParams = function (scroller, workflow) {
2953
- var adapter = scroller.adapter, viewport = scroller.viewport, items = scroller.buffer.items;
2954
- if (adapter.wanted.firstVisible) {
2955
- var item = viewport.getEdgeVisibleItem(items, exports.Direction.backward).item;
2956
- if (!item || item.element !== adapter.firstVisible.element) {
2957
- adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
2958
- }
2959
- }
2960
- // the workflow can be interrupter on firstVisible change
2961
- if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
2962
- var item = viewport.getEdgeVisibleItem(items, exports.Direction.forward).item;
2963
- if (!item || item.element !== adapter.lastVisible.element) {
2964
- adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
2965
- }
2966
- }
2967
- };
2968
- End.finalizeInnerLoop = function (scroller, error) {
2969
- var state = scroller.state, _a = scroller.state, cycle = _a.cycle, clip = _a.clip, fetch = _a.fetch;
2970
- var next = !!cycle.interrupter || (error ? false : End.getNext(scroller));
2971
- cycle.innerLoop.isInitial = false;
2972
- fetch.stopSimulate();
2973
- clip.reset(true);
2974
- state.endInnerLoop();
2975
- return next;
2976
- };
2977
- End.getNext = function (scroller) {
2978
- var _a = scroller.state, fetch = _a.fetch, render = _a.render;
2979
- if (fetch.simulate && fetch.isCheck && !render.noSize) { // Adapter.check
2980
- return true;
2981
- }
2982
- if (fetch.simulate && fetch.doRemove) { // Adapter.remove or Adapter.update with clip
2983
- return true;
2984
- }
2985
- if ( // common inner loop (App start, Scroll, Adapter.clip) accompanied by fetch
2986
- !fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
2987
- return true;
2988
- }
2989
- return false;
2990
- };
2991
- return End;
2992
- }(BaseProcessFactory(CommonProcess.end)));
2993
-
2994
3024
  var Logger = /** @class */ (function () {
2995
3025
  function Logger(scroller, packageInfo, adapter) {
2996
3026
  var _this = this;
@@ -3008,19 +3038,19 @@
3008
3038
  return arg;
3009
3039
  }
3010
3040
  else if (Array.isArray(arg)) {
3011
- return "[of " + arg.length + "]";
3041
+ return "[of ".concat(arg.length, "]");
3012
3042
  }
3013
3043
  return '{ ' + Object.keys(arg).join(', ') + ' }';
3014
3044
  })
3015
3045
  .join(', ');
3016
- _this.log("adapter: " + methodName + "(" + (params || '') + ")" + (add || ''));
3046
+ _this.log("adapter: ".concat(methodName, "(").concat(params || '', ")").concat(add || ''));
3017
3047
  };
3018
3048
  var settings = scroller.settings;
3019
3049
  this.debug = settings.debug;
3020
3050
  this.immediateLog = settings.immediateLog;
3021
3051
  this.logTime = settings.logTime;
3022
3052
  this.getTime = function () {
3023
- return scroller.state && " // time: " + scroller.state.time;
3053
+ return scroller.state && " // time: ".concat(scroller.state.time);
3024
3054
  };
3025
3055
  this.getStat = function () {
3026
3056
  var buffer = scroller.buffer, viewport = scroller.viewport;
@@ -3032,26 +3062,26 @@
3032
3062
  'fwd_p: ' + viewport.paddings.forward.size + ', ' +
3033
3063
  'default: ' + (buffer.defaultSize || 'no') + ', ' +
3034
3064
  'items: ' + buffer.getVisibleItemsCount() + ', ' +
3035
- 'range: ' + (first && last ? "[" + first.$index + ".." + last.$index + "]" : 'no');
3065
+ 'range: ' + (first && last ? "[".concat(first.$index, "..").concat(last.$index, "]") : 'no');
3036
3066
  };
3037
3067
  this.getFetchRange = function () {
3038
3068
  var _a = scroller.state.fetch, first = _a.first.index, last = _a.last.index;
3039
3069
  return !Number.isNaN(first) && !Number.isNaN(last)
3040
- ? "[" + first + ".." + last + "]"
3070
+ ? "[".concat(first, "..").concat(last, "]")
3041
3071
  : 'no';
3042
3072
  };
3043
3073
  this.getLoopId = function () { return scroller.state.cycle.loopId; };
3044
3074
  this.getLoopIdNext = function () { return scroller.state.cycle.loopIdNext; };
3045
3075
  this.getWorkflowCycleData = function () {
3046
- return settings.instanceIndex + "-" + scroller.state.cycle.count;
3076
+ return "".concat(settings.instanceIndex, "-").concat(scroller.state.cycle.count);
3047
3077
  };
3048
- this.getScrollPosition = function (element) { return scroller.routines.getScrollPosition(element); };
3078
+ this.getScrollPosition = function () { return scroller.routines.getScrollPosition(); };
3049
3079
  this.log(function () {
3050
3080
  return 'vscroll Workflow has been started, ' +
3051
- ("core: " + packageInfo.core.name + " v" + packageInfo.core.version + ", ") +
3052
- ("consumer: " + packageInfo.consumer.name + " v" + packageInfo.consumer.version + ", ") +
3053
- ("scroller instance: " + settings.instanceIndex + ", adapter ") +
3054
- (!adapter ? 'is not instantiated' : "instance: " + adapter.id);
3081
+ "core: ".concat(packageInfo.core.name, " v").concat(packageInfo.core.version, ", ") +
3082
+ "consumer: ".concat(packageInfo.consumer.name, " v").concat(packageInfo.consumer.version, ", ") +
3083
+ "scroller instance: ".concat(settings.instanceIndex, ", adapter ") +
3084
+ (!adapter ? 'is not instantiated' : "instance: ".concat(adapter.id));
3055
3085
  });
3056
3086
  }
3057
3087
  Logger.prototype.object = function (str, obj, stringify) {
@@ -3092,20 +3122,20 @@
3092
3122
  'color: #888; border: dashed #888 0; border-bottom-width: 0px',
3093
3123
  'color: #000; border-width: 0'
3094
3124
  ];
3095
- this.log(function () { return __spreadArray(['%cstat' + (str ? " " + str : '') + ',%c ' + _this.getStat()], __read(logStyles_1), false); });
3125
+ this.log(function () { return __spreadArray(['%cstat' + (str ? " ".concat(str) : '') + ',%c ' + _this.getStat()], __read(logStyles_1), false); });
3096
3126
  }
3097
3127
  };
3098
3128
  Logger.prototype.fetch = function (str) {
3099
3129
  var _this = this;
3100
3130
  if (this.debug) {
3101
- var _text_1 = 'fetch interval' + (str ? " " + str : '');
3131
+ var _text_1 = 'fetch interval' + (str ? " ".concat(str) : '');
3102
3132
  var logStyles_2 = ['color: #888', 'color: #000'];
3103
- this.log(function () { return __spreadArray(["%c" + _text_1 + ": %c" + _this.getFetchRange()], __read(logStyles_2), false); });
3133
+ this.log(function () { return __spreadArray(["%c".concat(_text_1, ": %c").concat(_this.getFetchRange())], __read(logStyles_2), false); });
3104
3134
  }
3105
3135
  };
3106
3136
  Logger.prototype.prepareForLog = function (data) {
3107
3137
  return data instanceof Event && data.target
3108
- ? this.getScrollPosition(data.target)
3138
+ ? this.getScrollPosition()
3109
3139
  : data;
3110
3140
  };
3111
3141
  Logger.prototype.logProcess = function (data) {
@@ -3116,13 +3146,13 @@
3116
3146
  // inner loop start-end log
3117
3147
  var loopLog = [];
3118
3148
  if (process === CommonProcess.init && status === ProcessStatus.next) {
3119
- loopLog.push("%c---=== loop " + this.getLoopIdNext() + " start");
3149
+ loopLog.push("%c---=== loop ".concat(this.getLoopIdNext(), " start"));
3120
3150
  }
3121
3151
  else if (process === CommonProcess.end) {
3122
- loopLog.push("%c---=== loop " + this.getLoopId() + " done");
3152
+ loopLog.push("%c---=== loop ".concat(this.getLoopId(), " done"));
3123
3153
  var parent_1 = payload && payload.process;
3124
3154
  if (status === ProcessStatus.next && (parent_1 !== AdapterProcess.reset && parent_1 !== AdapterProcess.reload)) {
3125
- loopLog[0] += ", loop " + this.getLoopIdNext() + " start";
3155
+ loopLog[0] += ", loop ".concat(this.getLoopIdNext(), " start");
3126
3156
  }
3127
3157
  }
3128
3158
  if (loopLog.length) {
@@ -3133,14 +3163,14 @@
3133
3163
  if (start === void 0) { start = true; }
3134
3164
  var logData = this.getWorkflowCycleData();
3135
3165
  var border = start ? '1px 0 0 1px' : '0 0 1px 1px';
3136
- var logStyles = "color: #0000aa; border: solid #555 1px; border-width: " + border + "; margin-left: -2px";
3137
- this.log(function () { return ["%c ~~~ WF Cycle " + logData + " " + (start ? 'STARTED' : 'FINALIZED') + " ~~~ ", logStyles]; });
3166
+ var logStyles = "color: #0000aa; border: solid #555 1px; border-width: ".concat(border, "; margin-left: -2px");
3167
+ this.log(function () { return ["%c ~~~ WF Cycle ".concat(logData, " ").concat(start ? 'STARTED' : 'FINALIZED', " ~~~ "), logStyles]; });
3138
3168
  };
3139
3169
  Logger.prototype.logError = function (str) {
3140
3170
  var _this = this;
3141
3171
  if (this.debug) {
3142
3172
  var logStyles_3 = ['color: #a00;', 'color: #000'];
3143
- this.log(function () { return __spreadArray(['error:%c' + (str ? " " + str : '') + ("%c (loop " + _this.getLoopIdNext() + ")")], __read(logStyles_3), false); });
3173
+ this.log(function () { return __spreadArray(['error:%c' + (str ? " ".concat(str) : '') + "%c (loop ".concat(_this.getLoopIdNext(), ")")], __read(logStyles_3), false); });
3144
3174
  }
3145
3175
  };
3146
3176
  Logger.prototype.log = function () {
@@ -3200,64 +3230,84 @@
3200
3230
  }());
3201
3231
 
3202
3232
  var Routines = /** @class */ (function () {
3203
- function Routines(settings) {
3204
- this.horizontal = settings.horizontal;
3205
- this.window = settings.windowViewport;
3206
- this.viewport = settings.viewport;
3233
+ function Routines(element, settings, CustomRoutines) {
3234
+ var _this = this;
3235
+ this.element = element;
3236
+ this.settings = {
3237
+ viewport: settings.viewport,
3238
+ horizontal: settings.horizontal,
3239
+ window: settings.windowViewport
3240
+ };
3241
+ // provide custom overrides for IRoutines methods
3242
+ if (CustomRoutines) {
3243
+ var routines_1 = new CustomRoutines(element, this.settings);
3244
+ Object.getOwnPropertyNames(Object.getPrototypeOf(routines_1))
3245
+ .filter(function (method) {
3246
+ return method !== 'constructor' &&
3247
+ typeof routines_1[method] === 'function' &&
3248
+ typeof _this[method] === 'function';
3249
+ })
3250
+ .forEach(function (method) {
3251
+ return _this[method] = function () {
3252
+ var args = [];
3253
+ for (var _i = 0; _i < arguments.length; _i++) {
3254
+ args[_i] = arguments[_i];
3255
+ }
3256
+ return routines_1[method].apply(_this, args);
3257
+ };
3258
+ });
3259
+ }
3260
+ // initialization
3261
+ this.viewport = this.getViewportElement();
3262
+ this.onInit(settings);
3207
3263
  }
3208
3264
  Routines.prototype.checkElement = function (element) {
3209
3265
  if (!element) {
3210
3266
  throw new Error('HTML element is not defined');
3211
3267
  }
3212
3268
  };
3213
- Routines.prototype.getHostElement = function (element) {
3214
- if (this.window) {
3269
+ Routines.prototype.getViewportElement = function () {
3270
+ if (this.settings.window) {
3215
3271
  return document.documentElement;
3216
3272
  }
3217
- if (this.viewport) {
3218
- return this.viewport;
3273
+ if (this.settings.viewport) {
3274
+ return this.settings.viewport;
3219
3275
  }
3220
- this.checkElement(element);
3221
- var parent = element.parentElement;
3276
+ this.checkElement(this.element);
3277
+ var parent = this.element.parentElement;
3222
3278
  this.checkElement(parent);
3223
3279
  return parent;
3224
3280
  };
3225
- Routines.prototype.getScrollEventReceiver = function (element) {
3226
- if (this.window) {
3227
- return window;
3281
+ Routines.prototype.onInit = function (settings) {
3282
+ if (settings.windowViewport) {
3283
+ if ('scrollRestoration' in history) {
3284
+ history.scrollRestoration = 'manual';
3285
+ }
3228
3286
  }
3229
- return this.getHostElement(element);
3230
- };
3231
- Routines.prototype.setupScrollRestoration = function () {
3232
- if ('scrollRestoration' in history) {
3233
- history.scrollRestoration = 'manual';
3287
+ if (settings.dismissOverflowAnchor) {
3288
+ this.viewport.style.overflowAnchor = 'none';
3234
3289
  }
3235
3290
  };
3236
- Routines.prototype.dismissOverflowAnchor = function (element) {
3237
- this.checkElement(element);
3238
- element.style.overflowAnchor = 'none';
3239
- };
3240
3291
  Routines.prototype.findElementBySelector = function (element, selector) {
3241
3292
  this.checkElement(element);
3242
3293
  return element.querySelector(selector);
3243
3294
  };
3244
- Routines.prototype.findPaddingElement = function (element, direction) {
3245
- return this.findElementBySelector(element, "[data-padding-" + direction + "]");
3295
+ Routines.prototype.findPaddingElement = function (direction) {
3296
+ return this.findElementBySelector(this.element, "[data-padding-".concat(direction, "]"));
3246
3297
  };
3247
- Routines.prototype.findItemElement = function (element, id) {
3248
- return this.findElementBySelector(element, "[data-sid=\"" + id + "\"]");
3298
+ Routines.prototype.findItemElement = function (id) {
3299
+ return this.findElementBySelector(this.element, "[data-sid=\"".concat(id, "\"]"));
3249
3300
  };
3250
- Routines.prototype.getScrollPosition = function (element) {
3251
- if (this.window) {
3252
- return window.pageYOffset;
3301
+ Routines.prototype.getScrollPosition = function () {
3302
+ if (this.settings.window) {
3303
+ return this.settings.horizontal ? window.pageXOffset : window.pageYOffset;
3253
3304
  }
3254
- this.checkElement(element);
3255
- return element[this.horizontal ? 'scrollLeft' : 'scrollTop'];
3305
+ return this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'];
3256
3306
  };
3257
- Routines.prototype.setScrollPosition = function (element, value) {
3307
+ Routines.prototype.setScrollPosition = function (value) {
3258
3308
  value = Math.max(0, value);
3259
- if (this.window) {
3260
- if (this.horizontal) {
3309
+ if (this.settings.window) {
3310
+ if (this.settings.horizontal) {
3261
3311
  window.scrollTo(value, window.scrollY);
3262
3312
  }
3263
3313
  else {
@@ -3265,49 +3315,62 @@
3265
3315
  }
3266
3316
  return;
3267
3317
  }
3268
- this.checkElement(element);
3269
- element[this.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
3318
+ this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
3270
3319
  };
3271
- Routines.prototype.getParams = function (element, doNotBind) {
3320
+ Routines.prototype.getElementParams = function (element) {
3272
3321
  this.checkElement(element);
3273
- if (this.window && doNotBind) {
3274
- var clientWidth = element.clientWidth, clientHeight = element.clientHeight, clientLeft = element.clientLeft, clientTop = element.clientTop;
3275
- return {
3276
- 'height': clientHeight,
3277
- 'width': clientWidth,
3278
- 'top': clientTop,
3279
- 'bottom': clientTop + clientHeight,
3280
- 'left': clientLeft,
3281
- 'right': clientLeft + clientWidth,
3282
- 'x': clientLeft,
3283
- 'y': clientTop,
3284
- 'toJSON': function () { return null; },
3285
- };
3286
- }
3287
3322
  return element.getBoundingClientRect();
3288
3323
  };
3289
- Routines.prototype.getSize = function (element, doNotBind) {
3290
- return this.getParams(element, doNotBind)[this.horizontal ? 'width' : 'height'];
3324
+ Routines.prototype.getWindowParams = function () {
3325
+ var _a = this.viewport, clientWidth = _a.clientWidth, clientHeight = _a.clientHeight, clientLeft = _a.clientLeft, clientTop = _a.clientTop;
3326
+ return {
3327
+ 'height': clientHeight,
3328
+ 'width': clientWidth,
3329
+ 'top': clientTop,
3330
+ 'bottom': clientTop + clientHeight,
3331
+ 'left': clientLeft,
3332
+ 'right': clientLeft + clientWidth,
3333
+ 'x': clientLeft,
3334
+ 'y': clientTop,
3335
+ 'toJSON': function () { return null; },
3336
+ };
3337
+ };
3338
+ Routines.prototype.getSize = function (element) {
3339
+ return this.getElementParams(element)[this.settings.horizontal ? 'width' : 'height'];
3340
+ };
3341
+ Routines.prototype.getScrollerSize = function () {
3342
+ return this.getElementParams(this.element)[this.settings.horizontal ? 'width' : 'height'];
3343
+ };
3344
+ Routines.prototype.getViewportSize = function () {
3345
+ if (this.settings.window) {
3346
+ return this.getWindowParams()[this.settings.horizontal ? 'width' : 'height'];
3347
+ }
3348
+ return this.getSize(this.viewport);
3291
3349
  };
3292
3350
  Routines.prototype.getSizeStyle = function (element) {
3293
3351
  this.checkElement(element);
3294
- var size = element.style[this.horizontal ? 'width' : 'height'];
3352
+ var size = element.style[this.settings.horizontal ? 'width' : 'height'];
3295
3353
  return parseFloat(size) || 0;
3296
3354
  };
3297
3355
  Routines.prototype.setSizeStyle = function (element, value) {
3298
3356
  this.checkElement(element);
3299
3357
  value = Math.max(0, Math.round(value));
3300
- element.style[this.horizontal ? 'width' : 'height'] = value + "px";
3358
+ element.style[this.settings.horizontal ? 'width' : 'height'] = "".concat(value, "px");
3301
3359
  };
3302
- Routines.prototype.getEdge = function (element, direction, doNotBind) {
3303
- var params = this.getParams(element, doNotBind);
3360
+ Routines.prototype.getEdge = function (element, direction) {
3361
+ var horizontal = this.settings.horizontal;
3362
+ var params = this.getElementParams(element);
3304
3363
  var isFwd = direction === exports.Direction.forward;
3305
- return params[isFwd ? (this.horizontal ? 'right' : 'bottom') : (this.horizontal ? 'left' : 'top')];
3364
+ return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
3306
3365
  };
3307
- Routines.prototype.getEdge2 = function (element, direction, relativeElement, opposite) {
3308
- // vertical only ?
3309
- return element.offsetTop - (relativeElement ? relativeElement.scrollTop : 0) +
3310
- (direction === (!opposite ? exports.Direction.forward : exports.Direction.backward) ? this.getSize(element) : 0);
3366
+ Routines.prototype.getViewportEdge = function (direction) {
3367
+ var _a = this.settings, window = _a.window, horizontal = _a.horizontal;
3368
+ if (window) {
3369
+ var params = this.getWindowParams();
3370
+ var isFwd = direction === exports.Direction.forward;
3371
+ return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
3372
+ }
3373
+ return this.getEdge(this.viewport, direction);
3311
3374
  };
3312
3375
  Routines.prototype.makeElementVisible = function (element) {
3313
3376
  this.checkElement(element);
@@ -3319,20 +3382,36 @@
3319
3382
  this.checkElement(element);
3320
3383
  element.style.display = 'none';
3321
3384
  };
3322
- Routines.prototype.getOffset = function (element) {
3323
- this.checkElement(element);
3324
- return (this.horizontal ? element.offsetLeft : element.offsetTop) || 0;
3385
+ Routines.prototype.getOffset = function () {
3386
+ var _this = this;
3387
+ var get = function (element) {
3388
+ return (_this.settings.horizontal ? element.offsetLeft : element.offsetTop) || 0;
3389
+ };
3390
+ return get(this.element) - (!this.settings.window ? get(this.viewport) : 0);
3325
3391
  };
3326
3392
  Routines.prototype.scrollTo = function (element, argument) {
3327
3393
  this.checkElement(element);
3328
3394
  element.scrollIntoView(argument);
3329
3395
  };
3396
+ Routines.prototype.render = function (cb) {
3397
+ var timeoutId = setTimeout(function () { return cb(); });
3398
+ return function () { return clearTimeout(timeoutId); };
3399
+ };
3400
+ Routines.prototype.animate = function (cb) {
3401
+ var animationFrameId = requestAnimationFrame(function () { return cb(); });
3402
+ return function () { return cancelAnimationFrame(animationFrameId); };
3403
+ };
3404
+ Routines.prototype.onScroll = function (handler) {
3405
+ var eventReceiver = this.settings.window ? window : this.viewport;
3406
+ eventReceiver.addEventListener('scroll', handler);
3407
+ return function () { return eventReceiver.removeEventListener('scroll', handler); };
3408
+ };
3330
3409
  return Routines;
3331
3410
  }());
3332
3411
 
3333
3412
  var Padding = /** @class */ (function () {
3334
- function Padding(element, direction, routines) {
3335
- var found = routines.findPaddingElement(element, direction);
3413
+ function Padding(direction, routines) {
3414
+ var found = routines.findPaddingElement(direction);
3336
3415
  routines.checkElement(found);
3337
3416
  this.element = found;
3338
3417
  this.direction = direction;
@@ -3354,10 +3433,10 @@
3354
3433
  return Padding;
3355
3434
  }());
3356
3435
  var Paddings = /** @class */ (function () {
3357
- function Paddings(element, routines, settings) {
3436
+ function Paddings(routines, settings) {
3358
3437
  this.settings = settings;
3359
- this.forward = new Padding(element, exports.Direction.forward, routines);
3360
- this.backward = new Padding(element, exports.Direction.backward, routines);
3438
+ this.forward = new Padding(exports.Direction.forward, routines);
3439
+ this.backward = new Padding(exports.Direction.backward, routines);
3361
3440
  }
3362
3441
  Paddings.prototype.byDirection = function (direction, opposite) {
3363
3442
  return direction === exports.Direction.backward
@@ -3409,27 +3488,18 @@
3409
3488
  }());
3410
3489
 
3411
3490
  var Viewport = /** @class */ (function () {
3412
- function Viewport(element, settings, routines, state, logger) {
3413
- this.element = element;
3491
+ function Viewport(settings, routines, state, logger) {
3414
3492
  this.settings = settings;
3415
3493
  this.routines = routines;
3416
3494
  this.state = state;
3417
3495
  this.logger = logger;
3418
- this.hostElement = this.routines.getHostElement(this.element);
3419
- this.scrollEventReceiver = this.routines.getScrollEventReceiver(this.element);
3420
- if (settings.windowViewport) {
3421
- this.routines.setupScrollRestoration();
3422
- }
3423
- if (settings.dismissOverflowAnchor) {
3424
- this.routines.dismissOverflowAnchor(this.hostElement);
3425
- }
3426
- this.paddings = new Paddings(this.element, this.routines, settings);
3496
+ this.paddings = new Paddings(this.routines, settings);
3427
3497
  }
3428
3498
  Viewport.prototype.reset = function (startIndex) {
3429
3499
  this.setOffset();
3430
3500
  this.paddings.reset(this.getSize(), startIndex, this.offset);
3431
3501
  this.scrollPosition = this.paddings.backward.size || 0;
3432
- this.state.scrollState.reset();
3502
+ this.state.scroll.reset();
3433
3503
  };
3434
3504
  Viewport.prototype.setPosition = function (value) {
3435
3505
  var oldPosition = this.scrollPosition;
@@ -3437,16 +3507,16 @@
3437
3507
  this.logger.log(function () { return ['setting scroll position at', value, '[cancelled]']; });
3438
3508
  return value;
3439
3509
  }
3440
- this.routines.setScrollPosition(this.hostElement, value);
3510
+ this.routines.setScrollPosition(value);
3441
3511
  var position = this.scrollPosition;
3442
3512
  this.logger.log(function () { return __spreadArray([
3443
3513
  'setting scroll position at', position
3444
- ], __read((position !== value ? ["(" + value + ")"] : [])), false); });
3514
+ ], __read((position !== value ? ["(".concat(value, ")")] : [])), false); });
3445
3515
  return position;
3446
3516
  };
3447
3517
  Object.defineProperty(Viewport.prototype, "scrollPosition", {
3448
3518
  get: function () {
3449
- return this.routines.getScrollPosition(this.hostElement);
3519
+ return this.routines.getScrollPosition();
3450
3520
  },
3451
3521
  set: function (value) {
3452
3522
  this.setPosition(value);
@@ -3455,25 +3525,25 @@
3455
3525
  configurable: true
3456
3526
  });
3457
3527
  Viewport.prototype.getSize = function () {
3458
- return this.routines.getSize(this.hostElement, true);
3528
+ return this.routines.getViewportSize();
3459
3529
  };
3460
3530
  Viewport.prototype.getScrollableSize = function () {
3461
- return this.routines.getSize(this.element);
3531
+ return this.routines.getScrollerSize();
3532
+ };
3533
+ Viewport.prototype.getMaxScrollPosition = function () {
3534
+ return this.getScrollableSize() - this.getSize();
3462
3535
  };
3463
3536
  Viewport.prototype.getBufferPadding = function () {
3464
3537
  return this.getSize() * this.settings.padding;
3465
3538
  };
3466
3539
  Viewport.prototype.getEdge = function (direction) {
3467
- return this.routines.getEdge(this.hostElement, direction, true);
3540
+ return this.routines.getViewportEdge(direction);
3468
3541
  };
3469
3542
  Viewport.prototype.setOffset = function () {
3470
- this.offset = this.routines.getOffset(this.element);
3471
- if (!this.settings.windowViewport) {
3472
- this.offset -= this.routines.getOffset(this.hostElement);
3473
- }
3543
+ this.offset = this.routines.getOffset();
3474
3544
  };
3475
3545
  Viewport.prototype.findItemElementById = function (id) {
3476
- return this.routines.findItemElement(this.element, id);
3546
+ return this.routines.findItemElement(id);
3477
3547
  };
3478
3548
  Viewport.prototype.getEdgeVisibleItem = function (items, direction) {
3479
3549
  var bwd = direction === exports.Direction.backward;
@@ -3687,7 +3757,7 @@
3687
3757
  Cache.prototype.recalculateDefaultSize = function () {
3688
3758
  var _this = this;
3689
3759
  if (this.defaultSize.recalculate(this.size)) {
3690
- this.logger.log(function () { return "default size has been updated: " + _this.defaultSize.get(); });
3760
+ this.logger.log(function () { return "default size has been updated: ".concat(_this.defaultSize.get()); });
3691
3761
  return true;
3692
3762
  }
3693
3763
  return false;
@@ -3906,7 +3976,7 @@
3906
3976
  this.logger.log('no items to fill the buffer; wrong indexes');
3907
3977
  return false;
3908
3978
  }
3909
- this.logger.log(function () { return "going to fill the buffer with " + items.length + " item(s)"; });
3979
+ this.logger.log(function () { return "going to fill the buffer with ".concat(items.length, " item(s)"); });
3910
3980
  return true;
3911
3981
  };
3912
3982
  CheckBufferCall.prototype.insertInBuffer = function (predicate, before, after) {
@@ -3930,18 +4000,18 @@
3930
4000
  if (index < finiteAbsMinIndex || index > finiteAbsMaxIndex) {
3931
4001
  this.logger.log(function () {
3932
4002
  return 'no items to insert virtually; ' +
3933
- ("selected index (" + index + ") does not match virtual area [" + finiteAbsMinIndex + ".." + finiteAbsMaxIndex + "]");
4003
+ "selected index (".concat(index, ") does not match virtual area [").concat(finiteAbsMinIndex, "..").concat(finiteAbsMaxIndex, "]");
3934
4004
  });
3935
4005
  return false;
3936
4006
  }
3937
4007
  var before = direction === exports.Direction.backward;
3938
4008
  if (!(index < firstIndex + (before ? 1 : 0) || index > lastIndex - (before ? 0 : 1))) {
3939
4009
  this.logger.log(function () {
3940
- return "no items to insert virtually; selected index (" + index + ") belongs Buffer [" + firstIndex + ".." + lastIndex + "]";
4010
+ return "no items to insert virtually; selected index (".concat(index, ") belongs Buffer [").concat(firstIndex, "..").concat(lastIndex, "]");
3941
4011
  });
3942
4012
  return false;
3943
4013
  }
3944
- this.logger.log(function () { return "going to insert " + items.length + " item(s) virtually"; });
4014
+ this.logger.log(function () { return "going to insert ".concat(items.length, " item(s) virtually"); });
3945
4015
  return true;
3946
4016
  };
3947
4017
  return CheckBufferCall;
@@ -3985,15 +4055,15 @@
3985
4055
  var start = this.startIndexUser;
3986
4056
  var index = Number(newStartIndex);
3987
4057
  if (Number.isNaN(index)) {
3988
- this.logger.log(function () { return "fallback startIndex to settings.startIndex (" + start + ")"; });
4058
+ this.logger.log(function () { return "fallback startIndex to settings.startIndex (".concat(start, ")"); });
3989
4059
  index = start;
3990
4060
  }
3991
4061
  if (index < min) {
3992
- this.logger.log(function () { return "setting startIndex to settings.minIndex (" + min + ") because " + index + " < " + min; });
4062
+ this.logger.log(function () { return "setting startIndex to settings.minIndex (".concat(min, ") because ").concat(index, " < ").concat(min); });
3993
4063
  index = min;
3994
4064
  }
3995
4065
  if (index > max) {
3996
- this.logger.log(function () { return "setting startIndex to settings.maxIndex (" + max + ") because " + index + " > " + max; });
4066
+ this.logger.log(function () { return "setting startIndex to settings.maxIndex (".concat(max, ") because ").concat(index, " > ").concat(max); });
3997
4067
  index = max;
3998
4068
  }
3999
4069
  this.startIndex = index;
@@ -4369,6 +4439,7 @@
4369
4439
  configurable: true
4370
4440
  });
4371
4441
  InnerLoopModel.prototype.done = function () {
4442
+ this.isInitial = false;
4372
4443
  this.count++;
4373
4444
  this.total++;
4374
4445
  this.busy.set(false);
@@ -4389,27 +4460,22 @@
4389
4460
  this.innerLoop = new InnerLoopModel(loopCount);
4390
4461
  this.interrupter = null;
4391
4462
  this.busy = new Reactive(false);
4392
- this.done(cycleCount);
4463
+ this.end(cycleCount);
4393
4464
  }
4394
4465
  Object.defineProperty(WorkflowCycleModel.prototype, "loopId", {
4395
4466
  get: function () {
4396
- return this.instanceIndex + "-" + this.count + "-" + this.innerLoop.total;
4467
+ return "".concat(this.instanceIndex, "-").concat(this.count, "-").concat(this.innerLoop.total);
4397
4468
  },
4398
4469
  enumerable: false,
4399
4470
  configurable: true
4400
4471
  });
4401
4472
  Object.defineProperty(WorkflowCycleModel.prototype, "loopIdNext", {
4402
4473
  get: function () {
4403
- return this.instanceIndex + "-" + this.count + "-" + (this.innerLoop.total + 1);
4474
+ return "".concat(this.instanceIndex, "-").concat(this.count, "-").concat(this.innerLoop.total + 1);
4404
4475
  },
4405
4476
  enumerable: false,
4406
4477
  configurable: true
4407
4478
  });
4408
- WorkflowCycleModel.prototype.done = function (count) {
4409
- this.count = count;
4410
- this.isInitial = false;
4411
- this.busy.set(false);
4412
- };
4413
4479
  WorkflowCycleModel.prototype.start = function (isInitial, initiator) {
4414
4480
  this.isInitial = isInitial;
4415
4481
  this.initiator = initiator;
@@ -4418,6 +4484,11 @@
4418
4484
  this.interrupter = null;
4419
4485
  this.busy.set(true);
4420
4486
  };
4487
+ WorkflowCycleModel.prototype.end = function (count) {
4488
+ this.count = count;
4489
+ this.isInitial = false;
4490
+ this.busy.set(false);
4491
+ };
4421
4492
  WorkflowCycleModel.prototype.dispose = function (forever) {
4422
4493
  if (forever) {
4423
4494
  // otherwise the value will be persisted during re-instantiation
@@ -4612,16 +4683,16 @@
4612
4683
  this.sizeBefore = 0;
4613
4684
  this.sizeAfter = 0;
4614
4685
  this.positionBefore = 0;
4615
- this.renderTimer = null;
4686
+ this.cancel = null;
4616
4687
  };
4617
4688
  return RenderModel;
4618
4689
  }());
4619
4690
 
4620
- var ScrollState = /** @class */ (function () {
4621
- function ScrollState() {
4691
+ var ScrollModel = /** @class */ (function () {
4692
+ function ScrollModel() {
4622
4693
  this.reset();
4623
4694
  }
4624
- ScrollState.prototype.reset = function () {
4695
+ ScrollModel.prototype.reset = function () {
4625
4696
  this.previous = null;
4626
4697
  this.current = null;
4627
4698
  this.syntheticPosition = null;
@@ -4629,24 +4700,24 @@
4629
4700
  this.positionBeforeAsync = null;
4630
4701
  this.positionBeforeAdjust = null;
4631
4702
  this.positionAfterAdjust = null;
4632
- this.cleanupTimers();
4703
+ this.stop();
4633
4704
  };
4634
- ScrollState.prototype.cleanupTimers = function () {
4705
+ ScrollModel.prototype.stop = function () {
4635
4706
  if (this.scrollTimer) {
4636
4707
  clearTimeout(this.scrollTimer);
4637
4708
  this.scrollTimer = null;
4638
4709
  }
4639
- if (this.animationFrameId) {
4640
- cancelAnimationFrame(this.animationFrameId);
4641
- this.animationFrameId = 0;
4710
+ if (this.cancelAnimation) {
4711
+ this.cancelAnimation();
4712
+ this.cancelAnimation = null;
4642
4713
  }
4643
4714
  };
4644
- ScrollState.prototype.hasPositionChanged = function (position) {
4715
+ ScrollModel.prototype.hasPositionChanged = function (position) {
4645
4716
  var before = this.positionBeforeAdjust;
4646
4717
  var after = this.positionAfterAdjust;
4647
4718
  return before === null || before !== position || after === null || after !== position;
4648
4719
  };
4649
- return ScrollState;
4720
+ return ScrollModel;
4650
4721
  }());
4651
4722
 
4652
4723
  var State = /** @class */ (function () {
@@ -4658,7 +4729,7 @@
4658
4729
  this.fetch = new FetchModel(settings.directionPriority);
4659
4730
  this.clip = new ClipModel();
4660
4731
  this.render = new RenderModel();
4661
- this.scrollState = new ScrollState();
4732
+ this.scroll = new ScrollModel();
4662
4733
  }
4663
4734
  Object.defineProperty(State.prototype, "time", {
4664
4735
  get: function () {
@@ -4667,20 +4738,14 @@
4667
4738
  enumerable: false,
4668
4739
  configurable: true
4669
4740
  });
4670
- State.prototype.endInnerLoop = function () {
4671
- var _a = this, fetch = _a.fetch, render = _a.render, cycle = _a.cycle;
4672
- if (fetch.cancel) {
4673
- fetch.cancel();
4674
- fetch.cancel = null;
4675
- }
4676
- if (render.renderTimer) {
4677
- clearTimeout(render.renderTimer);
4678
- render.renderTimer = null;
4679
- }
4680
- cycle.innerLoop.done();
4741
+ State.prototype.startWorkflowCycle = function (isInitial, initiator) {
4742
+ this.cycle.start(isInitial, initiator);
4743
+ };
4744
+ State.prototype.endWorkflowCycle = function (count) {
4745
+ this.cycle.end(count);
4681
4746
  };
4682
4747
  State.prototype.startInnerLoop = function () {
4683
- var _a = this, cycle = _a.cycle, scroll = _a.scrollState, fetch = _a.fetch, render = _a.render, clip = _a.clip;
4748
+ var _a = this, cycle = _a.cycle, scroll = _a.scroll, fetch = _a.fetch, render = _a.render, clip = _a.clip;
4684
4749
  cycle.innerLoop.start();
4685
4750
  scroll.positionBeforeAsync = null;
4686
4751
  if (!fetch.simulate) {
@@ -4693,10 +4758,24 @@
4693
4758
  doRender: fetch.simulate && fetch.items.length > 0
4694
4759
  } : {}));
4695
4760
  };
4761
+ State.prototype.endInnerLoop = function () {
4762
+ var _a = this, fetch = _a.fetch, clip = _a.clip, render = _a.render, cycle = _a.cycle;
4763
+ fetch.stopSimulate();
4764
+ clip.reset(true);
4765
+ if (fetch.cancel) {
4766
+ fetch.cancel();
4767
+ fetch.cancel = null;
4768
+ }
4769
+ if (render.cancel) {
4770
+ render.cancel();
4771
+ render.cancel = null;
4772
+ }
4773
+ cycle.innerLoop.done();
4774
+ };
4696
4775
  State.prototype.dispose = function () {
4776
+ this.scroll.stop();
4697
4777
  this.cycle.dispose();
4698
4778
  this.endInnerLoop();
4699
- this.scrollState.cleanupTimers();
4700
4779
  };
4701
4780
  return State;
4702
4781
  }());
@@ -5006,7 +5085,7 @@
5006
5085
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5007
5086
  Adapter.prototype.reset = function (options) {
5008
5087
  this.reloadCounter++;
5009
- this.logger.logAdapterMethod('reset', options, " of " + this.reloadId);
5088
+ this.logger.logAdapterMethod('reset', options, " of ".concat(this.reloadId));
5010
5089
  this.workflow.call({
5011
5090
  process: AdapterProcess.reset,
5012
5091
  status: ProcessStatus.start,
@@ -5016,7 +5095,7 @@
5016
5095
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5017
5096
  Adapter.prototype.reload = function (options) {
5018
5097
  this.reloadCounter++;
5019
- this.logger.logAdapterMethod('reload', options, " of " + this.reloadId);
5098
+ this.logger.logAdapterMethod('reload', options, " of ".concat(this.reloadId));
5020
5099
  this.workflow.call({
5021
5100
  process: AdapterProcess.reload,
5022
5101
  status: ProcessStatus.start,
@@ -5123,7 +5202,7 @@
5123
5202
  });
5124
5203
  }).then(function (immediate) {
5125
5204
  var success = reloadId === _this.reloadId;
5126
- _this.logger.log(function () { return !success ? "relax promise cancelled due to " + reloadId + " != " + _this.reloadId : void 0; });
5205
+ _this.logger.log(function () { return !success ? "relax promise cancelled due to ".concat(reloadId, " != ").concat(_this.reloadId) : void 0; });
5127
5206
  return {
5128
5207
  immediate: immediate,
5129
5208
  success: success,
@@ -5134,7 +5213,7 @@
5134
5213
  Adapter.prototype.relax = function (callback) {
5135
5214
  var _this = this;
5136
5215
  var reloadId = this.reloadId;
5137
- this.logger.logAdapterMethod('relax', callback, " of " + reloadId);
5216
+ this.logger.logAdapterMethod('relax', callback, " of ".concat(reloadId));
5138
5217
  if (!this.init) {
5139
5218
  return Promise.resolve(methodPreResult);
5140
5219
  }
@@ -5156,21 +5235,21 @@
5156
5235
  var instanceCount = 0;
5157
5236
  var Scroller = /** @class */ (function () {
5158
5237
  function Scroller(_a) {
5159
- var datasource = _a.datasource, consumer = _a.consumer, element = _a.element, workflow = _a.workflow, scroller = _a.scroller;
5238
+ var datasource = _a.datasource, consumer = _a.consumer, element = _a.element, workflow = _a.workflow, CustomRoutines = _a.Routines, scroller = _a.scroller;
5160
5239
  var get = validate(datasource, DATASOURCE).params.get;
5161
5240
  if (!get.isValid) {
5162
- throw new Error(INVALID_DATASOURCE_PREFIX + " " + get.errors[0]);
5241
+ throw new Error("".concat(INVALID_DATASOURCE_PREFIX, " ").concat(get.errors[0]));
5163
5242
  }
5164
5243
  var packageInfo = scroller ? scroller.state.packageInfo : { consumer: consumer, core: core };
5165
- element = scroller ? scroller.viewport.element : element;
5244
+ element = scroller ? scroller.routines.element : element;
5166
5245
  workflow = scroller ? scroller.workflow : workflow;
5167
5246
  this.workflow = workflow;
5168
5247
  this.settings = new Settings(datasource.settings, datasource.devSettings, ++instanceCount);
5169
5248
  this.logger = new Logger(this, packageInfo, datasource.adapter);
5170
- this.routines = new Routines(this.settings);
5249
+ this.routines = new Routines(element, this.settings, CustomRoutines);
5171
5250
  this.state = new State(packageInfo, this.settings, scroller ? scroller.state : void 0);
5172
5251
  this.buffer = new Buffer(this.settings, workflow.onDataChanged, this.logger);
5173
- this.viewport = new Viewport(element, this.settings, this.routines, this.state, this.logger);
5252
+ this.viewport = new Viewport(this.settings, this.routines, this.state, this.logger);
5174
5253
  this.logger.object('vscroll settings object', this.settings, true);
5175
5254
  this.initDatasource(datasource, scroller);
5176
5255
  }
@@ -5429,14 +5508,14 @@
5429
5508
  var Workflow = /** @class */ (function () {
5430
5509
  function Workflow(_a) {
5431
5510
  var _this = this;
5432
- var element = _a.element, datasource = _a.datasource, consumer = _a.consumer, run = _a.run;
5511
+ var element = _a.element, datasource = _a.datasource, consumer = _a.consumer, run = _a.run, Routines = _a.Routines;
5433
5512
  this.isInitialized = false;
5434
5513
  this.initTimer = null;
5435
5514
  this.adapterRun$ = new Reactive();
5436
5515
  this.cyclesDone = 0;
5437
5516
  this.interruptionCount = 0;
5438
5517
  this.errors = [];
5439
- this.disposeScrollEventHandler = function () { return null; };
5518
+ this.offScroll = function () { return null; };
5440
5519
  this.propagateChanges = run;
5441
5520
  this.stateMachineMethods = {
5442
5521
  run: this.runProcess(),
@@ -5444,7 +5523,13 @@
5444
5523
  done: this.done.bind(this),
5445
5524
  onError: this.onError.bind(this)
5446
5525
  };
5447
- this.scroller = new Scroller({ element: element, datasource: datasource, consumer: consumer, workflow: this.getUpdater() });
5526
+ this.scroller = new Scroller({
5527
+ element: element,
5528
+ datasource: datasource,
5529
+ consumer: consumer,
5530
+ workflow: this.getUpdater(),
5531
+ Routines: Routines
5532
+ });
5448
5533
  if (this.scroller.settings.initializeDelay) {
5449
5534
  this.initTimer = setTimeout(function () {
5450
5535
  _this.initTimer = null;
@@ -5465,16 +5550,13 @@
5465
5550
  status: ProcessStatus.start
5466
5551
  });
5467
5552
  // set up scroll event listener
5468
- var scrollEventReceiver = this.scroller.viewport.scrollEventReceiver;
5553
+ var routines = this.scroller.routines;
5469
5554
  var onScrollHandler = function (event) { return _this.callWorkflow({
5470
5555
  process: CommonProcess.scroll,
5471
5556
  status: ProcessStatus.start,
5472
5557
  payload: { event: event }
5473
5558
  }); };
5474
- scrollEventReceiver.addEventListener('scroll', onScrollHandler);
5475
- this.disposeScrollEventHandler = function () {
5476
- return scrollEventReceiver.removeEventListener('scroll', onScrollHandler);
5477
- };
5559
+ this.offScroll = routines.onScroll(onScrollHandler);
5478
5560
  };
5479
5561
  Workflow.prototype.changeItems = function (items) {
5480
5562
  this.propagateChanges(items);
@@ -5502,7 +5584,7 @@
5502
5584
  '%cfire%c'
5503
5585
  ], ['color: #cc7777;', 'color: #000000;'], false), [
5504
5586
  process,
5505
- "\"" + status + "\""
5587
+ "\"".concat(status, "\"")
5506
5588
  ], false), __read((payload !== void 0 ? [payload] : [])), false); });
5507
5589
  }
5508
5590
  this.scroller.logger.logProcess(data);
@@ -5558,7 +5640,7 @@
5558
5640
  workflow.call.interrupted = true;
5559
5641
  this.scroller.workflow = this.getUpdater();
5560
5642
  this.interruptionCount++;
5561
- logger_1.log(function () { return "workflow had been interrupted by the " + process + " process (" + _this.interruptionCount + ")"; });
5643
+ logger_1.log(function () { return "workflow had been interrupted by the ".concat(process, " process (").concat(_this.interruptionCount, ")"); });
5562
5644
  }
5563
5645
  if (datasource) { // Scroller re-initialization case
5564
5646
  this.scroller.adapter.relax(function () {
@@ -5574,7 +5656,7 @@
5574
5656
  var _a = this.scroller, state = _a.state, logger = _a.logger;
5575
5657
  this.cyclesDone++;
5576
5658
  logger.logCycle(false);
5577
- state.cycle.done(this.cyclesDone + 1);
5659
+ state.endWorkflowCycle(this.cyclesDone + 1);
5578
5660
  this.finalize();
5579
5661
  };
5580
5662
  Workflow.prototype.dispose = function () {
@@ -5582,7 +5664,7 @@
5582
5664
  if (this.initTimer) {
5583
5665
  clearTimeout(this.initTimer);
5584
5666
  }
5585
- this.disposeScrollEventHandler();
5667
+ this.offScroll();
5586
5668
  this.adapterRun$.dispose();
5587
5669
  this.scroller.dispose(true);
5588
5670
  Object.getOwnPropertyNames(this).forEach(function (prop) {