import "core-js/modules/es.array.includes"; import "core-js/modules/es.array.iterator"; import "core-js/modules/es.object.to-string"; import "core-js/modules/es.string.iterator"; import "core-js/modules/es.weak-map"; import "core-js/modules/web.dom-collections.iterator"; import "core-js/modules/web.timers"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } import { closestDown, hasClass, isChildOf, getParent } from './../../../helpers/dom/element'; import { partial } from './../../../helpers/function'; import { isTouchSupported } from './../../../helpers/feature'; import { isMobileBrowser } from './../../../helpers/browser'; import EventManager from './../../../eventManager'; var privatePool = new WeakMap(); /** * @class Event */ var Event = /*#__PURE__*/ function () { /** * @param {*} instance Walkontable instance. */ function Event(instance) { _classCallCheck(this, Event); /** * Instance of {@link Walkontable}. * * @private * @type {Walkontable} */ this.instance = instance; /** * Instance of {@link EventManager}. * * @private * @type {EventManager} */ this.eventManager = new EventManager(instance); privatePool.set(this, { selectedCellBeforeTouchEnd: void 0, dblClickTimeout: [null, null], dblClickOrigin: [null, null] }); this.registerEvents(); } /** * Adds listeners for mouse and touch events. * * @private */ _createClass(Event, [{ key: "registerEvents", value: function registerEvents() { var _this = this; this.eventManager.addEventListener(this.instance.wtTable.holder, 'contextmenu', function (event) { return _this.onContextMenu(event); }); this.eventManager.addEventListener(this.instance.wtTable.TABLE, 'mouseover', function (event) { return _this.onMouseOver(event); }); this.eventManager.addEventListener(this.instance.wtTable.TABLE, 'mouseout', function (event) { return _this.onMouseOut(event); }); var initTouchEvents = function initTouchEvents() { _this.eventManager.addEventListener(_this.instance.wtTable.holder, 'touchstart', function (event) { return _this.onTouchStart(event); }); _this.eventManager.addEventListener(_this.instance.wtTable.holder, 'touchend', function (event) { return _this.onTouchEnd(event); }); if (!_this.instance.momentumScrolling) { _this.instance.momentumScrolling = {}; } _this.eventManager.addEventListener(_this.instance.wtTable.holder, 'scroll', function () { clearTimeout(_this.instance.momentumScrolling._timeout); if (!_this.instance.momentumScrolling.ongoing) { _this.instance.getSetting('onBeforeTouchScroll'); } _this.instance.momentumScrolling.ongoing = true; _this.instance.momentumScrolling._timeout = setTimeout(function () { if (!_this.instance.touchApplied) { _this.instance.momentumScrolling.ongoing = false; _this.instance.getSetting('onAfterMomentumScroll'); } }, 200); }); }; var initMouseEvents = function initMouseEvents() { _this.eventManager.addEventListener(_this.instance.wtTable.holder, 'mouseup', function (event) { return _this.onMouseUp(event); }); _this.eventManager.addEventListener(_this.instance.wtTable.holder, 'mousedown', function (event) { return _this.onMouseDown(event); }); }; if (isMobileBrowser()) { initTouchEvents(); } else { // PC like devices which support both methods (touchscreen and ability to plug-in mouse). if (isTouchSupported()) { initTouchEvents(); } initMouseEvents(); } } /** * Checks if an element is already selected. * * @private * @param {Element} touchTarget * @returns {Boolean} */ }, { key: "selectedCellWasTouched", value: function selectedCellWasTouched(touchTarget) { var priv = privatePool.get(this); var cellUnderFinger = this.parentCell(touchTarget); var coordsOfCellUnderFinger = cellUnderFinger.coords; if (priv.selectedCellBeforeTouchEnd && coordsOfCellUnderFinger) { var _ref = [coordsOfCellUnderFinger.row, priv.selectedCellBeforeTouchEnd.from.row], rowTouched = _ref[0], rowSelected = _ref[1]; var _ref2 = [coordsOfCellUnderFinger.col, priv.selectedCellBeforeTouchEnd.from.col], colTouched = _ref2[0], colSelected = _ref2[1]; return rowTouched === rowSelected && colTouched === colSelected; } return false; } /** * Gets closest TD or TH element. * * @private * @param {Element} elem * @returns {Object} Contains coordinates and reference to TD or TH if it exists. Otherwise it's empty object. */ }, { key: "parentCell", value: function parentCell(elem) { var cell = {}; var TABLE = this.instance.wtTable.TABLE; var TD = closestDown(elem, ['TD', 'TH'], TABLE); if (TD) { cell.coords = this.instance.wtTable.getCoords(TD); cell.TD = TD; } else if (hasClass(elem, 'wtBorder') && hasClass(elem, 'current')) { cell.coords = this.instance.selections.getCell().cellRange.highlight; cell.TD = this.instance.wtTable.getCell(cell.coords); } else if (hasClass(elem, 'wtBorder') && hasClass(elem, 'area')) { if (this.instance.selections.createOrGetArea().cellRange) { cell.coords = this.instance.selections.createOrGetArea().cellRange.to; cell.TD = this.instance.wtTable.getCell(cell.coords); } } return cell; } /** * onMouseDown callback. * * @private * @param {MouseEvent} event */ }, { key: "onMouseDown", value: function onMouseDown(event) { var priv = privatePool.get(this); var activeElement = this.instance.rootDocument.activeElement; var getParentNode = partial(getParent, event.realTarget); var realTarget = event.realTarget; // ignore focusable element from mouse down processing (https://github.com/handsontable/handsontable/issues/3555) if (realTarget === activeElement || getParentNode(0) === activeElement || getParentNode(1) === activeElement) { return; } var cell = this.parentCell(realTarget); if (hasClass(realTarget, 'corner')) { this.instance.getSetting('onCellCornerMouseDown', event, realTarget); } else if (cell.TD && this.instance.hasSetting('onCellMouseDown')) { this.instance.getSetting('onCellMouseDown', event, cell.coords, cell.TD, this.instance); } // doubleclick reacts only for left mouse button or from touch events if ((event.button === 0 || this.instance.touchApplied) && cell.TD) { priv.dblClickOrigin[0] = cell.TD; clearTimeout(priv.dblClickTimeout[0]); priv.dblClickTimeout[0] = setTimeout(function () { priv.dblClickOrigin[0] = null; }, 1000); } } /** * onContextMenu callback. * * @private * @param {MouseEvent} event */ }, { key: "onContextMenu", value: function onContextMenu(event) { if (this.instance.hasSetting('onCellContextMenu')) { var cell = this.parentCell(event.realTarget); if (cell.TD) { this.instance.getSetting('onCellContextMenu', event, cell.coords, cell.TD, this.instance); } } } /** * onMouseOver callback. * * @private * @param {MouseEvent} event */ }, { key: "onMouseOver", value: function onMouseOver(event) { if (!this.instance.hasSetting('onCellMouseOver')) { return; } var table = this.instance.wtTable.TABLE; var td = closestDown(event.realTarget, ['TD', 'TH'], table); var mainWOT = this.instance.cloneSource || this.instance; if (td && td !== mainWOT.lastMouseOver && isChildOf(td, table)) { mainWOT.lastMouseOver = td; this.instance.getSetting('onCellMouseOver', event, this.instance.wtTable.getCoords(td), td, this.instance); } } /** * onMouseOut callback. * * @private * @param {MouseEvent} event */ }, { key: "onMouseOut", value: function onMouseOut(event) { if (!this.instance.hasSetting('onCellMouseOut')) { return; } var table = this.instance.wtTable.TABLE; var lastTD = closestDown(event.realTarget, ['TD', 'TH'], table); var nextTD = closestDown(event.relatedTarget, ['TD', 'TH'], table); if (lastTD && lastTD !== nextTD && isChildOf(lastTD, table)) { this.instance.getSetting('onCellMouseOut', event, this.instance.wtTable.getCoords(lastTD), lastTD, this.instance); } } /** * onMouseUp callback. * * @private * @param {MouseEvent} event */ }, { key: "onMouseUp", value: function onMouseUp(event) { var priv = privatePool.get(this); var cell = this.parentCell(event.realTarget); if (cell.TD && this.instance.hasSetting('onCellMouseUp')) { this.instance.getSetting('onCellMouseUp', event, cell.coords, cell.TD, this.instance); } // if not left mouse button, and the origin event is not comes from touch if (event.button !== 0 && !this.instance.touchApplied) { return; } if (cell.TD === priv.dblClickOrigin[0] && cell.TD === priv.dblClickOrigin[1]) { if (hasClass(event.realTarget, 'corner')) { this.instance.getSetting('onCellCornerDblClick', event, cell.coords, cell.TD, this.instance); } else { this.instance.getSetting('onCellDblClick', event, cell.coords, cell.TD, this.instance); } priv.dblClickOrigin[0] = null; priv.dblClickOrigin[1] = null; } else if (cell.TD === priv.dblClickOrigin[0]) { priv.dblClickOrigin[1] = cell.TD; clearTimeout(priv.dblClickTimeout[1]); priv.dblClickTimeout[1] = setTimeout(function () { priv.dblClickOrigin[1] = null; }, 500); } } /** * onTouchStart callback. Simulates mousedown event. * * @private * @param {MouseEvent} event */ }, { key: "onTouchStart", value: function onTouchStart(event) { var priv = privatePool.get(this); priv.selectedCellBeforeTouchEnd = this.instance.selections.getCell().cellRange; this.instance.touchApplied = true; this.onMouseDown(event); } /** * onTouchEnd callback. Simulates mouseup event. * * @private * @param {MouseEvent} event */ }, { key: "onTouchEnd", value: function onTouchEnd(event) { var excludeTags = ['A', 'BUTTON', 'INPUT']; var target = event.target; // When the standard event was performed on the link element (a cell which contains HTML `a` element) then here // we check if it should be canceled. Click is blocked in a situation when the element is rendered outside // selected cells. This prevents accidentally page reloads while selecting adjacent cells. if (this.selectedCellWasTouched(target) === false && excludeTags.includes(target.tagName)) { event.preventDefault(); } this.onMouseUp(event); this.instance.touchApplied = false; } /** * Clears double-click timeouts and destroys the internal eventManager instance. */ }, { key: "destroy", value: function destroy() { var priv = privatePool.get(this); clearTimeout(priv.dblClickTimeout[0]); clearTimeout(priv.dblClickTimeout[1]); this.eventManager.destroy(); } }]); return Event; }(); export default Event;