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) FESM5
3
- * Version: 1.4.1 (2021-11-02T00:21:05.317Z)
3
+ * Version: 1.5.0 (2022-02-02T15:07:19.169Z)
4
4
  * Author: Denis Hilt
5
5
  * License: MIT
6
6
  */
@@ -343,7 +343,7 @@ var reactiveConfigStorage = new Map();
343
343
 
344
344
  var core = {
345
345
  name: 'vscroll',
346
- version: '1.4.1'
346
+ version: '1.5.0'
347
347
  };
348
348
 
349
349
  var instanceCount$1 = 0;
@@ -452,7 +452,7 @@ var ValidatorType;
452
452
  ValidatorType["enum"] = "must belong to {arg1} list";
453
453
  })(ValidatorType || (ValidatorType = {}));
454
454
  var getError = function (msg, args) {
455
- return (args || ['']).reduce(function (acc, arg, index) { return acc.replace("{arg" + (index + 1) + "}", arg); }, msg);
455
+ return (args || ['']).reduce(function (acc, arg, index) { return acc.replace("{arg".concat(index + 1, "}"), arg); }, msg);
456
456
  };
457
457
  var getNumber = function (value) {
458
458
  return typeof value === 'number' || (typeof value === 'string' && value !== '')
@@ -617,7 +617,7 @@ var onOneOf = function (tokens, must) { return function (value, context) {
617
617
  }
618
618
  var isAnotherPresent = context && Object.prototype.hasOwnProperty.call(context, token);
619
619
  if (isSet && isAnotherPresent) {
620
- errors.push(getError(err, [tokens.join('", "')]) + (" (" + token + " is present)"));
620
+ errors.push(getError(err, [tokens.join('", "')]) + " (".concat(token, " is present)"));
621
621
  break;
622
622
  }
623
623
  if (noOneIsPresent && isAnotherPresent) {
@@ -742,9 +742,9 @@ var ValidatedData = /** @class */ (function () {
742
742
  ValidatedData.prototype.setParam = function (token, value) {
743
743
  if (!value.isValid) {
744
744
  value.errors = !value.isSet
745
- ? ["\"" + token + "\" must be set"]
745
+ ? ["\"".concat(token, "\" must be set")]
746
746
  : value.errors.map(function (err) {
747
- return "\"" + token + "\" " + err;
747
+ return "\"".concat(token, "\" ").concat(err);
748
748
  });
749
749
  }
750
750
  this.params[token] = value;
@@ -1332,7 +1332,7 @@ var BaseAdapterProcessFactory = function (process) { var _a; return _a = /** @cl
1332
1332
  scroller.workflow.call({
1333
1333
  process: process,
1334
1334
  status: ProcessStatus.error,
1335
- payload: { error: "Wrong argument of the \"" + process + "\" method call" }
1335
+ payload: { error: "Wrong argument of the \"".concat(process, "\" method call") }
1336
1336
  });
1337
1337
  }
1338
1338
  }
@@ -1350,10 +1350,10 @@ var Init = /** @class */ (function (_super) {
1350
1350
  return _super !== null && _super.apply(this, arguments) || this;
1351
1351
  }
1352
1352
  Init.run = function (scroller, process) {
1353
- var cycle = scroller.state.cycle, workflow = scroller.workflow;
1353
+ var state = scroller.state, workflow = scroller.workflow;
1354
1354
  var isInitial = initProcesses.includes(process);
1355
1355
  scroller.logger.logCycle(true);
1356
- cycle.start(isInitial, process);
1356
+ state.startWorkflowCycle(isInitial, process);
1357
1357
  workflow.call({
1358
1358
  process: Init.process,
1359
1359
  status: ProcessStatus.next
@@ -1379,16 +1379,16 @@ var Scroll = /** @class */ (function (_super) {
1379
1379
  });
1380
1380
  };
1381
1381
  Scroll.onSynthetic = function (scroller, position) {
1382
- var scrollState = scroller.state.scrollState;
1383
- var synthPos = scrollState.syntheticPosition;
1382
+ var scroll = scroller.state.scroll;
1383
+ var synthPos = scroll.syntheticPosition;
1384
1384
  if (synthPos !== null) {
1385
- if (scrollState.syntheticFulfill) {
1386
- scrollState.syntheticPosition = null;
1385
+ if (scroll.syntheticFulfill) {
1386
+ scroll.syntheticPosition = null;
1387
1387
  }
1388
- if (!scrollState.syntheticFulfill || synthPos === position) {
1388
+ if (!scroll.syntheticFulfill || synthPos === position) {
1389
1389
  scroller.logger.log(function () { return [
1390
1390
  'skipping scroll', position,
1391
- "[" + (scrollState.syntheticFulfill ? '' : 'pre-') + "synthetic]"
1391
+ "[".concat(scroll.syntheticFulfill ? '' : 'pre-', "synthetic]")
1392
1392
  ]; });
1393
1393
  return true;
1394
1394
  }
@@ -1399,31 +1399,31 @@ var Scroll = /** @class */ (function (_super) {
1399
1399
  return false;
1400
1400
  };
1401
1401
  Scroll.onThrottle = function (scroller, position, done) {
1402
- var scrollState = scroller.state.scrollState, throttle = scroller.settings.throttle, logger = scroller.logger;
1403
- scrollState.current = Scroll.getScrollEvent(position, scrollState.previous);
1404
- var _a = scrollState.current, direction = _a.direction, time = _a.time;
1405
- var timeDiff = scrollState.previous ? time - scrollState.previous.time : Infinity;
1402
+ var scroll = scroller.state.scroll, throttle = scroller.settings.throttle, logger = scroller.logger;
1403
+ scroll.current = Scroll.getScrollEvent(position, scroll.previous);
1404
+ var _a = scroll.current, direction = _a.direction, time = _a.time;
1405
+ var timeDiff = scroll.previous ? time - scroll.previous.time : Infinity;
1406
1406
  var delta = throttle - timeDiff;
1407
1407
  var shouldDelay = isFinite(delta) && delta > 0;
1408
- var alreadyDelayed = !!scrollState.scrollTimer;
1408
+ var alreadyDelayed = !!scroll.scrollTimer;
1409
1409
  logger.log(function () { return [
1410
1410
  direction === Direction.backward ? '\u2934' : '\u2935',
1411
1411
  position,
1412
1412
  shouldDelay ? (timeDiff + 'ms') : '0ms',
1413
- shouldDelay ? (alreadyDelayed ? 'delayed' : "/ " + delta + "ms delay") : ''
1413
+ shouldDelay ? (alreadyDelayed ? 'delayed' : "/ ".concat(delta, "ms delay")) : ''
1414
1414
  ]; });
1415
1415
  if (!shouldDelay) {
1416
- if (scrollState.scrollTimer) {
1417
- clearTimeout(scrollState.scrollTimer);
1418
- scrollState.scrollTimer = null;
1416
+ if (scroll.scrollTimer) {
1417
+ clearTimeout(scroll.scrollTimer);
1418
+ scroll.scrollTimer = null;
1419
1419
  }
1420
1420
  done();
1421
1421
  return;
1422
1422
  }
1423
1423
  if (!alreadyDelayed) {
1424
- scrollState.scrollTimer = setTimeout(function () {
1424
+ scroll.scrollTimer = setTimeout(function () {
1425
1425
  logger.log(function () {
1426
- var curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scrollState.current);
1426
+ var curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scroll.current);
1427
1427
  return [
1428
1428
  curr.direction === Direction.backward ? '\u2934' : '\u2935',
1429
1429
  curr.position,
@@ -1432,7 +1432,7 @@ var Scroll = /** @class */ (function (_super) {
1432
1432
  position
1433
1433
  ];
1434
1434
  });
1435
- scrollState.scrollTimer = null;
1435
+ scroll.scrollTimer = null;
1436
1436
  done();
1437
1437
  }, delta);
1438
1438
  }
@@ -1451,11 +1451,11 @@ var Scroll = /** @class */ (function (_super) {
1451
1451
  return { position: position, direction: direction, time: time };
1452
1452
  };
1453
1453
  Scroll.onScroll = function (scroller, workflow) {
1454
- var _a = scroller.state, scrollState = _a.scrollState, cycle = _a.cycle;
1455
- scrollState.previous = __assign({}, scrollState.current);
1456
- scrollState.current = null;
1454
+ var _a = scroller.state, scroll = _a.scroll, cycle = _a.cycle;
1455
+ scroll.previous = __assign({}, scroll.current);
1456
+ scroll.current = null;
1457
1457
  if (cycle.busy.get()) {
1458
- scroller.logger.log(function () { return ['skipping scroll', scrollState.previous.position, '[pending]']; });
1458
+ scroller.logger.log(function () { return ['skipping scroll', scroll.previous.position, '[pending]']; });
1459
1459
  return;
1460
1460
  }
1461
1461
  workflow.call({
@@ -1516,7 +1516,7 @@ var Reload = /** @class */ (function (_super) {
1516
1516
  viewport.reset(buffer.startIndex);
1517
1517
  var payload = {};
1518
1518
  if (state.cycle.busy.get()) {
1519
- state.scrollState.cleanupTimers();
1519
+ state.scroll.stop();
1520
1520
  payload.finalize = true;
1521
1521
  state.cycle.interrupter = Reload.process;
1522
1522
  }
@@ -1906,7 +1906,7 @@ var Remove = /** @class */ (function (_super) {
1906
1906
  }
1907
1907
  }
1908
1908
  // virtual removal
1909
- scroller.logger.log(function () { return "going to remove " + toRemove.length + " item(s) virtually"; });
1909
+ scroller.logger.log(function () { return "going to remove ".concat(toRemove.length, " item(s) virtually"); });
1910
1910
  buffer.removeVirtually(toRemove, !!increase);
1911
1911
  buffer.checkDefaultSize();
1912
1912
  Remove.shiftFirstVisibleIndex(scroller, toRemove, !!increase);
@@ -2140,8 +2140,8 @@ var PreFetch = /** @class */ (function (_super) {
2140
2140
  startDelta += buffer.getSizeByIndex(index);
2141
2141
  }
2142
2142
  scroller.logger.log(function () { return __spreadArray([
2143
- "start delta is " + startDelta
2144
- ], __read((offset ? [" (+" + offset + " offset)"] : [])), false); });
2143
+ "start delta is ".concat(startDelta)
2144
+ ], __read((offset ? [" (+".concat(offset, " offset)")] : [])), false); });
2145
2145
  return startDelta;
2146
2146
  };
2147
2147
  PreFetch.setFirstIndex = function (scroller) {
@@ -2312,17 +2312,17 @@ var PreFetch = /** @class */ (function (_super) {
2312
2312
  direction_1 = fetch.last.index < buffer.items[0].$index ? Direction.backward : Direction.forward;
2313
2313
  }
2314
2314
  fetch.direction = direction_1;
2315
- scroller.logger.log(function () { return "fetch direction is \"" + direction_1 + "\""; });
2315
+ scroller.logger.log(function () { return "fetch direction is \"".concat(direction_1, "\""); });
2316
2316
  }
2317
2317
  };
2318
2318
  PreFetch.getStatus = function (scroller) {
2319
2319
  var _a = scroller.state, cycle = _a.cycle, fetch = _a.fetch;
2320
2320
  if (cycle.initiator === AdapterProcess.clip) {
2321
- scroller.logger.log(function () { return "going to skip fetch due to \"" + AdapterProcess.clip + "\" process"; });
2321
+ scroller.logger.log(function () { return "going to skip fetch due to \"".concat(AdapterProcess.clip, "\" process"); });
2322
2322
  return ProcessStatus.next;
2323
2323
  }
2324
2324
  if (fetch.shouldFetch) {
2325
- scroller.logger.log(function () { return "going to fetch " + fetch.count + " items started from index " + fetch.index; });
2325
+ scroller.logger.log(function () { return "going to fetch ".concat(fetch.count, " items started from index ").concat(fetch.index); });
2326
2326
  return ProcessStatus.next;
2327
2327
  }
2328
2328
  return ProcessStatus.done;
@@ -2340,8 +2340,8 @@ var Fetch = /** @class */ (function (_super) {
2340
2340
  var box = {
2341
2341
  success: function (data) {
2342
2342
  scroller.logger.log(function () {
2343
- return "resolved " + data.length + " items " +
2344
- ("(index = " + scroller.state.fetch.index + ", count = " + scroller.state.fetch.count + ")");
2343
+ return "resolved ".concat(data.length, " items ") +
2344
+ "(index = ".concat(scroller.state.fetch.index, ", count = ").concat(scroller.state.fetch.count, ")");
2345
2345
  });
2346
2346
  scroller.state.fetch.newItemsData = data;
2347
2347
  workflow.call({
@@ -2371,9 +2371,9 @@ var Fetch = /** @class */ (function (_super) {
2371
2371
  }
2372
2372
  }
2373
2373
  else {
2374
- var _b = scroller.state, scrollState = _b.scrollState, fetch_1 = _b.fetch, viewport = scroller.viewport;
2375
- if (scrollState.positionBeforeAsync === null) {
2376
- scrollState.positionBeforeAsync = viewport.scrollPosition;
2374
+ var _b = scroller.state, scroll_1 = _b.scroll, fetch_1 = _b.fetch, viewport = scroller.viewport;
2375
+ if (scroll_1.positionBeforeAsync === null) {
2376
+ scroll_1.positionBeforeAsync = viewport.scrollPosition;
2377
2377
  }
2378
2378
  fetch_1.cancel = function () {
2379
2379
  box.success = function () { return null; };
@@ -2505,13 +2505,13 @@ var Render = /** @class */ (function (_super) {
2505
2505
  return _super !== null && _super.apply(this, arguments) || this;
2506
2506
  }
2507
2507
  Render.run = function (scroller) {
2508
- var workflow = scroller.workflow, _a = scroller.state, cycle = _a.cycle, render = _a.render, scrollState = _a.scrollState, viewport = scroller.viewport;
2508
+ var workflow = scroller.workflow, _a = scroller.state, cycle = _a.cycle, render = _a.render, scroll = _a.scroll, viewport = scroller.viewport, routines = scroller.routines;
2509
2509
  scroller.logger.stat('before new items render');
2510
- if (scrollState.positionBeforeAsync === null) {
2511
- scrollState.positionBeforeAsync = viewport.scrollPosition;
2510
+ if (scroll.positionBeforeAsync === null) {
2511
+ scroll.positionBeforeAsync = viewport.scrollPosition;
2512
2512
  }
2513
- render.renderTimer = setTimeout(function () {
2514
- render.renderTimer = null;
2513
+ render.cancel = routines.render(function () {
2514
+ render.cancel = null;
2515
2515
  if (Render.doRender(scroller)) {
2516
2516
  workflow.call({
2517
2517
  process: Render.process,
@@ -2526,7 +2526,7 @@ var Render = /** @class */ (function (_super) {
2526
2526
  payload: { error: 'Can\'t associate item with element' }
2527
2527
  });
2528
2528
  }
2529
- }, 0);
2529
+ });
2530
2530
  };
2531
2531
  Render.doRender = function (scroller) {
2532
2532
  var _a = scroller.state, fetch = _a.fetch, render = _a.render, viewport = scroller.viewport, buffer = scroller.buffer, logger = scroller.logger;
@@ -2560,18 +2560,92 @@ var Render = /** @class */ (function (_super) {
2560
2560
  return Render;
2561
2561
  }(BaseProcessFactory(CommonProcess.render)));
2562
2562
 
2563
+ var isInterrupted = function (_a) {
2564
+ var call = _a.call;
2565
+ return !!call.interrupted;
2566
+ };
2567
+ var End = /** @class */ (function (_super) {
2568
+ __extends(End, _super);
2569
+ function End() {
2570
+ return _super !== null && _super.apply(this, arguments) || this;
2571
+ }
2572
+ End.run = function (scroller, _a) {
2573
+ var _b = _a === void 0 ? {} : _a, error = _b.error;
2574
+ var workflow = scroller.workflow, interrupter = scroller.state.cycle.interrupter;
2575
+ if (!error && !interrupter) {
2576
+ // set out params accessible via Adapter
2577
+ End.calculateParams(scroller, workflow);
2578
+ }
2579
+ // explicit interruption for we don't want to go through the inner loop finalizing
2580
+ if (isInterrupted(workflow)) {
2581
+ workflow.call({ process: End.process, status: ProcessStatus.done });
2582
+ return;
2583
+ }
2584
+ var next = End.shouldContinueRun(scroller, error);
2585
+ scroller.state.endInnerLoop();
2586
+ workflow.call({
2587
+ process: End.process,
2588
+ status: next ? ProcessStatus.next : ProcessStatus.done,
2589
+ payload: __assign({}, (interrupter ? { process: interrupter } : {}))
2590
+ });
2591
+ };
2592
+ End.calculateParams = function (scroller, workflow) {
2593
+ var adapter = scroller.adapter, viewport = scroller.viewport, items = scroller.buffer.items;
2594
+ if (adapter.wanted.firstVisible) {
2595
+ var item = viewport.getEdgeVisibleItem(items, Direction.backward).item;
2596
+ if (!item || item.element !== adapter.firstVisible.element) {
2597
+ adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
2598
+ }
2599
+ }
2600
+ // the workflow can be interrupter on firstVisible change
2601
+ if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
2602
+ var item = viewport.getEdgeVisibleItem(items, Direction.forward).item;
2603
+ if (!item || item.element !== adapter.lastVisible.element) {
2604
+ adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
2605
+ }
2606
+ }
2607
+ };
2608
+ End.shouldContinueRun = function (scroller, error) {
2609
+ var _a = scroller.state, cycle = _a.cycle, fetch = _a.fetch, render = _a.render;
2610
+ // Adapter.reload or Adapter.reset
2611
+ if (cycle.interrupter) {
2612
+ return true;
2613
+ }
2614
+ // critical error
2615
+ if (error) {
2616
+ return false;
2617
+ }
2618
+ // Adapter.check
2619
+ if (fetch.simulate && fetch.isCheck && !render.noSize) {
2620
+ return true;
2621
+ }
2622
+ // Adapter.remove or Adapter.update with clip
2623
+ if (fetch.simulate && fetch.doRemove) {
2624
+ return true;
2625
+ }
2626
+ // common inner loop (App start, scroll, Adapter.clip) with full fetch
2627
+ if (!fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
2628
+ return true;
2629
+ }
2630
+ return false;
2631
+ };
2632
+ return End;
2633
+ }(BaseProcessFactory(CommonProcess.end)));
2634
+
2563
2635
  var Adjust = /** @class */ (function (_super) {
2564
2636
  __extends(Adjust, _super);
2565
2637
  function Adjust() {
2566
2638
  return _super !== null && _super.apply(this, arguments) || this;
2567
2639
  }
2568
2640
  Adjust.run = function (scroller) {
2569
- var workflow = scroller.workflow, viewport = scroller.viewport, scrollState = scroller.state.scrollState;
2570
- scrollState.positionBeforeAdjust = viewport.scrollPosition;
2641
+ var workflow = scroller.workflow, viewport = scroller.viewport, scroll = scroller.state.scroll;
2642
+ scroll.positionBeforeAdjust = viewport.scrollPosition;
2571
2643
  Adjust.setPaddings(scroller);
2572
- scrollState.positionAfterAdjust = viewport.scrollPosition;
2644
+ scroll.positionAfterAdjust = viewport.scrollPosition;
2573
2645
  // scroll position adjustments
2574
2646
  var position = Adjust.calculatePosition(scroller);
2647
+ // additional adjustment if the position can't be reached during the initial cycle
2648
+ Adjust.setAdditionalForwardPadding(scroller, position);
2575
2649
  // set new position using animation frame
2576
2650
  Adjust.setPosition(scroller, position, function () {
2577
2651
  return workflow.call({
@@ -2604,7 +2678,8 @@ var Adjust = /** @class */ (function (_super) {
2604
2678
  }
2605
2679
  // lack of items case
2606
2680
  var bufferSize = viewport.getScrollableSize() - forward.size - backward.size;
2607
- var viewportSizeDiff = viewport.getSize() - (bwdSize + bufferSize + fwdSize);
2681
+ var scrollSize = bwdSize + bufferSize + fwdSize;
2682
+ var viewportSizeDiff = viewport.getSize() - scrollSize;
2608
2683
  if (viewportSizeDiff > 0) {
2609
2684
  if (inverse) {
2610
2685
  bwdSize += viewportSizeDiff;
@@ -2613,7 +2688,7 @@ var Adjust = /** @class */ (function (_super) {
2613
2688
  fwdSize += viewportSizeDiff;
2614
2689
  }
2615
2690
  scroller.logger.log(function () {
2616
- return inverse ? 'backward' : 'forward' + (" padding will be increased by " + viewportSizeDiff + " to fill the viewport");
2691
+ return inverse ? 'backward' : 'forward' + " padding will be increased by ".concat(viewportSizeDiff, " to fill the viewport");
2617
2692
  });
2618
2693
  }
2619
2694
  backward.size = bwdSize;
@@ -2621,11 +2696,11 @@ var Adjust = /** @class */ (function (_super) {
2621
2696
  scroller.logger.stat('after paddings adjustments');
2622
2697
  };
2623
2698
  Adjust.calculatePosition = function (scroller) {
2624
- var viewport = scroller.viewport, buffer = scroller.buffer, _a = scroller.state, fetch = _a.fetch, render = _a.render, scrollState = _a.scrollState;
2699
+ var viewport = scroller.viewport, buffer = scroller.buffer, _a = scroller.state, fetch = _a.fetch, render = _a.render, scroll = _a.scroll;
2625
2700
  var position = viewport.paddings.backward.size;
2626
2701
  // increase the position to meet the expectation of the first visible item
2627
2702
  if (!isNaN(fetch.firstVisible.index) && !isNaN(buffer.firstIndex)) {
2628
- scroller.logger.log("first index = " + fetch.firstVisible.index + ", delta = " + fetch.firstVisible.delta);
2703
+ scroller.logger.log("first index = ".concat(fetch.firstVisible.index, ", delta = ").concat(fetch.firstVisible.delta));
2629
2704
  var shouldCheckPreSizeExpectation_1 = fetch.shouldCheckPreSizeExpectation(buffer.lastIndex);
2630
2705
  buffer.items.forEach(function (item) {
2631
2706
  // 1) shift of the buffered items before the first visible item
@@ -2644,10 +2719,10 @@ var Adjust = /** @class */ (function (_super) {
2644
2719
  });
2645
2720
  }
2646
2721
  // slow fetch/render case
2647
- if (scrollState.positionBeforeAsync !== null) {
2648
- var diff = render.positionBefore - scrollState.positionBeforeAsync;
2722
+ if (scroll.positionBeforeAsync !== null) {
2723
+ var diff = render.positionBefore - scroll.positionBeforeAsync;
2649
2724
  if (diff !== 0) {
2650
- scroller.logger.log("shift position due to fetch-render difference (" + diff + ")");
2725
+ scroller.logger.log("shift position due to fetch-render difference (".concat(diff, ")"));
2651
2726
  position += diff;
2652
2727
  }
2653
2728
  }
@@ -2657,22 +2732,47 @@ var Adjust = /** @class */ (function (_super) {
2657
2732
  }
2658
2733
  return Math.round(position);
2659
2734
  };
2735
+ Adjust.setAdditionalForwardPadding = function (scroller, position) {
2736
+ var viewport = scroller.viewport, buffer = scroller.buffer, cycle = scroller.state.cycle;
2737
+ if (!cycle.isInitial || !End.shouldContinueRun(scroller, null)) {
2738
+ return;
2739
+ }
2740
+ var diff = position - viewport.getMaxScrollPosition();
2741
+ if (diff <= 0) {
2742
+ return;
2743
+ }
2744
+ var last = buffer.getLastVisibleItem();
2745
+ if (!last) {
2746
+ return;
2747
+ }
2748
+ var size = 0;
2749
+ var index = last.$index + 1;
2750
+ while (size <= diff && index <= buffer.absMaxIndex) {
2751
+ size += buffer.getSizeByIndex(index++);
2752
+ }
2753
+ var shift = Math.min(size, diff);
2754
+ if (shift) {
2755
+ viewport.paddings.forward.size += shift;
2756
+ scroller.logger.log("increase fwd padding due to lack of items (".concat(diff, " -> ").concat(shift, ")"));
2757
+ }
2758
+ };
2660
2759
  Adjust.setPosition = function (scroller, position, done) {
2661
- var scrollState = scroller.state.scrollState, viewport = scroller.viewport;
2662
- if (!scrollState.hasPositionChanged(position)) {
2760
+ var scroll = scroller.state.scroll, viewport = scroller.viewport, routines = scroller.routines;
2761
+ if (!scroll.hasPositionChanged(position)) {
2663
2762
  return done();
2664
2763
  }
2665
- scrollState.syntheticPosition = position;
2666
- scrollState.syntheticFulfill = false;
2667
- scrollState.animationFrameId = requestAnimationFrame(function () {
2668
- var inertiaDiff = scrollState.positionAfterAdjust - viewport.scrollPosition;
2764
+ scroll.syntheticPosition = position;
2765
+ scroll.syntheticFulfill = false;
2766
+ scroll.cancelAnimation = routines.animate(function () {
2767
+ scroll.cancelAnimation = null;
2768
+ var inertiaDiff = scroll.positionAfterAdjust - viewport.scrollPosition;
2669
2769
  var diffLog = '';
2670
2770
  if (inertiaDiff > 0) {
2671
2771
  position -= inertiaDiff;
2672
- scrollState.syntheticPosition = position;
2673
- diffLog = " (-" + inertiaDiff + ")";
2772
+ scroll.syntheticPosition = position;
2773
+ diffLog = " (-".concat(inertiaDiff, ")");
2674
2774
  }
2675
- scrollState.syntheticFulfill = true;
2775
+ scroll.syntheticFulfill = true;
2676
2776
  viewport.scrollPosition = position;
2677
2777
  scroller.logger.stat('after scroll adjustment' + diffLog);
2678
2778
  done();
@@ -2704,8 +2804,8 @@ var PreClip = /** @class */ (function (_super) {
2704
2804
  var firstIndex = fetch.first.indexBuffer;
2705
2805
  var lastIndex = fetch.last.indexBuffer;
2706
2806
  scroller.logger.log(function () {
2707
- return "looking for " + (fetch.direction ? 'anti-' + fetch.direction + ' ' : '') + "items " +
2708
- ("that are out of [" + firstIndex + ".." + lastIndex + "] range");
2807
+ return "looking for ".concat(fetch.direction ? 'anti-' + fetch.direction + ' ' : '', "items ") +
2808
+ "that are out of [".concat(firstIndex, "..").concat(lastIndex, "] range");
2709
2809
  });
2710
2810
  if (PreClip.isBackward(scroller, firstIndex)) {
2711
2811
  PreClip.prepareClipByDirection(scroller, Direction.backward, firstIndex);
@@ -2789,7 +2889,7 @@ var Clip = /** @class */ (function (_super) {
2789
2889
  var _a;
2790
2890
  var buffer = scroller.buffer, paddings = scroller.viewport.paddings, clip = scroller.state.clip, logger = scroller.logger;
2791
2891
  var size = (_a = {}, _a[Direction.backward] = 0, _a[Direction.forward] = 0, _a);
2792
- logger.stat("before clip (" + ++clip.callCount + ")");
2892
+ logger.stat("before clip (".concat(++clip.callCount, ")"));
2793
2893
  var itemsToRemove = buffer.items.filter(function (item) {
2794
2894
  if (!item.toRemove) {
2795
2895
  return false;
@@ -2817,10 +2917,10 @@ var Clip = /** @class */ (function (_super) {
2817
2917
  });
2818
2918
  return list.length
2819
2919
  ? [
2820
- "clipped " + list.length + " item(s) from Buffer" +
2821
- (size.backward ? ", +" + size.backward + " fwd px" : '') +
2822
- (size.forward ? ", +" + size.forward + " bwd px" : '') +
2823
- (", range: [" + list[0] + ".." + list[list.length - 1] + "]")
2920
+ "clipped ".concat(list.length, " item(s) from Buffer") +
2921
+ (size.backward ? ", +".concat(size.backward, " fwd px") : '') +
2922
+ (size.forward ? ", +".concat(size.forward, " bwd px") : '') +
2923
+ ", range: [".concat(list[0], "..").concat(list[list.length - 1], "]")
2824
2924
  ]
2825
2925
  : 'clipped 0 items from Buffer';
2826
2926
  });
@@ -2829,76 +2929,6 @@ var Clip = /** @class */ (function (_super) {
2829
2929
  return Clip;
2830
2930
  }(BaseProcessFactory(CommonProcess.clip)));
2831
2931
 
2832
- var isInterrupted = function (_a) {
2833
- var call = _a.call;
2834
- return !!call.interrupted;
2835
- };
2836
- var End = /** @class */ (function (_super) {
2837
- __extends(End, _super);
2838
- function End() {
2839
- return _super !== null && _super.apply(this, arguments) || this;
2840
- }
2841
- End.run = function (scroller, _a) {
2842
- var _b = _a === void 0 ? {} : _a, error = _b.error;
2843
- var workflow = scroller.workflow, interrupter = scroller.state.cycle.interrupter;
2844
- if (!error && !interrupter) {
2845
- // set out params accessible via Adapter
2846
- End.calculateParams(scroller, workflow);
2847
- }
2848
- // explicit interruption for we don't want to go through the inner loop finalizing
2849
- if (isInterrupted(workflow)) {
2850
- workflow.call({ process: End.process, status: ProcessStatus.done });
2851
- return;
2852
- }
2853
- var next = End.finalizeInnerLoop(scroller, error);
2854
- workflow.call({
2855
- process: End.process,
2856
- status: next ? ProcessStatus.next : ProcessStatus.done,
2857
- payload: __assign({}, (interrupter ? { process: interrupter } : {}))
2858
- });
2859
- };
2860
- End.calculateParams = function (scroller, workflow) {
2861
- var adapter = scroller.adapter, viewport = scroller.viewport, items = scroller.buffer.items;
2862
- if (adapter.wanted.firstVisible) {
2863
- var item = viewport.getEdgeVisibleItem(items, Direction.backward).item;
2864
- if (!item || item.element !== adapter.firstVisible.element) {
2865
- adapter.firstVisible = item ? item.get() : EMPTY_ITEM;
2866
- }
2867
- }
2868
- // the workflow can be interrupter on firstVisible change
2869
- if (adapter.wanted.lastVisible && !isInterrupted(workflow)) {
2870
- var item = viewport.getEdgeVisibleItem(items, Direction.forward).item;
2871
- if (!item || item.element !== adapter.lastVisible.element) {
2872
- adapter.lastVisible = item ? item.get() : EMPTY_ITEM;
2873
- }
2874
- }
2875
- };
2876
- End.finalizeInnerLoop = function (scroller, error) {
2877
- var state = scroller.state, _a = scroller.state, cycle = _a.cycle, clip = _a.clip, fetch = _a.fetch;
2878
- var next = !!cycle.interrupter || (error ? false : End.getNext(scroller));
2879
- cycle.innerLoop.isInitial = false;
2880
- fetch.stopSimulate();
2881
- clip.reset(true);
2882
- state.endInnerLoop();
2883
- return next;
2884
- };
2885
- End.getNext = function (scroller) {
2886
- var _a = scroller.state, fetch = _a.fetch, render = _a.render;
2887
- if (fetch.simulate && fetch.isCheck && !render.noSize) { // Adapter.check
2888
- return true;
2889
- }
2890
- if (fetch.simulate && fetch.doRemove) { // Adapter.remove or Adapter.update with clip
2891
- return true;
2892
- }
2893
- if ( // common inner loop (App start, Scroll, Adapter.clip) accompanied by fetch
2894
- !fetch.simulate && ((fetch.hasNewItems && !render.noSize) || fetch.hasAnotherPack)) {
2895
- return true;
2896
- }
2897
- return false;
2898
- };
2899
- return End;
2900
- }(BaseProcessFactory(CommonProcess.end)));
2901
-
2902
2932
  var Logger = /** @class */ (function () {
2903
2933
  function Logger(scroller, packageInfo, adapter) {
2904
2934
  var _this = this;
@@ -2916,19 +2946,19 @@ var Logger = /** @class */ (function () {
2916
2946
  return arg;
2917
2947
  }
2918
2948
  else if (Array.isArray(arg)) {
2919
- return "[of " + arg.length + "]";
2949
+ return "[of ".concat(arg.length, "]");
2920
2950
  }
2921
2951
  return '{ ' + Object.keys(arg).join(', ') + ' }';
2922
2952
  })
2923
2953
  .join(', ');
2924
- _this.log("adapter: " + methodName + "(" + (params || '') + ")" + (add || ''));
2954
+ _this.log("adapter: ".concat(methodName, "(").concat(params || '', ")").concat(add || ''));
2925
2955
  };
2926
2956
  var settings = scroller.settings;
2927
2957
  this.debug = settings.debug;
2928
2958
  this.immediateLog = settings.immediateLog;
2929
2959
  this.logTime = settings.logTime;
2930
2960
  this.getTime = function () {
2931
- return scroller.state && " // time: " + scroller.state.time;
2961
+ return scroller.state && " // time: ".concat(scroller.state.time);
2932
2962
  };
2933
2963
  this.getStat = function () {
2934
2964
  var buffer = scroller.buffer, viewport = scroller.viewport;
@@ -2940,26 +2970,26 @@ var Logger = /** @class */ (function () {
2940
2970
  'fwd_p: ' + viewport.paddings.forward.size + ', ' +
2941
2971
  'default: ' + (buffer.defaultSize || 'no') + ', ' +
2942
2972
  'items: ' + buffer.getVisibleItemsCount() + ', ' +
2943
- 'range: ' + (first && last ? "[" + first.$index + ".." + last.$index + "]" : 'no');
2973
+ 'range: ' + (first && last ? "[".concat(first.$index, "..").concat(last.$index, "]") : 'no');
2944
2974
  };
2945
2975
  this.getFetchRange = function () {
2946
2976
  var _a = scroller.state.fetch, first = _a.first.index, last = _a.last.index;
2947
2977
  return !Number.isNaN(first) && !Number.isNaN(last)
2948
- ? "[" + first + ".." + last + "]"
2978
+ ? "[".concat(first, "..").concat(last, "]")
2949
2979
  : 'no';
2950
2980
  };
2951
2981
  this.getLoopId = function () { return scroller.state.cycle.loopId; };
2952
2982
  this.getLoopIdNext = function () { return scroller.state.cycle.loopIdNext; };
2953
2983
  this.getWorkflowCycleData = function () {
2954
- return settings.instanceIndex + "-" + scroller.state.cycle.count;
2984
+ return "".concat(settings.instanceIndex, "-").concat(scroller.state.cycle.count);
2955
2985
  };
2956
- this.getScrollPosition = function (element) { return scroller.routines.getScrollPosition(element); };
2986
+ this.getScrollPosition = function () { return scroller.routines.getScrollPosition(); };
2957
2987
  this.log(function () {
2958
2988
  return 'vscroll Workflow has been started, ' +
2959
- ("core: " + packageInfo.core.name + " v" + packageInfo.core.version + ", ") +
2960
- ("consumer: " + packageInfo.consumer.name + " v" + packageInfo.consumer.version + ", ") +
2961
- ("scroller instance: " + settings.instanceIndex + ", adapter ") +
2962
- (!adapter ? 'is not instantiated' : "instance: " + adapter.id);
2989
+ "core: ".concat(packageInfo.core.name, " v").concat(packageInfo.core.version, ", ") +
2990
+ "consumer: ".concat(packageInfo.consumer.name, " v").concat(packageInfo.consumer.version, ", ") +
2991
+ "scroller instance: ".concat(settings.instanceIndex, ", adapter ") +
2992
+ (!adapter ? 'is not instantiated' : "instance: ".concat(adapter.id));
2963
2993
  });
2964
2994
  }
2965
2995
  Logger.prototype.object = function (str, obj, stringify) {
@@ -3000,20 +3030,20 @@ var Logger = /** @class */ (function () {
3000
3030
  'color: #888; border: dashed #888 0; border-bottom-width: 0px',
3001
3031
  'color: #000; border-width: 0'
3002
3032
  ];
3003
- this.log(function () { return __spreadArray(['%cstat' + (str ? " " + str : '') + ',%c ' + _this.getStat()], __read(logStyles_1), false); });
3033
+ this.log(function () { return __spreadArray(['%cstat' + (str ? " ".concat(str) : '') + ',%c ' + _this.getStat()], __read(logStyles_1), false); });
3004
3034
  }
3005
3035
  };
3006
3036
  Logger.prototype.fetch = function (str) {
3007
3037
  var _this = this;
3008
3038
  if (this.debug) {
3009
- var _text_1 = 'fetch interval' + (str ? " " + str : '');
3039
+ var _text_1 = 'fetch interval' + (str ? " ".concat(str) : '');
3010
3040
  var logStyles_2 = ['color: #888', 'color: #000'];
3011
- this.log(function () { return __spreadArray(["%c" + _text_1 + ": %c" + _this.getFetchRange()], __read(logStyles_2), false); });
3041
+ this.log(function () { return __spreadArray(["%c".concat(_text_1, ": %c").concat(_this.getFetchRange())], __read(logStyles_2), false); });
3012
3042
  }
3013
3043
  };
3014
3044
  Logger.prototype.prepareForLog = function (data) {
3015
3045
  return data instanceof Event && data.target
3016
- ? this.getScrollPosition(data.target)
3046
+ ? this.getScrollPosition()
3017
3047
  : data;
3018
3048
  };
3019
3049
  Logger.prototype.logProcess = function (data) {
@@ -3024,13 +3054,13 @@ var Logger = /** @class */ (function () {
3024
3054
  // inner loop start-end log
3025
3055
  var loopLog = [];
3026
3056
  if (process === CommonProcess.init && status === ProcessStatus.next) {
3027
- loopLog.push("%c---=== loop " + this.getLoopIdNext() + " start");
3057
+ loopLog.push("%c---=== loop ".concat(this.getLoopIdNext(), " start"));
3028
3058
  }
3029
3059
  else if (process === CommonProcess.end) {
3030
- loopLog.push("%c---=== loop " + this.getLoopId() + " done");
3060
+ loopLog.push("%c---=== loop ".concat(this.getLoopId(), " done"));
3031
3061
  var parent_1 = payload && payload.process;
3032
3062
  if (status === ProcessStatus.next && (parent_1 !== AdapterProcess.reset && parent_1 !== AdapterProcess.reload)) {
3033
- loopLog[0] += ", loop " + this.getLoopIdNext() + " start";
3063
+ loopLog[0] += ", loop ".concat(this.getLoopIdNext(), " start");
3034
3064
  }
3035
3065
  }
3036
3066
  if (loopLog.length) {
@@ -3041,14 +3071,14 @@ var Logger = /** @class */ (function () {
3041
3071
  if (start === void 0) { start = true; }
3042
3072
  var logData = this.getWorkflowCycleData();
3043
3073
  var border = start ? '1px 0 0 1px' : '0 0 1px 1px';
3044
- var logStyles = "color: #0000aa; border: solid #555 1px; border-width: " + border + "; margin-left: -2px";
3045
- this.log(function () { return ["%c ~~~ WF Cycle " + logData + " " + (start ? 'STARTED' : 'FINALIZED') + " ~~~ ", logStyles]; });
3074
+ var logStyles = "color: #0000aa; border: solid #555 1px; border-width: ".concat(border, "; margin-left: -2px");
3075
+ this.log(function () { return ["%c ~~~ WF Cycle ".concat(logData, " ").concat(start ? 'STARTED' : 'FINALIZED', " ~~~ "), logStyles]; });
3046
3076
  };
3047
3077
  Logger.prototype.logError = function (str) {
3048
3078
  var _this = this;
3049
3079
  if (this.debug) {
3050
3080
  var logStyles_3 = ['color: #a00;', 'color: #000'];
3051
- this.log(function () { return __spreadArray(['error:%c' + (str ? " " + str : '') + ("%c (loop " + _this.getLoopIdNext() + ")")], __read(logStyles_3), false); });
3081
+ this.log(function () { return __spreadArray(['error:%c' + (str ? " ".concat(str) : '') + "%c (loop ".concat(_this.getLoopIdNext(), ")")], __read(logStyles_3), false); });
3052
3082
  }
3053
3083
  };
3054
3084
  Logger.prototype.log = function () {
@@ -3108,64 +3138,84 @@ var Logger = /** @class */ (function () {
3108
3138
  }());
3109
3139
 
3110
3140
  var Routines = /** @class */ (function () {
3111
- function Routines(settings) {
3112
- this.horizontal = settings.horizontal;
3113
- this.window = settings.windowViewport;
3114
- this.viewport = settings.viewport;
3141
+ function Routines(element, settings, CustomRoutines) {
3142
+ var _this = this;
3143
+ this.element = element;
3144
+ this.settings = {
3145
+ viewport: settings.viewport,
3146
+ horizontal: settings.horizontal,
3147
+ window: settings.windowViewport
3148
+ };
3149
+ // provide custom overrides for IRoutines methods
3150
+ if (CustomRoutines) {
3151
+ var routines_1 = new CustomRoutines(element, this.settings);
3152
+ Object.getOwnPropertyNames(Object.getPrototypeOf(routines_1))
3153
+ .filter(function (method) {
3154
+ return method !== 'constructor' &&
3155
+ typeof routines_1[method] === 'function' &&
3156
+ typeof _this[method] === 'function';
3157
+ })
3158
+ .forEach(function (method) {
3159
+ return _this[method] = function () {
3160
+ var args = [];
3161
+ for (var _i = 0; _i < arguments.length; _i++) {
3162
+ args[_i] = arguments[_i];
3163
+ }
3164
+ return routines_1[method].apply(_this, args);
3165
+ };
3166
+ });
3167
+ }
3168
+ // initialization
3169
+ this.viewport = this.getViewportElement();
3170
+ this.onInit(settings);
3115
3171
  }
3116
3172
  Routines.prototype.checkElement = function (element) {
3117
3173
  if (!element) {
3118
3174
  throw new Error('HTML element is not defined');
3119
3175
  }
3120
3176
  };
3121
- Routines.prototype.getHostElement = function (element) {
3122
- if (this.window) {
3177
+ Routines.prototype.getViewportElement = function () {
3178
+ if (this.settings.window) {
3123
3179
  return document.documentElement;
3124
3180
  }
3125
- if (this.viewport) {
3126
- return this.viewport;
3181
+ if (this.settings.viewport) {
3182
+ return this.settings.viewport;
3127
3183
  }
3128
- this.checkElement(element);
3129
- var parent = element.parentElement;
3184
+ this.checkElement(this.element);
3185
+ var parent = this.element.parentElement;
3130
3186
  this.checkElement(parent);
3131
3187
  return parent;
3132
3188
  };
3133
- Routines.prototype.getScrollEventReceiver = function (element) {
3134
- if (this.window) {
3135
- return window;
3189
+ Routines.prototype.onInit = function (settings) {
3190
+ if (settings.windowViewport) {
3191
+ if ('scrollRestoration' in history) {
3192
+ history.scrollRestoration = 'manual';
3193
+ }
3136
3194
  }
3137
- return this.getHostElement(element);
3138
- };
3139
- Routines.prototype.setupScrollRestoration = function () {
3140
- if ('scrollRestoration' in history) {
3141
- history.scrollRestoration = 'manual';
3195
+ if (settings.dismissOverflowAnchor) {
3196
+ this.viewport.style.overflowAnchor = 'none';
3142
3197
  }
3143
3198
  };
3144
- Routines.prototype.dismissOverflowAnchor = function (element) {
3145
- this.checkElement(element);
3146
- element.style.overflowAnchor = 'none';
3147
- };
3148
3199
  Routines.prototype.findElementBySelector = function (element, selector) {
3149
3200
  this.checkElement(element);
3150
3201
  return element.querySelector(selector);
3151
3202
  };
3152
- Routines.prototype.findPaddingElement = function (element, direction) {
3153
- return this.findElementBySelector(element, "[data-padding-" + direction + "]");
3203
+ Routines.prototype.findPaddingElement = function (direction) {
3204
+ return this.findElementBySelector(this.element, "[data-padding-".concat(direction, "]"));
3154
3205
  };
3155
- Routines.prototype.findItemElement = function (element, id) {
3156
- return this.findElementBySelector(element, "[data-sid=\"" + id + "\"]");
3206
+ Routines.prototype.findItemElement = function (id) {
3207
+ return this.findElementBySelector(this.element, "[data-sid=\"".concat(id, "\"]"));
3157
3208
  };
3158
- Routines.prototype.getScrollPosition = function (element) {
3159
- if (this.window) {
3160
- return window.pageYOffset;
3209
+ Routines.prototype.getScrollPosition = function () {
3210
+ if (this.settings.window) {
3211
+ return this.settings.horizontal ? window.pageXOffset : window.pageYOffset;
3161
3212
  }
3162
- this.checkElement(element);
3163
- return element[this.horizontal ? 'scrollLeft' : 'scrollTop'];
3213
+ return this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'];
3164
3214
  };
3165
- Routines.prototype.setScrollPosition = function (element, value) {
3215
+ Routines.prototype.setScrollPosition = function (value) {
3166
3216
  value = Math.max(0, value);
3167
- if (this.window) {
3168
- if (this.horizontal) {
3217
+ if (this.settings.window) {
3218
+ if (this.settings.horizontal) {
3169
3219
  window.scrollTo(value, window.scrollY);
3170
3220
  }
3171
3221
  else {
@@ -3173,49 +3223,62 @@ var Routines = /** @class */ (function () {
3173
3223
  }
3174
3224
  return;
3175
3225
  }
3176
- this.checkElement(element);
3177
- element[this.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
3226
+ this.viewport[this.settings.horizontal ? 'scrollLeft' : 'scrollTop'] = value;
3178
3227
  };
3179
- Routines.prototype.getParams = function (element, doNotBind) {
3228
+ Routines.prototype.getElementParams = function (element) {
3180
3229
  this.checkElement(element);
3181
- if (this.window && doNotBind) {
3182
- var clientWidth = element.clientWidth, clientHeight = element.clientHeight, clientLeft = element.clientLeft, clientTop = element.clientTop;
3183
- return {
3184
- 'height': clientHeight,
3185
- 'width': clientWidth,
3186
- 'top': clientTop,
3187
- 'bottom': clientTop + clientHeight,
3188
- 'left': clientLeft,
3189
- 'right': clientLeft + clientWidth,
3190
- 'x': clientLeft,
3191
- 'y': clientTop,
3192
- 'toJSON': function () { return null; },
3193
- };
3194
- }
3195
3230
  return element.getBoundingClientRect();
3196
3231
  };
3197
- Routines.prototype.getSize = function (element, doNotBind) {
3198
- return this.getParams(element, doNotBind)[this.horizontal ? 'width' : 'height'];
3232
+ Routines.prototype.getWindowParams = function () {
3233
+ var _a = this.viewport, clientWidth = _a.clientWidth, clientHeight = _a.clientHeight, clientLeft = _a.clientLeft, clientTop = _a.clientTop;
3234
+ return {
3235
+ 'height': clientHeight,
3236
+ 'width': clientWidth,
3237
+ 'top': clientTop,
3238
+ 'bottom': clientTop + clientHeight,
3239
+ 'left': clientLeft,
3240
+ 'right': clientLeft + clientWidth,
3241
+ 'x': clientLeft,
3242
+ 'y': clientTop,
3243
+ 'toJSON': function () { return null; },
3244
+ };
3245
+ };
3246
+ Routines.prototype.getSize = function (element) {
3247
+ return this.getElementParams(element)[this.settings.horizontal ? 'width' : 'height'];
3248
+ };
3249
+ Routines.prototype.getScrollerSize = function () {
3250
+ return this.getElementParams(this.element)[this.settings.horizontal ? 'width' : 'height'];
3251
+ };
3252
+ Routines.prototype.getViewportSize = function () {
3253
+ if (this.settings.window) {
3254
+ return this.getWindowParams()[this.settings.horizontal ? 'width' : 'height'];
3255
+ }
3256
+ return this.getSize(this.viewport);
3199
3257
  };
3200
3258
  Routines.prototype.getSizeStyle = function (element) {
3201
3259
  this.checkElement(element);
3202
- var size = element.style[this.horizontal ? 'width' : 'height'];
3260
+ var size = element.style[this.settings.horizontal ? 'width' : 'height'];
3203
3261
  return parseFloat(size) || 0;
3204
3262
  };
3205
3263
  Routines.prototype.setSizeStyle = function (element, value) {
3206
3264
  this.checkElement(element);
3207
3265
  value = Math.max(0, Math.round(value));
3208
- element.style[this.horizontal ? 'width' : 'height'] = value + "px";
3266
+ element.style[this.settings.horizontal ? 'width' : 'height'] = "".concat(value, "px");
3209
3267
  };
3210
- Routines.prototype.getEdge = function (element, direction, doNotBind) {
3211
- var params = this.getParams(element, doNotBind);
3268
+ Routines.prototype.getEdge = function (element, direction) {
3269
+ var horizontal = this.settings.horizontal;
3270
+ var params = this.getElementParams(element);
3212
3271
  var isFwd = direction === Direction.forward;
3213
- return params[isFwd ? (this.horizontal ? 'right' : 'bottom') : (this.horizontal ? 'left' : 'top')];
3272
+ return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
3214
3273
  };
3215
- Routines.prototype.getEdge2 = function (element, direction, relativeElement, opposite) {
3216
- // vertical only ?
3217
- return element.offsetTop - (relativeElement ? relativeElement.scrollTop : 0) +
3218
- (direction === (!opposite ? Direction.forward : Direction.backward) ? this.getSize(element) : 0);
3274
+ Routines.prototype.getViewportEdge = function (direction) {
3275
+ var _a = this.settings, window = _a.window, horizontal = _a.horizontal;
3276
+ if (window) {
3277
+ var params = this.getWindowParams();
3278
+ var isFwd = direction === Direction.forward;
3279
+ return params[isFwd ? (horizontal ? 'right' : 'bottom') : (horizontal ? 'left' : 'top')];
3280
+ }
3281
+ return this.getEdge(this.viewport, direction);
3219
3282
  };
3220
3283
  Routines.prototype.makeElementVisible = function (element) {
3221
3284
  this.checkElement(element);
@@ -3227,20 +3290,36 @@ var Routines = /** @class */ (function () {
3227
3290
  this.checkElement(element);
3228
3291
  element.style.display = 'none';
3229
3292
  };
3230
- Routines.prototype.getOffset = function (element) {
3231
- this.checkElement(element);
3232
- return (this.horizontal ? element.offsetLeft : element.offsetTop) || 0;
3293
+ Routines.prototype.getOffset = function () {
3294
+ var _this = this;
3295
+ var get = function (element) {
3296
+ return (_this.settings.horizontal ? element.offsetLeft : element.offsetTop) || 0;
3297
+ };
3298
+ return get(this.element) - (!this.settings.window ? get(this.viewport) : 0);
3233
3299
  };
3234
3300
  Routines.prototype.scrollTo = function (element, argument) {
3235
3301
  this.checkElement(element);
3236
3302
  element.scrollIntoView(argument);
3237
3303
  };
3304
+ Routines.prototype.render = function (cb) {
3305
+ var timeoutId = setTimeout(function () { return cb(); });
3306
+ return function () { return clearTimeout(timeoutId); };
3307
+ };
3308
+ Routines.prototype.animate = function (cb) {
3309
+ var animationFrameId = requestAnimationFrame(function () { return cb(); });
3310
+ return function () { return cancelAnimationFrame(animationFrameId); };
3311
+ };
3312
+ Routines.prototype.onScroll = function (handler) {
3313
+ var eventReceiver = this.settings.window ? window : this.viewport;
3314
+ eventReceiver.addEventListener('scroll', handler);
3315
+ return function () { return eventReceiver.removeEventListener('scroll', handler); };
3316
+ };
3238
3317
  return Routines;
3239
3318
  }());
3240
3319
 
3241
3320
  var Padding = /** @class */ (function () {
3242
- function Padding(element, direction, routines) {
3243
- var found = routines.findPaddingElement(element, direction);
3321
+ function Padding(direction, routines) {
3322
+ var found = routines.findPaddingElement(direction);
3244
3323
  routines.checkElement(found);
3245
3324
  this.element = found;
3246
3325
  this.direction = direction;
@@ -3262,10 +3341,10 @@ var Padding = /** @class */ (function () {
3262
3341
  return Padding;
3263
3342
  }());
3264
3343
  var Paddings = /** @class */ (function () {
3265
- function Paddings(element, routines, settings) {
3344
+ function Paddings(routines, settings) {
3266
3345
  this.settings = settings;
3267
- this.forward = new Padding(element, Direction.forward, routines);
3268
- this.backward = new Padding(element, Direction.backward, routines);
3346
+ this.forward = new Padding(Direction.forward, routines);
3347
+ this.backward = new Padding(Direction.backward, routines);
3269
3348
  }
3270
3349
  Paddings.prototype.byDirection = function (direction, opposite) {
3271
3350
  return direction === Direction.backward
@@ -3317,27 +3396,18 @@ var Paddings = /** @class */ (function () {
3317
3396
  }());
3318
3397
 
3319
3398
  var Viewport = /** @class */ (function () {
3320
- function Viewport(element, settings, routines, state, logger) {
3321
- this.element = element;
3399
+ function Viewport(settings, routines, state, logger) {
3322
3400
  this.settings = settings;
3323
3401
  this.routines = routines;
3324
3402
  this.state = state;
3325
3403
  this.logger = logger;
3326
- this.hostElement = this.routines.getHostElement(this.element);
3327
- this.scrollEventReceiver = this.routines.getScrollEventReceiver(this.element);
3328
- if (settings.windowViewport) {
3329
- this.routines.setupScrollRestoration();
3330
- }
3331
- if (settings.dismissOverflowAnchor) {
3332
- this.routines.dismissOverflowAnchor(this.hostElement);
3333
- }
3334
- this.paddings = new Paddings(this.element, this.routines, settings);
3404
+ this.paddings = new Paddings(this.routines, settings);
3335
3405
  }
3336
3406
  Viewport.prototype.reset = function (startIndex) {
3337
3407
  this.setOffset();
3338
3408
  this.paddings.reset(this.getSize(), startIndex, this.offset);
3339
3409
  this.scrollPosition = this.paddings.backward.size || 0;
3340
- this.state.scrollState.reset();
3410
+ this.state.scroll.reset();
3341
3411
  };
3342
3412
  Viewport.prototype.setPosition = function (value) {
3343
3413
  var oldPosition = this.scrollPosition;
@@ -3345,16 +3415,16 @@ var Viewport = /** @class */ (function () {
3345
3415
  this.logger.log(function () { return ['setting scroll position at', value, '[cancelled]']; });
3346
3416
  return value;
3347
3417
  }
3348
- this.routines.setScrollPosition(this.hostElement, value);
3418
+ this.routines.setScrollPosition(value);
3349
3419
  var position = this.scrollPosition;
3350
3420
  this.logger.log(function () { return __spreadArray([
3351
3421
  'setting scroll position at', position
3352
- ], __read((position !== value ? ["(" + value + ")"] : [])), false); });
3422
+ ], __read((position !== value ? ["(".concat(value, ")")] : [])), false); });
3353
3423
  return position;
3354
3424
  };
3355
3425
  Object.defineProperty(Viewport.prototype, "scrollPosition", {
3356
3426
  get: function () {
3357
- return this.routines.getScrollPosition(this.hostElement);
3427
+ return this.routines.getScrollPosition();
3358
3428
  },
3359
3429
  set: function (value) {
3360
3430
  this.setPosition(value);
@@ -3363,25 +3433,25 @@ var Viewport = /** @class */ (function () {
3363
3433
  configurable: true
3364
3434
  });
3365
3435
  Viewport.prototype.getSize = function () {
3366
- return this.routines.getSize(this.hostElement, true);
3436
+ return this.routines.getViewportSize();
3367
3437
  };
3368
3438
  Viewport.prototype.getScrollableSize = function () {
3369
- return this.routines.getSize(this.element);
3439
+ return this.routines.getScrollerSize();
3440
+ };
3441
+ Viewport.prototype.getMaxScrollPosition = function () {
3442
+ return this.getScrollableSize() - this.getSize();
3370
3443
  };
3371
3444
  Viewport.prototype.getBufferPadding = function () {
3372
3445
  return this.getSize() * this.settings.padding;
3373
3446
  };
3374
3447
  Viewport.prototype.getEdge = function (direction) {
3375
- return this.routines.getEdge(this.hostElement, direction, true);
3448
+ return this.routines.getViewportEdge(direction);
3376
3449
  };
3377
3450
  Viewport.prototype.setOffset = function () {
3378
- this.offset = this.routines.getOffset(this.element);
3379
- if (!this.settings.windowViewport) {
3380
- this.offset -= this.routines.getOffset(this.hostElement);
3381
- }
3451
+ this.offset = this.routines.getOffset();
3382
3452
  };
3383
3453
  Viewport.prototype.findItemElementById = function (id) {
3384
- return this.routines.findItemElement(this.element, id);
3454
+ return this.routines.findItemElement(id);
3385
3455
  };
3386
3456
  Viewport.prototype.getEdgeVisibleItem = function (items, direction) {
3387
3457
  var bwd = direction === Direction.backward;
@@ -3595,7 +3665,7 @@ var Cache = /** @class */ (function () {
3595
3665
  Cache.prototype.recalculateDefaultSize = function () {
3596
3666
  var _this = this;
3597
3667
  if (this.defaultSize.recalculate(this.size)) {
3598
- this.logger.log(function () { return "default size has been updated: " + _this.defaultSize.get(); });
3668
+ this.logger.log(function () { return "default size has been updated: ".concat(_this.defaultSize.get()); });
3599
3669
  return true;
3600
3670
  }
3601
3671
  return false;
@@ -3814,7 +3884,7 @@ var CheckBufferCall = /** @class */ (function () {
3814
3884
  this.logger.log('no items to fill the buffer; wrong indexes');
3815
3885
  return false;
3816
3886
  }
3817
- this.logger.log(function () { return "going to fill the buffer with " + items.length + " item(s)"; });
3887
+ this.logger.log(function () { return "going to fill the buffer with ".concat(items.length, " item(s)"); });
3818
3888
  return true;
3819
3889
  };
3820
3890
  CheckBufferCall.prototype.insertInBuffer = function (predicate, before, after) {
@@ -3838,18 +3908,18 @@ var CheckBufferCall = /** @class */ (function () {
3838
3908
  if (index < finiteAbsMinIndex || index > finiteAbsMaxIndex) {
3839
3909
  this.logger.log(function () {
3840
3910
  return 'no items to insert virtually; ' +
3841
- ("selected index (" + index + ") does not match virtual area [" + finiteAbsMinIndex + ".." + finiteAbsMaxIndex + "]");
3911
+ "selected index (".concat(index, ") does not match virtual area [").concat(finiteAbsMinIndex, "..").concat(finiteAbsMaxIndex, "]");
3842
3912
  });
3843
3913
  return false;
3844
3914
  }
3845
3915
  var before = direction === Direction.backward;
3846
3916
  if (!(index < firstIndex + (before ? 1 : 0) || index > lastIndex - (before ? 0 : 1))) {
3847
3917
  this.logger.log(function () {
3848
- return "no items to insert virtually; selected index (" + index + ") belongs Buffer [" + firstIndex + ".." + lastIndex + "]";
3918
+ return "no items to insert virtually; selected index (".concat(index, ") belongs Buffer [").concat(firstIndex, "..").concat(lastIndex, "]");
3849
3919
  });
3850
3920
  return false;
3851
3921
  }
3852
- this.logger.log(function () { return "going to insert " + items.length + " item(s) virtually"; });
3922
+ this.logger.log(function () { return "going to insert ".concat(items.length, " item(s) virtually"); });
3853
3923
  return true;
3854
3924
  };
3855
3925
  return CheckBufferCall;
@@ -3893,15 +3963,15 @@ var Buffer = /** @class */ (function () {
3893
3963
  var start = this.startIndexUser;
3894
3964
  var index = Number(newStartIndex);
3895
3965
  if (Number.isNaN(index)) {
3896
- this.logger.log(function () { return "fallback startIndex to settings.startIndex (" + start + ")"; });
3966
+ this.logger.log(function () { return "fallback startIndex to settings.startIndex (".concat(start, ")"); });
3897
3967
  index = start;
3898
3968
  }
3899
3969
  if (index < min) {
3900
- this.logger.log(function () { return "setting startIndex to settings.minIndex (" + min + ") because " + index + " < " + min; });
3970
+ this.logger.log(function () { return "setting startIndex to settings.minIndex (".concat(min, ") because ").concat(index, " < ").concat(min); });
3901
3971
  index = min;
3902
3972
  }
3903
3973
  if (index > max) {
3904
- this.logger.log(function () { return "setting startIndex to settings.maxIndex (" + max + ") because " + index + " > " + max; });
3974
+ this.logger.log(function () { return "setting startIndex to settings.maxIndex (".concat(max, ") because ").concat(index, " > ").concat(max); });
3905
3975
  index = max;
3906
3976
  }
3907
3977
  this.startIndex = index;
@@ -4277,6 +4347,7 @@ var InnerLoopModel = /** @class */ (function () {
4277
4347
  configurable: true
4278
4348
  });
4279
4349
  InnerLoopModel.prototype.done = function () {
4350
+ this.isInitial = false;
4280
4351
  this.count++;
4281
4352
  this.total++;
4282
4353
  this.busy.set(false);
@@ -4297,27 +4368,22 @@ var WorkflowCycleModel = /** @class */ (function () {
4297
4368
  this.innerLoop = new InnerLoopModel(loopCount);
4298
4369
  this.interrupter = null;
4299
4370
  this.busy = new Reactive(false);
4300
- this.done(cycleCount);
4371
+ this.end(cycleCount);
4301
4372
  }
4302
4373
  Object.defineProperty(WorkflowCycleModel.prototype, "loopId", {
4303
4374
  get: function () {
4304
- return this.instanceIndex + "-" + this.count + "-" + this.innerLoop.total;
4375
+ return "".concat(this.instanceIndex, "-").concat(this.count, "-").concat(this.innerLoop.total);
4305
4376
  },
4306
4377
  enumerable: false,
4307
4378
  configurable: true
4308
4379
  });
4309
4380
  Object.defineProperty(WorkflowCycleModel.prototype, "loopIdNext", {
4310
4381
  get: function () {
4311
- return this.instanceIndex + "-" + this.count + "-" + (this.innerLoop.total + 1);
4382
+ return "".concat(this.instanceIndex, "-").concat(this.count, "-").concat(this.innerLoop.total + 1);
4312
4383
  },
4313
4384
  enumerable: false,
4314
4385
  configurable: true
4315
4386
  });
4316
- WorkflowCycleModel.prototype.done = function (count) {
4317
- this.count = count;
4318
- this.isInitial = false;
4319
- this.busy.set(false);
4320
- };
4321
4387
  WorkflowCycleModel.prototype.start = function (isInitial, initiator) {
4322
4388
  this.isInitial = isInitial;
4323
4389
  this.initiator = initiator;
@@ -4326,6 +4392,11 @@ var WorkflowCycleModel = /** @class */ (function () {
4326
4392
  this.interrupter = null;
4327
4393
  this.busy.set(true);
4328
4394
  };
4395
+ WorkflowCycleModel.prototype.end = function (count) {
4396
+ this.count = count;
4397
+ this.isInitial = false;
4398
+ this.busy.set(false);
4399
+ };
4329
4400
  WorkflowCycleModel.prototype.dispose = function (forever) {
4330
4401
  if (forever) {
4331
4402
  // otherwise the value will be persisted during re-instantiation
@@ -4520,16 +4591,16 @@ var RenderModel = /** @class */ (function () {
4520
4591
  this.sizeBefore = 0;
4521
4592
  this.sizeAfter = 0;
4522
4593
  this.positionBefore = 0;
4523
- this.renderTimer = null;
4594
+ this.cancel = null;
4524
4595
  };
4525
4596
  return RenderModel;
4526
4597
  }());
4527
4598
 
4528
- var ScrollState = /** @class */ (function () {
4529
- function ScrollState() {
4599
+ var ScrollModel = /** @class */ (function () {
4600
+ function ScrollModel() {
4530
4601
  this.reset();
4531
4602
  }
4532
- ScrollState.prototype.reset = function () {
4603
+ ScrollModel.prototype.reset = function () {
4533
4604
  this.previous = null;
4534
4605
  this.current = null;
4535
4606
  this.syntheticPosition = null;
@@ -4537,24 +4608,24 @@ var ScrollState = /** @class */ (function () {
4537
4608
  this.positionBeforeAsync = null;
4538
4609
  this.positionBeforeAdjust = null;
4539
4610
  this.positionAfterAdjust = null;
4540
- this.cleanupTimers();
4611
+ this.stop();
4541
4612
  };
4542
- ScrollState.prototype.cleanupTimers = function () {
4613
+ ScrollModel.prototype.stop = function () {
4543
4614
  if (this.scrollTimer) {
4544
4615
  clearTimeout(this.scrollTimer);
4545
4616
  this.scrollTimer = null;
4546
4617
  }
4547
- if (this.animationFrameId) {
4548
- cancelAnimationFrame(this.animationFrameId);
4549
- this.animationFrameId = 0;
4618
+ if (this.cancelAnimation) {
4619
+ this.cancelAnimation();
4620
+ this.cancelAnimation = null;
4550
4621
  }
4551
4622
  };
4552
- ScrollState.prototype.hasPositionChanged = function (position) {
4623
+ ScrollModel.prototype.hasPositionChanged = function (position) {
4553
4624
  var before = this.positionBeforeAdjust;
4554
4625
  var after = this.positionAfterAdjust;
4555
4626
  return before === null || before !== position || after === null || after !== position;
4556
4627
  };
4557
- return ScrollState;
4628
+ return ScrollModel;
4558
4629
  }());
4559
4630
 
4560
4631
  var State = /** @class */ (function () {
@@ -4566,7 +4637,7 @@ var State = /** @class */ (function () {
4566
4637
  this.fetch = new FetchModel(settings.directionPriority);
4567
4638
  this.clip = new ClipModel();
4568
4639
  this.render = new RenderModel();
4569
- this.scrollState = new ScrollState();
4640
+ this.scroll = new ScrollModel();
4570
4641
  }
4571
4642
  Object.defineProperty(State.prototype, "time", {
4572
4643
  get: function () {
@@ -4575,20 +4646,14 @@ var State = /** @class */ (function () {
4575
4646
  enumerable: false,
4576
4647
  configurable: true
4577
4648
  });
4578
- State.prototype.endInnerLoop = function () {
4579
- var _a = this, fetch = _a.fetch, render = _a.render, cycle = _a.cycle;
4580
- if (fetch.cancel) {
4581
- fetch.cancel();
4582
- fetch.cancel = null;
4583
- }
4584
- if (render.renderTimer) {
4585
- clearTimeout(render.renderTimer);
4586
- render.renderTimer = null;
4587
- }
4588
- cycle.innerLoop.done();
4649
+ State.prototype.startWorkflowCycle = function (isInitial, initiator) {
4650
+ this.cycle.start(isInitial, initiator);
4651
+ };
4652
+ State.prototype.endWorkflowCycle = function (count) {
4653
+ this.cycle.end(count);
4589
4654
  };
4590
4655
  State.prototype.startInnerLoop = function () {
4591
- var _a = this, cycle = _a.cycle, scroll = _a.scrollState, fetch = _a.fetch, render = _a.render, clip = _a.clip;
4656
+ var _a = this, cycle = _a.cycle, scroll = _a.scroll, fetch = _a.fetch, render = _a.render, clip = _a.clip;
4592
4657
  cycle.innerLoop.start();
4593
4658
  scroll.positionBeforeAsync = null;
4594
4659
  if (!fetch.simulate) {
@@ -4601,10 +4666,24 @@ var State = /** @class */ (function () {
4601
4666
  doRender: fetch.simulate && fetch.items.length > 0
4602
4667
  } : {}));
4603
4668
  };
4669
+ State.prototype.endInnerLoop = function () {
4670
+ var _a = this, fetch = _a.fetch, clip = _a.clip, render = _a.render, cycle = _a.cycle;
4671
+ fetch.stopSimulate();
4672
+ clip.reset(true);
4673
+ if (fetch.cancel) {
4674
+ fetch.cancel();
4675
+ fetch.cancel = null;
4676
+ }
4677
+ if (render.cancel) {
4678
+ render.cancel();
4679
+ render.cancel = null;
4680
+ }
4681
+ cycle.innerLoop.done();
4682
+ };
4604
4683
  State.prototype.dispose = function () {
4684
+ this.scroll.stop();
4605
4685
  this.cycle.dispose();
4606
4686
  this.endInnerLoop();
4607
- this.scrollState.cleanupTimers();
4608
4687
  };
4609
4688
  return State;
4610
4689
  }());
@@ -4914,7 +4993,7 @@ var Adapter = /** @class */ (function () {
4914
4993
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4915
4994
  Adapter.prototype.reset = function (options) {
4916
4995
  this.reloadCounter++;
4917
- this.logger.logAdapterMethod('reset', options, " of " + this.reloadId);
4996
+ this.logger.logAdapterMethod('reset', options, " of ".concat(this.reloadId));
4918
4997
  this.workflow.call({
4919
4998
  process: AdapterProcess.reset,
4920
4999
  status: ProcessStatus.start,
@@ -4924,7 +5003,7 @@ var Adapter = /** @class */ (function () {
4924
5003
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4925
5004
  Adapter.prototype.reload = function (options) {
4926
5005
  this.reloadCounter++;
4927
- this.logger.logAdapterMethod('reload', options, " of " + this.reloadId);
5006
+ this.logger.logAdapterMethod('reload', options, " of ".concat(this.reloadId));
4928
5007
  this.workflow.call({
4929
5008
  process: AdapterProcess.reload,
4930
5009
  status: ProcessStatus.start,
@@ -5031,7 +5110,7 @@ var Adapter = /** @class */ (function () {
5031
5110
  });
5032
5111
  }).then(function (immediate) {
5033
5112
  var success = reloadId === _this.reloadId;
5034
- _this.logger.log(function () { return !success ? "relax promise cancelled due to " + reloadId + " != " + _this.reloadId : void 0; });
5113
+ _this.logger.log(function () { return !success ? "relax promise cancelled due to ".concat(reloadId, " != ").concat(_this.reloadId) : void 0; });
5035
5114
  return {
5036
5115
  immediate: immediate,
5037
5116
  success: success,
@@ -5042,7 +5121,7 @@ var Adapter = /** @class */ (function () {
5042
5121
  Adapter.prototype.relax = function (callback) {
5043
5122
  var _this = this;
5044
5123
  var reloadId = this.reloadId;
5045
- this.logger.logAdapterMethod('relax', callback, " of " + reloadId);
5124
+ this.logger.logAdapterMethod('relax', callback, " of ".concat(reloadId));
5046
5125
  if (!this.init) {
5047
5126
  return Promise.resolve(methodPreResult);
5048
5127
  }
@@ -5064,21 +5143,21 @@ var INVALID_DATASOURCE_PREFIX = 'Invalid datasource:';
5064
5143
  var instanceCount = 0;
5065
5144
  var Scroller = /** @class */ (function () {
5066
5145
  function Scroller(_a) {
5067
- var datasource = _a.datasource, consumer = _a.consumer, element = _a.element, workflow = _a.workflow, scroller = _a.scroller;
5146
+ var datasource = _a.datasource, consumer = _a.consumer, element = _a.element, workflow = _a.workflow, CustomRoutines = _a.Routines, scroller = _a.scroller;
5068
5147
  var get = validate(datasource, DATASOURCE).params.get;
5069
5148
  if (!get.isValid) {
5070
- throw new Error(INVALID_DATASOURCE_PREFIX + " " + get.errors[0]);
5149
+ throw new Error("".concat(INVALID_DATASOURCE_PREFIX, " ").concat(get.errors[0]));
5071
5150
  }
5072
5151
  var packageInfo = scroller ? scroller.state.packageInfo : { consumer: consumer, core: core };
5073
- element = scroller ? scroller.viewport.element : element;
5152
+ element = scroller ? scroller.routines.element : element;
5074
5153
  workflow = scroller ? scroller.workflow : workflow;
5075
5154
  this.workflow = workflow;
5076
5155
  this.settings = new Settings(datasource.settings, datasource.devSettings, ++instanceCount);
5077
5156
  this.logger = new Logger(this, packageInfo, datasource.adapter);
5078
- this.routines = new Routines(this.settings);
5157
+ this.routines = new Routines(element, this.settings, CustomRoutines);
5079
5158
  this.state = new State(packageInfo, this.settings, scroller ? scroller.state : void 0);
5080
5159
  this.buffer = new Buffer(this.settings, workflow.onDataChanged, this.logger);
5081
- this.viewport = new Viewport(element, this.settings, this.routines, this.state, this.logger);
5160
+ this.viewport = new Viewport(this.settings, this.routines, this.state, this.logger);
5082
5161
  this.logger.object('vscroll settings object', this.settings, true);
5083
5162
  this.initDatasource(datasource, scroller);
5084
5163
  }
@@ -5337,14 +5416,14 @@ var runStateMachine = function (_a) {
5337
5416
  var Workflow = /** @class */ (function () {
5338
5417
  function Workflow(_a) {
5339
5418
  var _this = this;
5340
- var element = _a.element, datasource = _a.datasource, consumer = _a.consumer, run = _a.run;
5419
+ var element = _a.element, datasource = _a.datasource, consumer = _a.consumer, run = _a.run, Routines = _a.Routines;
5341
5420
  this.isInitialized = false;
5342
5421
  this.initTimer = null;
5343
5422
  this.adapterRun$ = new Reactive();
5344
5423
  this.cyclesDone = 0;
5345
5424
  this.interruptionCount = 0;
5346
5425
  this.errors = [];
5347
- this.disposeScrollEventHandler = function () { return null; };
5426
+ this.offScroll = function () { return null; };
5348
5427
  this.propagateChanges = run;
5349
5428
  this.stateMachineMethods = {
5350
5429
  run: this.runProcess(),
@@ -5352,7 +5431,13 @@ var Workflow = /** @class */ (function () {
5352
5431
  done: this.done.bind(this),
5353
5432
  onError: this.onError.bind(this)
5354
5433
  };
5355
- this.scroller = new Scroller({ element: element, datasource: datasource, consumer: consumer, workflow: this.getUpdater() });
5434
+ this.scroller = new Scroller({
5435
+ element: element,
5436
+ datasource: datasource,
5437
+ consumer: consumer,
5438
+ workflow: this.getUpdater(),
5439
+ Routines: Routines
5440
+ });
5356
5441
  if (this.scroller.settings.initializeDelay) {
5357
5442
  this.initTimer = setTimeout(function () {
5358
5443
  _this.initTimer = null;
@@ -5373,16 +5458,13 @@ var Workflow = /** @class */ (function () {
5373
5458
  status: ProcessStatus.start
5374
5459
  });
5375
5460
  // set up scroll event listener
5376
- var scrollEventReceiver = this.scroller.viewport.scrollEventReceiver;
5461
+ var routines = this.scroller.routines;
5377
5462
  var onScrollHandler = function (event) { return _this.callWorkflow({
5378
5463
  process: CommonProcess.scroll,
5379
5464
  status: ProcessStatus.start,
5380
5465
  payload: { event: event }
5381
5466
  }); };
5382
- scrollEventReceiver.addEventListener('scroll', onScrollHandler);
5383
- this.disposeScrollEventHandler = function () {
5384
- return scrollEventReceiver.removeEventListener('scroll', onScrollHandler);
5385
- };
5467
+ this.offScroll = routines.onScroll(onScrollHandler);
5386
5468
  };
5387
5469
  Workflow.prototype.changeItems = function (items) {
5388
5470
  this.propagateChanges(items);
@@ -5410,7 +5492,7 @@ var Workflow = /** @class */ (function () {
5410
5492
  '%cfire%c'
5411
5493
  ], ['color: #cc7777;', 'color: #000000;'], false), [
5412
5494
  process,
5413
- "\"" + status + "\""
5495
+ "\"".concat(status, "\"")
5414
5496
  ], false), __read((payload !== void 0 ? [payload] : [])), false); });
5415
5497
  }
5416
5498
  this.scroller.logger.logProcess(data);
@@ -5466,7 +5548,7 @@ var Workflow = /** @class */ (function () {
5466
5548
  workflow.call.interrupted = true;
5467
5549
  this.scroller.workflow = this.getUpdater();
5468
5550
  this.interruptionCount++;
5469
- logger_1.log(function () { return "workflow had been interrupted by the " + process + " process (" + _this.interruptionCount + ")"; });
5551
+ logger_1.log(function () { return "workflow had been interrupted by the ".concat(process, " process (").concat(_this.interruptionCount, ")"); });
5470
5552
  }
5471
5553
  if (datasource) { // Scroller re-initialization case
5472
5554
  this.scroller.adapter.relax(function () {
@@ -5482,7 +5564,7 @@ var Workflow = /** @class */ (function () {
5482
5564
  var _a = this.scroller, state = _a.state, logger = _a.logger;
5483
5565
  this.cyclesDone++;
5484
5566
  logger.logCycle(false);
5485
- state.cycle.done(this.cyclesDone + 1);
5567
+ state.endWorkflowCycle(this.cyclesDone + 1);
5486
5568
  this.finalize();
5487
5569
  };
5488
5570
  Workflow.prototype.dispose = function () {
@@ -5490,7 +5572,7 @@ var Workflow = /** @class */ (function () {
5490
5572
  if (this.initTimer) {
5491
5573
  clearTimeout(this.initTimer);
5492
5574
  }
5493
- this.disposeScrollEventHandler();
5575
+ this.offScroll();
5494
5576
  this.adapterRun$.dispose();
5495
5577
  this.scroller.dispose(true);
5496
5578
  Object.getOwnPropertyNames(this).forEach(function (prop) {