handsontable 18.1.0-rc7 → 18.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/3rdparty/walkontable/src/event.d.ts +17 -0
- package/3rdparty/walkontable/src/event.js +188 -21
- package/3rdparty/walkontable/src/event.mjs +188 -21
- package/CHANGELOG.md +12 -30
- package/base.js +2 -2
- package/base.mjs +2 -2
- package/dist/handsontable.full.js +2263 -2011
- package/dist/handsontable.full.min.js +117 -117
- package/dist/handsontable.js +2262 -2011
- package/dist/handsontable.min.js +117 -117
- package/dist/themes/classic.js +2 -2
- package/dist/themes/classic.min.js +2 -2
- package/dist/themes/horizon.js +2 -2
- package/dist/themes/horizon.min.js +2 -2
- package/dist/themes/main.js +2 -2
- package/dist/themes/main.min.js +2 -2
- package/dist/themes/static/variables/colors/ant.js +2 -2
- package/dist/themes/static/variables/colors/ant.min.js +2 -2
- package/dist/themes/static/variables/colors/classic.js +2 -2
- package/dist/themes/static/variables/colors/classic.min.js +2 -2
- package/dist/themes/static/variables/colors/horizon.js +2 -2
- package/dist/themes/static/variables/colors/horizon.min.js +2 -2
- package/dist/themes/static/variables/colors/main.js +2 -2
- package/dist/themes/static/variables/colors/main.min.js +2 -2
- package/dist/themes/static/variables/colors/material.js +2 -2
- package/dist/themes/static/variables/colors/material.min.js +2 -2
- package/dist/themes/static/variables/colors/shadcn.js +2 -2
- package/dist/themes/static/variables/colors/shadcn.min.js +2 -2
- package/dist/themes/static/variables/density.js +2 -2
- package/dist/themes/static/variables/density.min.js +2 -2
- package/dist/themes/static/variables/helpers/iconsMap.js +2 -2
- package/dist/themes/static/variables/helpers/iconsMap.min.js +2 -2
- package/dist/themes/static/variables/icons/horizon.js +2 -2
- package/dist/themes/static/variables/icons/horizon.min.js +2 -2
- package/dist/themes/static/variables/icons/main.js +2 -2
- package/dist/themes/static/variables/icons/main.min.js +2 -2
- package/dist/themes/static/variables/sizing.js +2 -2
- package/dist/themes/static/variables/sizing.min.js +2 -2
- package/dist/themes/static/variables/tokens/classic.js +2 -2
- package/dist/themes/static/variables/tokens/classic.min.js +2 -2
- package/dist/themes/static/variables/tokens/horizon.js +2 -2
- package/dist/themes/static/variables/tokens/horizon.min.js +2 -2
- package/dist/themes/static/variables/tokens/main.js +2 -2
- package/dist/themes/static/variables/tokens/main.min.js +2 -2
- package/helpers/dom/inputOrigin.d.mts +1 -0
- package/helpers/dom/inputOrigin.d.ts +38 -0
- package/helpers/dom/inputOrigin.js +54 -0
- package/helpers/dom/inputOrigin.mjs +48 -0
- package/helpers/mixed.js +20 -5
- package/helpers/mixed.mjs +20 -5
- package/package.json +1 -1
- package/styles/handsontable.css +2 -2
- package/styles/handsontable.min.css +2 -2
- package/styles/handsontableStyles.js +1 -1
- package/styles/handsontableStyles.mjs +1 -1
- package/styles/ht-icons-horizon.min.css +2 -2
- package/styles/ht-icons-main.min.css +2 -2
- package/styles/ht-theme-classic-no-icons.min.css +2 -2
- package/styles/ht-theme-classic.min.css +2 -2
- package/styles/ht-theme-horizon-no-icons.min.css +2 -2
- package/styles/ht-theme-horizon.min.css +2 -2
- package/styles/ht-theme-main-no-icons.min.css +2 -2
- package/styles/ht-theme-main.min.css +2 -2
- package/tableView.js +16 -12
- package/tableView.mjs +16 -12
- package/utils/entitlementLicenseKey/constants.d.ts +9 -3
- package/utils/entitlementLicenseKey/constants.mjs +9 -3
- package/utils/entitlementLicenseKey/types.d.ts +9 -3
- package/utils/licenseBranding/index.js +22 -7
- package/utils/licenseBranding/index.mjs +22 -7
- package/utils/licenseNotification.js +2 -2
- package/utils/licenseNotification.mjs +2 -2
- package/styles/handsontableStyles.d.mts +0 -2
- package/styles/handsontableStyles.d.ts +0 -2
|
@@ -138,6 +138,23 @@ declare class Event {
|
|
|
138
138
|
* @param {TouchEvent} event The touch event object.
|
|
139
139
|
*/
|
|
140
140
|
onTouchEnd(event: TouchEvent): void;
|
|
141
|
+
/**
|
|
142
|
+
* OnTouchCancel callback. Browsers cancel a gesture instead of ending it whenever the system
|
|
143
|
+
* claims the touch (an edge-swipe, a dialog, a context callout) — `touchend` then never fires.
|
|
144
|
+
* Without this reset `touchApplied` stays `true` and every REAL mouse `mouseup` is routed into
|
|
145
|
+
* the touch tap detector, which has no button filter, so two right-clicks or two drag-selections
|
|
146
|
+
* ending on the same cell within the double-tap window would fire a phantom double-click.
|
|
147
|
+
* It also releases the mouse-down flag: a long-press fires `onMouseDown` from its timer, and
|
|
148
|
+
* after a cancel no `mouseup` ever follows, which would leave mouse-move selection dragging
|
|
149
|
+
* armed until the next click. The pending synthesized-pair flag is cleared for the same reason
|
|
150
|
+
* the scroll branch of `onTouchEnd` clears it: a cancelled gesture armed nothing, so a
|
|
151
|
+
* still-pending flag belongs to an earlier gesture whose pair never came, and left in place it
|
|
152
|
+
* would drop the next real mouse pair inside the ceiling on engines that do not report the
|
|
153
|
+
* input origin.
|
|
154
|
+
*
|
|
155
|
+
* @private
|
|
156
|
+
*/
|
|
157
|
+
onTouchCancel(): void;
|
|
141
158
|
/**
|
|
142
159
|
* Holder `scroll` callback. Cancels the long-press timer and runs the momentum-scroll
|
|
143
160
|
* bookkeeping. When called during an active touch sequence it also marks the gesture
|
|
@@ -20,6 +20,7 @@ const _element = require("../../../helpers/dom/element");
|
|
|
20
20
|
const _pointerToCoords = require("./utils/pointerToCoords");
|
|
21
21
|
const _feature = require("../../../helpers/feature");
|
|
22
22
|
const _browser = require("../../../helpers/browser");
|
|
23
|
+
const _inputOrigin = require("../../../helpers/dom/inputOrigin");
|
|
23
24
|
function _check_private_redeclaration(obj, privateCollection) {
|
|
24
25
|
if (privateCollection.has(obj)) {
|
|
25
26
|
throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
@@ -72,6 +73,20 @@ function _class_private_method_init(obj, privateSet) {
|
|
|
72
73
|
}
|
|
73
74
|
const LONG_PRESS_DELAY = 500;
|
|
74
75
|
const LONG_PRESS_MOVE_THRESHOLD = 10;
|
|
76
|
+
/**
|
|
77
|
+
* How long (ms) after a mousedown the double-click detector keeps waiting for the matching
|
|
78
|
+
* second click. Mirrors the OS double-click tolerance with margin.
|
|
79
|
+
*/ const DBLCLICK_MOUSEDOWN_TIMEOUT = 1000;
|
|
80
|
+
/**
|
|
81
|
+
* How long (ms) after a mouseup the double-click detector keeps the first click "armed"
|
|
82
|
+
* for a mouse-driven double-click.
|
|
83
|
+
*/ const DBLCLICK_MOUSEUP_TIMEOUT = 500;
|
|
84
|
+
/**
|
|
85
|
+
* How long (ms) after a touch tap a second tap on the same cell counts as a double-tap. Touch
|
|
86
|
+
* taps are paired by `#handleTouchTap()`, independently of the mouse double-click slots, so a
|
|
87
|
+
* real mouse click after a tap never pairs with it. iOS drops taps under ~250 ms and humans
|
|
88
|
+
* double-tap at 300–600 ms (DEV-2687).
|
|
89
|
+
*/ const TOUCH_DBLTAP_TIMEOUT = 1000;
|
|
75
90
|
function createEventDeps(ctx) {
|
|
76
91
|
return {
|
|
77
92
|
facadeGetter: ctx.getFacade(),
|
|
@@ -99,6 +114,17 @@ var /**
|
|
|
99
114
|
*/ _dblClickTimeout = /*#__PURE__*/ new WeakMap(), /**
|
|
100
115
|
* @type {number[]}
|
|
101
116
|
*/ _dblClickOrigin = /*#__PURE__*/ new WeakMap(), /**
|
|
117
|
+
* Coordinates of the most recent touch tap, kept for double-tap detection. Coordinates, not the
|
|
118
|
+
* resolved TD: Walkontable recycles TD elements across scrolls and re-renders, so element
|
|
119
|
+
* identity can pair two taps that landed on different cells (DEV-2687 review). Touch taps never
|
|
120
|
+
* arm the mouse double-click slots, so a mouse click after a tap cannot pair with a tap.
|
|
121
|
+
*
|
|
122
|
+
* @type {CellCoords|null}
|
|
123
|
+
*/ _lastTapCoords = /*#__PURE__*/ new WeakMap(), /**
|
|
124
|
+
* Timestamp (ms) of the most recent touch tap.
|
|
125
|
+
*
|
|
126
|
+
* @type {number}
|
|
127
|
+
*/ _lastTapAt = /*#__PURE__*/ new WeakMap(), /**
|
|
102
128
|
* Timer ID for the long-press gesture detection.
|
|
103
129
|
*
|
|
104
130
|
* @type {number|null}
|
|
@@ -123,12 +149,25 @@ var /**
|
|
|
123
149
|
* @type {TouchEvent|null}
|
|
124
150
|
*/ _deferredTouchStartEvent = /*#__PURE__*/ new WeakMap(), /**
|
|
125
151
|
* Timestamp (ms) of the most recent `onMouseUp` call that originated from a touch gesture.
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
152
|
+
* On devices that register both touch and mouse listeners (iPad with a desktop UA, Windows
|
|
153
|
+
* touchscreens) the browser synthesizes a `mousedown`/`mouseup`/`click` sequence after
|
|
154
|
+
* `touchend`. The whole sequence must be ignored – dropping only one half fires
|
|
155
|
+
* `onCellMouseDown` a second time per tap, and the leaked pair would act as a phantom mouse
|
|
156
|
+
* click (DEV-2687).
|
|
157
|
+
* Used as the fallback for engines that do not expose `sourceCapabilities`
|
|
158
|
+
* (see `#isTouchSynthesizedMouseEvent`).
|
|
129
159
|
*
|
|
130
160
|
* @type {number}
|
|
131
161
|
*/ _lastTouchMouseUpAt = /*#__PURE__*/ new WeakMap(), /**
|
|
162
|
+
* `true` between a touch-driven `onMouseUp` and the browser-synthesized `mouseup` that follows it.
|
|
163
|
+
* Only that first pair is dropped; once it is consumed, real mouse events pass even inside the
|
|
164
|
+
* `TOUCH_SYNTHESIZED_MOUSE_WINDOW` ceiling, so a fill-handle drag or a drag-selection started with
|
|
165
|
+
* a mouse right after a tap works on engines that do not report the input origin (DEV-2687). The
|
|
166
|
+
* flag is re-armed by every touch-driven `onMouseUp` and cleared when a scroll-classified gesture
|
|
167
|
+
* ends, so a tap that synthesized nothing cannot swallow that gesture's own compatibility pair.
|
|
168
|
+
*
|
|
169
|
+
* @type {boolean}
|
|
170
|
+
*/ _synthesizedPairPending = /*#__PURE__*/ new WeakMap(), /**
|
|
132
171
|
* @type {boolean}
|
|
133
172
|
*/ _mouseDown = /*#__PURE__*/ new WeakMap(), /**
|
|
134
173
|
* The last renderable coords seen in `onMouseMove` while the mouse was outside the viewport.
|
|
@@ -137,6 +176,18 @@ var /**
|
|
|
137
176
|
*
|
|
138
177
|
* @type {{ row: number, col: number } | null}
|
|
139
178
|
*/ _mouseOverOutsideLastCoords = /*#__PURE__*/ new WeakMap(), /**
|
|
179
|
+
* Decides whether a mouse event caught by the mouse listeners is one half of the browser-synthesized
|
|
180
|
+
* `mousedown`/`mouseup` pair that follows a touch tap, and must therefore be dropped. Order of the
|
|
181
|
+
* checks: an engine that reports the input origin and says "not touch" wins (Blink, a real mouse or
|
|
182
|
+
* pen is never dropped); otherwise the event is synthesized only if a touch-driven `onMouseUp` just
|
|
183
|
+
* armed the pair (`#synthesizedPairPending`) and the ceiling has not passed. The `mouseup` half
|
|
184
|
+
* consumes the pair, so any later mouse event inside the ceiling is treated as real. Dropping both
|
|
185
|
+
* halves keeps `onCellMouseDown` at one call per tap and context-menu commands at one execution
|
|
186
|
+
* (#12803); a tap that left no stamp (a gesture treated as a scroll) has its pair processed.
|
|
187
|
+
*
|
|
188
|
+
* @param {MouseEvent} event The mouse event object.
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/ _isTouchSynthesizedMouseEvent = /*#__PURE__*/ new WeakSet(), /**
|
|
140
191
|
* Returns the cell coordinates for the given mouse position and whether the mouse is
|
|
141
192
|
* outside the visible viewport. When the mouse is outside, the nearest edge cell is returned.
|
|
142
193
|
*
|
|
@@ -145,6 +196,19 @@ var /**
|
|
|
145
196
|
* @param {number} mouseY Client Y coordinate of the mouse.
|
|
146
197
|
* @returns {{ coords: CellCoords, isOutside: boolean }}
|
|
147
198
|
*/ _getCellCoordsFromMousePosition = /*#__PURE__*/ new WeakSet(), /**
|
|
199
|
+
* Pairs touch taps into double-taps. Called from `onMouseUp` while `touchApplied` is `true`,
|
|
200
|
+
* i.e. for the `onMouseUp` that `onTouchEnd` drives. Two taps on the same coordinates within
|
|
201
|
+
* `TOUCH_DBLTAP_TIMEOUT` fire the double-click callbacks; a long-press, a tap outside the cells,
|
|
202
|
+
* or a tap on different coordinates resets the detector.
|
|
203
|
+
*
|
|
204
|
+
* @param {MouseEvent|TouchEvent} event The event that ended the tap.
|
|
205
|
+
* @param {ParentCell} cell The tapped cell, as returned by `parentCell()`.
|
|
206
|
+
*/ _handleTouchTap = /*#__PURE__*/ new WeakSet(), /**
|
|
207
|
+
* Fires the corner or the cell double-click callback for the given cell.
|
|
208
|
+
*
|
|
209
|
+
* @param {MouseEvent|TouchEvent} event The event that completed the double-click.
|
|
210
|
+
* @param {ParentCell} cell The double-clicked cell.
|
|
211
|
+
*/ _fireDblClick = /*#__PURE__*/ new WeakSet(), /**
|
|
148
212
|
* Starts the long-press timer. When the timer fires, a synthetic `contextmenu` event is
|
|
149
213
|
* dispatched on the original touch target so that the existing contextmenu hook chain
|
|
150
214
|
* (and ContextMenu plugin) work without changes.
|
|
@@ -178,20 +242,27 @@ var /**
|
|
|
178
242
|
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'touchstart', (event)=>this.onTouchStart(event));
|
|
179
243
|
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'touchend', (event)=>this.onTouchEnd(event));
|
|
180
244
|
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'touchmove', (event)=>this.onTouchMove(event));
|
|
245
|
+
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'touchcancel', ()=>this.onTouchCancel());
|
|
181
246
|
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'scroll', ()=>this.onHolderScroll());
|
|
182
247
|
};
|
|
183
248
|
const initMouseEvents = ()=>{
|
|
249
|
+
// On devices that register both touch and mouse listeners (e.g. iPad Safari with a
|
|
250
|
+
// desktop UA), `touchend` already drove `onMouseDown`/`onMouseUp`. The browser then
|
|
251
|
+
// synthesizes a `mousedown`/`mouseup` pair ~0-50 ms later; drop BOTH halves when the
|
|
252
|
+
// touch path handled the tap, so `onCellMouseDown` fires once per tap (DEV-2687) and
|
|
253
|
+
// context-menu commands do not execute twice (#12803).
|
|
184
254
|
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'mouseup', (event)=>{
|
|
185
|
-
|
|
186
|
-
// `touchend` fires first and calls `onMouseUp` directly. The browser then
|
|
187
|
-
// synthesizes a `mouseup` event ~0-50 ms later; suppress it to prevent
|
|
188
|
-
// context-menu commands from executing twice.
|
|
189
|
-
if (Date.now() - _class_private_field_get(this, _lastTouchMouseUpAt) < 500) {
|
|
255
|
+
if (_class_private_method_get(this, _isTouchSynthesizedMouseEvent, isTouchSynthesizedMouseEvent).call(this, event)) {
|
|
190
256
|
return;
|
|
191
257
|
}
|
|
192
258
|
this.onMouseUp(event);
|
|
193
259
|
});
|
|
194
|
-
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'mousedown', (event)=>
|
|
260
|
+
_class_private_field_get(this, _deps).eventManager.addEventListener(_class_private_field_get(this, _deps).wtTable.holder, 'mousedown', (event)=>{
|
|
261
|
+
if (_class_private_method_get(this, _isTouchSynthesizedMouseEvent, isTouchSynthesizedMouseEvent).call(this, event)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.onMouseDown(event);
|
|
265
|
+
});
|
|
195
266
|
};
|
|
196
267
|
if ((0, _browser.isMobileBrowser)()) {
|
|
197
268
|
initTouchEvents();
|
|
@@ -288,15 +359,16 @@ var /**
|
|
|
288
359
|
this.callListener('onCellMouseDown', event, cell.coords, cell.TD);
|
|
289
360
|
}
|
|
290
361
|
}
|
|
291
|
-
//
|
|
292
|
-
|
|
362
|
+
// The mouse double-click slots are armed by mouse clicks only; touch taps are paired by
|
|
363
|
+
// #handleTouchTap() in onMouseUp (DEV-2687).
|
|
364
|
+
if (!this.touchApplied && event.button === 0 && cell.TD) {
|
|
293
365
|
_class_private_field_get(this, _dblClickOrigin)[0] = cell.TD;
|
|
294
366
|
if (_class_private_field_get(this, _dblClickTimeout)[0] !== null) {
|
|
295
367
|
clearTimeout(_class_private_field_get(this, _dblClickTimeout)[0]);
|
|
296
368
|
}
|
|
297
369
|
_class_private_field_get(this, _dblClickTimeout)[0] = setTimeout(()=>{
|
|
298
370
|
_class_private_field_get(this, _dblClickOrigin)[0] = null;
|
|
299
|
-
},
|
|
371
|
+
}, DBLCLICK_MOUSEDOWN_TIMEOUT);
|
|
300
372
|
}
|
|
301
373
|
}
|
|
302
374
|
/**
|
|
@@ -405,16 +477,16 @@ var /**
|
|
|
405
477
|
if (cell.TD && _class_private_field_get(this, _deps).wtSettings.has('onCellMouseUp')) {
|
|
406
478
|
this.callListener('onCellMouseUp', event, cell.coords, cell.TD);
|
|
407
479
|
}
|
|
408
|
-
|
|
409
|
-
|
|
480
|
+
if (this.touchApplied) {
|
|
481
|
+
_class_private_method_get(this, _handleTouchTap, handleTouchTap).call(this, event, cell);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
// ignore non-left mouse buttons
|
|
485
|
+
if (event.button !== 0) {
|
|
410
486
|
return;
|
|
411
487
|
}
|
|
412
488
|
if (cell.TD && cell.TD === _class_private_field_get(this, _dblClickOrigin)[0] && cell.TD === _class_private_field_get(this, _dblClickOrigin)[1]) {
|
|
413
|
-
|
|
414
|
-
this.callListener('onCellCornerDblClick', event, cell.coords, cell.TD);
|
|
415
|
-
} else {
|
|
416
|
-
this.callListener('onCellDblClick', event, cell.coords, cell.TD);
|
|
417
|
-
}
|
|
489
|
+
_class_private_method_get(this, _fireDblClick, fireDblClick).call(this, event, cell);
|
|
418
490
|
_class_private_field_get(this, _dblClickOrigin)[0] = null;
|
|
419
491
|
_class_private_field_get(this, _dblClickOrigin)[1] = null;
|
|
420
492
|
} else if (cell.TD && cell.TD === _class_private_field_get(this, _dblClickOrigin)[0]) {
|
|
@@ -424,7 +496,7 @@ var /**
|
|
|
424
496
|
}
|
|
425
497
|
_class_private_field_get(this, _dblClickTimeout)[1] = setTimeout(()=>{
|
|
426
498
|
_class_private_field_get(this, _dblClickOrigin)[1] = null;
|
|
427
|
-
},
|
|
499
|
+
}, DBLCLICK_MOUSEUP_TIMEOUT);
|
|
428
500
|
}
|
|
429
501
|
}
|
|
430
502
|
/**
|
|
@@ -494,14 +566,51 @@ var /**
|
|
|
494
566
|
// before/after hooks (e.g. nestedHeaders, ContextMenu close logic).
|
|
495
567
|
// Suppress only for pure scroll gestures, where onMouseDown was never fired.
|
|
496
568
|
if (!wasScrolled || _class_private_field_get(this, _longPressFired)) {
|
|
497
|
-
|
|
569
|
+
// The stamp is taken AFTER the tap is handled, so the selection/render work onMouseUp does
|
|
570
|
+
// is not charged against the TOUCH_SYNTHESIZED_MOUSE_WINDOW ceiling. Everything onMouseUp
|
|
571
|
+
// triggers is synchronous; the browser only dispatches the synthesized mousedown/mouseup
|
|
572
|
+
// sequence after this touchend handler returns.
|
|
498
573
|
this.onMouseUp(event);
|
|
574
|
+
_class_private_field_set(this, _lastTouchMouseUpAt, Date.now());
|
|
575
|
+
_class_private_field_set(this, _synthesizedPairPending, true);
|
|
576
|
+
} else {
|
|
577
|
+
// A pure scroll gesture calls neither onMouseDown nor onMouseUp, so #handleTouchTap never
|
|
578
|
+
// runs to reset the tap detector. Reset it here so a scroll between two taps can't pair them.
|
|
579
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
580
|
+
// This gesture armed nothing, so a still-pending flag belongs to an earlier gesture whose
|
|
581
|
+
// pair never came; clear it so THIS gesture's compatibility pair is processed.
|
|
582
|
+
_class_private_field_set(this, _synthesizedPairPending, false);
|
|
499
583
|
}
|
|
500
584
|
this.touchApplied = false;
|
|
501
585
|
_class_private_field_set(this, _touchWasMoved, false);
|
|
502
586
|
_class_private_field_set(this, _longPressFired, false);
|
|
503
587
|
}
|
|
504
588
|
/**
|
|
589
|
+
* OnTouchCancel callback. Browsers cancel a gesture instead of ending it whenever the system
|
|
590
|
+
* claims the touch (an edge-swipe, a dialog, a context callout) — `touchend` then never fires.
|
|
591
|
+
* Without this reset `touchApplied` stays `true` and every REAL mouse `mouseup` is routed into
|
|
592
|
+
* the touch tap detector, which has no button filter, so two right-clicks or two drag-selections
|
|
593
|
+
* ending on the same cell within the double-tap window would fire a phantom double-click.
|
|
594
|
+
* It also releases the mouse-down flag: a long-press fires `onMouseDown` from its timer, and
|
|
595
|
+
* after a cancel no `mouseup` ever follows, which would leave mouse-move selection dragging
|
|
596
|
+
* armed until the next click. The pending synthesized-pair flag is cleared for the same reason
|
|
597
|
+
* the scroll branch of `onTouchEnd` clears it: a cancelled gesture armed nothing, so a
|
|
598
|
+
* still-pending flag belongs to an earlier gesture whose pair never came, and left in place it
|
|
599
|
+
* would drop the next real mouse pair inside the ceiling on engines that do not report the
|
|
600
|
+
* input origin.
|
|
601
|
+
*
|
|
602
|
+
* @private
|
|
603
|
+
*/ onTouchCancel() {
|
|
604
|
+
_class_private_method_get(this, _cancelLongPressTimer, cancelLongPressTimer).call(this);
|
|
605
|
+
this.touchApplied = false;
|
|
606
|
+
_class_private_field_set(this, _mouseDown, false);
|
|
607
|
+
_class_private_field_set(this, _touchWasMoved, false);
|
|
608
|
+
_class_private_field_set(this, _longPressFired, false);
|
|
609
|
+
_class_private_field_set(this, _deferredTouchStartEvent, null);
|
|
610
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
611
|
+
_class_private_field_set(this, _synthesizedPairPending, false);
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
505
614
|
* Holder `scroll` callback. Cancels the long-press timer and runs the momentum-scroll
|
|
506
615
|
* bookkeeping. When called during an active touch sequence it also marks the gesture
|
|
507
616
|
* as a scroll so the deferred mousedown is not fired on `touchend` - native scrolling
|
|
@@ -585,7 +694,10 @@ var /**
|
|
|
585
694
|
* @param {EventDeps} deps The Event module dependencies.
|
|
586
695
|
* @param {Event} [parent=null] The main Event instance.
|
|
587
696
|
*/ constructor(deps, parent = null){
|
|
697
|
+
_class_private_method_init(this, _isTouchSynthesizedMouseEvent);
|
|
588
698
|
_class_private_method_init(this, _getCellCoordsFromMousePosition);
|
|
699
|
+
_class_private_method_init(this, _handleTouchTap);
|
|
700
|
+
_class_private_method_init(this, _fireDblClick);
|
|
589
701
|
_class_private_method_init(this, _startLongPressTimer);
|
|
590
702
|
_class_private_method_init(this, _cancelLongPressTimer);
|
|
591
703
|
_class_private_field_init(this, _deps, {
|
|
@@ -608,6 +720,14 @@ var /**
|
|
|
608
720
|
writable: true,
|
|
609
721
|
value: void 0
|
|
610
722
|
});
|
|
723
|
+
_class_private_field_init(this, _lastTapCoords, {
|
|
724
|
+
writable: true,
|
|
725
|
+
value: void 0
|
|
726
|
+
});
|
|
727
|
+
_class_private_field_init(this, _lastTapAt, {
|
|
728
|
+
writable: true,
|
|
729
|
+
value: void 0
|
|
730
|
+
});
|
|
611
731
|
_class_private_field_init(this, _longPressTimeout, {
|
|
612
732
|
writable: true,
|
|
613
733
|
value: void 0
|
|
@@ -632,6 +752,10 @@ var /**
|
|
|
632
752
|
writable: true,
|
|
633
753
|
value: void 0
|
|
634
754
|
});
|
|
755
|
+
_class_private_field_init(this, _synthesizedPairPending, {
|
|
756
|
+
writable: true,
|
|
757
|
+
value: void 0
|
|
758
|
+
});
|
|
635
759
|
_class_private_field_init(this, _mouseDown, {
|
|
636
760
|
writable: true,
|
|
637
761
|
value: void 0
|
|
@@ -649,12 +773,15 @@ var /**
|
|
|
649
773
|
null,
|
|
650
774
|
null
|
|
651
775
|
]);
|
|
776
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
777
|
+
_class_private_field_set(this, _lastTapAt, 0);
|
|
652
778
|
_class_private_field_set(this, _longPressTimeout, null);
|
|
653
779
|
_class_private_field_set(this, _longPressFired, false);
|
|
654
780
|
_class_private_field_set(this, _touchStartCoords, null);
|
|
655
781
|
_class_private_field_set(this, _touchWasMoved, false);
|
|
656
782
|
_class_private_field_set(this, _deferredTouchStartEvent, null);
|
|
657
783
|
_class_private_field_set(this, _lastTouchMouseUpAt, 0);
|
|
784
|
+
_class_private_field_set(this, _synthesizedPairPending, false);
|
|
658
785
|
_class_private_field_set(this, _mouseDown, false);
|
|
659
786
|
_class_private_field_set(this, _mouseOverOutsideLastCoords, null);
|
|
660
787
|
_class_private_field_set(this, _deps, deps);
|
|
@@ -662,9 +789,48 @@ var /**
|
|
|
662
789
|
this.registerEvents();
|
|
663
790
|
}
|
|
664
791
|
}
|
|
792
|
+
function isTouchSynthesizedMouseEvent(event) {
|
|
793
|
+
if ((0, _inputOrigin.getMouseEventTouchOrigin)(event) === false) {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
const withinCeiling = Date.now() - _class_private_field_get(this, _lastTouchMouseUpAt) < _inputOrigin.TOUCH_SYNTHESIZED_MOUSE_WINDOW;
|
|
797
|
+
if (!_class_private_field_get(this, _synthesizedPairPending) || !withinCeiling) {
|
|
798
|
+
_class_private_field_set(this, _synthesizedPairPending, false);
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
if (event.type === 'mouseup') {
|
|
802
|
+
_class_private_field_set(this, _synthesizedPairPending, false);
|
|
803
|
+
}
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
665
806
|
function getCellCoordsFromMousePosition(mouseX, mouseY) {
|
|
666
807
|
return (0, _pointerToCoords.getCellCoordsFromMousePosition)(_class_private_field_get(this, _deps), mouseX, mouseY);
|
|
667
808
|
}
|
|
809
|
+
function handleTouchTap(event, cell) {
|
|
810
|
+
if (_class_private_field_get(this, _longPressFired) || !cell.TD || !cell.coords) {
|
|
811
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const now = Date.now();
|
|
815
|
+
const isSameCell = _class_private_field_get(this, _lastTapCoords) !== null && _class_private_field_get(this, _lastTapCoords).row === cell.coords.row && _class_private_field_get(this, _lastTapCoords).col === cell.coords.col;
|
|
816
|
+
if (isSameCell && now - _class_private_field_get(this, _lastTapAt) < TOUCH_DBLTAP_TIMEOUT) {
|
|
817
|
+
_class_private_method_get(this, _fireDblClick, fireDblClick).call(this, event, cell);
|
|
818
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
// Clone: parentCell()'s border branches return references into the live selection CellRange,
|
|
822
|
+
// which normalize() mutates in place — a stored alias could silently shift within the
|
|
823
|
+
// double-tap window.
|
|
824
|
+
_class_private_field_set(this, _lastTapCoords, cell.coords.clone());
|
|
825
|
+
_class_private_field_set(this, _lastTapAt, now);
|
|
826
|
+
}
|
|
827
|
+
function fireDblClick(event, cell) {
|
|
828
|
+
if ((0, _element.hasClass)((0, _element.eventTargetEl)(event), 'corner')) {
|
|
829
|
+
this.callListener('onCellCornerDblClick', event, cell.coords, cell.TD);
|
|
830
|
+
} else {
|
|
831
|
+
this.callListener('onCellDblClick', event, cell.coords, cell.TD);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
668
834
|
function startLongPressTimer(event) {
|
|
669
835
|
_class_private_method_get(this, _cancelLongPressTimer, cancelLongPressTimer).call(this);
|
|
670
836
|
const touch = event.touches[0];
|
|
@@ -685,6 +851,7 @@ function startLongPressTimer(event) {
|
|
|
685
851
|
this.onMouseDown(event);
|
|
686
852
|
_class_private_field_get(this, _dblClickOrigin)[0] = null;
|
|
687
853
|
_class_private_field_get(this, _dblClickOrigin)[1] = null;
|
|
854
|
+
_class_private_field_set(this, _lastTapCoords, null);
|
|
688
855
|
if (_class_private_field_get(this, _dblClickTimeout)[0] !== null) {
|
|
689
856
|
clearTimeout(_class_private_field_get(this, _dblClickTimeout)[0]);
|
|
690
857
|
}
|