targetj 1.0.233 → 1.0.235

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # TargetJS: State as Destination, Code Order as UI Sequence
2
2
 
3
+ ### Most frameworks are great at rendering state. TargetJS is designed for the journey between states.
4
+
3
5
  **[targetjs.io](https://targetjs.io)**
4
6
  [![MIT LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/livetrails/targetjs/blob/main/LICENSE)
5
7
  [![Stars](https://img.shields.io/github/stars/livetrails/targetjs.svg)](https://github.com/livetrails/targetjs/stargazers)
6
8
  [![npm version](https://img.shields.io/npm/v/targetj.svg)](https://www.npmjs.com/package/targetj)
7
9
 
8
- Most frameworks are great at rendering the next state. TargetJS is designed for the journey between states.
9
-
10
- TargetJS is a JavaScript UI framework that replaces the "State → Render" model with "State → transition → Render". It also lets code order directly define the UI sequence. It unifies UI, animations, API calls, event handling, and state into self-contained "Targets" that stack together like intelligent Lego pieces using Code-Ordered Reactivity.
10
+ TargetJS is a JavaScript UI framework that replaces the "State → Render" model with "State → Transition → Render". It also lets code order directly define the UI sequence. It unifies UI, animations, API calls, event handling, and state into self-contained "Targets" that stack together like intelligent Lego pieces using Code-Ordered Reactivity.
11
11
 
12
12
  It can be used as a full-featured framework or as a lightweight library alongside other frameworks. It is also a highly performant web framework, as shown in the [framework benchmark](https://krausest.github.io/js-framework-benchmark/current.html).
13
13
 
@@ -550,19 +550,19 @@ var BaseModel = exports.BaseModel = /*#__PURE__*/function () {
550
550
  return ((_this$targetValues$ke6 = this.targetValues[key]) === null || _this$targetValues$ke6 === void 0 ? void 0 : _this$targetValues$ke6.status) === 'complete' ? true : this.targetValues[key] === undefined ? undefined : false;
551
551
  }
552
552
  }, {
553
- key: "isTargetCompleteDeep",
554
- value: function isTargetCompleteDeep(key) {
555
- return _TargetUtil.TargetUtil.isTargetCompleteDeep(this, key);
553
+ key: "isTargetTreeComplete",
554
+ value: function isTargetTreeComplete(key) {
555
+ return _TargetUtil.TargetUtil.isTargetTreeComplete(this, key) === true;
556
556
  }
557
557
  }, {
558
558
  key: "isTargetFullyCompleted",
559
559
  value: function isTargetFullyCompleted(key) {
560
- return _TargetUtil.TargetUtil.isTargetFullyCompleted(this, key);
560
+ return _TargetUtil.TargetUtil.isTargetFullyCompleted(this, key) === true;
561
561
  }
562
562
  }, {
563
563
  key: "arePreviousTargetsComplete",
564
564
  value: function arePreviousTargetsComplete(key) {
565
- return _TargetUtil.TargetUtil.arePreviousTargetsComplete(this, key);
565
+ return _TargetUtil.TargetUtil.arePreviousTargetsComplete(this, key) === true;
566
566
  }
567
567
  }, {
568
568
  key: "cleanupTarget",
@@ -1147,9 +1147,9 @@ var BaseModel = exports.BaseModel = /*#__PURE__*/function () {
1147
1147
  actualOptions = value;
1148
1148
  }
1149
1149
  if (this.canTargetBeActivated(key)) {
1150
- var _actualOptions, _target$childAction, _target$addChildActio;
1150
+ var _actualOptions;
1151
1151
  if ((_actualOptions = actualOptions) !== null && _actualOptions !== void 0 && _actualOptions.reset) {
1152
- _TargetUtil.TargetUtil.resetTargetPipelineState(this, key);
1152
+ _TargetUtil.TargetUtil.resetTargetState(this, key);
1153
1153
  }
1154
1154
  if (_TUtil.TUtil.isDefined(actualValue)) {
1155
1155
  this.val("___".concat(key), actualValue);
@@ -1157,13 +1157,6 @@ var BaseModel = exports.BaseModel = /*#__PURE__*/function () {
1157
1157
  if (this.isVisible()) {
1158
1158
  this.markLayoutDirty(key);
1159
1159
  }
1160
- var target = this.targets[key];
1161
- if (target !== null && target !== void 0 && (_target$childAction = target.childAction) !== null && _target$childAction !== void 0 && _target$childAction.length) {
1162
- target.childAction = [];
1163
- }
1164
- if (target !== null && target !== void 0 && (_target$addChildActio = target.addChildAction) !== null && _target$addChildActio !== void 0 && _target$addChildActio.length) {
1165
- target.addChildAction = [];
1166
- }
1167
1160
  var invokerTModel = _TargetUtil.TargetUtil.currentTModel;
1168
1161
  var invokerTarget = _TargetUtil.TargetUtil.currentTargetName;
1169
1162
  var targetValue = this.targetValues[key] || _TargetUtil.TargetUtil.emptyValue();
@@ -145,13 +145,13 @@ var BracketGenerator = exports.BracketGenerator = /*#__PURE__*/function () {
145
145
  var bracket = targetBracket;
146
146
  bracket.startIndex = Math.min(bracket.startIndex, index);
147
147
  bracket.endIndex = bracket.startIndex + bracket.allChildrenList.length;
148
- bracket.currentStatus = 'new';
148
+ bracket.currentBrakcetStatus = 2;
149
149
  bracket.markLayoutDirty('update');
150
150
  bracket = targetBracket.getParent();
151
151
  while (bracket instanceof _Bracket.Bracket) {
152
152
  bracket.startIndex = Math.min(bracket.startIndex, index);
153
153
  bracket.endIndex = Math.max(bracket.endIndex, index + 1);
154
- bracket.currentStatus = 'new';
154
+ bracket.currentBrakcetStatus = 2;
155
155
  bracket.markLayoutDirty('update');
156
156
  bracket = bracket.getParent();
157
157
  }
@@ -296,7 +296,7 @@ var BracketGenerator = exports.BracketGenerator = /*#__PURE__*/function () {
296
296
  value: function markBracketDirty(bracket) {
297
297
  var current = bracket;
298
298
  while (current && current.type === 'BI') {
299
- current.currentStatus = 'new';
299
+ current.currentBrakcetStatus = 2;
300
300
  current.markLayoutDirty('update');
301
301
  current = current.parent;
302
302
  }
@@ -60,6 +60,7 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
60
60
  this.swipeStartY = 0;
61
61
  this.currentEventName = '';
62
62
  this.currentEventType = '';
63
+ this.currentEventTModel = undefined;
63
64
  this.currentOriginalEvent = undefined;
64
65
  this.currentKey = '';
65
66
  this.currentHandlers = {
@@ -83,6 +84,11 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
83
84
  this.allEvents = {};
84
85
  this.windowScrollX = window.scrollX | 0;
85
86
  this.windowScrollY = window.scrollY | 0;
87
+ this.windowScrollEndTimer = 0;
88
+ this.scrollEndTimeStamp = {
89
+ x: 0,
90
+ y: 0
91
+ };
86
92
  this.windowEpoch = 0;
87
93
  this.eventEpoch = 0;
88
94
  Object.values(_TargetData.TargetData.events).forEach(function (group) {
@@ -221,8 +227,9 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
221
227
  }, {
222
228
  key: "resetEventsOnTimeout",
223
229
  value: function resetEventsOnTimeout() {
224
- if (this.currentTouch.deltaY || this.currentTouch.deltaX || this.currentTouch.pinchDelta) {
225
- var diff = this.touchTimeStamp - _TUtil.TUtil.now();
230
+ if (this.scrollEndTimeStamp.x > 0 || this.scrollEndTimeStamp.y > 0 || this.currentTouch.pinchDelta) {
231
+ var now = _TUtil.TUtil.now();
232
+ var diff = Math.max(this.scrollEndTimeStamp.x - now, this.scrollEndTimeStamp.y - now);
226
233
  if (diff > 100) {
227
234
  this.currentTouch.deltaY *= 0.95;
228
235
  this.currentTouch.deltaX *= 0.95;
@@ -236,16 +243,19 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
236
243
  if (Math.abs(this.currentTouch.pinchDelta) < 0.1) {
237
244
  this.currentTouch.pinchDelta = 0;
238
245
  }
239
- if (this.currentTouch.deltaX === 0 && this.currentTouch.deltaY === 0 && this.currentTouch.pinchDelta === 0) {
240
- this.touchTimeStamp = 0;
241
- }
242
246
  }
243
- if (diff <= 0 || this.touchTimeStamp === 0) {
247
+ if (diff <= 0) {
244
248
  this.currentTouch.deltaY = 0;
245
249
  this.currentTouch.deltaX = 0;
246
250
  this.currentTouch.pinchDelta = 0;
247
- this.currentTouch.dir = '';
248
- this.touchTimeStamp = 0;
251
+ }
252
+ if (!this.currentTouch.deltaX && this.scrollEndTimeStamp.x && now >= this.scrollEndTimeStamp.x && this.touchCount === 0) {
253
+ this.scrollEndTimeStamp.x = 0;
254
+ this.queueScrollEndEvent('x', this.currentHandlers.scrollLeft);
255
+ }
256
+ if (!this.currentTouch.deltaY && this.scrollEndTimeStamp.y && now >= this.scrollEndTimeStamp.y && this.touchCount === 0) {
257
+ this.queueScrollEndEvent('y', this.currentHandlers.scrollTop);
258
+ this.scrollEndTimeStamp.y = 0;
249
259
  }
250
260
  (0, _App.getRunScheduler)().schedule(10, 'scroll decay');
251
261
  }
@@ -297,12 +307,13 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
297
307
  if (this.eventQueue.length === 0) {
298
308
  this.currentEventName = '';
299
309
  this.currentEventType = '';
310
+ this.currentEventTModel = undefined;
300
311
  this.currentOriginalEvent = undefined;
301
312
  this.currentKey = '';
302
313
  return;
303
314
  }
304
315
  var lastEvent = this.eventQueue.shift();
305
- if (this.canFindHandlers) {
316
+ if (this.canFindHandlers && !lastEvent.synthetic) {
306
317
  this.findEventHandlers(lastEvent);
307
318
  }
308
319
  if (lastEvent.eventType === 'end' || lastEvent.eventType === 'click') {
@@ -316,6 +327,7 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
316
327
  }
317
328
  this.currentEventName = lastEvent.eventName;
318
329
  this.currentEventType = lastEvent.eventType;
330
+ this.currentEventTModel = lastEvent.tmodel;
319
331
  this.currentOriginalEvent = lastEvent.originalEvent;
320
332
  this.currentTouch.key = '';
321
333
  }
@@ -332,7 +344,16 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
332
344
  }, {
333
345
  key: "handleEvent",
334
346
  value: function handleEvent(event, isDocEvent, isWindowEvent) {
335
- var _this$lastEvent, _tmodel, _tmodel2, _this$currentHandlers2, _this$currentHandlers3, _this$currentHandlers4, _this$currentHandlers5, _this$currentHandlers7, _this$currentHandlers8;
347
+ var _this$lastEvent,
348
+ _tmodel,
349
+ _tmodel2,
350
+ _this$currentHandlers2,
351
+ _this$currentHandlers3,
352
+ _this$currentHandlers4,
353
+ _this$currentHandlers5,
354
+ _this$currentHandlers7,
355
+ _this$currentHandlers8,
356
+ _this7 = this;
336
357
  if (!event) {
337
358
  return;
338
359
  }
@@ -435,7 +456,8 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
435
456
  }
436
457
  if (this.touchCount > 0) {
437
458
  var _this$currentHandlers6;
438
- this.touchTimeStamp = now + 10;
459
+ this.scrollEndTimeStamp.x = 0;
460
+ this.scrollEndTimeStamp.y = 0;
439
461
  this.move(event);
440
462
  event.stopPropagation();
441
463
  (_this$currentHandlers6 = this.currentHandlers.swipe) === null || _this$currentHandlers6 === void 0 || _this$currentHandlers6.markLayoutDirty('swipe-event');
@@ -485,7 +507,7 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
485
507
  event.preventDefault();
486
508
  event.stopPropagation();
487
509
  }
488
- this.touchTimeStamp = now + 500;
510
+ this.touchCount = 0;
489
511
  this.wheel(event);
490
512
  break;
491
513
  case 'mouseleave':
@@ -528,20 +550,85 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
528
550
  });
529
551
  break;
530
552
  case 'scroll':
553
+ clearTimeout(this.windowScrollEndTimer);
554
+ this.windowScrollEndTimer = setTimeout(function () {
555
+ _this7.queueWindowScrollEndEvent('x', tmodel);
556
+ _this7.queueWindowScrollEndEvent('y', tmodel);
557
+ _this7.windowScrollEndTimer = 0;
558
+ }, 120);
531
559
  if (isWindowEvent) {
532
560
  this.windowEpoch++;
533
561
  this.windowScrollX = window.scrollX | 0;
534
562
  this.windowScrollY = window.scrollY | 0;
535
563
  (0, _App.getLocationManager)().domIslandSet.forEach(function (t) {
536
- t.markLayoutDirty('winScroll-event');
564
+ t.markLayoutDirty('window-scroll-event');
537
565
  });
538
566
  } else {
539
- tmodel.markLayoutDirty('winScroll-event');
567
+ tmodel.markLayoutDirty('container-scroll-event');
568
+ clearTimeout(tmodel.scrollEndTimer);
569
+ tmodel.scrollEndTimer = setTimeout(function () {
570
+ _this7.queueWindowScrollEndEvent('x', tmodel, 'container');
571
+ _this7.queueWindowScrollEndEvent('y', tmodel, 'container');
572
+ tmodel.scrollEndTimer = 0;
573
+ }, 120);
540
574
  }
541
575
  break;
542
576
  }
543
577
  (0, _App.getRunScheduler)().schedule(0, "".concat(originalName, "-").concat(eventName, "-").concat((event.target.tagName || '').toUpperCase()));
544
578
  }
579
+ }, {
580
+ key: "queueScrollEndEvent",
581
+ value: function queueScrollEndEvent(axis, handler) {
582
+ if (!handler) {
583
+ return;
584
+ }
585
+ var eventType = axis === 'x' ? 'scrollleftend' : 'scrolltopend';
586
+ this.removeScrollEndEvents(axis);
587
+ this.eventQueue.push({
588
+ eventName: eventType,
589
+ eventType: eventType,
590
+ originalName: eventType,
591
+ tmodel: handler,
592
+ originalEvent: undefined,
593
+ timeStamp: _TUtil.TUtil.now(),
594
+ synthetic: true
595
+ });
596
+ this.eventEpoch++;
597
+ handler.markEventDirty();
598
+ handler.markLayoutDirty(eventType);
599
+ (0, _App.getRunScheduler)().schedule(0, eventType);
600
+ }
601
+ }, {
602
+ key: "queueWindowScrollEndEvent",
603
+ value: function queueWindowScrollEndEvent(axis, tmodel) {
604
+ var scrollSource = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'window';
605
+ var eventType = axis === 'x' ? 'windowscrollleftend' : 'windowscrolltopend';
606
+ this.removeScrollEndEvents(axis);
607
+ this.eventQueue.push({
608
+ eventName: eventType,
609
+ eventType: eventType,
610
+ originalName: eventType,
611
+ tmodel: tmodel,
612
+ originalEvent: undefined,
613
+ timeStamp: _TUtil.TUtil.now(),
614
+ synthetic: true,
615
+ scrollSource: scrollSource
616
+ });
617
+ this.eventEpoch++;
618
+ (0, _App.getLocationManager)().domIslandSet.forEach(function (t) {
619
+ t.markEventDirty();
620
+ t.markLayoutDirty(eventType);
621
+ });
622
+ (0, _App.getRunScheduler)().schedule(0, eventType);
623
+ }
624
+ }, {
625
+ key: "removeScrollEndEvents",
626
+ value: function removeScrollEndEvents(axis) {
627
+ var types = axis === 'x' ? new Set(['scrollleftend', 'windowscrollleftend']) : new Set(['scrolltopend', 'windowscrolltopend']);
628
+ this.eventQueue = this.eventQueue.filter(function (event) {
629
+ return !types.has(event.eventType);
630
+ });
631
+ }
545
632
  }, {
546
633
  key: "resizeRoot",
547
634
  value: function resizeRoot() {
@@ -607,7 +694,6 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
607
694
  this.clearEnd();
608
695
  this.clearTouch();
609
696
  this.eventQueue.length = 0;
610
- this.touchTimeStamp = 0;
611
697
  this.touchCount = 0;
612
698
  this.canFindHandlers = true;
613
699
  this.lastEvent = undefined;
@@ -616,6 +702,10 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
616
702
  this.swipeStartX = 0;
617
703
  this.swipeStartY = 0;
618
704
  this.hovered.clear();
705
+ clearTimeout(this.windowScrollEndTimer);
706
+ this.windowScrollEndTimer = 0;
707
+ this.scrollEndTimeStamp.x = 0;
708
+ this.scrollEndTimeStamp.y = 0;
619
709
  }
620
710
  }, {
621
711
  key: "deltaX",
@@ -760,6 +850,11 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
760
850
  value: function getEventType() {
761
851
  return this.currentEventType;
762
852
  }
853
+ }, {
854
+ key: "getEventTModel",
855
+ value: function getEventTModel() {
856
+ return this.currentEventTModel;
857
+ }
763
858
  }, {
764
859
  key: "isClickHandler",
765
860
  value: function isClickHandler(handler) {
@@ -834,6 +929,26 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
834
929
  value: function isScrollTopHandler(handler) {
835
930
  return this.currentHandlers.scrollTop === handler;
836
931
  }
932
+ }, {
933
+ key: "isScrollLeftEndHandler",
934
+ value: function isScrollLeftEndHandler(handler) {
935
+ return this.currentHandlers.scrollLeft === handler && this.currentEventType === 'scrollleftend';
936
+ }
937
+ }, {
938
+ key: "isScrollTopEndHandler",
939
+ value: function isScrollTopEndHandler(handler) {
940
+ return this.currentHandlers.scrollTop === handler && this.currentEventType === 'scrolltopend';
941
+ }
942
+ }, {
943
+ key: "isScrolling",
944
+ value: function isScrolling() {
945
+ return this.scrollEndTimeStamp.x > 0 || this.scrollEndTimeStamp.y > 0;
946
+ }
947
+ }, {
948
+ key: "isWindowScrolling",
949
+ value: function isWindowScrolling() {
950
+ return this.windowScrollEndTimer > 0;
951
+ }
837
952
  }, {
838
953
  key: "isPinchHandler",
839
954
  value: function isPinchHandler(handler) {
@@ -919,15 +1034,15 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
919
1034
  var momentum;
920
1035
  if (this.currentTouch.orientation === 'horizontal' && Math.abs(deltaX) > 0 && period > 0) {
921
1036
  momentum = _TUtil.TUtil.momentum(0, deltaX, period);
922
- this.touchTimeStamp = this.end0.timeStamp + momentum.duration;
923
- if (this.touchTimeStamp - _TUtil.TUtil.now() > 0) {
1037
+ this.scrollEndTimeStamp.x = this.end0.timeStamp + momentum.duration;
1038
+ if (this.scrollEndTimeStamp.x - _TUtil.TUtil.now() > 0) {
924
1039
  this.currentTouch.deltaX = momentum.distance;
925
1040
  this.currentTouch.manualMomentumFlag = true;
926
1041
  }
927
1042
  } else if (this.currentTouch.orientation === 'vertical' && Math.abs(deltaY) > 0 && period > 0) {
928
1043
  momentum = _TUtil.TUtil.momentum(0, deltaY, period);
929
- this.touchTimeStamp = this.end0.timeStamp + momentum.duration;
930
- if (this.touchTimeStamp - _TUtil.TUtil.now() > 0) {
1044
+ this.scrollEndTimeStamp.y = this.end0.timeStamp + momentum.duration;
1045
+ if (this.scrollEndTimeStamp.y - _TUtil.TUtil.now() > 0) {
931
1046
  this.currentTouch.deltaY = momentum.distance;
932
1047
  this.currentTouch.manualMomentumFlag = true;
933
1048
  }
@@ -945,10 +1060,16 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
945
1060
  } else if (this.currentTouch.orientation === 'none' || this.currentTouch.orientation === 'horizontal' && diff <= -2 || this.currentTouch.orientation === 'vertical') {
946
1061
  this.currentTouch.orientation = 'vertical';
947
1062
  }
1063
+ var now = _TUtil.TUtil.now();
1064
+ var endDelay = source === 'touch' ? 0 : 500;
948
1065
  if (this.currentTouch.orientation === 'horizontal') {
949
1066
  this.currentTouch.dir = deltaX < 0 ? 'left' : deltaX > 0 ? 'right' : this.currentTouch.dir;
1067
+ this.scrollEndTimeStamp.x = now + endDelay;
1068
+ this.removeScrollEndEvents('x');
950
1069
  } else {
951
1070
  this.currentTouch.dir = deltaY < 0 ? 'up' : deltaY > 0 ? 'down' : this.currentTouch.dir;
1071
+ this.scrollEndTimeStamp.y = now + endDelay;
1072
+ this.removeScrollEndEvents('y');
952
1073
  }
953
1074
  this.currentTouch.source = source;
954
1075
 
@@ -957,6 +1078,9 @@ var EventListener = exports.EventListener = /*#__PURE__*/function () {
957
1078
  this.currentTouch.prevDeltaY += deltaY;
958
1079
  this.currentTouch.deltaX = this.currentTouch.prevDeltaX;
959
1080
  this.currentTouch.deltaY = this.currentTouch.prevDeltaY;
1081
+ if (this.scrollEndTimeStamp.x > 0 || this.scrollEndTimeStamp.y > 0) {
1082
+ (0, _App.getRunScheduler)().schedule(endDelay, 'scroll-end-check');
1083
+ }
960
1084
  }
961
1085
  }, {
962
1086
  key: "wheel",
@@ -51,6 +51,7 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
51
51
  this.resumePausedList = [];
52
52
  this.resumePausedMap = {};
53
53
  this.resumeScheduled = false;
54
+ this.calcEpoch = 0;
54
55
  }
55
56
  return _createClass(LocationManager, [{
56
57
  key: "clear",
@@ -91,6 +92,7 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
91
92
  value: function () {
92
93
  var _calculateAll = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
93
94
  var budgetMs,
95
+ calcEpoch,
94
96
  stack,
95
97
  ctx,
96
98
  _args = arguments;
@@ -98,42 +100,49 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
98
100
  while (1) switch (_context.prev = _context.next) {
99
101
  case 0:
100
102
  budgetMs = _args.length > 0 && _args[0] !== undefined ? _args[0] : 8;
103
+ calcEpoch = this.calcEpoch;
101
104
  if (!this.calcBusy) {
102
- _context.next = 4;
105
+ _context.next = 5;
103
106
  break;
104
107
  }
105
108
  this.calcQueued = true;
106
109
  return _context.abrupt("return");
107
- case 4:
110
+ case 5:
108
111
  this.calcBusy = true;
109
112
  this.hasLocationList.length = 0;
110
113
  this.hasLocationMap = {};
111
114
  this.locationListStats = [];
112
- stack = [];
113
- stack.push({
115
+ stack = [{
114
116
  container: (0, _App.tRoot)(),
115
117
  stage: 'init',
116
118
  children: [],
117
119
  viewport: undefined,
118
120
  index: 0
119
- });
121
+ }];
120
122
  ctx = {
121
123
  budgetMs: budgetMs,
122
- sliceStart: _TUtil.TUtil.now()
124
+ sliceStart: _TUtil.TUtil.now(),
125
+ calcEpoch: calcEpoch
123
126
  };
124
127
  _context.next = 13;
125
128
  return this.processStack(stack, ctx);
126
129
  case 13:
130
+ if (!(ctx.calcEpoch !== this.calcEpoch)) {
131
+ _context.next = 15;
132
+ break;
133
+ }
134
+ return _context.abrupt("return");
135
+ case 15:
127
136
  this.processAfterStack();
128
137
  this.scheduleResumePaused();
129
138
  this.calcBusy = false;
130
139
  if (!this.calcQueued) {
131
- _context.next = 19;
140
+ _context.next = 21;
132
141
  break;
133
142
  }
134
143
  this.calcQueued = false;
135
144
  return _context.abrupt("return", this.calculateAll(budgetMs));
136
- case 19:
145
+ case 21:
137
146
  case "end":
138
147
  return _context.stop();
139
148
  }
@@ -144,6 +153,13 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
144
153
  }
145
154
  return calculateAll;
146
155
  }()
156
+ }, {
157
+ key: "cancelCurrentCalculation",
158
+ value: function cancelCurrentCalculation() {
159
+ this.calcEpoch++;
160
+ this.calcBusy = false;
161
+ this.calcQueued = false;
162
+ }
147
163
  }, {
148
164
  key: "processStack",
149
165
  value: function () {
@@ -294,19 +310,31 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
294
310
  };
295
311
  case 4:
296
312
  if (!stack.length) {
297
- _context2.next = 21;
313
+ _context2.next = 25;
314
+ break;
315
+ }
316
+ if (!(ctx.calcEpoch !== this.calcEpoch)) {
317
+ _context2.next = 7;
298
318
  break;
299
319
  }
320
+ return _context2.abrupt("return");
321
+ case 7:
300
322
  if (!(_TUtil.TUtil.now() - ctx.sliceStart > ctx.budgetMs)) {
301
- _context2.next = 10;
323
+ _context2.next = 14;
302
324
  break;
303
325
  }
304
- _context2.next = 8;
326
+ _context2.next = 10;
305
327
  return new Promise(requestAnimationFrame);
306
- case 8:
328
+ case 10:
329
+ if (!(ctx.calcEpoch !== this.calcEpoch)) {
330
+ _context2.next = 12;
331
+ break;
332
+ }
333
+ return _context2.abrupt("return");
334
+ case 12:
307
335
  ctx.sliceStart = _TUtil.TUtil.now();
308
336
  return _context2.abrupt("continue", 4);
309
- case 10:
337
+ case 14:
310
338
  job = stack[stack.length - 1];
311
339
  if (job.stage === 'init') {
312
340
  container = job.container;
@@ -333,19 +361,19 @@ var LocationManager = exports.LocationManager = /*#__PURE__*/function () {
333
361
  processAfterChild(job);
334
362
  }
335
363
  if (!(job.index >= job.children.length)) {
336
- _context2.next = 18;
364
+ _context2.next = 22;
337
365
  break;
338
366
  }
339
367
  processAfterAllChildren(job);
340
368
  stack.pop();
341
369
  return _context2.abrupt("continue", 4);
342
- case 18:
370
+ case 22:
343
371
  if (job.stage === 'child') {
344
372
  processChild(job);
345
373
  }
346
374
  _context2.next = 4;
347
375
  break;
348
- case 21:
376
+ case 25:
349
377
  case "end":
350
378
  return _context2.stop();
351
379
  }