From c563c84f05750cd0783f747f11631e3c9540ceae Mon Sep 17 00:00:00 2001 From: "Rochmar Nicolas (DevExpress)" Date: Tue, 23 Jul 2024 17:28:08 +0800 Subject: [PATCH] Migrate events engine to TS --- .../__internal/events/core/m_events_engine.ts | 1082 +++++++++-------- .../js/events/core/events_engine.js | 1 + 2 files changed, 547 insertions(+), 536 deletions(-) create mode 100644 packages/devextreme/js/events/core/events_engine.js diff --git a/packages/devextreme/js/__internal/events/core/m_events_engine.ts b/packages/devextreme/js/__internal/events/core/m_events_engine.ts index 853c9d5cee3b..aac8eadaef55 100644 --- a/packages/devextreme/js/__internal/events/core/m_events_engine.ts +++ b/packages/devextreme/js/__internal/events/core/m_events_engine.ts @@ -1,685 +1,695 @@ -import registerEventCallbacks from './event_registrator_callbacks'; -import { extend } from '../../core/utils/extend'; -import { getEventTarget } from '../utils/event_target'; -import domAdapter from '../../core/dom_adapter'; -import { getWindow, hasWindow } from '../../core/utils/window'; +/* eslint-disable guard-for-in */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable @typescript-eslint/no-dynamic-delete */ +import domAdapter from '@js/core/dom_adapter'; +import errors from '@js/core/errors'; +import callOnce from '@js/core/utils/call_once'; +import Callbacks from '@js/core/utils/callbacks'; +import injector from '@js/core/utils/dependency_injector'; +import { extend } from '@js/core/utils/extend'; +import { + isFunction, isObject, isString, isWindow, +} from '@js/core/utils/type'; +import { getWindow, hasWindow } from '@js/core/utils/window'; +import registerEventCallbacks from '@js/events/core/event_registrator_callbacks'; +import hookTouchProps from '@js/events/core/hook_touch_props'; +import { getEventTarget } from '@js/events/utils/event_target'; + const window = getWindow(); -import injector from '../../core/utils/dependency_injector'; -import { isWindow, isFunction, isString, isObject } from '../../core/utils/type'; -import Callbacks from '../../core/utils/callbacks'; -import errors from '../../core/errors'; -import hookTouchProps from '../../events/core/hook_touch_props'; -import callOnce from '../../core/utils/call_once'; const EMPTY_EVENT_NAME = 'dxEmptyEventType'; const NATIVE_EVENTS_TO_SUBSCRIBE = { - 'mouseenter': 'mouseover', - 'mouseleave': 'mouseout', - 'pointerenter': 'pointerover', - 'pointerleave': 'pointerout' + mouseenter: 'mouseover', + mouseleave: 'mouseout', + pointerenter: 'pointerover', + pointerleave: 'pointerout', }; const NATIVE_EVENTS_TO_TRIGGER = { - 'focusin': 'focus', - 'focusout': 'blur' + focusin: 'focus', + focusout: 'blur', }; const NO_BUBBLE_EVENTS = ['blur', 'focus', 'load']; const forcePassiveFalseEventNames = ['touchmove', 'wheel', 'mousewheel', 'touchstart']; const EVENT_PROPERTIES = [ - 'target', - 'relatedTarget', - 'delegateTarget', - 'altKey', - 'bubbles', - 'cancelable', - 'changedTouches', - 'ctrlKey', - 'detail', - 'eventPhase', - 'metaKey', - 'shiftKey', - 'view', - 'char', - 'code', - 'charCode', - 'key', - 'keyCode', - 'button', - 'buttons', - 'offsetX', - 'offsetY', - 'pointerId', - 'pointerType', - 'targetTouches', - 'toElement', - 'touches' + 'target', + 'relatedTarget', + 'delegateTarget', + 'altKey', + 'bubbles', + 'cancelable', + 'changedTouches', + 'ctrlKey', + 'detail', + 'eventPhase', + 'metaKey', + 'shiftKey', + 'view', + 'char', + 'code', + 'charCode', + 'key', + 'keyCode', + 'button', + 'buttons', + 'offsetX', + 'offsetY', + 'pointerId', + 'pointerType', + 'targetTouches', + 'toElement', + 'touches', ]; function matchesSafe(target, selector) { - return !isWindow(target) && target.nodeName !== '#document' && domAdapter.elementMatches(target, selector); + return !isWindow(target) && target.nodeName !== '#document' && (domAdapter as any).elementMatches(target, selector); } const elementDataMap = new WeakMap(); let guid = 0; let skipEvent; -const special = (function() { - const specialData = {}; - - registerEventCallbacks.add(function(eventName, eventObject) { - specialData[eventName] = eventObject; - }); - - return { - getField: function(eventName, field) { - return specialData[eventName] && specialData[eventName][field]; - }, - callMethod: function(eventName, methodName, context, args) { - return specialData[eventName] && specialData[eventName][methodName] && specialData[eventName][methodName].apply(context, args); - } - }; +const special = (function () { + const specialData = {}; + + registerEventCallbacks.add((eventName, eventObject) => { + specialData[eventName] = eventObject; + }); + + return { + getField(eventName, field) { + return specialData[eventName] && specialData[eventName][field]; + }, + callMethod(eventName, methodName, context, args) { + return specialData[eventName] && specialData[eventName][methodName] && specialData[eventName][methodName].apply(context, args); + }, + }; }()); const eventsEngine = injector({ - on: getHandler(normalizeOnArguments(iterate(function(element, eventName, selector, data, handler) { - const handlersController = getHandlersController(element, eventName); - handlersController.addHandler(handler, selector, data); - }))), - - one: getHandler(normalizeOnArguments(function(element, eventName, selector, data, handler) { - const oneTimeHandler = function() { - eventsEngine.off(element, eventName, selector, oneTimeHandler); - handler.apply(this, arguments); - }; - - eventsEngine.on(element, eventName, selector, data, oneTimeHandler); - })), - - off: getHandler(normalizeOffArguments(iterate(function(element, eventName, selector, handler) { - const handlersController = getHandlersController(element, eventName); - handlersController.removeHandler(handler, selector); - }))), - - trigger: getHandler(normalizeTriggerArguments(function(element, event, extraParameters) { - const eventName = event.type; - const handlersController = getHandlersController(element, event.type); - - special.callMethod(eventName, 'trigger', element, [ event, extraParameters ]); - handlersController.callHandlers(event, extraParameters); - - const noBubble = special.getField(eventName, 'noBubble') - || event.isPropagationStopped() - || NO_BUBBLE_EVENTS.indexOf(eventName) !== -1; - - if(!noBubble) { - const parents = []; - const getParents = function(element) { - const parent = element.parentNode - ?? (isObject(element.host) ? element.host : null); - if(parent) { - parents.push(parent); - getParents(parent); - } - }; - getParents(element); - parents.push(window); - - let i = 0; - - while(parents[i] && !event.isPropagationStopped()) { - const parentDataByEvent = getHandlersController(parents[i], event.type); - parentDataByEvent.callHandlers(extend(event, { currentTarget: parents[i] }), extraParameters); - i++; - } - } + on: getHandler(normalizeOnArguments(iterate((element, eventName, selector, data, handler) => { + const handlersController = getHandlersController(element, eventName); + handlersController.addHandler(handler, selector, data); + }))), + + one: getHandler(normalizeOnArguments((element, eventName, selector, data, handler) => { + const oneTimeHandler = function () { + eventsEngine.off(element, eventName, selector, oneTimeHandler); + handler.apply(this, arguments); + }; - if(element.nodeType || isWindow(element)) { - special.callMethod(eventName, '_default', element, [ event, extraParameters ]); - callNativeMethod(eventName, element); + eventsEngine.on(element, eventName, selector, data, oneTimeHandler); + })), + + off: getHandler(normalizeOffArguments(iterate((element, eventName, selector, handler) => { + const handlersController = getHandlersController(element, eventName); + handlersController.removeHandler(handler, selector); + }))), + + trigger: getHandler(normalizeTriggerArguments((element, event, extraParameters) => { + const eventName = event.type; + const handlersController = getHandlersController(element, event.type); + + special.callMethod(eventName, 'trigger', element, [event, extraParameters]); + handlersController.callHandlers(event, extraParameters); + + const noBubble = special.getField(eventName, 'noBubble') + || event.isPropagationStopped() + || NO_BUBBLE_EVENTS.includes(eventName); + + if (!noBubble) { + const parents: any = []; + const getParents = function (element) { + const parent = element.parentNode + ?? (isObject(element.host) ? element.host : null); + if (parent) { + parents.push(parent); + getParents(parent); } - })), + }; + getParents(element); + parents.push(window); - triggerHandler: getHandler(normalizeTriggerArguments(function(element, event, extraParameters) { - const handlersController = getHandlersController(element, event.type); - handlersController.callHandlers(event, extraParameters); - })) + let i = 0; + + while (parents[i] && !event.isPropagationStopped()) { + const parentDataByEvent = getHandlersController(parents[i], event.type); + parentDataByEvent.callHandlers(extend(event, { currentTarget: parents[i] }), extraParameters); + i++; + } + } + + if (element.nodeType || isWindow(element)) { + special.callMethod(eventName, '_default', element, [event, extraParameters]); + callNativeMethod(eventName, element); + } + })), + + triggerHandler: getHandler(normalizeTriggerArguments((element, event, extraParameters) => { + const handlersController = getHandlersController(element, event.type); + handlersController.callHandlers(event, extraParameters); + })), }); function applyForEach(args, method) { - const element = args[0]; + const element = args[0]; - if(!element) { - return; - } + if (!element) { + return; + } - if(domAdapter.isNode(element) || isWindow(element)) { - method.apply(eventsEngine, args); - } else if(!isString(element) && 'length' in element) { - const itemArgs = Array.prototype.slice.call(args, 0); + if (domAdapter.isNode(element) || isWindow(element)) { + method.apply(eventsEngine, args); + } else if (!isString(element) && 'length' in element) { + const itemArgs = Array.prototype.slice.call(args, 0); - Array.prototype.forEach.call(element, function(itemElement) { - itemArgs[0] = itemElement; - applyForEach(itemArgs, method); - }); - } else { - throw errors.Error('E0025'); - } + Array.prototype.forEach.call(element, (itemElement) => { + itemArgs[0] = itemElement; + applyForEach(itemArgs, method); + }); + } else { + throw errors.Error('E0025'); + } } function getHandler(method) { - return function() { - applyForEach(arguments, method); - }; + return function () { + applyForEach(arguments, method); + }; } function detectPassiveEventHandlersSupport() { - let isSupported = false; - - try { - const options = Object.defineProperty({ }, 'passive', { - get: function() { - isSupported = true; - return true; - } - }); + let isSupported = false; + + try { + const options = Object.defineProperty({}, 'passive', { + get() { + isSupported = true; + return true; + }, + }); - window.addEventListener('test', null, options); - } catch(e) { } + (window as any).addEventListener('test', null, options); + } catch (e) { + // + } - return isSupported; + return isSupported; } const passiveEventHandlersSupported = callOnce(detectPassiveEventHandlersSupport); const contains = (container, element) => { - if(isWindow(container)) { - return contains(container.document, element); - } + if (isWindow(container)) { + return contains(container.document, element); + } - return container.contains - ? container.contains(element) - : !!(element.compareDocumentPosition(container) & element.DOCUMENT_POSITION_CONTAINS); + return container.contains + ? container.contains(element) + : !!(element.compareDocumentPosition(container) & element.DOCUMENT_POSITION_CONTAINS); }; function getHandlersController(element, eventName) { - let elementData = elementDataMap.get(element); + let elementData = elementDataMap.get(element); - eventName = eventName || ''; + eventName = eventName || ''; - const eventNameParts = eventName.split('.'); - const namespaces = eventNameParts.slice(1); - const eventNameIsDefined = !!eventNameParts[0]; + const eventNameParts = eventName.split('.'); + const namespaces = eventNameParts.slice(1); + const eventNameIsDefined = !!eventNameParts[0]; - eventName = eventNameParts[0] || EMPTY_EVENT_NAME; + eventName = eventNameParts[0] || EMPTY_EVENT_NAME; - if(!elementData) { - elementData = {}; - elementDataMap.set(element, elementData); - } + if (!elementData) { + elementData = {}; + elementDataMap.set(element, elementData); + } - if(!elementData[eventName]) { - elementData[eventName] = { - handleObjects: [], - nativeHandler: null - }; - } + if (!elementData[eventName]) { + elementData[eventName] = { + handleObjects: [], + nativeHandler: null, + }; + } - const eventData = elementData[eventName]; - - return { - addHandler: function(handler, selector, data) { - const callHandler = function(e, extraParameters) { - const handlerArgs = [e]; - const target = e.currentTarget; - const relatedTarget = e.relatedTarget; - let secondaryTargetIsInside; - let result; - - if(eventName in NATIVE_EVENTS_TO_SUBSCRIBE) { - secondaryTargetIsInside = relatedTarget && target && (relatedTarget === target || contains(target, relatedTarget)); - } - - if(extraParameters !== undefined) { - handlerArgs.push(extraParameters); - } - - special.callMethod(eventName, 'handle', element, [ e, data ]); - - if(!secondaryTargetIsInside) { - result = handler.apply(target, handlerArgs); - } - - if(result === false) { - e.preventDefault(); - e.stopPropagation(); - } - }; - - const wrappedHandler = function(e, extraParameters) { - if(skipEvent && e.type === skipEvent) { - return; - } - - e.data = data; - e.delegateTarget = element; - - if(selector) { - let currentTarget = e.target; - - while(currentTarget && currentTarget !== element) { - if(matchesSafe(currentTarget, selector)) { - e.currentTarget = currentTarget; - callHandler(e, extraParameters); - } - currentTarget = currentTarget.parentNode; - } - } else { - e.currentTarget = e.delegateTarget || e.target; - - const isTargetInShadowDOM = Boolean(e.target?.shadowRoot); - if(isTargetInShadowDOM) { - const target = getEventTarget(e); - e.target = target; - } - - callHandler(e, extraParameters); - } - }; - - const handleObject = { - handler: handler, - wrappedHandler: wrappedHandler, - selector: selector, - type: eventName, - data: data, - namespace: namespaces.join('.'), - namespaces: namespaces, - guid: ++guid - }; - - eventData.handleObjects.push(handleObject); - - const firstHandlerForTheType = eventData.handleObjects.length === 1; - let shouldAddNativeListener = firstHandlerForTheType && eventNameIsDefined; - let nativeListenerOptions; - - if(shouldAddNativeListener) { - shouldAddNativeListener = !special.callMethod(eventName, 'setup', element, [ data, namespaces, handler ]); - } + const eventData = elementData[eventName]; - if(shouldAddNativeListener) { - eventData.nativeHandler = getNativeHandler(eventName); + return { + addHandler(handler, selector, data) { + const callHandler = function (e, extraParameters) { + const handlerArgs = [e]; + const target = e.currentTarget; + const { relatedTarget } = e; + let secondaryTargetIsInside; + let result; - if(passiveEventHandlersSupported() && forcePassiveFalseEventNames.indexOf(eventName) > -1) { - nativeListenerOptions = { - passive: false - }; - } + if (eventName in NATIVE_EVENTS_TO_SUBSCRIBE) { + secondaryTargetIsInside = relatedTarget && target && (relatedTarget === target || contains(target, relatedTarget)); + } - eventData.removeListener = domAdapter.listen(element, NATIVE_EVENTS_TO_SUBSCRIBE[eventName] || eventName, eventData.nativeHandler, nativeListenerOptions); - } + if (extraParameters !== undefined) { + handlerArgs.push(extraParameters); + } - special.callMethod(eventName, 'add', element, [ handleObject ]); - }, - - removeHandler: function(handler, selector) { - const removeByEventName = function(eventName) { - const eventData = elementData[eventName]; - - if(!eventData.handleObjects.length) { - delete elementData[eventName]; - return; - } - let removedHandler; - - eventData.handleObjects = eventData.handleObjects.filter(function(handleObject) { - const skip = namespaces.length && !isSubset(handleObject.namespaces, namespaces) - || handler && handleObject.handler !== handler - || selector && handleObject.selector !== selector; - - if(!skip) { - removedHandler = handleObject.handler; - special.callMethod(eventName, 'remove', element, [ handleObject ]); - } - - return skip; - }); - - const lastHandlerForTheType = !eventData.handleObjects.length; - const shouldRemoveNativeListener = lastHandlerForTheType && eventName !== EMPTY_EVENT_NAME; - - if(shouldRemoveNativeListener) { - special.callMethod(eventName, 'teardown', element, [ namespaces, removedHandler ]); - if(eventData.nativeHandler) { - eventData.removeListener(); - } - delete elementData[eventName]; - } - }; - - if(eventNameIsDefined) { - removeByEventName(eventName); - } else { - for(const name in elementData) { - removeByEventName(name); - } - } + special.callMethod(eventName, 'handle', element, [e, data]); - const elementDataIsEmpty = Object.keys(elementData).length === 0; + if (!secondaryTargetIsInside) { + result = handler.apply(target, handlerArgs); + } - if(elementDataIsEmpty) { - elementDataMap.delete(element); - } - }, + if (result === false) { + e.preventDefault(); + e.stopPropagation(); + } + }; - callHandlers: function(event, extraParameters) { - let forceStop = false; + const wrappedHandler = function (e, extraParameters) { + if (skipEvent && e.type === skipEvent) { + return; + } - const handleCallback = function(handleObject) { - if(forceStop) { - return; - } + e.data = data; + e.delegateTarget = element; - if(!namespaces.length || isSubset(handleObject.namespaces, namespaces)) { - handleObject.wrappedHandler(event, extraParameters); - forceStop = event.isImmediatePropagationStopped(); - } - }; + if (selector) { + let currentTarget = e.target; - eventData.handleObjects.forEach(handleCallback); - if(namespaces.length && elementData[EMPTY_EVENT_NAME]) { - elementData[EMPTY_EVENT_NAME].handleObjects.forEach(handleCallback); + while (currentTarget && currentTarget !== element) { + if (matchesSafe(currentTarget, selector)) { + e.currentTarget = currentTarget; + callHandler(e, extraParameters); } + currentTarget = currentTarget.parentNode; + } + } else { + e.currentTarget = e.delegateTarget || e.target; + + const isTargetInShadowDOM = Boolean(e.target?.shadowRoot); + if (isTargetInShadowDOM) { + const target = getEventTarget(e); + e.target = target; + } + + callHandler(e, extraParameters); } - }; + }; + + const handleObject = { + handler, + wrappedHandler, + selector, + type: eventName, + data, + namespace: namespaces.join('.'), + namespaces, + guid: ++guid, + }; + + eventData.handleObjects.push(handleObject); + + const firstHandlerForTheType = eventData.handleObjects.length === 1; + let shouldAddNativeListener = firstHandlerForTheType && eventNameIsDefined; + let nativeListenerOptions; + + if (shouldAddNativeListener) { + shouldAddNativeListener = !special.callMethod(eventName, 'setup', element, [data, namespaces, handler]); + } + + if (shouldAddNativeListener) { + eventData.nativeHandler = getNativeHandler(eventName); + + if (passiveEventHandlersSupported() && forcePassiveFalseEventNames.includes(eventName)) { + nativeListenerOptions = { + passive: false, + }; + } + + eventData.removeListener = (domAdapter as any).listen(element, NATIVE_EVENTS_TO_SUBSCRIBE[eventName] || eventName, eventData.nativeHandler, nativeListenerOptions); + } + + special.callMethod(eventName, 'add', element, [handleObject]); + }, + + removeHandler(handler, selector) { + const removeByEventName = function (eventName) { + const eventData = elementData[eventName]; + + if (!eventData.handleObjects.length) { + delete elementData[eventName]; + return; + } + let removedHandler; + + eventData.handleObjects = eventData.handleObjects.filter((handleObject) => { + const skip = namespaces.length && !isSubset(handleObject.namespaces, namespaces) + || handler && handleObject.handler !== handler + || selector && handleObject.selector !== selector; + + if (!skip) { + removedHandler = handleObject.handler; + special.callMethod(eventName, 'remove', element, [handleObject]); + } + + return skip; + }); + + const lastHandlerForTheType = !eventData.handleObjects.length; + const shouldRemoveNativeListener = lastHandlerForTheType && eventName !== EMPTY_EVENT_NAME; + + if (shouldRemoveNativeListener) { + special.callMethod(eventName, 'teardown', element, [namespaces, removedHandler]); + if (eventData.nativeHandler) { + eventData.removeListener(); + } + delete elementData[eventName]; + } + }; + + if (eventNameIsDefined) { + removeByEventName(eventName); + } else { + for (const name in elementData) { + removeByEventName(name); + } + } + + const elementDataIsEmpty = Object.keys(elementData).length === 0; + + if (elementDataIsEmpty) { + elementDataMap.delete(element); + } + }, + + callHandlers(event, extraParameters) { + let forceStop = false; + + const handleCallback = function (handleObject) { + if (forceStop) { + return; + } + + if (!namespaces.length || isSubset(handleObject.namespaces, namespaces)) { + handleObject.wrappedHandler(event, extraParameters); + forceStop = event.isImmediatePropagationStopped(); + } + }; + + eventData.handleObjects.forEach(handleCallback); + if (namespaces.length && elementData[EMPTY_EVENT_NAME]) { + elementData[EMPTY_EVENT_NAME].handleObjects.forEach(handleCallback); + } + }, + }; } function getNativeHandler(subscribeName) { - return function(event, extraParameters) { - const handlersController = getHandlersController(this, subscribeName); - event = eventsEngine.Event(event); - handlersController.callHandlers(event, extraParameters); - }; + return function (event, extraParameters) { + const handlersController = getHandlersController(this, subscribeName); + event = eventsEngine.Event(event); + handlersController.callHandlers(event, extraParameters); + }; } function isSubset(original, checked) { - for(let i = 0; i < checked.length; i++) { - if(original.indexOf(checked[i]) < 0) return false; - } - return true; + for (let i = 0; i < checked.length; i++) { + if (original.indexOf(checked[i]) < 0) return false; + } + return true; } function normalizeOnArguments(callback) { - return function(element, eventName, selector, data, handler) { - if(!handler) { - handler = data; - data = undefined; - } - if(typeof selector !== 'string') { - data = selector; - selector = undefined; - } + return function (element, eventName, selector, data, handler) { + if (!handler) { + handler = data; + data = undefined; + } + if (typeof selector !== 'string') { + data = selector; + selector = undefined; + } - if(!handler && typeof eventName === 'string') { - handler = data || selector; - selector = undefined; - data = undefined; - } + if (!handler && typeof eventName === 'string') { + handler = data || selector; + selector = undefined; + data = undefined; + } - callback(element, eventName, selector, data, handler); - }; + callback(element, eventName, selector, data, handler); + }; } function normalizeOffArguments(callback) { - return function(element, eventName, selector, handler) { - if(typeof selector === 'function') { - handler = selector; - selector = undefined; - } + return function (element, eventName, selector, handler) { + if (typeof selector === 'function') { + handler = selector; + selector = undefined; + } - callback(element, eventName, selector, handler); - }; + callback(element, eventName, selector, handler); + }; } function normalizeTriggerArguments(callback) { - return function(element, src, extraParameters) { - if(typeof src === 'string') { - src = { - type: src - }; - } + return function (element, src, extraParameters) { + if (typeof src === 'string') { + src = { + type: src, + }; + } - if(!src.target) { - src.target = element; - } + if (!src.target) { + src.target = element; + } - src.currentTarget = element; + src.currentTarget = element; - if(!src.delegateTarget) { - src.delegateTarget = element; - } + if (!src.delegateTarget) { + src.delegateTarget = element; + } - if(!src.type && src.originalEvent) { - src.type = src.originalEvent.type; - } + if (!src.type && src.originalEvent) { + src.type = src.originalEvent.type; + } - callback(element, (src instanceof eventsEngine.Event) ? src : eventsEngine.Event(src), extraParameters); - }; + callback(element, src instanceof eventsEngine.Event ? src : eventsEngine.Event(src), extraParameters); + }; } function normalizeEventArguments(callback) { - eventsEngine.Event = function(src, config) { - if(!(this instanceof eventsEngine.Event)) { - return new eventsEngine.Event(src, config); - } - - if(!src) { - src = {}; - } + eventsEngine.Event = function (src, config) { + if (!(this instanceof eventsEngine.Event)) { + return new eventsEngine.Event(src, config); + } - if(typeof src === 'string') { - src = { - type: src - }; - } + if (!src) { + src = {}; + } - if(!config) { - config = {}; - } + if (typeof src === 'string') { + src = { + type: src, + }; + } - callback.call(this, src, config); - }; - Object.assign(eventsEngine.Event.prototype, { - _propagationStopped: false, - _immediatePropagationStopped: false, - _defaultPrevented: false, - isPropagationStopped: function() { - return !!(this._propagationStopped || this.originalEvent && this.originalEvent.propagationStopped); - }, - stopPropagation: function() { - this._propagationStopped = true; - this.originalEvent && this.originalEvent.stopPropagation(); - }, - isImmediatePropagationStopped: function() { - return this._immediatePropagationStopped; - }, - stopImmediatePropagation: function() { - this.stopPropagation(); - this._immediatePropagationStopped = true; - this.originalEvent && this.originalEvent.stopImmediatePropagation(); - }, - isDefaultPrevented: function() { - return !!(this._defaultPrevented || this.originalEvent && this.originalEvent.defaultPrevented); - }, - preventDefault: function() { - this._defaultPrevented = true; - this.originalEvent && this.originalEvent.preventDefault(); - } + if (!config) { + config = {}; + } - }); - return eventsEngine.Event; + callback.call(this, src, config); + }; + Object.assign(eventsEngine.Event.prototype, { + _propagationStopped: false, + _immediatePropagationStopped: false, + _defaultPrevented: false, + isPropagationStopped() { + return !!(this._propagationStopped || this.originalEvent && this.originalEvent.propagationStopped); + }, + stopPropagation() { + this._propagationStopped = true; + this.originalEvent && this.originalEvent.stopPropagation(); + }, + isImmediatePropagationStopped() { + return this._immediatePropagationStopped; + }, + stopImmediatePropagation() { + this.stopPropagation(); + this._immediatePropagationStopped = true; + this.originalEvent && this.originalEvent.stopImmediatePropagation(); + }, + isDefaultPrevented() { + return !!(this._defaultPrevented || this.originalEvent && this.originalEvent.defaultPrevented); + }, + preventDefault() { + this._defaultPrevented = true; + this.originalEvent && this.originalEvent.preventDefault(); + }, + + }); + return eventsEngine.Event; } function iterate(callback) { - const iterateEventNames = function(element, eventName) { - if(eventName && eventName.indexOf(' ') > -1) { - const args = Array.prototype.slice.call(arguments, 0); - eventName.split(' ').forEach(function(eventName) { - args[1] = eventName; - callback.apply(this, args); - }); - } else { - callback.apply(this, arguments); - } - }; + const iterateEventNames = function (element, eventName) { + if (eventName && eventName.indexOf(' ') > -1) { + const args = Array.prototype.slice.call(arguments, 0); + eventName.split(' ').forEach(function (eventName) { + args[1] = eventName; + callback.apply(this, args); + }); + } else { + callback.apply(this, arguments); + } + }; - return function(element, eventName) { - if(typeof eventName === 'object') { - const args = Array.prototype.slice.call(arguments, 0); + return function (element, eventName) { + if (typeof eventName === 'object') { + const args: any = Array.prototype.slice.call(arguments, 0); - for(const name in eventName) { - args[1] = name; - args[args.length - 1] = eventName[name]; - iterateEventNames.apply(this, args); - } - } else { - iterateEventNames.apply(this, arguments); - } - }; + for (const name in eventName) { + args[1] = name; + args[args.length - 1] = eventName[name]; + iterateEventNames.apply(this, args); + } + } else { + iterateEventNames.apply(this, arguments as any); + } + }; } function callNativeMethod(eventName, element) { - const nativeMethodName = NATIVE_EVENTS_TO_TRIGGER[eventName] || eventName; + const nativeMethodName = NATIVE_EVENTS_TO_TRIGGER[eventName] || eventName; - const isLinkClickEvent = function(eventName, element) { - return eventName === 'click' && element.localName === 'a'; - }; + const isLinkClickEvent = function (eventName, element) { + return eventName === 'click' && element.localName === 'a'; + }; - if(isLinkClickEvent(eventName, element)) return; + if (isLinkClickEvent(eventName, element)) return; - if(isFunction(element[nativeMethodName])) { - skipEvent = eventName; - element[nativeMethodName](); - skipEvent = undefined; - } + if (isFunction(element[nativeMethodName])) { + skipEvent = eventName; + element[nativeMethodName](); + skipEvent = undefined; + } } function calculateWhich(event) { - const setForMouseEvent = function(event) { - const mouseEventRegex = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; - return !event.which && event.button !== undefined && mouseEventRegex.test(event.type); + const setForMouseEvent = function (event) { + const mouseEventRegex = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; + return !event.which && event.button !== undefined && mouseEventRegex.test(event.type); + }; + + const setForKeyEvent = function (event) { + return event.which == null && event.type.indexOf('key') === 0; + }; + + if (setForKeyEvent(event)) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + if (setForMouseEvent(event)) { + const whichByButton = { + 1: 1, 2: 3, 3: 1, 4: 2, }; + return whichByButton[event.button]; + } - const setForKeyEvent = function(event) { - return event.which == null && event.type.indexOf('key') === 0; - }; - - if(setForKeyEvent(event)) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - if(setForMouseEvent(event)) { - const whichByButton = { 1: 1, 2: 3, 3: 1, 4: 2 }; - return whichByButton[event.button]; - } - - return event.which; + return event.which; } function initEvent(EventClass) { - if(EventClass) { - eventsEngine.Event = EventClass; - eventsEngine.Event.prototype = EventClass.prototype; - } + if (EventClass) { + eventsEngine.Event = EventClass; + eventsEngine.Event.prototype = EventClass.prototype; + } } -initEvent(normalizeEventArguments(function(src, config) { - const srcIsEvent = src instanceof eventsEngine.Event - || (hasWindow() && src instanceof window.Event) - || (src.view?.Event && src instanceof src.view.Event); - - if(srcIsEvent) { - this.originalEvent = src; - this.type = src.type; - this.currentTarget = undefined; - if(Object.prototype.hasOwnProperty.call(src, 'isTrusted')) { - this.isTrusted = src.isTrusted; - } - this.timeStamp = src.timeStamp || Date.now(); - } else { - Object.assign(this, src); +initEvent(normalizeEventArguments(function (src, config) { + const srcIsEvent = src instanceof eventsEngine.Event + || (hasWindow() && src instanceof (window as any).Event) + || (src.view?.Event && src instanceof src.view.Event); + + if (srcIsEvent) { + this.originalEvent = src; + this.type = src.type; + this.currentTarget = undefined; + if (Object.prototype.hasOwnProperty.call(src, 'isTrusted')) { + this.isTrusted = src.isTrusted; } + this.timeStamp = src.timeStamp || Date.now(); + } else { + Object.assign(this, src); + } - addProperty('which', calculateWhich, this); + addProperty('which', calculateWhich, this); - if(src.type.indexOf('touch') === 0) { - delete config.pageX; - delete config.pageY; - } + if (src.type.indexOf('touch') === 0) { + delete config.pageX; + delete config.pageY; + } - Object.assign(this, config); + Object.assign(this, config); - this.guid = ++guid; + this.guid = ++guid; })); function addProperty(propName, hook, eventInstance) { - Object.defineProperty(eventInstance || eventsEngine.Event.prototype, propName, { + Object.defineProperty(eventInstance || eventsEngine.Event.prototype, propName, { + enumerable: true, + configurable: true, + + get() { + return this.originalEvent && hook(this.originalEvent); + }, + + set(value) { + Object.defineProperty(this, propName, { enumerable: true, configurable: true, - - get: function() { - return this.originalEvent && hook(this.originalEvent); - }, - - set: function(value) { - Object.defineProperty(this, propName, { - enumerable: true, - configurable: true, - writable: true, - value: value - }); - } - }); + writable: true, + value, + }); + }, + }); } - -EVENT_PROPERTIES.forEach(prop => addProperty(prop, (event) => (event[prop]))); +// @ts-expect-error +EVENT_PROPERTIES.forEach((prop) => addProperty(prop, (event) => event[prop])); hookTouchProps(addProperty); const beforeSetStrategy = Callbacks(); const afterSetStrategy = Callbacks(); -eventsEngine.set = function(engine) { - beforeSetStrategy.fire(); - eventsEngine.inject(engine); - initEvent(engine.Event); - afterSetStrategy.fire(); +eventsEngine.set = function (engine) { + beforeSetStrategy.fire(); + eventsEngine.inject(engine); + initEvent(engine.Event); + afterSetStrategy.fire(); }; -eventsEngine.subscribeGlobal = function() { - applyForEach(arguments, normalizeOnArguments(function() { - const args = arguments; +eventsEngine.subscribeGlobal = function () { + applyForEach(arguments, normalizeOnArguments(function () { + const args = arguments; - eventsEngine.on.apply(this, args); + eventsEngine.on.apply(this, args); - beforeSetStrategy.add(function() { - const offArgs = Array.prototype.slice.call(args, 0); - offArgs.splice(3, 1); - eventsEngine.off.apply(this, offArgs); - }); + beforeSetStrategy.add(function () { + const offArgs = Array.prototype.slice.call(args, 0); + offArgs.splice(3, 1); + eventsEngine.off.apply(this, offArgs); + }); - afterSetStrategy.add(function() { - eventsEngine.on.apply(this, args); - }); - })); + afterSetStrategy.add(function () { + eventsEngine.on.apply(this, args); + }); + })); }; eventsEngine.forcePassiveFalseEventNames = forcePassiveFalseEventNames; eventsEngine.passiveEventHandlersSupported = passiveEventHandlersSupported; -///#DEBUG +/// #DEBUG eventsEngine.elementDataMap = elementDataMap; eventsEngine.detectPassiveEventHandlersSupport = detectPassiveEventHandlersSupport; -///#ENDDEBUG +/// #ENDDEBUG export default eventsEngine; diff --git a/packages/devextreme/js/events/core/events_engine.js b/packages/devextreme/js/events/core/events_engine.js new file mode 100644 index 000000000000..a8e5d0c5e304 --- /dev/null +++ b/packages/devextreme/js/events/core/events_engine.js @@ -0,0 +1 @@ +export { default } from '../../__internal/events/core/m_events_engine';