UNPKG

react-big-calendar

Version:
515 lines (503 loc) 18.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; exports.getBoundsForNode = getBoundsForNode; exports.getEventNodeFromPoint = getEventNodeFromPoint; exports.getShowMoreNodeFromPoint = getShowMoreNodeFromPoint; exports.isEvent = isEvent; exports.isShowMore = isShowMore; exports.objectsCollide = objectsCollide; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _contains = _interopRequireDefault(require("dom-helpers/contains")); var _closest = _interopRequireDefault(require("dom-helpers/closest")); var _listen = _interopRequireDefault(require("dom-helpers/listen")); function addEventListener(type, handler) { var target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : document; return (0, _listen.default)(target, type, handler, { passive: false }); } function isOverContainer(container, x, y) { return !container || (0, _contains.default)(container, document.elementFromPoint(x, y)); } function getEventNodeFromPoint(node, _ref) { var clientX = _ref.clientX, clientY = _ref.clientY; var target = document.elementFromPoint(clientX, clientY); return (0, _closest.default)(target, '.rbc-event', node); } function getShowMoreNodeFromPoint(node, _ref2) { var clientX = _ref2.clientX, clientY = _ref2.clientY; var target = document.elementFromPoint(clientX, clientY); return (0, _closest.default)(target, '.rbc-show-more', node); } function isEvent(node, bounds) { return !!getEventNodeFromPoint(node, bounds); } function isShowMore(node, bounds) { return !!getShowMoreNodeFromPoint(node, bounds); } function getEventCoordinates(e) { var target = e; if (e.touches && e.touches.length) { target = e.touches[0]; } return { clientX: target.clientX, clientY: target.clientY, pageX: target.pageX, pageY: target.pageY }; } var clickTolerance = 5; var clickInterval = 250; var Selection = /*#__PURE__*/function () { function Selection(node) { var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref3$global = _ref3.global, global = _ref3$global === void 0 ? false : _ref3$global, _ref3$longPressThresh = _ref3.longPressThreshold, longPressThreshold = _ref3$longPressThresh === void 0 ? 250 : _ref3$longPressThresh, _ref3$validContainers = _ref3.validContainers, validContainers = _ref3$validContainers === void 0 ? [] : _ref3$validContainers; (0, _classCallCheck2.default)(this, Selection); this._initialEvent = null; this.selecting = false; this.isDetached = false; this.container = node; this.globalMouse = !node || global; this.longPressThreshold = longPressThreshold; this.validContainers = validContainers; this._listeners = Object.create(null); this._handleInitialEvent = this._handleInitialEvent.bind(this); this._handleMoveEvent = this._handleMoveEvent.bind(this); this._handleTerminatingEvent = this._handleTerminatingEvent.bind(this); this._keyListener = this._keyListener.bind(this); this._dropFromOutsideListener = this._dropFromOutsideListener.bind(this); this._dragOverFromOutsideListener = this._dragOverFromOutsideListener.bind(this); // Fixes an iOS 10 bug where scrolling could not be prevented on the window. // https://github.com/metafizzy/flickity/issues/457#issuecomment-254501356 this._removeTouchMoveWindowListener = addEventListener('touchmove', function () {}, window); this._removeKeyDownListener = addEventListener('keydown', this._keyListener); this._removeKeyUpListener = addEventListener('keyup', this._keyListener); this._removeDropFromOutsideListener = addEventListener('drop', this._dropFromOutsideListener); this._removeDragOverFromOutsideListener = addEventListener('dragover', this._dragOverFromOutsideListener); this._addInitialEventListener(); } return (0, _createClass2.default)(Selection, [{ key: "on", value: function on(type, handler) { var handlers = this._listeners[type] || (this._listeners[type] = []); handlers.push(handler); return { remove: function remove() { var idx = handlers.indexOf(handler); if (idx !== -1) handlers.splice(idx, 1); } }; } }, { key: "emit", value: function emit(type) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } var result; var handlers = this._listeners[type] || []; handlers.forEach(function (fn) { if (result === undefined) result = fn.apply(void 0, args); }); return result; } }, { key: "teardown", value: function teardown() { this._initialEvent = null; this._initialEventData = null; this._selectRect = null; this.selecting = false; this._lastClickData = null; this.isDetached = true; this._listeners = Object.create(null); this._removeTouchMoveWindowListener && this._removeTouchMoveWindowListener(); this._removeInitialEventListener && this._removeInitialEventListener(); this._removeEndListener && this._removeEndListener(); this._onEscListener && this._onEscListener(); this._removeMoveListener && this._removeMoveListener(); this._removeKeyUpListener && this._removeKeyUpListener(); this._removeKeyDownListener && this._removeKeyDownListener(); this._removeDropFromOutsideListener && this._removeDropFromOutsideListener(); this._removeDragOverFromOutsideListener && this._removeDragOverFromOutsideListener(); } }, { key: "isSelected", value: function isSelected(node) { var box = this._selectRect; if (!box || !this.selecting) return false; return objectsCollide(box, getBoundsForNode(node)); } }, { key: "filter", value: function filter(items) { var box = this._selectRect; //not selecting if (!box || !this.selecting) return []; return items.filter(this.isSelected, this); } // Adds a listener that will call the handler only after the user has pressed on the screen // without moving their finger for 250ms. }, { key: "_addLongPressListener", value: function _addLongPressListener(handler, initialEvent) { var _this = this; var timer = null; var removeTouchMoveListener = null; var removeTouchEndListener = null; var handleTouchStart = function handleTouchStart(initialEvent) { timer = setTimeout(function () { cleanup(); handler(initialEvent); }, _this.longPressThreshold); removeTouchMoveListener = addEventListener('touchmove', function () { return cleanup(); }); removeTouchEndListener = addEventListener('touchend', function () { return cleanup(); }); }; var removeTouchStartListener = addEventListener('touchstart', handleTouchStart); var cleanup = function cleanup() { if (timer) { clearTimeout(timer); } if (removeTouchMoveListener) { removeTouchMoveListener(); } if (removeTouchEndListener) { removeTouchEndListener(); } timer = null; removeTouchMoveListener = null; removeTouchEndListener = null; }; if (initialEvent) { handleTouchStart(initialEvent); } return function () { cleanup(); removeTouchStartListener(); }; } // Listen for mousedown and touchstart events. When one is received, disable the other and setup // future event handling based on the type of event. }, { key: "_addInitialEventListener", value: function _addInitialEventListener() { var _this2 = this; var removeMouseDownListener = addEventListener('mousedown', function (e) { _this2._removeInitialEventListener(); _this2._handleInitialEvent(e); _this2._removeInitialEventListener = addEventListener('mousedown', _this2._handleInitialEvent); }); var removeTouchStartListener = addEventListener('touchstart', function (e) { _this2._removeInitialEventListener(); _this2._removeInitialEventListener = _this2._addLongPressListener(_this2._handleInitialEvent, e); }); this._removeInitialEventListener = function () { removeMouseDownListener(); removeTouchStartListener(); }; } }, { key: "_dropFromOutsideListener", value: function _dropFromOutsideListener(e) { var _getEventCoordinates = getEventCoordinates(e), pageX = _getEventCoordinates.pageX, pageY = _getEventCoordinates.pageY, clientX = _getEventCoordinates.clientX, clientY = _getEventCoordinates.clientY; this.emit('dropFromOutside', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); e.preventDefault(); } }, { key: "_dragOverFromOutsideListener", value: function _dragOverFromOutsideListener(e) { var _getEventCoordinates2 = getEventCoordinates(e), pageX = _getEventCoordinates2.pageX, pageY = _getEventCoordinates2.pageY, clientX = _getEventCoordinates2.clientX, clientY = _getEventCoordinates2.clientY; this.emit('dragOverFromOutside', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); e.preventDefault(); } }, { key: "_handleInitialEvent", value: function _handleInitialEvent(e) { this._initialEvent = e; if (this.isDetached) { return; } var _getEventCoordinates3 = getEventCoordinates(e), clientX = _getEventCoordinates3.clientX, clientY = _getEventCoordinates3.clientY, pageX = _getEventCoordinates3.pageX, pageY = _getEventCoordinates3.pageY; var node = this.container(), collides, offsetData; // Right clicks if (e.which === 3 || e.button === 2 || !isOverContainer(node, clientX, clientY)) return; if (!this.globalMouse && node && !(0, _contains.default)(node, e.target)) { var _normalizeDistance = normalizeDistance(0), top = _normalizeDistance.top, left = _normalizeDistance.left, bottom = _normalizeDistance.bottom, right = _normalizeDistance.right; offsetData = getBoundsForNode(node); collides = objectsCollide({ top: offsetData.top - top, left: offsetData.left - left, bottom: offsetData.bottom + bottom, right: offsetData.right + right }, { top: pageY, left: pageX }); if (!collides) return; } var result = this.emit('beforeSelect', this._initialEventData = { isTouch: /^touch/.test(e.type), x: pageX, y: pageY, clientX: clientX, clientY: clientY }); if (result === false) return; switch (e.type) { case 'mousedown': this._removeEndListener = addEventListener('mouseup', this._handleTerminatingEvent); this._onEscListener = addEventListener('keydown', this._handleTerminatingEvent); this._removeMoveListener = addEventListener('mousemove', this._handleMoveEvent); break; case 'touchstart': this._handleMoveEvent(e); this._removeEndListener = addEventListener('touchend', this._handleTerminatingEvent); this._removeMoveListener = addEventListener('touchmove', this._handleMoveEvent); break; default: break; } } // Check whether provided event target element // - is contained within a valid container }, { key: "_isWithinValidContainer", value: function _isWithinValidContainer(e) { var eventTarget = e.target; var containers = this.validContainers; if (!containers || !containers.length || !eventTarget) { return true; } return containers.some(function (target) { return !!eventTarget.closest(target); }); } }, { key: "_handleTerminatingEvent", value: function _handleTerminatingEvent(e) { var selecting = this.selecting; var bounds = this._selectRect; // If it's not in selecting state, it's a click event if (!selecting && e.type.includes('key')) { e = this._initialEvent; } this.selecting = false; this._removeEndListener && this._removeEndListener(); this._removeMoveListener && this._removeMoveListener(); this._selectRect = null; this._initialEvent = null; this._initialEventData = null; if (!e) return; var inRoot = !this.container || (0, _contains.default)(this.container(), e.target); var isWithinValidContainer = this._isWithinValidContainer(e); if (e.key === 'Escape' || !isWithinValidContainer) { return this.emit('reset'); } if (!selecting && inRoot) { return this._handleClickEvent(e); } // User drag-clicked in the Selectable area if (selecting) return this.emit('select', bounds); return this.emit('reset'); } }, { key: "_handleClickEvent", value: function _handleClickEvent(e) { var _getEventCoordinates4 = getEventCoordinates(e), pageX = _getEventCoordinates4.pageX, pageY = _getEventCoordinates4.pageY, clientX = _getEventCoordinates4.clientX, clientY = _getEventCoordinates4.clientY; var now = new Date().getTime(); if (this._lastClickData && now - this._lastClickData.timestamp < clickInterval) { // Double click event this._lastClickData = null; return this.emit('doubleClick', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); } // Click event this._lastClickData = { timestamp: now }; return this.emit('click', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); } }, { key: "_handleMoveEvent", value: function _handleMoveEvent(e) { if (this._initialEventData === null || this.isDetached) { return; } var _this$_initialEventDa = this._initialEventData, x = _this$_initialEventDa.x, y = _this$_initialEventDa.y; var _getEventCoordinates5 = getEventCoordinates(e), pageX = _getEventCoordinates5.pageX, pageY = _getEventCoordinates5.pageY; var w = Math.abs(x - pageX); var h = Math.abs(y - pageY); var left = Math.min(pageX, x), top = Math.min(pageY, y), old = this.selecting; var click = this.isClick(pageX, pageY); // Prevent emitting selectStart event until mouse is moved. // in Chrome on Windows, mouseMove event may be fired just after mouseDown event. if (click && !old && !(w || h)) { return; } if (!old && !click) { this.emit('selectStart', this._initialEventData); } if (!click) { this.selecting = true; this._selectRect = { top: top, left: left, x: pageX, y: pageY, right: left + w, bottom: top + h }; this.emit('selecting', this._selectRect); } e.preventDefault(); } }, { key: "_keyListener", value: function _keyListener(e) { this.ctrl = e.metaKey || e.ctrlKey; } }, { key: "isClick", value: function isClick(pageX, pageY) { var _this$_initialEventDa2 = this._initialEventData, x = _this$_initialEventDa2.x, y = _this$_initialEventDa2.y, isTouch = _this$_initialEventDa2.isTouch; return !isTouch && Math.abs(pageX - x) <= clickTolerance && Math.abs(pageY - y) <= clickTolerance; } }]); }(); /** * Resolve the disance prop from either an Int or an Object * @return {Object} */ function normalizeDistance() { var distance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; if ((0, _typeof2.default)(distance) !== 'object') distance = { top: distance, left: distance, right: distance, bottom: distance }; return distance; } /** * Given two objects containing "top", "left", "offsetWidth" and "offsetHeight" * properties, determine if they collide. * @param {Object|HTMLElement} a * @param {Object|HTMLElement} b * @return {bool} */ function objectsCollide(nodeA, nodeB) { var tolerance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var _getBoundsForNode = getBoundsForNode(nodeA), aTop = _getBoundsForNode.top, aLeft = _getBoundsForNode.left, _getBoundsForNode$rig = _getBoundsForNode.right, aRight = _getBoundsForNode$rig === void 0 ? aLeft : _getBoundsForNode$rig, _getBoundsForNode$bot = _getBoundsForNode.bottom, aBottom = _getBoundsForNode$bot === void 0 ? aTop : _getBoundsForNode$bot; var _getBoundsForNode2 = getBoundsForNode(nodeB), bTop = _getBoundsForNode2.top, bLeft = _getBoundsForNode2.left, _getBoundsForNode2$ri = _getBoundsForNode2.right, bRight = _getBoundsForNode2$ri === void 0 ? bLeft : _getBoundsForNode2$ri, _getBoundsForNode2$bo = _getBoundsForNode2.bottom, bBottom = _getBoundsForNode2$bo === void 0 ? bTop : _getBoundsForNode2$bo; return !( // 'a' bottom doesn't touch 'b' top aBottom - tolerance < bTop || // 'a' top doesn't touch 'b' bottom aTop + tolerance > bBottom || // 'a' right doesn't touch 'b' left aRight - tolerance < bLeft || // 'a' left doesn't touch 'b' right aLeft + tolerance > bRight); } /** * Given a node, get everything needed to calculate its boundaries * @param {HTMLElement} node * @return {Object} */ function getBoundsForNode(node) { if (!node.getBoundingClientRect) return node; var rect = node.getBoundingClientRect(), left = rect.left + pageOffset('left'), top = rect.top + pageOffset('top'); return { top: top, left: left, right: (node.offsetWidth || 0) + left, bottom: (node.offsetHeight || 0) + top }; } function pageOffset(dir) { if (dir === 'left') return window.pageXOffset || document.body.scrollLeft || 0; if (dir === 'top') return window.pageYOffset || document.body.scrollTop || 0; } var _default = exports.default = Selection;