diff --git a/packages/devextreme/js/__internal/events/core/m_emitter.feedback.ts b/packages/devextreme/js/__internal/events/core/m_emitter.feedback.ts
new file mode 100644
index 000000000000..bf19246fa872
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_emitter.feedback.ts
@@ -0,0 +1,181 @@
+import Class from '@js/core/class';
+import devices from '@js/core/devices';
+import { ensureDefined, noop } from '@js/core/utils/common';
+import { contains } from '@js/core/utils/dom';
+import Emitter from '@js/events/core/emitter';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import pointerEvents from '@js/events/pointer';
+import { isMouseEvent } from '@js/events/utils/index';
+
+const ACTIVE_EVENT_NAME = 'dxactive';
+const INACTIVE_EVENT_NAME = 'dxinactive';
+
+const ACTIVE_TIMEOUT = 30;
+const INACTIVE_TIMEOUT = 400;
+
+const FeedbackEvent = Class.inherit({
+
+ ctor(timeout, fire) {
+ this._timeout = timeout;
+ this._fire = fire;
+ },
+
+ start() {
+ const that = this;
+
+ this._schedule(() => {
+ that.force();
+ });
+ },
+
+ _schedule(fn) {
+ this.stop();
+ this._timer = setTimeout(fn, this._timeout);
+ },
+
+ stop() {
+ clearTimeout(this._timer);
+ },
+
+ force() {
+ if (this._fired) {
+ return;
+ }
+
+ this.stop();
+ this._fire();
+ this._fired = true;
+ },
+
+ fired() {
+ return this._fired;
+ },
+
+});
+
+let activeFeedback;
+
+const FeedbackEmitter = Emitter.inherit({
+
+ ctor() {
+ this.callBase.apply(this, arguments);
+
+ this._active = new FeedbackEvent(0, noop);
+ this._inactive = new FeedbackEvent(0, noop);
+ },
+
+ /* eslint-disable default-case */
+ configure(data, eventName) {
+ switch (eventName) {
+ case ACTIVE_EVENT_NAME:
+ data.activeTimeout = data.timeout;
+ break;
+ case INACTIVE_EVENT_NAME:
+ data.inactiveTimeout = data.timeout;
+ break;
+ }
+
+ this.callBase(data);
+ },
+
+ start(e) {
+ if (activeFeedback) {
+ const activeChildExists = contains(this.getElement().get(0), activeFeedback.getElement().get(0));
+ const childJustActivated = !activeFeedback._active.fired();
+
+ if (activeChildExists && childJustActivated) {
+ this._cancel();
+ return;
+ }
+
+ activeFeedback._inactive.force();
+ }
+ activeFeedback = this;
+
+ this._initEvents(e);
+ this._active.start();
+ },
+
+ _initEvents(e) {
+ const that = this;
+
+ const eventTarget = this._getEmitterTarget(e);
+
+ const mouseEvent = isMouseEvent(e);
+ const isSimulator = devices.isSimulator();
+ const deferFeedback = isSimulator || !mouseEvent;
+
+ const activeTimeout = ensureDefined(this.activeTimeout, ACTIVE_TIMEOUT);
+ const inactiveTimeout = ensureDefined(this.inactiveTimeout, INACTIVE_TIMEOUT);
+
+ this._active = new FeedbackEvent(deferFeedback ? activeTimeout : 0, () => {
+ that._fireEvent(ACTIVE_EVENT_NAME, e, { target: eventTarget });
+ });
+ this._inactive = new FeedbackEvent(deferFeedback ? inactiveTimeout : 0, () => {
+ that._fireEvent(INACTIVE_EVENT_NAME, e, { target: eventTarget });
+ activeFeedback = null;
+ });
+ },
+
+ cancel(e) {
+ this.end(e);
+ },
+
+ end(e) {
+ const skipTimers = e.type !== pointerEvents.up;
+
+ if (skipTimers) {
+ this._active.stop();
+ } else {
+ this._active.force();
+ }
+
+ this._inactive.start();
+
+ if (skipTimers) {
+ this._inactive.force();
+ }
+ },
+
+ dispose() {
+ this._active.stop();
+ this._inactive.stop();
+
+ if (activeFeedback === this) {
+ activeFeedback = null;
+ }
+
+ this.callBase();
+ },
+
+ lockInactive() {
+ this._active.force();
+ this._inactive.stop();
+ activeFeedback = null;
+ this._cancel();
+
+ return this._inactive.force.bind(this._inactive);
+ },
+
+});
+// @ts-expect-error
+FeedbackEmitter.lock = function (deferred) {
+ const lockInactive = activeFeedback ? activeFeedback.lockInactive() : noop;
+
+ deferred.done(lockInactive);
+};
+
+registerEmitter({
+ emitter: FeedbackEmitter,
+ events: [
+ ACTIVE_EVENT_NAME,
+ INACTIVE_EVENT_NAME,
+ ],
+});
+
+// @ts-expect-error
+export const { lock } = FeedbackEmitter;
+export {
+ ACTIVE_EVENT_NAME as active,
+ INACTIVE_EVENT_NAME as inactive,
+};
diff --git a/packages/devextreme/js/__internal/events/core/m_emitter.ts b/packages/devextreme/js/__internal/events/core/m_emitter.ts
new file mode 100644
index 000000000000..65d31a3b7aa6
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_emitter.ts
@@ -0,0 +1,106 @@
+import Class from '@js/core/class';
+import $ from '@js/core/renderer';
+import Callbacks from '@js/core/utils/callbacks';
+import { noop } from '@js/core/utils/common';
+import { extend } from '@js/core/utils/extend';
+import { fireEvent, hasTouches, isDxMouseWheelEvent } from '@js/events/utils/index';
+
+const Emitter = Class.inherit({
+
+ ctor(element) {
+ this._$element = $(element);
+
+ this._cancelCallback = Callbacks();
+ this._acceptCallback = Callbacks();
+ },
+
+ getElement() {
+ return this._$element;
+ },
+
+ validate(e) {
+ return !isDxMouseWheelEvent(e);
+ },
+
+ validatePointers(e) {
+ return hasTouches(e) === 1;
+ },
+
+ allowInterruptionByMouseWheel() {
+ return true;
+ },
+
+ configure(data) {
+ extend(this, data);
+ },
+
+ addCancelCallback(callback) {
+ this._cancelCallback.add(callback);
+ },
+
+ removeCancelCallback() {
+ this._cancelCallback.empty();
+ },
+
+ _cancel(e) {
+ this._cancelCallback.fire(this, e);
+ },
+
+ addAcceptCallback(callback) {
+ this._acceptCallback.add(callback);
+ },
+
+ removeAcceptCallback() {
+ this._acceptCallback.empty();
+ },
+
+ _accept(e) {
+ this._acceptCallback.fire(this, e);
+ },
+
+ _requestAccept(e) {
+ this._acceptRequestEvent = e;
+ },
+
+ _forgetAccept() {
+ this._accept(this._acceptRequestEvent);
+ this._acceptRequestEvent = null;
+ },
+
+ start: noop,
+ move: noop,
+ end: noop,
+
+ cancel: noop,
+ reset() {
+ if (this._acceptRequestEvent) {
+ this._accept(this._acceptRequestEvent);
+ }
+ },
+
+ _fireEvent(eventName, e, params) {
+ const eventData = extend({
+ type: eventName,
+ originalEvent: e,
+ target: this._getEmitterTarget(e),
+ delegateTarget: this.getElement().get(0),
+ }, params);
+
+ e = fireEvent(eventData);
+
+ if (e.cancel) {
+ this._cancel(e);
+ }
+
+ return e;
+ },
+
+ _getEmitterTarget(e) {
+ return (this.delegateSelector ? $(e.target).closest(this.delegateSelector) : this.getElement()).get(0);
+ },
+
+ dispose: noop,
+
+});
+
+export default Emitter;
diff --git a/packages/devextreme/js/__internal/events/core/m_emitter_registrator.ts b/packages/devextreme/js/__internal/events/core/m_emitter_registrator.ts
new file mode 100644
index 000000000000..77540f77ce3c
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_emitter_registrator.ts
@@ -0,0 +1,303 @@
+import Class from '@js/core/class';
+import domAdapter from '@js/core/dom_adapter';
+import { data as elementData } from '@js/core/element_data';
+import $ from '@js/core/renderer';
+import { extend } from '@js/core/utils/extend';
+import { each } from '@js/core/utils/iterator';
+import readyCallbacks from '@js/core/utils/ready_callbacks';
+import registerEvent from '@js/events/core/event_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import { name as wheelEventName } from '@js/events/core/wheel';
+import pointerEvents from '@js/events/pointer';
+import { addNamespace, isMouseEvent } from '@js/events/utils/index';
+
+const MANAGER_EVENT = 'dxEventManager';
+const EMITTER_DATA = 'dxEmitter';
+
+const EventManager = Class.inherit({
+
+ ctor() {
+ this._attachHandlers();
+ this.reset();
+
+ this._proxiedCancelHandler = this._cancelHandler.bind(this);
+ this._proxiedAcceptHandler = this._acceptHandler.bind(this);
+ },
+
+ _attachHandlers() {
+ readyCallbacks.add(() => {
+ const document = domAdapter.getDocument();
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.down, MANAGER_EVENT), this._pointerDownHandler.bind(this));
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.move, MANAGER_EVENT), this._pointerMoveHandler.bind(this));
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace([pointerEvents.up, pointerEvents.cancel].join(' '), MANAGER_EVENT), this._pointerUpHandler.bind(this));
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace(wheelEventName, MANAGER_EVENT), this._mouseWheelHandler.bind(this));
+ });
+ },
+
+ _eachEmitter(callback) {
+ const activeEmitters = this._activeEmitters || [];
+ let i = 0;
+
+ while (activeEmitters.length > i) {
+ const emitter = activeEmitters[i];
+ if (callback(emitter) === false) {
+ break;
+ }
+
+ if (activeEmitters[i] === emitter) {
+ i++;
+ }
+ }
+ },
+
+ _applyToEmitters(method, arg) {
+ this._eachEmitter((emitter) => {
+ emitter[method].call(emitter, arg);
+ });
+ },
+
+ reset() {
+ this._eachEmitter(this._proxiedCancelHandler);
+ this._activeEmitters = [];
+ },
+
+ resetEmitter(emitter) {
+ this._proxiedCancelHandler(emitter);
+ },
+
+ _pointerDownHandler(e) {
+ if (isMouseEvent(e) && e.which > 1) {
+ return;
+ }
+
+ this._updateEmitters(e);
+ },
+
+ _updateEmitters(e) {
+ if (!this._isSetChanged(e)) {
+ return;
+ }
+
+ this._cleanEmitters(e);
+ this._fetchEmitters(e);
+ },
+
+ _isSetChanged(e) {
+ const currentSet = this._closestEmitter(e);
+ const previousSet = this._emittersSet || [];
+
+ let setChanged = currentSet.length !== previousSet.length;
+
+ each(currentSet, (index, emitter) => {
+ setChanged = setChanged || previousSet[index] !== emitter;
+ return !setChanged;
+ });
+
+ this._emittersSet = currentSet;
+
+ return setChanged;
+ },
+
+ _closestEmitter(e) {
+ const that = this;
+
+ const result: any = [];
+ let $element = $(e.target);
+
+ function handleEmitter(_, emitter) {
+ if (!!emitter && emitter.validatePointers(e) && emitter.validate(e)) {
+ emitter.addCancelCallback(that._proxiedCancelHandler);
+ emitter.addAcceptCallback(that._proxiedAcceptHandler);
+ result.push(emitter);
+ }
+ }
+
+ while ($element.length) {
+ const emitters = elementData($element.get(0), EMITTER_DATA) || [];
+ each(emitters, handleEmitter);
+ $element = $element.parent();
+ }
+
+ return result;
+ },
+
+ _acceptHandler(acceptedEmitter, e) {
+ this._eachEmitter((emitter) => {
+ if (emitter !== acceptedEmitter) {
+ this._cancelEmitter(emitter, e);
+ }
+ });
+ },
+
+ _cancelHandler(canceledEmitter, e) {
+ this._cancelEmitter(canceledEmitter, e);
+ },
+
+ _cancelEmitter(emitter, e) {
+ const activeEmitters = this._activeEmitters;
+
+ if (e) {
+ emitter.cancel(e);
+ } else {
+ emitter.reset();
+ }
+
+ emitter.removeCancelCallback();
+ emitter.removeAcceptCallback();
+
+ const emitterIndex = activeEmitters.indexOf(emitter);
+ if (emitterIndex > -1) {
+ activeEmitters.splice(emitterIndex, 1);
+ }
+ },
+
+ _cleanEmitters(e) {
+ this._applyToEmitters('end', e);
+ this.reset(e);
+ },
+
+ _fetchEmitters(e) {
+ this._activeEmitters = this._emittersSet.slice();
+ this._applyToEmitters('start', e);
+ },
+
+ _pointerMoveHandler(e) {
+ this._applyToEmitters('move', e);
+ },
+
+ _pointerUpHandler(e) {
+ this._updateEmitters(e);
+ },
+
+ _mouseWheelHandler(e) {
+ if (!this._allowInterruptionByMouseWheel()) {
+ return;
+ }
+
+ e.pointers = [null];
+ this._pointerDownHandler(e);
+
+ this._adjustWheelEvent(e);
+
+ this._pointerMoveHandler(e);
+ e.pointers = [];
+ this._pointerUpHandler(e);
+ },
+
+ _allowInterruptionByMouseWheel() {
+ let allowInterruption = true;
+ this._eachEmitter((emitter) => {
+ allowInterruption = emitter.allowInterruptionByMouseWheel() && allowInterruption;
+ return allowInterruption;
+ });
+ return allowInterruption;
+ },
+
+ _adjustWheelEvent(e) {
+ let closestGestureEmitter: any = null;
+ // @ts-expect-error
+ this._eachEmitter((emitter) => {
+ if (!emitter.gesture) {
+ return;
+ }
+
+ const direction = emitter.getDirection(e);
+ if (direction !== 'horizontal' && !e.shiftKey || direction !== 'vertical' && e.shiftKey) {
+ closestGestureEmitter = emitter;
+ return false;
+ }
+ });
+
+ if (!closestGestureEmitter) {
+ return;
+ }
+
+ const direction = closestGestureEmitter.getDirection(e);
+ const verticalGestureDirection = direction === 'both' && !e.shiftKey || direction === 'vertical';
+ const prop = verticalGestureDirection ? 'pageY' : 'pageX';
+
+ e[prop] += e.delta;
+ },
+
+ isActive(element) {
+ let result = false;
+ this._eachEmitter((emitter) => {
+ result = result || emitter.getElement().is(element);
+ });
+ return result;
+ },
+});
+
+const eventManager = new EventManager();
+
+const EMITTER_SUBSCRIPTION_DATA = 'dxEmitterSubscription';
+
+const registerEmitter = function (emitterConfig) {
+ const EmitterClass = emitterConfig.emitter;
+ const emitterName = emitterConfig.events[0];
+ const emitterEvents = emitterConfig.events;
+
+ each(emitterEvents, (_, eventName) => {
+ registerEvent(eventName, {
+
+ noBubble: !emitterConfig.bubble,
+
+ setup(element) {
+ const subscriptions = elementData(element, EMITTER_SUBSCRIPTION_DATA) || {};
+
+ const emitters = elementData(element, EMITTER_DATA) || {};
+ const emitter = emitters[emitterName] || new EmitterClass(element);
+
+ subscriptions[eventName] = true;
+ emitters[emitterName] = emitter;
+
+ elementData(element, EMITTER_DATA, emitters);
+ elementData(element, EMITTER_SUBSCRIPTION_DATA, subscriptions);
+ },
+
+ add(element, handleObj) {
+ const emitters = elementData(element, EMITTER_DATA);
+ const emitter = emitters[emitterName];
+
+ emitter.configure(extend({
+ delegateSelector: handleObj.selector,
+ }, handleObj.data), handleObj.type);
+ },
+
+ teardown(element) {
+ const subscriptions = elementData(element, EMITTER_SUBSCRIPTION_DATA);
+
+ const emitters = elementData(element, EMITTER_DATA);
+ const emitter = emitters[emitterName];
+
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ delete subscriptions[eventName];
+
+ let disposeEmitter = true;
+ each(emitterEvents, (_, eventName) => {
+ disposeEmitter = disposeEmitter && !subscriptions[eventName];
+ return disposeEmitter;
+ });
+
+ if (disposeEmitter) {
+ // @ts-expect-error
+ if (eventManager.isActive(element)) {
+ // @ts-expect-error
+ eventManager.resetEmitter(emitter);
+ }
+
+ emitter && emitter.dispose();
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ delete emitters[emitterName];
+ }
+ },
+
+ });
+ });
+};
+
+export default registerEmitter;
diff --git a/packages/devextreme/js/__internal/events/core/m_event_registrator.ts b/packages/devextreme/js/__internal/events/core/m_event_registrator.ts
new file mode 100644
index 000000000000..1300b04f4577
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_event_registrator.ts
@@ -0,0 +1,35 @@
+import { each } from '@js/core/utils/iterator';
+import callbacks from '@js/events/core/event_registrator_callbacks';
+
+const registerEvent = function (name, eventObject) {
+ const strategy: any = {};
+
+ if ('noBubble' in eventObject) {
+ strategy.noBubble = eventObject.noBubble;
+ }
+
+ if ('bindType' in eventObject) {
+ strategy.bindType = eventObject.bindType;
+ }
+
+ if ('delegateType' in eventObject) {
+ strategy.delegateType = eventObject.delegateType;
+ }
+
+ each(['setup', 'teardown', 'add', 'remove', 'trigger', 'handle', '_default', 'dispose'], (_, methodName) => {
+ if (!eventObject[methodName]) {
+ return;
+ }
+
+ strategy[methodName] = function () {
+ const args: any = [].slice.call(arguments);
+ args.unshift(this);
+ return eventObject[methodName].apply(eventObject, args);
+ };
+ });
+
+ callbacks.fire(name, strategy);
+};
+registerEvent.callbacks = callbacks;
+
+export default registerEvent;
diff --git a/packages/devextreme/js/__internal/events/core/m_events_engine.ts b/packages/devextreme/js/__internal/events/core/m_events_engine.ts
new file mode 100644
index 000000000000..75b3058cd4db
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_events_engine.ts
@@ -0,0 +1,701 @@
+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();
+
+/* eslint-disable spellcheck/spell-checker */
+const EMPTY_EVENT_NAME = 'dxEmptyEventType';
+const NATIVE_EVENTS_TO_SUBSCRIBE = {
+ mouseenter: 'mouseover',
+ mouseleave: 'mouseout',
+ pointerenter: 'pointerover',
+ pointerleave: 'pointerout',
+};
+const NATIVE_EVENTS_TO_TRIGGER = {
+ 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',
+];
+
+function matchesSafe(target, selector) {
+ // @ts-expect-error
+ return !isWindow(target) && target.nodeName !== '#document' && domAdapter.elementMatches(target, selector);
+}
+const elementDataMap = new WeakMap();
+let guid = 0;
+let skipEvent;
+
+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((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);
+ };
+
+ 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);
+
+ 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];
+
+ 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);
+
+ 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);
+ };
+}
+
+function detectPassiveEventHandlersSupport() {
+ let isSupported = false;
+
+ try {
+ const options = Object.defineProperty({}, 'passive', {
+ get() {
+ isSupported = true;
+ return true;
+ },
+ });
+
+ // @ts-expect-error
+ window.addEventListener('test', null, options);
+ // eslint-disable-next-line no-empty
+ } catch (e) { }
+
+ return isSupported;
+}
+
+const passiveEventHandlersSupported = callOnce(detectPassiveEventHandlersSupport);
+
+const contains = (container, element) => {
+ if (isWindow(container)) {
+ return contains(container.document, element);
+ }
+
+ return container.contains
+ ? container.contains(element)
+ : !!(element.compareDocumentPosition(container) & element.DOCUMENT_POSITION_CONTAINS);
+};
+
+function getHandlersController(element, eventName) {
+ let elementData = elementDataMap.get(element);
+
+ eventName = eventName || '';
+
+ const eventNameParts = eventName.split('.');
+ const namespaces = eventNameParts.slice(1);
+ const eventNameIsDefined = !!eventNameParts[0];
+
+ eventName = eventNameParts[0] || EMPTY_EVENT_NAME;
+
+ if (!elementData) {
+ elementData = {};
+ elementDataMap.set(element, elementData);
+ }
+
+ if (!elementData[eventName]) {
+ elementData[eventName] = {
+ handleObjects: [],
+ nativeHandler: null,
+ };
+ }
+
+ const eventData = elementData[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 (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,
+ 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,
+ };
+ }
+
+ // @ts-expect-error
+ eventData.removeListener = domAdapter.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) {
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ 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();
+ }
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ delete elementData[eventName];
+ }
+ };
+
+ if (eventNameIsDefined) {
+ removeByEventName(eventName);
+ } else {
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
+ 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);
+ };
+}
+
+function isSubset(original, checked) {
+ 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;
+ }
+
+ if (!handler && typeof eventName === 'string') {
+ handler = data || selector;
+ selector = undefined;
+ data = undefined;
+ }
+
+ callback(element, eventName, selector, data, handler);
+ };
+}
+
+function normalizeOffArguments(callback) {
+ return function (element, eventName, selector, handler) {
+ if (typeof selector === 'function') {
+ handler = selector;
+ selector = undefined;
+ }
+
+ callback(element, eventName, selector, handler);
+ };
+}
+
+function normalizeTriggerArguments(callback) {
+ return function (element, src, extraParameters) {
+ if (typeof src === 'string') {
+ src = {
+ type: src,
+ };
+ }
+
+ if (!src.target) {
+ src.target = element;
+ }
+
+ src.currentTarget = element;
+
+ if (!src.delegateTarget) {
+ src.delegateTarget = element;
+ }
+
+ if (!src.type && src.originalEvent) {
+ src.type = src.originalEvent.type;
+ }
+
+ 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 = {};
+ }
+
+ if (typeof src === 'string') {
+ src = {
+ type: src,
+ };
+ }
+
+ if (!config) {
+ config = {};
+ }
+
+ 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);
+ }
+ };
+
+ return function (element, eventName) {
+ if (typeof eventName === 'object') {
+ const args: any = Array.prototype.slice.call(arguments, 0);
+
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
+ for (const name in eventName) {
+ args[1] = name;
+ args[args.length - 1] = eventName[name];
+ iterateEventNames.apply(this, args);
+ }
+ } else {
+ // @ts-expect-error
+ iterateEventNames.apply(this, arguments);
+ }
+ };
+}
+
+function callNativeMethod(eventName, element) {
+ const nativeMethodName = NATIVE_EVENTS_TO_TRIGGER[eventName] || eventName;
+
+ const isLinkClickEvent = function (eventName, element) {
+ return eventName === 'click' && element.localName === 'a';
+ };
+
+ if (isLinkClickEvent(eventName, element)) return;
+
+ 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 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;
+}
+
+function initEvent(EventClass) {
+ if (EventClass) {
+ eventsEngine.Event = EventClass;
+ eventsEngine.Event.prototype = EventClass.prototype;
+ }
+}
+
+initEvent(normalizeEventArguments(function (src, config) {
+ const srcIsEvent = src instanceof eventsEngine.Event
+ // @ts-expect-error
+ || (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);
+ }
+
+ addProperty('which', calculateWhich, this);
+
+ if (src.type.indexOf('touch') === 0) {
+ delete config.pageX;
+ delete config.pageY;
+ }
+
+ Object.assign(this, config);
+
+ this.guid = ++guid;
+}));
+
+function addProperty(propName, hook, eventInstance) {
+ 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,
+ writable: true,
+ value,
+ });
+ },
+ });
+}
+// @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.subscribeGlobal = function () {
+ applyForEach(arguments, normalizeOnArguments(function () {
+ const args = arguments;
+
+ 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);
+ });
+
+ afterSetStrategy.add(function () {
+ eventsEngine.on.apply(this, args);
+ });
+ }));
+};
+
+eventsEngine.forcePassiveFalseEventNames = forcePassiveFalseEventNames;
+eventsEngine.passiveEventHandlersSupported = passiveEventHandlersSupported;
+
+/// #DEBUG
+eventsEngine.elementDataMap = elementDataMap;
+eventsEngine.detectPassiveEventHandlersSupport = detectPassiveEventHandlersSupport;
+
+/// #ENDDEBUG
+
+export default eventsEngine;
diff --git a/packages/devextreme/js/__internal/events/core/m_hook_touch_props.ts b/packages/devextreme/js/__internal/events/core/m_hook_touch_props.ts
new file mode 100644
index 000000000000..8099d17c4fbd
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_hook_touch_props.ts
@@ -0,0 +1,19 @@
+const touchPropsToHook = ['pageX', 'pageY', 'screenX', 'screenY', 'clientX', 'clientY'];
+const touchPropHook = function (name, event) {
+ if (event[name] && !event.touches || !event.touches) {
+ return event[name];
+ }
+
+ const touches = event.touches.length ? event.touches : event.changedTouches;
+ if (!touches.length) {
+ return;
+ }
+
+ return touches[0][name];
+};
+
+export default function (callback) {
+ touchPropsToHook.forEach((name) => {
+ callback(name, (event) => touchPropHook(name, event));
+ }, this);
+}
diff --git a/packages/devextreme/js/__internal/events/core/m_keyboard_processor.ts b/packages/devextreme/js/__internal/events/core/m_keyboard_processor.ts
new file mode 100644
index 000000000000..bc3194beeda1
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_keyboard_processor.ts
@@ -0,0 +1,80 @@
+import Class from '@js/core/class';
+import $ from '@js/core/renderer';
+import eventsEngine from '@js/events/core/events_engine';
+import { addNamespace, normalizeKeyName } from '@js/events/utils/index';
+
+const COMPOSITION_START_EVENT = 'compositionstart';
+const COMPOSITION_END_EVENT = 'compositionend';
+const KEYDOWN_EVENT = 'keydown';
+const NAMESPACE = 'KeyboardProcessor';
+
+const createKeyDownOptions = (e) => ({
+ keyName: normalizeKeyName(e),
+ key: e.key,
+ code: e.code,
+ ctrl: e.ctrlKey,
+ location: e.location,
+ metaKey: e.metaKey,
+ shift: e.shiftKey,
+ alt: e.altKey,
+ which: e.which,
+ originalEvent: e,
+});
+
+const KeyboardProcessor = Class.inherit({
+ _keydown: addNamespace(KEYDOWN_EVENT, NAMESPACE),
+ _compositionStart: addNamespace(COMPOSITION_START_EVENT, NAMESPACE),
+ _compositionEnd: addNamespace(COMPOSITION_END_EVENT, NAMESPACE),
+
+ ctor(options) {
+ options = options || {};
+ if (options.element) {
+ this._element = $(options.element);
+ }
+ if (options.focusTarget) {
+ this._focusTarget = options.focusTarget;
+ }
+ this._handler = options.handler;
+
+ if (this._element) {
+ this._processFunction = (e) => {
+ const focusTargets = $(this._focusTarget).toArray();
+ const isNotFocusTarget = this._focusTarget && this._focusTarget !== e.target && !focusTargets.includes(e.target);
+ const shouldSkipProcessing = this._isComposingJustFinished && e.which === 229 || this._isComposing || isNotFocusTarget;
+
+ this._isComposingJustFinished = false;
+ if (!shouldSkipProcessing) {
+ this.process(e);
+ }
+ };
+ this._toggleProcessingWithContext = this.toggleProcessing.bind(this);
+
+ eventsEngine.on(this._element, this._keydown, this._processFunction);
+ eventsEngine.on(this._element, this._compositionStart, this._toggleProcessingWithContext);
+ eventsEngine.on(this._element, this._compositionEnd, this._toggleProcessingWithContext);
+ }
+ },
+
+ dispose() {
+ if (this._element) {
+ eventsEngine.off(this._element, this._keydown, this._processFunction);
+ eventsEngine.off(this._element, this._compositionStart, this._toggleProcessingWithContext);
+ eventsEngine.off(this._element, this._compositionEnd, this._toggleProcessingWithContext);
+ }
+ this._element = undefined;
+ this._handler = undefined;
+ },
+
+ process(e) {
+ this._handler(createKeyDownOptions(e));
+ },
+
+ toggleProcessing({ type }) {
+ this._isComposing = type === COMPOSITION_START_EVENT;
+ this._isComposingJustFinished = !this._isComposing;
+ },
+});
+// @ts-expect-error
+KeyboardProcessor.createKeyDownOptions = createKeyDownOptions;
+
+export default KeyboardProcessor;
diff --git a/packages/devextreme/js/__internal/events/core/m_wheel.ts b/packages/devextreme/js/__internal/events/core/m_wheel.ts
new file mode 100644
index 000000000000..f4f94e27f02a
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/core/m_wheel.ts
@@ -0,0 +1,55 @@
+import $ from '@js/core/renderer';
+import registerEvent from '@js/events/core/event_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import { addNamespace, fireEvent } from '@js/events/utils/index';
+
+const EVENT_NAME = 'dxmousewheel';
+const EVENT_NAMESPACE = 'dxWheel';
+const NATIVE_EVENT_NAME = 'wheel';
+
+const PIXEL_MODE = 0;
+const DELTA_MUTLIPLIER = 30;
+
+const wheel = {
+ setup(element) {
+ const $element = $(element);
+ eventsEngine.on($element, addNamespace(NATIVE_EVENT_NAME, EVENT_NAMESPACE), wheel._wheelHandler.bind(wheel));
+ },
+
+ teardown(element) {
+ eventsEngine.off(element, `.${EVENT_NAMESPACE}`);
+ },
+
+ _wheelHandler(e) {
+ const {
+ deltaMode, deltaY, deltaX, deltaZ,
+ } = e.originalEvent;
+
+ fireEvent({
+ type: EVENT_NAME,
+ originalEvent: e,
+ // @ts-expect-error
+ delta: this._normalizeDelta(deltaY, deltaMode),
+ deltaX,
+ deltaY,
+ deltaZ,
+ deltaMode,
+ pointerType: 'mouse',
+ });
+
+ e.stopPropagation();
+ },
+
+ _normalizeDelta(delta, deltaMode = PIXEL_MODE) {
+ if (deltaMode === PIXEL_MODE) {
+ return -delta;
+ }
+ // Use multiplier to get rough delta value in px for the LINE or PAGE mode
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460
+ return -DELTA_MUTLIPLIER * delta;
+ },
+};
+
+registerEvent(EVENT_NAME, wheel);
+
+export { EVENT_NAME as name };
diff --git a/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.scroll.ts b/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.scroll.ts
new file mode 100644
index 000000000000..b8ba6593c113
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.scroll.ts
@@ -0,0 +1,341 @@
+import { cancelAnimationFrame, requestAnimationFrame } from '@js/animation/frame';
+import Class from '@js/core/class';
+import devices from '@js/core/devices';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import GestureEmitter from '@js/events/gesture/emitter.gesture';
+import {
+ addNamespace, eventData, eventDelta, isDxMouseWheelEvent, isMouseEvent,
+} from '@js/events/utils/index';
+
+const { abstract } = Class;
+
+const realDevice = devices.real();
+
+const SCROLL_EVENT = 'scroll';
+const SCROLL_INIT_EVENT = 'dxscrollinit';
+const SCROLL_START_EVENT = 'dxscrollstart';
+const SCROLL_MOVE_EVENT = 'dxscroll';
+const SCROLL_END_EVENT = 'dxscrollend';
+const SCROLL_STOP_EVENT = 'dxscrollstop';
+const SCROLL_CANCEL_EVENT = 'dxscrollcancel';
+
+const Locker = Class.inherit((function () {
+ const NAMESPACED_SCROLL_EVENT = addNamespace(SCROLL_EVENT, 'dxScrollEmitter');
+
+ return {
+
+ ctor(element) {
+ this._element = element;
+
+ this._locked = false;
+
+ this._proxiedScroll = (e) => {
+ if (!this._disposed) {
+ this._scroll(e);
+ }
+ };
+ eventsEngine.on(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll);
+ },
+
+ _scroll: abstract,
+
+ check(e, callback) {
+ if (this._locked) {
+ callback();
+ }
+ },
+
+ dispose() {
+ this._disposed = true;
+ eventsEngine.off(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll);
+ },
+
+ };
+})());
+
+const TimeoutLocker = Locker.inherit((function () {
+ return {
+
+ ctor(element, timeout) {
+ this.callBase(element);
+
+ this._timeout = timeout;
+ },
+
+ _scroll() {
+ this._prepare();
+ this._forget();
+ },
+
+ _prepare() {
+ if (this._timer) {
+ this._clearTimer();
+ }
+ this._locked = true;
+ },
+
+ _clearTimer() {
+ clearTimeout(this._timer);
+ this._locked = false;
+ this._timer = null;
+ },
+
+ _forget() {
+ const that = this;
+
+ this._timer = setTimeout(() => {
+ that._clearTimer();
+ }, this._timeout);
+ },
+
+ dispose() {
+ this.callBase();
+
+ this._clearTimer();
+ },
+
+ };
+})());
+
+const WheelLocker = TimeoutLocker.inherit((function () {
+ const WHEEL_UNLOCK_TIMEOUT = 400;
+
+ return {
+
+ ctor(element) {
+ this.callBase(element, WHEEL_UNLOCK_TIMEOUT);
+
+ this._lastWheelDirection = null;
+ },
+
+ check(e, callback) {
+ this._checkDirectionChanged(e);
+
+ this.callBase(e, callback);
+ },
+
+ _checkDirectionChanged(e) {
+ if (!isDxMouseWheelEvent(e)) {
+ this._lastWheelDirection = null;
+ return;
+ }
+
+ const direction = e.shiftKey || false;
+ const directionChange = this._lastWheelDirection !== null && direction !== this._lastWheelDirection;
+ this._lastWheelDirection = direction;
+
+ this._locked = this._locked && !directionChange;
+ },
+
+ };
+})());
+
+let PointerLocker = TimeoutLocker.inherit((function () {
+ const POINTER_UNLOCK_TIMEOUT = 400;
+
+ return {
+
+ ctor(element) {
+ this.callBase(element, POINTER_UNLOCK_TIMEOUT);
+ },
+
+ };
+})());
+
+(function () {
+ const { ios: isIos, android: isAndroid } = realDevice;
+
+ if (!(isIos || isAndroid)) {
+ return;
+ }
+
+ PointerLocker = Locker.inherit((function () {
+ return {
+
+ _scroll() {
+ this._locked = true;
+
+ const that = this;
+ cancelAnimationFrame(this._scrollFrame);
+ this._scrollFrame = requestAnimationFrame(() => {
+ that._locked = false;
+ });
+ },
+
+ check(e, callback) {
+ cancelAnimationFrame(this._scrollFrame);
+ cancelAnimationFrame(this._checkFrame);
+
+ const that = this;
+ const { callBase } = this;
+ this._checkFrame = requestAnimationFrame(() => {
+ callBase.call(that, e, callback);
+
+ that._locked = false;
+ });
+ },
+
+ dispose() {
+ this.callBase();
+
+ cancelAnimationFrame(this._scrollFrame);
+ cancelAnimationFrame(this._checkFrame);
+ },
+
+ };
+ })());
+}());
+
+const ScrollEmitter = GestureEmitter.inherit((function () {
+ const INERTIA_TIMEOUT = 100;
+ const VELOCITY_CALC_TIMEOUT = 200;
+ const FRAME_DURATION = Math.round(1000 / 60);
+
+ return {
+
+ ctor(element) {
+ this.callBase.apply(this, arguments);
+ this.direction = 'both';
+
+ this._pointerLocker = new PointerLocker(element);
+ this._wheelLocker = new WheelLocker(element);
+ },
+
+ validate() {
+ return true;
+ },
+
+ configure(data) {
+ if (data.scrollTarget) {
+ this._pointerLocker.dispose();
+ this._wheelLocker.dispose();
+ this._pointerLocker = new PointerLocker(data.scrollTarget);
+ this._wheelLocker = new WheelLocker(data.scrollTarget);
+ }
+
+ this.callBase(data);
+ },
+
+ _init(e) {
+ this._wheelLocker.check(e, () => {
+ if (isDxMouseWheelEvent(e)) {
+ this._accept(e);
+ }
+ });
+
+ this._pointerLocker.check(e, () => {
+ const skipCheck = this.isNative && isMouseEvent(e);
+ if (!isDxMouseWheelEvent(e) && !skipCheck) {
+ this._accept(e);
+ }
+ });
+
+ this._fireEvent(SCROLL_INIT_EVENT, e);
+
+ this._prevEventData = eventData(e);
+ },
+
+ move(e) {
+ this.callBase.apply(this, arguments);
+
+ e.isScrollingEvent = this.isNative || e.isScrollingEvent;
+ },
+
+ _start(e) {
+ this._savedEventData = eventData(e);
+
+ this._fireEvent(SCROLL_START_EVENT, e);
+
+ this._prevEventData = eventData(e);
+ },
+
+ _move(e) {
+ const currentEventData: any = eventData(e);
+
+ this._fireEvent(SCROLL_MOVE_EVENT, e, {
+ delta: eventDelta(this._prevEventData, currentEventData),
+ });
+
+ const delta = eventDelta(this._savedEventData, currentEventData);
+ if (delta.time > VELOCITY_CALC_TIMEOUT) {
+ this._savedEventData = this._prevEventData;
+ }
+
+ this._prevEventData = eventData(e);
+ },
+
+ _end(e) {
+ // @ts-expect-error
+ const endEventDelta = eventDelta(this._prevEventData, eventData(e));
+ let velocity = { x: 0, y: 0 };
+
+ if (!isDxMouseWheelEvent(e) && endEventDelta.time < INERTIA_TIMEOUT) {
+ const delta = eventDelta(this._savedEventData, this._prevEventData);
+ const velocityMultiplier = FRAME_DURATION / delta.time;
+
+ velocity = { x: delta.x * velocityMultiplier, y: delta.y * velocityMultiplier };
+ }
+
+ this._fireEvent(SCROLL_END_EVENT, e, {
+ velocity,
+ });
+ },
+
+ _stop(e) {
+ this._fireEvent(SCROLL_STOP_EVENT, e);
+ },
+
+ cancel(e) {
+ this.callBase.apply(this, arguments);
+
+ this._fireEvent(SCROLL_CANCEL_EVENT, e);
+ },
+
+ dispose() {
+ this.callBase.apply(this, arguments);
+
+ this._pointerLocker.dispose();
+ this._wheelLocker.dispose();
+ },
+
+ _clearSelection() {
+ if (this.isNative) {
+ return;
+ }
+
+ return this.callBase.apply(this, arguments);
+ },
+
+ _toggleGestureCover() {
+ if (this.isNative) {
+ return;
+ }
+
+ return this.callBase.apply(this, arguments);
+ },
+
+ };
+})());
+
+registerEmitter({
+ emitter: ScrollEmitter,
+ events: [
+ SCROLL_INIT_EVENT,
+ SCROLL_START_EVENT,
+ SCROLL_MOVE_EVENT,
+ SCROLL_END_EVENT,
+ SCROLL_STOP_EVENT,
+ SCROLL_CANCEL_EVENT,
+ ],
+});
+
+export default {
+ init: SCROLL_INIT_EVENT,
+ start: SCROLL_START_EVENT,
+ move: SCROLL_MOVE_EVENT,
+ end: SCROLL_END_EVENT,
+ stop: SCROLL_STOP_EVENT,
+ cancel: SCROLL_CANCEL_EVENT,
+ scroll: SCROLL_EVENT,
+};
diff --git a/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.ts b/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.ts
new file mode 100644
index 000000000000..b74fd5ff811b
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/gesture/m_emitter.gesture.ts
@@ -0,0 +1,244 @@
+import devices from '@js/core/devices';
+import $ from '@js/core/renderer';
+import callOnce from '@js/core/utils/call_once';
+import { noop } from '@js/core/utils/common';
+import { clearSelection, resetActiveElement } from '@js/core/utils/dom';
+import { sign } from '@js/core/utils/math';
+import readyCallbacks from '@js/core/utils/ready_callbacks';
+import { styleProp } from '@js/core/utils/style';
+import { isDefined } from '@js/core/utils/type';
+import Emitter from '@js/events/core/emitter';
+import eventsEngine from '@js/events/core/events_engine';
+import {
+ createEvent, eventData, eventDelta, isDxMouseWheelEvent, isTouchEvent, needSkipEvent,
+} from '@js/events/utils/index';
+
+const ready = readyCallbacks.add;
+const { abs } = Math;
+
+const SLEEP = 0;
+const INITED = 1;
+const STARTED = 2;
+
+let TOUCH_BOUNDARY = 10;
+const IMMEDIATE_TOUCH_BOUNDARY = 0;
+const IMMEDIATE_TIMEOUT = 180;
+
+const supportPointerEvents = function () {
+ return styleProp('pointer-events');
+};
+
+const setGestureCover = callOnce(() => {
+ const GESTURE_COVER_CLASS = 'dx-gesture-cover';
+
+ const isDesktop = devices.real().deviceType === 'desktop';
+
+ if (!supportPointerEvents() || !isDesktop) {
+ return noop;
+ }
+
+ const $cover = $('
')
+ .addClass(GESTURE_COVER_CLASS)
+ .css('pointerEvents', 'none');
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal($cover, 'dxmousewheel', (e) => {
+ e.preventDefault();
+ });
+
+ ready(() => {
+ // @ts-expect-error
+ $cover.appendTo('body');
+ });
+
+ return function (toggle, cursor) {
+ $cover.css('pointerEvents', toggle ? 'all' : 'none');
+ toggle && $cover.css('cursor', cursor);
+ };
+});
+
+const gestureCover = function (toggle, cursor) {
+ const gestureCoverStrategy = setGestureCover();
+ gestureCoverStrategy(toggle, cursor);
+};
+
+const GestureEmitter = Emitter.inherit({
+
+ gesture: true,
+
+ configure(data) {
+ this.getElement().css('msTouchAction', data.immediate ? 'pinch-zoom' : '');
+
+ this.callBase(data);
+ },
+
+ allowInterruptionByMouseWheel() {
+ return this._stage !== STARTED;
+ },
+
+ getDirection() {
+ return this.direction;
+ },
+
+ _cancel() {
+ this.callBase.apply(this, arguments);
+
+ this._toggleGestureCover(false);
+ this._stage = SLEEP;
+ },
+
+ start(e) {
+ if (e._needSkipEvent || needSkipEvent(e)) {
+ this._cancel(e);
+ return;
+ }
+
+ this._startEvent = createEvent(e);
+ this._startEventData = eventData(e);
+
+ this._stage = INITED;
+ this._init(e);
+
+ this._setupImmediateTimer();
+ },
+
+ _setupImmediateTimer() {
+ clearTimeout(this._immediateTimer);
+ this._immediateAccepted = false;
+
+ if (!this.immediate) {
+ return;
+ }
+
+ if (this.immediateTimeout === 0) {
+ this._immediateAccepted = true;
+ return;
+ }
+
+ this._immediateTimer = setTimeout(() => {
+ this._immediateAccepted = true;
+ }, this.immediateTimeout ?? IMMEDIATE_TIMEOUT);
+ },
+
+ move(e) {
+ if (this._stage === INITED && this._directionConfirmed(e)) {
+ this._stage = STARTED;
+
+ this._resetActiveElement();
+ this._toggleGestureCover(true);
+ this._clearSelection(e);
+
+ this._adjustStartEvent(e);
+ this._start(this._startEvent);
+
+ if (this._stage === SLEEP) {
+ return;
+ }
+
+ this._requestAccept(e);
+ this._move(e);
+ this._forgetAccept();
+ } else if (this._stage === STARTED) {
+ this._clearSelection(e);
+ this._move(e);
+ }
+ },
+
+ _directionConfirmed(e) {
+ const touchBoundary = this._getTouchBoundary(e);
+ // @ts-expect-error
+ const delta = eventDelta(this._startEventData, eventData(e));
+ const deltaX = abs(delta.x);
+ const deltaY = abs(delta.y);
+
+ const horizontalMove = this._validateMove(touchBoundary, deltaX, deltaY);
+ const verticalMove = this._validateMove(touchBoundary, deltaY, deltaX);
+
+ const direction = this.getDirection(e);
+ const bothAccepted = direction === 'both' && (horizontalMove || verticalMove);
+ const horizontalAccepted = direction === 'horizontal' && horizontalMove;
+ const verticalAccepted = direction === 'vertical' && verticalMove;
+
+ return bothAccepted || horizontalAccepted || verticalAccepted || this._immediateAccepted;
+ },
+
+ _validateMove(touchBoundary, mainAxis, crossAxis) {
+ return mainAxis && mainAxis >= touchBoundary && (this.immediate ? mainAxis >= crossAxis : true);
+ },
+
+ _getTouchBoundary(e) {
+ return this.immediate || isDxMouseWheelEvent(e) ? IMMEDIATE_TOUCH_BOUNDARY : TOUCH_BOUNDARY;
+ },
+
+ _adjustStartEvent(e) {
+ const touchBoundary = this._getTouchBoundary(e);
+ // @ts-expect-error
+ const delta = eventDelta(this._startEventData, eventData(e));
+
+ this._startEvent.pageX += sign(delta.x) * touchBoundary;
+ this._startEvent.pageY += sign(delta.y) * touchBoundary;
+ },
+
+ _resetActiveElement() {
+ if (devices.real().platform === 'ios' && this.getElement().find(':focus').length) {
+ resetActiveElement();
+ }
+ },
+
+ _toggleGestureCover(toggle) {
+ this._toggleGestureCoverImpl(toggle);
+ },
+
+ _toggleGestureCoverImpl(toggle) {
+ const isStarted = this._stage === STARTED;
+
+ if (isStarted) {
+ gestureCover(toggle, this.getElement().css('cursor'));
+ }
+ },
+
+ _clearSelection(e) {
+ if (isDxMouseWheelEvent(e) || isTouchEvent(e)) {
+ return;
+ }
+
+ clearSelection();
+ },
+
+ end(e) {
+ this._toggleGestureCover(false);
+
+ if (this._stage === STARTED) {
+ this._end(e);
+ } else if (this._stage === INITED) {
+ this._stop(e);
+ }
+
+ this._stage = SLEEP;
+ },
+
+ dispose() {
+ clearTimeout(this._immediateTimer);
+ this.callBase.apply(this, arguments);
+ this._toggleGestureCover(false);
+ },
+
+ _init: noop,
+ _start: noop,
+ _move: noop,
+ _stop: noop,
+ _end: noop,
+
+});
+// @ts-expect-error
+GestureEmitter.initialTouchBoundary = TOUCH_BOUNDARY;
+// @ts-expect-error
+GestureEmitter.touchBoundary = function (newBoundary) {
+ if (isDefined(newBoundary)) {
+ TOUCH_BOUNDARY = newBoundary;
+ return;
+ }
+
+ return TOUCH_BOUNDARY;
+};
+
+export default GestureEmitter;
diff --git a/packages/devextreme/js/__internal/events/gesture/m_swipeable.ts b/packages/devextreme/js/__internal/events/gesture/m_swipeable.ts
new file mode 100644
index 000000000000..4ba1540119cd
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/gesture/m_swipeable.ts
@@ -0,0 +1,110 @@
+import DOMComponent from '@js/core/dom_component';
+import { extend } from '@js/core/utils/extend';
+import { each } from '@js/core/utils/iterator';
+import { name } from '@js/core/utils/public_component';
+import eventsEngine from '@js/events/core/events_engine';
+import {
+ end as swipeEventEnd,
+ start as swipeEventStart,
+ swipe as swipeEventSwipe,
+} from '@js/events/swipe';
+import { addNamespace } from '@js/events/utils/index';
+
+const DX_SWIPEABLE = 'dxSwipeable';
+const SWIPEABLE_CLASS = 'dx-swipeable';
+
+const ACTION_TO_EVENT_MAP = {
+ onStart: swipeEventStart,
+ onUpdated: swipeEventSwipe,
+ onEnd: swipeEventEnd,
+ onCancel: 'dxswipecancel',
+};
+
+const IMMEDIATE_TIMEOUT = 180;
+// @ts-expect-error
+const Swipeable = DOMComponent.inherit({
+
+ _getDefaultOptions() {
+ return extend(this.callBase(), {
+ elastic: true,
+ immediate: false,
+ immediateTimeout: IMMEDIATE_TIMEOUT,
+ direction: 'horizontal',
+ itemSizeFunc: null,
+ onStart: null,
+ onUpdated: null,
+ onEnd: null,
+ onCancel: null,
+ });
+ },
+
+ _render() {
+ this.callBase();
+
+ this.$element().addClass(SWIPEABLE_CLASS);
+ this._attachEventHandlers();
+ },
+
+ _attachEventHandlers() {
+ this._detachEventHandlers();
+
+ if (this.option('disabled')) {
+ return;
+ }
+
+ const { NAME } = this;
+
+ this._createEventData();
+
+ each(ACTION_TO_EVENT_MAP, (actionName, eventName) => {
+ const action = this._createActionByOption(actionName, { context: this });
+
+ eventName = addNamespace(eventName, NAME);
+
+ eventsEngine.on(this.$element(), eventName, this._eventData, (e) => action({ event: e }));
+ });
+ },
+
+ _createEventData() {
+ this._eventData = {
+ elastic: this.option('elastic'),
+ itemSizeFunc: this.option('itemSizeFunc'),
+ direction: this.option('direction'),
+ immediate: this.option('immediate'),
+ immediateTimeout: this.option('immediateTimeout'),
+ };
+ },
+
+ _detachEventHandlers() {
+ eventsEngine.off(this.$element(), `.${DX_SWIPEABLE}`);
+ },
+
+ _optionChanged(args) {
+ switch (args.name) {
+ case 'disabled':
+ case 'onStart':
+ case 'onUpdated':
+ case 'onEnd':
+ case 'onCancel':
+ case 'elastic':
+ case 'immediate':
+ case 'itemSizeFunc':
+ case 'direction':
+ this._detachEventHandlers();
+ this._attachEventHandlers();
+ break;
+ case 'rtlEnabled':
+ break;
+ default:
+ this.callBase(args);
+ }
+ },
+
+ _useTemplates() {
+ return false;
+ },
+});
+
+name(Swipeable, DX_SWIPEABLE);
+
+export default Swipeable;
diff --git a/packages/devextreme/js/__internal/events/m_click.ts b/packages/devextreme/js/__internal/events/m_click.ts
new file mode 100644
index 000000000000..adbe5737fb8c
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_click.ts
@@ -0,0 +1,122 @@
+import { cancelAnimationFrame, requestAnimationFrame } from '@js/animation/frame';
+import devices from '@js/core/devices';
+import domAdapter from '@js/core/dom_adapter';
+import $ from '@js/core/renderer';
+import { resetActiveElement } from '@js/core/utils/dom';
+import Emitter from '@js/events/core/emitter';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import pointerEvents from '@js/events/pointer';
+import { subscribeNodesDisposing, unsubscribeNodesDisposing } from '@js/events/utils/event_nodes_disposing';
+import { getEventTarget } from '@js/events/utils/event_target';
+import { addNamespace, fireEvent } from '@js/events/utils/index';
+
+const CLICK_EVENT_NAME = 'dxclick';
+
+const misc = { requestAnimationFrame, cancelAnimationFrame };
+
+let prevented: boolean | null = null;
+let lastFiredEvent = null;
+
+const onNodeRemove = () => {
+ lastFiredEvent = null;
+};
+
+const clickHandler = function (e) {
+ const { originalEvent } = e;
+ const eventAlreadyFired = lastFiredEvent === originalEvent || originalEvent && originalEvent.DXCLICK_FIRED;
+ const leftButton = !e.which || e.which === 1;
+
+ if (leftButton && !prevented && !eventAlreadyFired) {
+ if (originalEvent) {
+ originalEvent.DXCLICK_FIRED = true;
+ }
+
+ unsubscribeNodesDisposing(lastFiredEvent, onNodeRemove);
+ lastFiredEvent = originalEvent;
+ subscribeNodesDisposing(lastFiredEvent, onNodeRemove);
+
+ fireEvent({
+ type: CLICK_EVENT_NAME,
+ originalEvent: e,
+ });
+ }
+};
+
+const ClickEmitter = Emitter.inherit({
+
+ ctor(element) {
+ this.callBase(element);
+ eventsEngine.on(this.getElement(), 'click', clickHandler);
+ },
+
+ start() {
+ prevented = null;
+ },
+
+ cancel() {
+ prevented = true;
+ },
+
+ dispose() {
+ eventsEngine.off(this.getElement(), 'click', clickHandler);
+ },
+});
+
+// NOTE: fixes native click blur on slow devices
+(function () {
+ const desktopDevice = devices.real().generic;
+
+ if (!desktopDevice) {
+ let startTarget = null;
+ let blurPrevented = false;
+
+ const isInput = function (element) {
+ return $(element).is('input, textarea, select, button ,:focus, :focus *');
+ };
+
+ const pointerDownHandler = function (e) {
+ startTarget = e.target;
+ blurPrevented = e.isDefaultPrevented();
+ };
+
+ const getTarget = function (e) {
+ const target = getEventTarget(e);
+ return $(target);
+ };
+
+ const clickHandler = function (e) {
+ const $target = getTarget(e);
+
+ if (!blurPrevented && startTarget && !$target.is(startTarget) && !$(startTarget).is('label') && isInput($target)) {
+ resetActiveElement();
+ }
+
+ startTarget = null;
+ blurPrevented = false;
+ };
+
+ const NATIVE_CLICK_FIXER_NAMESPACE = 'NATIVE_CLICK_FIXER';
+ const document = domAdapter.getDocument();
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.down, NATIVE_CLICK_FIXER_NAMESPACE), pointerDownHandler);
+ // @ts-expect-error
+ eventsEngine.subscribeGlobal(document, addNamespace('click', NATIVE_CLICK_FIXER_NAMESPACE), clickHandler);
+ }
+}());
+
+registerEmitter({
+ emitter: ClickEmitter,
+ bubble: true,
+ events: [
+ CLICK_EVENT_NAME,
+ ],
+});
+
+export { CLICK_EVENT_NAME as name };
+
+/// #DEBUG
+export {
+ misc,
+};
+/// #ENDDEBUG
diff --git a/packages/devextreme/js/__internal/events/m_contextmenu.ts b/packages/devextreme/js/__internal/events/m_contextmenu.ts
new file mode 100644
index 000000000000..958534cfd4d8
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_contextmenu.ts
@@ -0,0 +1,56 @@
+import Class from '@js/core/class';
+import devices from '@js/core/devices';
+import $ from '@js/core/renderer';
+import { touch } from '@js/core/utils/support';
+import registerEvent from '@js/events/core/event_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import holdEvent from '@js/events/hold';
+import { addNamespace, fireEvent, isMouseEvent } from '@js/events/utils/index';
+
+const CONTEXTMENU_NAMESPACE = 'dxContexMenu';
+
+const CONTEXTMENU_NAMESPACED_EVENT_NAME = addNamespace('contextmenu', CONTEXTMENU_NAMESPACE);
+const HOLD_NAMESPACED_EVENT_NAME = addNamespace(holdEvent.name, CONTEXTMENU_NAMESPACE);
+
+const CONTEXTMENU_EVENT_NAME = 'dxcontextmenu';
+
+const ContextMenu = Class.inherit({
+
+ setup(element) {
+ const $element = $(element);
+
+ eventsEngine.on($element, CONTEXTMENU_NAMESPACED_EVENT_NAME, this._contextMenuHandler.bind(this));
+
+ if (touch || devices.isSimulator()) {
+ eventsEngine.on($element, HOLD_NAMESPACED_EVENT_NAME, this._holdHandler.bind(this));
+ }
+ },
+
+ _holdHandler(e) {
+ if (isMouseEvent(e) && !devices.isSimulator()) {
+ return;
+ }
+
+ this._fireContextMenu(e);
+ },
+
+ _contextMenuHandler(e) {
+ this._fireContextMenu(e);
+ },
+
+ _fireContextMenu(e) {
+ return fireEvent({
+ type: CONTEXTMENU_EVENT_NAME,
+ originalEvent: e,
+ });
+ },
+
+ teardown(element) {
+ eventsEngine.off(element, `.${CONTEXTMENU_NAMESPACE}`);
+ },
+
+});
+
+registerEvent(CONTEXTMENU_EVENT_NAME, new ContextMenu());
+
+export const name = CONTEXTMENU_EVENT_NAME;
diff --git a/packages/devextreme/js/__internal/events/dblclick.ts b/packages/devextreme/js/__internal/events/m_dblclick.ts
similarity index 100%
rename from packages/devextreme/js/__internal/events/dblclick.ts
rename to packages/devextreme/js/__internal/events/m_dblclick.ts
diff --git a/packages/devextreme/js/__internal/events/m_drag.ts b/packages/devextreme/js/__internal/events/m_drag.ts
new file mode 100644
index 000000000000..952dd4b7f624
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_drag.ts
@@ -0,0 +1,311 @@
+import { data as elementData, removeData } from '@js/core/element_data';
+import $ from '@js/core/renderer';
+import { wrapToArray } from '@js/core/utils/array';
+import { contains } from '@js/core/utils/dom';
+import * as iteratorUtils from '@js/core/utils/iterator';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import registerEvent from '@js/events/core/event_registrator';
+import GestureEmitter from '@js/events/gesture/emitter.gesture';
+import { eventData as eData, fireEvent } from '@js/events/utils/index';
+
+const DRAG_START_EVENT = 'dxdragstart';
+const DRAG_EVENT = 'dxdrag';
+const DRAG_END_EVENT = 'dxdragend';
+
+const DRAG_ENTER_EVENT = 'dxdragenter';
+const DRAG_LEAVE_EVENT = 'dxdragleave';
+const DROP_EVENT = 'dxdrop';
+
+const DX_DRAG_EVENTS_COUNT_KEY = 'dxDragEventsCount';
+
+const knownDropTargets: Element[] = [];
+const knownDropTargetSelectors: any[] = [];
+const knownDropTargetConfigs: any[] = [];
+
+const dropTargetRegistration = {
+
+ setup(element, data) {
+ const knownDropTarget = knownDropTargets.includes(element);
+ if (!knownDropTarget) {
+ knownDropTargets.push(element);
+ knownDropTargetSelectors.push([]);
+ knownDropTargetConfigs.push(data || {});
+ }
+ },
+
+ add(element, handleObj) {
+ const index = knownDropTargets.indexOf(element);
+ this.updateEventsCounter(element, handleObj.type, 1);
+
+ const { selector } = handleObj;
+ if (!knownDropTargetSelectors[index].includes(selector)) {
+ knownDropTargetSelectors[index].push(selector);
+ }
+ },
+
+ updateEventsCounter(element, event, value) {
+ if ([DRAG_ENTER_EVENT, DRAG_LEAVE_EVENT, DROP_EVENT].includes(event)) {
+ const eventsCount = elementData(element, DX_DRAG_EVENTS_COUNT_KEY) || 0;
+ elementData(element, DX_DRAG_EVENTS_COUNT_KEY, Math.max(0, eventsCount + value));
+ }
+ },
+
+ remove(element, handleObj) {
+ this.updateEventsCounter(element, handleObj.type, -1);
+ },
+
+ teardown(element) {
+ const handlersCount = elementData(element, DX_DRAG_EVENTS_COUNT_KEY);
+ if (!handlersCount) {
+ const index = knownDropTargets.indexOf(element);
+ knownDropTargets.splice(index, 1);
+ knownDropTargetSelectors.splice(index, 1);
+ knownDropTargetConfigs.splice(index, 1);
+ removeData(element, DX_DRAG_EVENTS_COUNT_KEY);
+ }
+ },
+
+};
+
+registerEvent(DRAG_ENTER_EVENT, dropTargetRegistration);
+registerEvent(DRAG_LEAVE_EVENT, dropTargetRegistration);
+registerEvent(DROP_EVENT, dropTargetRegistration);
+
+const getItemDelegatedTargets = function ($element) {
+ const dropTargetIndex = knownDropTargets.indexOf($element.get(0));
+ const dropTargetSelectors = knownDropTargetSelectors[dropTargetIndex].filter((selector) => selector);
+
+ let $delegatedTargets = $element.find(dropTargetSelectors.join(', '));
+ if (knownDropTargetSelectors[dropTargetIndex].includes(undefined)) {
+ $delegatedTargets = $delegatedTargets.add($element);
+ }
+ return $delegatedTargets;
+};
+
+const getItemConfig = function ($element) {
+ const dropTargetIndex = knownDropTargets.indexOf($element.get(0));
+ return knownDropTargetConfigs[dropTargetIndex];
+};
+
+const getItemPosition = function (dropTargetConfig, $element) {
+ if (dropTargetConfig.itemPositionFunc) {
+ return dropTargetConfig.itemPositionFunc($element);
+ }
+ return $element.offset();
+};
+
+const getItemSize = function (dropTargetConfig, $element) {
+ if (dropTargetConfig.itemSizeFunc) {
+ return dropTargetConfig.itemSizeFunc($element);
+ }
+
+ return {
+ width: $element.get(0).getBoundingClientRect().width,
+ height: $element.get(0).getBoundingClientRect().height,
+ };
+};
+
+const DragEmitter = GestureEmitter.inherit({
+
+ ctor(element) {
+ this.callBase(element);
+
+ this.direction = 'both';
+ },
+
+ _init(e) {
+ this._initEvent = e;
+ },
+
+ _start(e) {
+ e = this._fireEvent(DRAG_START_EVENT, this._initEvent);
+
+ this._maxLeftOffset = e.maxLeftOffset;
+ this._maxRightOffset = e.maxRightOffset;
+ this._maxTopOffset = e.maxTopOffset;
+ this._maxBottomOffset = e.maxBottomOffset;
+
+ if (e.targetElements || e.targetElements === null) {
+ const dropTargets = wrapToArray(e.targetElements || []);
+ this._dropTargets = iteratorUtils.map(dropTargets, (element) => $(element).get(0));
+ } else {
+ this._dropTargets = knownDropTargets;
+ }
+ },
+
+ _move(e) {
+ const eventData = eData(e);
+ const dragOffset = this._calculateOffset(eventData);
+
+ e = this._fireEvent(DRAG_EVENT, e, {
+ offset: dragOffset,
+ });
+
+ this._processDropTargets(e);
+
+ if (!e._cancelPreventDefault) {
+ e.preventDefault();
+ }
+ },
+
+ _calculateOffset(eventData) {
+ return {
+ x: this._calculateXOffset(eventData),
+ y: this._calculateYOffset(eventData),
+ };
+ },
+
+ _calculateXOffset(eventData) {
+ if (this.direction !== 'vertical') {
+ const offset = eventData.x - this._startEventData.x;
+
+ return this._fitOffset(offset, this._maxLeftOffset, this._maxRightOffset);
+ }
+ return 0;
+ },
+
+ _calculateYOffset(eventData) {
+ if (this.direction !== 'horizontal') {
+ const offset = eventData.y - this._startEventData.y;
+
+ return this._fitOffset(offset, this._maxTopOffset, this._maxBottomOffset);
+ }
+ return 0;
+ },
+
+ _fitOffset(offset, minOffset, maxOffset) {
+ if (minOffset != null) {
+ offset = Math.max(offset, -minOffset);
+ }
+ if (maxOffset != null) {
+ offset = Math.min(offset, maxOffset);
+ }
+
+ return offset;
+ },
+
+ _processDropTargets(e) {
+ const target = this._findDropTarget(e);
+ const sameTarget = target === this._currentDropTarget;
+
+ if (!sameTarget) {
+ this._fireDropTargetEvent(e, DRAG_LEAVE_EVENT);
+ this._currentDropTarget = target;
+ this._fireDropTargetEvent(e, DRAG_ENTER_EVENT);
+ }
+ },
+
+ _fireDropTargetEvent(event, eventName) {
+ if (!this._currentDropTarget) {
+ return;
+ }
+
+ const eventData = {
+ type: eventName,
+ originalEvent: event,
+ draggingElement: this._$element.get(0),
+ target: this._currentDropTarget,
+ };
+
+ fireEvent(eventData);
+ },
+
+ _findDropTarget(e) {
+ const that = this;
+ let result;
+
+ iteratorUtils.each(knownDropTargets, (_, target) => {
+ if (!that._checkDropTargetActive(target)) {
+ return;
+ }
+
+ const $target = $(target);
+ iteratorUtils.each(getItemDelegatedTargets($target), (_, delegatedTarget) => {
+ const $delegatedTarget = $(delegatedTarget);
+ if (that._checkDropTarget(getItemConfig($target), $delegatedTarget, $(result), e)) {
+ result = delegatedTarget;
+ }
+ });
+ });
+
+ return result;
+ },
+
+ _checkDropTargetActive(target) {
+ let active = false;
+
+ iteratorUtils.each(this._dropTargets, (_, activeTarget) => {
+ active = active || activeTarget === target || contains(activeTarget, target);
+ return !active;
+ });
+
+ return active;
+ },
+
+ _checkDropTarget(config, $target, $prevTarget, e) {
+ const isDraggingElement = $target.get(0) === $(e.target).get(0);
+ if (isDraggingElement) {
+ return false;
+ }
+
+ const targetPosition = getItemPosition(config, $target);
+ if (e.pageX < targetPosition.left) {
+ return false;
+ }
+ if (e.pageY < targetPosition.top) {
+ return false;
+ }
+
+ const targetSize = getItemSize(config, $target);
+ if (e.pageX > targetPosition.left + targetSize.width) {
+ return false;
+ }
+ if (e.pageY > targetPosition.top + targetSize.height) {
+ return false;
+ }
+
+ if ($prevTarget.length && $prevTarget.closest($target).length) {
+ return false;
+ }
+
+ if (config.checkDropTarget && !config.checkDropTarget($target, e)) {
+ return false;
+ }
+
+ return $target;
+ },
+
+ _end(e) {
+ const eventData = eData(e);
+
+ this._fireEvent(DRAG_END_EVENT, e, {
+ offset: this._calculateOffset(eventData),
+ });
+
+ this._fireDropTargetEvent(e, DROP_EVENT);
+ delete this._currentDropTarget;
+ },
+
+});
+
+registerEmitter({
+ emitter: DragEmitter,
+ events: [
+ DRAG_START_EVENT,
+ DRAG_EVENT,
+ DRAG_END_EVENT,
+ ],
+});
+
+/// #DEBUG
+export { knownDropTargets as dropTargets };
+/// #ENDDEBUG
+
+export {
+ DROP_EVENT as drop,
+ DRAG_END_EVENT as end,
+ DRAG_ENTER_EVENT as enter,
+ DRAG_LEAVE_EVENT as leave,
+ DRAG_EVENT as move,
+ DRAG_START_EVENT as start,
+};
diff --git a/packages/devextreme/js/__internal/events/m_hold.ts b/packages/devextreme/js/__internal/events/m_hold.ts
new file mode 100644
index 000000000000..f5fb13543588
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_hold.ts
@@ -0,0 +1,71 @@
+import Emitter from '@js/events/core/emitter';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import { eventData, eventDelta } from '@js/events/utils/index';
+
+const { abs } = Math;
+
+const HOLD_EVENT_NAME = 'dxhold';
+const HOLD_TIMEOUT = 750;
+const TOUCH_BOUNDARY = 5;
+
+const HoldEmitter = Emitter.inherit({
+
+ start(e) {
+ this._startEventData = eventData(e);
+
+ this._startTimer(e);
+ },
+
+ _startTimer(e) {
+ const holdTimeout = 'timeout' in this ? this.timeout : HOLD_TIMEOUT;
+ this._holdTimer = setTimeout(() => {
+ this._requestAccept(e);
+ this._fireEvent(HOLD_EVENT_NAME, e, {
+ target: e.target,
+ });
+ this._forgetAccept();
+ }, holdTimeout);
+ },
+
+ move(e) {
+ if (this._touchWasMoved(e)) {
+ this._cancel(e);
+ }
+ },
+
+ _touchWasMoved(e) {
+ // @ts-expect-error
+ const delta = eventDelta(this._startEventData, eventData(e));
+
+ return abs(delta.x) > TOUCH_BOUNDARY || abs(delta.y) > TOUCH_BOUNDARY;
+ },
+
+ end() {
+ this._stopTimer();
+ },
+
+ _stopTimer() {
+ clearTimeout(this._holdTimer);
+ },
+
+ cancel() {
+ this._stopTimer();
+ },
+
+ dispose() {
+ this._stopTimer();
+ },
+
+});
+
+registerEmitter({
+ emitter: HoldEmitter,
+ bubble: true,
+ events: [
+ HOLD_EVENT_NAME,
+ ],
+});
+
+export default {
+ name: HOLD_EVENT_NAME,
+};
diff --git a/packages/devextreme/js/__internal/events/m_hover.ts b/packages/devextreme/js/__internal/events/m_hover.ts
new file mode 100644
index 000000000000..d28353334c2b
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_hover.ts
@@ -0,0 +1,98 @@
+import Class from '@js/core/class';
+import devices from '@js/core/devices';
+import { data as elementData, removeData } from '@js/core/element_data';
+import registerEvent from '@js/events/core/event_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+import pointerEvents from '@js/events/pointer';
+import { addNamespace, fireEvent, isTouchEvent } from '@js/events/utils/index';
+
+const HOVERSTART_NAMESPACE = 'dxHoverStart';
+const HOVERSTART = 'dxhoverstart';
+const POINTERENTER_NAMESPACED_EVENT_NAME = addNamespace(pointerEvents.enter, HOVERSTART_NAMESPACE);
+
+const HOVEREND_NAMESPACE = 'dxHoverEnd';
+const HOVEREND = 'dxhoverend';
+const POINTERLEAVE_NAMESPACED_EVENT_NAME = addNamespace(pointerEvents.leave, HOVEREND_NAMESPACE);
+
+const Hover = Class.inherit({
+
+ noBubble: true,
+
+ ctor() {
+ this._handlerArrayKeyPath = `${this._eventNamespace}_HandlerStore`;
+ },
+
+ setup(element) {
+ elementData(element, this._handlerArrayKeyPath, {});
+ },
+
+ add(element, handleObj) {
+ const that = this;
+ const handler = function (e) {
+ that._handler(e);
+ };
+
+ eventsEngine.on(element, this._originalEventName, handleObj.selector, handler);
+ elementData(element, this._handlerArrayKeyPath)[handleObj.guid] = handler;
+ },
+
+ _handler(e) {
+ if (isTouchEvent(e) || devices.isSimulator()) {
+ return;
+ }
+
+ fireEvent({
+ type: this._eventName,
+ originalEvent: e,
+ delegateTarget: e.delegateTarget,
+ });
+ },
+
+ remove(element, handleObj) {
+ const handler = elementData(element, this._handlerArrayKeyPath)[handleObj.guid];
+ // @ts-expect-error
+ eventsEngine.off(element, this._originalEventName, handleObj.selector, handler);
+ },
+
+ teardown(element) {
+ removeData(element, this._handlerArrayKeyPath);
+ },
+
+});
+
+const HoverStart = Hover.inherit({
+
+ ctor() {
+ this._eventNamespace = HOVERSTART_NAMESPACE;
+ this._eventName = HOVERSTART;
+ this._originalEventName = POINTERENTER_NAMESPACED_EVENT_NAME;
+ this.callBase();
+ },
+
+ _handler(e) {
+ const pointers = e.pointers || [];
+ if (!pointers.length) {
+ this.callBase(e);
+ }
+ },
+
+});
+
+const HoverEnd = Hover.inherit({
+
+ ctor() {
+ this._eventNamespace = HOVEREND_NAMESPACE;
+ this._eventName = HOVEREND;
+ this._originalEventName = POINTERLEAVE_NAMESPACED_EVENT_NAME;
+ this.callBase();
+ },
+
+});
+
+registerEvent(HOVERSTART, new HoverStart());
+registerEvent(HOVEREND, new HoverEnd());
+
+export {
+ HOVEREND as end,
+ HOVERSTART as start,
+};
diff --git a/packages/devextreme/js/__internal/events/m_pointer.ts b/packages/devextreme/js/__internal/events/m_pointer.ts
new file mode 100644
index 000000000000..7b1f09b1aae5
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_pointer.ts
@@ -0,0 +1,62 @@
+import GlobalConfig from '@js/core/config';
+import devices from '@js/core/devices';
+import { each } from '@js/core/utils/iterator';
+import * as support from '@js/core/utils/support';
+import registerEvent from '@js/events/core/event_registrator';
+import MouseStrategy from '@js/events/pointer/mouse';
+import MouseAndTouchStrategy from '@js/events/pointer/mouse_and_touch';
+import TouchStrategy from '@js/events/pointer/touch';
+
+const getStrategy = (support, { tablet, phone }) => {
+ const pointerEventStrategy = getStrategyFromGlobalConfig();
+
+ if (pointerEventStrategy) {
+ return pointerEventStrategy;
+ }
+
+ if (support.touch && !(tablet || phone)) {
+ return MouseAndTouchStrategy;
+ }
+
+ if (support.touch) {
+ return TouchStrategy;
+ }
+
+ return MouseStrategy;
+};
+// @ts-expect-error
+const EventStrategy = getStrategy(support, devices.real());
+
+each(EventStrategy.map, (pointerEvent, originalEvents) => {
+ registerEvent(pointerEvent, new EventStrategy(pointerEvent, originalEvents));
+});
+
+const pointer = {
+ down: 'dxpointerdown',
+ up: 'dxpointerup',
+ move: 'dxpointermove',
+ cancel: 'dxpointercancel',
+ enter: 'dxpointerenter',
+ leave: 'dxpointerleave',
+ over: 'dxpointerover',
+ out: 'dxpointerout',
+};
+
+function getStrategyFromGlobalConfig() {
+ const eventStrategyName = GlobalConfig().pointerEventStrategy;
+
+ return {
+ 'mouse-and-touch': MouseAndTouchStrategy,
+ touch: TouchStrategy,
+ mouse: MouseStrategy,
+ // @ts-expect-error
+ }[eventStrategyName];
+}
+
+/// #DEBUG
+// @ts-expect-error
+pointer.getStrategy = getStrategy;
+
+/// #ENDDEBUG
+
+export default pointer;
diff --git a/packages/devextreme/js/__internal/events/m_remove.ts b/packages/devextreme/js/__internal/events/m_remove.ts
new file mode 100644
index 000000000000..7db6f04f4725
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_remove.ts
@@ -0,0 +1,27 @@
+import { beforeCleanData } from '@js/core/element_data';
+import $ from '@js/core/renderer';
+import registerEvent from '@js/events/core/event_registrator';
+import eventsEngine from '@js/events/core/events_engine';
+
+export const removeEvent = 'dxremove';
+const eventPropName = 'dxRemoveEvent';
+
+beforeCleanData((elements) => {
+ elements = [].slice.call(elements);
+ for (let i = 0; i < elements.length; i++) {
+ const $element = $(elements[i]);
+ // @ts-expect-error
+ if ($element.prop(eventPropName)) {
+ $element[0][eventPropName] = null;
+ // @ts-expect-error
+ eventsEngine.triggerHandler($element, removeEvent);
+ }
+ }
+});
+
+registerEvent(removeEvent, {
+ noBubble: true,
+ setup(element) {
+ $(element).prop(eventPropName, true);
+ },
+});
diff --git a/packages/devextreme/js/__internal/events/m_short.ts b/packages/devextreme/js/__internal/events/m_short.ts
new file mode 100644
index 000000000000..4ef502a5058f
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_short.ts
@@ -0,0 +1,136 @@
+import eventsEngine from '@js/events/core/events_engine';
+import KeyboardProcessor from '@js/events/core/keyboard_processor';
+import { addNamespace as pureAddNamespace } from '@js/events/utils/index';
+
+function addNamespace(event, namespace) {
+ return namespace ? pureAddNamespace(event, namespace) : event;
+}
+
+function executeAction(action, args) {
+ return typeof action === 'function' ? action(args) : action.execute(args);
+}
+
+export const active = {
+ on: ($el, active, inactive, opts) => {
+ const {
+ selector, showTimeout, hideTimeout, namespace,
+ } = opts;
+
+ eventsEngine.on(
+ $el,
+ addNamespace('dxactive', namespace),
+ selector,
+ { timeout: showTimeout },
+ // @ts-expect-error
+ (event) => executeAction(active, { event, element: event.currentTarget }),
+ );
+ eventsEngine.on(
+ $el,
+ addNamespace('dxinactive', namespace),
+ selector,
+ { timeout: hideTimeout },
+ // @ts-expect-error
+ (event) => executeAction(inactive, { event, element: event.currentTarget }),
+ );
+ },
+
+ off: ($el, { namespace, selector }) => {
+ eventsEngine.off($el, addNamespace('dxactive', namespace), selector);
+ eventsEngine.off($el, addNamespace('dxinactive', namespace), selector);
+ },
+};
+
+export const resize = {
+ on: ($el, resize, { namespace }: any = {}) => {
+ eventsEngine.on($el, addNamespace('dxresize', namespace), resize);
+ },
+ off: ($el, { namespace }: any = {}) => {
+ eventsEngine.off($el, addNamespace('dxresize', namespace));
+ },
+};
+
+export const hover = {
+ on: ($el, start, end, { selector, namespace }) => {
+ eventsEngine.on($el, addNamespace('dxhoverend', namespace), selector, (event) => end(event));
+ eventsEngine.on(
+ $el,
+ addNamespace('dxhoverstart', namespace),
+ selector,
+ (event) => executeAction(start, { element: event.target, event }),
+ );
+ },
+
+ off: ($el, { selector, namespace }) => {
+ eventsEngine.off($el, addNamespace('dxhoverstart', namespace), selector);
+ eventsEngine.off($el, addNamespace('dxhoverend', namespace), selector);
+ },
+};
+
+export const visibility = {
+ on: ($el, shown, hiding, { namespace }) => {
+ eventsEngine.on($el, addNamespace('dxhiding', namespace), hiding);
+ eventsEngine.on($el, addNamespace('dxshown', namespace), shown);
+ },
+
+ off: ($el, { namespace }) => {
+ eventsEngine.off($el, addNamespace('dxhiding', namespace));
+ eventsEngine.off($el, addNamespace('dxshown', namespace));
+ },
+};
+
+export const focus = {
+ on: ($el, focusIn, focusOut, { namespace }) => {
+ eventsEngine.on($el, addNamespace('focusin', namespace), focusIn);
+ eventsEngine.on($el, addNamespace('focusout', namespace), focusOut);
+ },
+
+ off: ($el, { namespace }) => {
+ eventsEngine.off($el, addNamespace('focusin', namespace));
+ eventsEngine.off($el, addNamespace('focusout', namespace));
+ },
+ // @ts-expect-error
+ trigger: ($el) => eventsEngine.trigger($el, 'focus'),
+};
+
+export const dxClick = {
+ on: ($el, click, { namespace }: any = {}) => {
+ eventsEngine.on($el, addNamespace('dxclick', namespace), click);
+ },
+ off: ($el, { namespace }: any = {}) => {
+ eventsEngine.off($el, addNamespace('dxclick', namespace));
+ },
+};
+
+export const click = {
+ on: ($el, click, { namespace }: any = {}) => {
+ eventsEngine.on($el, addNamespace('click', namespace), click);
+ },
+ off: ($el, { namespace }: any = {}) => {
+ eventsEngine.off($el, addNamespace('click', namespace));
+ },
+};
+
+let index = 0;
+const keyboardProcessors = {};
+const generateListenerId = () => `keyboardProcessorId${index++}`;
+
+export const keyboard = {
+ on: (element, focusTarget, handler) => {
+ const listenerId = generateListenerId();
+
+ keyboardProcessors[listenerId] = new KeyboardProcessor({ element, focusTarget, handler });
+
+ return listenerId;
+ },
+
+ off: (listenerId) => {
+ if (listenerId && keyboardProcessors[listenerId]) {
+ keyboardProcessors[listenerId].dispose();
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ delete keyboardProcessors[listenerId];
+ }
+ },
+
+ // NOTE: For tests
+ _getProcessor: (listenerId) => keyboardProcessors[listenerId],
+};
diff --git a/packages/devextreme/js/__internal/events/m_swipe.ts b/packages/devextreme/js/__internal/events/m_swipe.ts
new file mode 100644
index 000000000000..fbea0dddd200
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_swipe.ts
@@ -0,0 +1,180 @@
+import { getHeight, getWidth } from '@js/core/utils/size';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import GestureEmitter from '@js/events/gesture/emitter.gesture';
+import { eventData } from '@js/events/utils/index';
+
+const SWIPE_START_EVENT = 'dxswipestart';
+const SWIPE_EVENT = 'dxswipe';
+const SWIPE_END_EVENT = 'dxswipeend';
+
+const HorizontalStrategy = {
+ defaultItemSizeFunc() {
+ return getWidth(this.getElement());
+ },
+
+ getBounds() {
+ return [
+ this._maxLeftOffset,
+ this._maxRightOffset,
+ ];
+ },
+
+ calcOffsetRatio(e) {
+ const endEventData = eventData(e);
+ return (endEventData.x - (this._savedEventData && this._savedEventData.x || 0)) / this._itemSizeFunc().call(this, e);
+ },
+
+ isFastSwipe(e) {
+ const endEventData = eventData(e);
+ return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.x - this._tickData.x) >= (endEventData.time - this._tickData.time);
+ },
+};
+
+const VerticalStrategy = {
+ defaultItemSizeFunc() {
+ return getHeight(this.getElement());
+ },
+
+ getBounds() {
+ return [
+ this._maxTopOffset,
+ this._maxBottomOffset,
+ ];
+ },
+
+ calcOffsetRatio(e) {
+ const endEventData = eventData(e);
+ return (endEventData.y - (this._savedEventData && this._savedEventData.y || 0)) / this._itemSizeFunc().call(this, e);
+ },
+
+ isFastSwipe(e) {
+ const endEventData = eventData(e);
+ return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.y - this._tickData.y) >= (endEventData.time - this._tickData.time);
+ },
+};
+
+const STRATEGIES = {
+ horizontal: HorizontalStrategy,
+ vertical: VerticalStrategy,
+};
+
+const SwipeEmitter = GestureEmitter.inherit({
+
+ TICK_INTERVAL: 300,
+ FAST_SWIPE_SPEED_LIMIT: 10,
+
+ ctor(element) {
+ this.callBase(element);
+
+ this.direction = 'horizontal';
+ this.elastic = true;
+ },
+
+ _getStrategy() {
+ return STRATEGIES[this.direction];
+ },
+
+ _defaultItemSizeFunc() {
+ return this._getStrategy().defaultItemSizeFunc.call(this);
+ },
+
+ _itemSizeFunc() {
+ return this.itemSizeFunc || this._defaultItemSizeFunc;
+ },
+
+ _init(e) {
+ this._tickData = eventData(e);
+ },
+
+ _start(e) {
+ this._savedEventData = eventData(e);
+
+ e = this._fireEvent(SWIPE_START_EVENT, e);
+
+ if (!e.cancel) {
+ this._maxLeftOffset = e.maxLeftOffset;
+ this._maxRightOffset = e.maxRightOffset;
+ this._maxTopOffset = e.maxTopOffset;
+ this._maxBottomOffset = e.maxBottomOffset;
+ }
+ },
+
+ _move(e) {
+ const strategy = this._getStrategy();
+ const moveEventData = eventData(e);
+ let offset = strategy.calcOffsetRatio.call(this, e);
+
+ offset = this._fitOffset(offset, this.elastic);
+
+ if (moveEventData.time - this._tickData.time > this.TICK_INTERVAL) {
+ this._tickData = moveEventData;
+ }
+
+ this._fireEvent(SWIPE_EVENT, e, {
+ offset,
+ });
+
+ if (e.cancelable !== false) {
+ e.preventDefault();
+ }
+ },
+
+ _end(e) {
+ const strategy = this._getStrategy();
+ const offsetRatio = strategy.calcOffsetRatio.call(this, e);
+ const isFast = strategy.isFastSwipe.call(this, e);
+ let startOffset = offsetRatio;
+ let targetOffset = this._calcTargetOffset(offsetRatio, isFast);
+
+ startOffset = this._fitOffset(startOffset, this.elastic);
+ targetOffset = this._fitOffset(targetOffset, false);
+
+ this._fireEvent(SWIPE_END_EVENT, e, {
+ offset: startOffset,
+ targetOffset,
+ });
+ },
+
+ _fitOffset(offset, elastic) {
+ const strategy = this._getStrategy();
+ const bounds = strategy.getBounds.call(this);
+
+ if (offset < -bounds[0]) {
+ return elastic ? (-2 * bounds[0] + offset) / 3 : -bounds[0];
+ }
+
+ if (offset > bounds[1]) {
+ return elastic ? (2 * bounds[1] + offset) / 3 : bounds[1];
+ }
+
+ return offset;
+ },
+
+ _calcTargetOffset(offsetRatio, isFast) {
+ let result;
+ if (isFast) {
+ result = Math.ceil(Math.abs(offsetRatio));
+ if (offsetRatio < 0) {
+ result = -result;
+ }
+ } else {
+ result = Math.round(offsetRatio);
+ }
+ return result;
+ },
+});
+
+registerEmitter({
+ emitter: SwipeEmitter,
+ events: [
+ SWIPE_START_EVENT,
+ SWIPE_EVENT,
+ SWIPE_END_EVENT,
+ ],
+});
+
+export {
+ SWIPE_END_EVENT as end,
+ SWIPE_START_EVENT as start,
+ SWIPE_EVENT as swipe,
+};
diff --git a/packages/devextreme/js/__internal/events/m_transform.ts b/packages/devextreme/js/__internal/events/m_transform.ts
new file mode 100644
index 000000000000..6f3ae247bc28
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_transform.ts
@@ -0,0 +1,172 @@
+import * as iteratorUtils from '@js/core/utils/iterator';
+import { fitIntoRange, sign as mathSign } from '@js/core/utils/math';
+import Emitter from '@js/events/core/emitter';
+import registerEmitter from '@js/events/core/emitter_registrator';
+import { hasTouches } from '@js/events/utils/index';
+
+interface EventAlias {
+ name: string;
+ args: any;
+}
+
+const DX_PREFIX = 'dx';
+
+const TRANSFORM = 'transform';
+const TRANSLATE = 'translate';
+const PINCH = 'pinch';
+const ROTATE = 'rotate';
+
+const START_POSTFIX = 'start';
+const UPDATE_POSTFIX = '';
+const END_POSTFIX = 'end';
+
+const eventAliases: EventAlias[] = [];
+const addAlias = function (eventName, eventArgs) {
+ eventAliases.push({
+ name: eventName,
+ args: eventArgs,
+ });
+};
+
+addAlias(TRANSFORM, {
+ scale: true,
+ deltaScale: true,
+ rotation: true,
+ deltaRotation: true,
+ translation: true,
+ deltaTranslation: true,
+});
+
+addAlias(TRANSLATE, {
+ translation: true,
+ deltaTranslation: true,
+});
+
+addAlias(PINCH, {
+ scale: true,
+ deltaScale: true,
+});
+
+addAlias(ROTATE, {
+ rotation: true,
+ deltaRotation: true,
+});
+
+const getVector = function (first, second) {
+ return {
+ x: second.pageX - first.pageX,
+ y: -second.pageY + first.pageY,
+ centerX: (second.pageX + first.pageX) * 0.5,
+ centerY: (second.pageY + first.pageY) * 0.5,
+ };
+};
+
+const getEventVector = function (e) {
+ const { pointers } = e;
+
+ return getVector(pointers[0], pointers[1]);
+};
+
+const getDistance = function (vector) {
+ return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
+};
+
+const getScale = function (firstVector, secondVector) {
+ return getDistance(firstVector) / getDistance(secondVector);
+};
+
+const getRotation = function (firstVector, secondVector) {
+ const scalarProduct = firstVector.x * secondVector.x + firstVector.y * secondVector.y;
+ const distanceProduct = getDistance(firstVector) * getDistance(secondVector);
+
+ if (distanceProduct === 0) {
+ return 0;
+ }
+
+ const sign = mathSign(firstVector.x * secondVector.y - secondVector.x * firstVector.y);
+ const angle = Math.acos(fitIntoRange(scalarProduct / distanceProduct, -1, 1));
+
+ return sign * angle;
+};
+
+const getTranslation = function (firstVector, secondVector) {
+ return {
+ x: firstVector.centerX - secondVector.centerX,
+ y: firstVector.centerY - secondVector.centerY,
+ };
+};
+
+const TransformEmitter = Emitter.inherit({
+
+ validatePointers(e) {
+ return hasTouches(e) > 1;
+ },
+
+ start(e) {
+ this._accept(e);
+
+ const startVector = getEventVector(e);
+ this._startVector = startVector;
+ this._prevVector = startVector;
+
+ this._fireEventAliases(START_POSTFIX, e);
+ },
+
+ move(e) {
+ const currentVector = getEventVector(e);
+ const eventArgs = this._getEventArgs(currentVector);
+
+ this._fireEventAliases(UPDATE_POSTFIX, e, eventArgs);
+ this._prevVector = currentVector;
+ },
+
+ end(e) {
+ const eventArgs = this._getEventArgs(this._prevVector);
+ this._fireEventAliases(END_POSTFIX, e, eventArgs);
+ },
+
+ _getEventArgs(vector) {
+ return {
+ scale: getScale(vector, this._startVector),
+ deltaScale: getScale(vector, this._prevVector),
+ rotation: getRotation(vector, this._startVector),
+ deltaRotation: getRotation(vector, this._prevVector),
+ translation: getTranslation(vector, this._startVector),
+ deltaTranslation: getTranslation(vector, this._prevVector),
+ };
+ },
+
+ _fireEventAliases(eventPostfix, originalEvent, eventArgs) {
+ eventArgs = eventArgs || {};
+
+ iteratorUtils.each(eventAliases, (_, eventAlias) => {
+ const args = {};
+ iteratorUtils.each(eventAlias.args, (name) => {
+ if (name in eventArgs) {
+ args[name] = eventArgs[name];
+ }
+ });
+
+ this._fireEvent(DX_PREFIX + eventAlias.name + eventPostfix, originalEvent, args);
+ });
+ },
+
+});
+
+const eventNames = eventAliases.reduce((result: string[], eventAlias) => {
+ [START_POSTFIX, UPDATE_POSTFIX, END_POSTFIX].forEach((eventPostfix) => {
+ result.push(DX_PREFIX + eventAlias.name + eventPostfix);
+ });
+ return result;
+}, []);
+
+registerEmitter({
+ emitter: TransformEmitter,
+ events: eventNames,
+});
+const exportNames: Record
= {};
+iteratorUtils.each(eventNames, (_, eventName: string) => {
+ exportNames[eventName.substring(DX_PREFIX.length)] = eventName;
+});
+
+export { exportNames };
diff --git a/packages/devextreme/js/__internal/events/m_visibility_change.ts b/packages/devextreme/js/__internal/events/m_visibility_change.ts
new file mode 100644
index 000000000000..73649aaeb138
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/m_visibility_change.ts
@@ -0,0 +1,28 @@
+import $ from '@js/core/renderer';
+import eventsEngine from '@js/events/core/events_engine';
+
+const triggerVisibilityChangeEvent = function (eventName) {
+ const VISIBILITY_CHANGE_SELECTOR = '.dx-visibility-change-handler';
+
+ return function (element) {
+ const $element = $(element || 'body');
+
+ const changeHandlers = $element.filter(VISIBILITY_CHANGE_SELECTOR)
+ // @ts-expect-error
+ .add($element.find(VISIBILITY_CHANGE_SELECTOR));
+
+ for (let i = 0; i < changeHandlers.length; i++) {
+ eventsEngine.triggerHandler(changeHandlers[i], eventName);
+ }
+ };
+};
+
+export const triggerShownEvent = triggerVisibilityChangeEvent('dxshown');
+export const triggerHidingEvent = triggerVisibilityChangeEvent('dxhiding');
+export const triggerResizeEvent = triggerVisibilityChangeEvent('dxresize');
+
+export default {
+ triggerHidingEvent,
+ triggerResizeEvent,
+ triggerShownEvent,
+};
diff --git a/packages/devextreme/js/__internal/events/pointer/m_base.ts b/packages/devextreme/js/__internal/events/pointer/m_base.ts
new file mode 100644
index 000000000000..9f09bc77971f
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/pointer/m_base.ts
@@ -0,0 +1,114 @@
+import Class from '@js/core/class';
+import domAdapter from '@js/core/dom_adapter';
+import browser from '@js/core/utils/browser';
+import eventsEngine from '@js/events/core/events_engine';
+import { getEventTarget } from '@js/events/utils/event_target';
+import { addNamespace, eventSource, fireEvent } from '@js/events/utils/index';
+
+const POINTER_EVENTS_NAMESPACE = 'dxPointerEvents';
+
+const BaseStrategy = Class.inherit({
+
+ ctor(eventName, originalEvents) {
+ this._eventName = eventName;
+ this._originalEvents = addNamespace(originalEvents, POINTER_EVENTS_NAMESPACE);
+ this._handlerCount = 0;
+ this.noBubble = this._isNoBubble();
+ },
+
+ _isNoBubble() {
+ const eventName = this._eventName;
+
+ return eventName === 'dxpointerenter'
+ || eventName === 'dxpointerleave';
+ },
+
+ _handler(e) {
+ const delegateTarget = this._getDelegateTarget(e);
+
+ const event = {
+ type: this._eventName,
+ pointerType: e.pointerType || eventSource(e),
+ originalEvent: e,
+ delegateTarget,
+ // NOTE: TimeStamp normalization (FF bug #238041) (T277118)
+ timeStamp: browser.mozilla ? new Date().getTime() : e.timeStamp,
+ };
+
+ const target = getEventTarget(e);
+ // @ts-expect-error
+ event.target = target;
+
+ return this._fireEvent(event);
+ },
+
+ _getDelegateTarget(e) {
+ let delegateTarget;
+
+ if (this.noBubble) {
+ delegateTarget = e.delegateTarget;
+ }
+
+ return delegateTarget;
+ },
+
+ _fireEvent(args) {
+ return fireEvent(args);
+ },
+
+ _setSelector(handleObj) {
+ this._selector = this.noBubble && handleObj ? handleObj.selector : null;
+ },
+
+ _getSelector() {
+ return this._selector;
+ },
+
+ setup() {
+ return true;
+ },
+
+ add(element, handleObj) {
+ if (this._handlerCount <= 0 || this.noBubble) {
+ element = this.noBubble ? element : domAdapter.getDocument();
+ this._setSelector(handleObj);
+
+ const that = this;
+ eventsEngine.on(element, this._originalEvents, this._getSelector(), (e) => {
+ that._handler(e);
+ });
+ }
+
+ if (!this.noBubble) {
+ this._handlerCount++;
+ }
+ },
+
+ remove(handleObj) {
+ this._setSelector(handleObj);
+
+ if (!this.noBubble) {
+ this._handlerCount--;
+ }
+ },
+
+ teardown(element) {
+ if (this._handlerCount && !this.noBubble) {
+ return;
+ }
+
+ element = this.noBubble ? element : domAdapter.getDocument();
+
+ if (this._originalEvents !== `.${POINTER_EVENTS_NAMESPACE}`) {
+ eventsEngine.off(element, this._originalEvents, this._getSelector());
+ }
+ },
+
+ dispose(element) {
+ element = this.noBubble ? element : domAdapter.getDocument();
+
+ eventsEngine.off(element, this._originalEvents);
+ },
+});
+
+export default BaseStrategy;
diff --git a/packages/devextreme/js/__internal/events/pointer/m_mouse.ts b/packages/devextreme/js/__internal/events/pointer/m_mouse.ts
new file mode 100644
index 000000000000..87cf81e5e738
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/pointer/m_mouse.ts
@@ -0,0 +1,62 @@
+import { extend } from '@js/core/utils/extend';
+import BaseStrategy from '@js/events/pointer/base';
+import Observer from '@js/events/pointer/observer';
+
+/* eslint-disable spellcheck/spell-checker */
+const eventMap = {
+ dxpointerdown: 'mousedown',
+ dxpointermove: 'mousemove',
+ dxpointerup: 'mouseup',
+ dxpointercancel: '',
+ dxpointerover: 'mouseover',
+ dxpointerout: 'mouseout',
+ dxpointerenter: 'mouseenter',
+ dxpointerleave: 'mouseleave',
+};
+
+const normalizeMouseEvent = function (e) {
+ e.pointerId = 1;
+
+ return {
+ pointers: observer.pointers(),
+ pointerId: 1,
+ };
+};
+
+let observer;
+let activated = false;
+const activateStrategy = function () {
+ if (activated) {
+ return;
+ }
+ // @ts-expect-error
+ observer = new Observer(eventMap, () => true);
+
+ activated = true;
+};
+
+const MouseStrategy = BaseStrategy.inherit({
+
+ ctor() {
+ this.callBase.apply(this, arguments);
+
+ activateStrategy();
+ },
+
+ _fireEvent(args) {
+ return this.callBase(extend(normalizeMouseEvent(args.originalEvent), args));
+ },
+
+});
+// @ts-expect-error
+MouseStrategy.map = eventMap;
+// @ts-expect-error
+MouseStrategy.normalize = normalizeMouseEvent;
+// @ts-expect-error
+MouseStrategy.activate = activateStrategy;
+// @ts-expect-error
+MouseStrategy.resetObserver = function () {
+ observer.reset();
+};
+
+export default MouseStrategy;
diff --git a/packages/devextreme/js/__internal/events/pointer/m_mouse_and_touch.ts b/packages/devextreme/js/__internal/events/pointer/m_mouse_and_touch.ts
new file mode 100644
index 000000000000..ca198b4a1bf0
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/pointer/m_mouse_and_touch.ts
@@ -0,0 +1,88 @@
+import { extend } from '@js/core/utils/extend';
+import BaseStrategy from '@js/events/pointer/base';
+import MouseStrategy from '@js/events/pointer/mouse';
+import TouchStrategy from '@js/events/pointer/touch';
+import { isMouseEvent } from '@js/events/utils/index';
+
+/* eslint-disable spellcheck/spell-checker */
+const eventMap = {
+ dxpointerdown: 'touchstart mousedown',
+ dxpointermove: 'touchmove mousemove',
+ dxpointerup: 'touchend mouseup',
+ dxpointercancel: 'touchcancel',
+ dxpointerover: 'mouseover',
+ dxpointerout: 'mouseout',
+ dxpointerenter: 'mouseenter',
+ dxpointerleave: 'mouseleave',
+};
+
+let activated = false;
+const activateStrategy = function () {
+ if (activated) {
+ return;
+ }
+ // @ts-expect-error
+ MouseStrategy.activate();
+
+ activated = true;
+};
+
+const MouseAndTouchStrategy = BaseStrategy.inherit({
+
+ EVENT_LOCK_TIMEOUT: 100,
+
+ ctor() {
+ this.callBase.apply(this, arguments);
+
+ activateStrategy();
+ },
+
+ _handler(e) {
+ const isMouse = isMouseEvent(e);
+
+ if (!isMouse) {
+ this._skipNextEvents = true;
+ }
+
+ if (isMouse && this._mouseLocked) {
+ return;
+ }
+
+ if (isMouse && this._skipNextEvents) {
+ this._skipNextEvents = false;
+ this._mouseLocked = true;
+
+ clearTimeout(this._unlockMouseTimer);
+
+ const that = this;
+ this._unlockMouseTimer = setTimeout(() => {
+ that._mouseLocked = false;
+ }, this.EVENT_LOCK_TIMEOUT);
+
+ return;
+ }
+
+ return this.callBase(e);
+ },
+
+ _fireEvent(args) {
+ // @ts-expect-error
+ const normalizer = isMouseEvent(args.originalEvent) ? MouseStrategy.normalize : TouchStrategy.normalize;
+
+ return this.callBase(extend(normalizer(args.originalEvent), args));
+ },
+
+ dispose() {
+ this.callBase();
+ this._skipNextEvents = false;
+ this._mouseLocked = false;
+ clearTimeout(this._unlockMouseTimer);
+ },
+});
+
+// @ts-expect-error
+MouseAndTouchStrategy.map = eventMap;
+// @ts-expect-error
+MouseAndTouchStrategy.resetObserver = MouseStrategy.resetObserver;
+
+export default MouseAndTouchStrategy;
diff --git a/packages/devextreme/js/__internal/events/pointer/m_observer.ts b/packages/devextreme/js/__internal/events/pointer/m_observer.ts
new file mode 100644
index 000000000000..1a50a5f8f5cd
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/pointer/m_observer.ts
@@ -0,0 +1,69 @@
+import domAdapter from '@js/core/dom_adapter';
+import { each } from '@js/core/utils/iterator';
+import readyCallbacks from '@js/core/utils/ready_callbacks';
+
+const addEventsListener = function (events, handler) {
+ readyCallbacks.add(() => {
+ events
+ .split(' ')
+ .forEach((event) => {
+ // @ts-expect-error
+ domAdapter.listen(domAdapter.getDocument(), event, handler, true);
+ });
+ });
+};
+
+const Observer = function (eventMap, pointerEquals, onPointerAdding) {
+ onPointerAdding = onPointerAdding || function () { };
+
+ let pointers: any = [];
+
+ const getPointerIndex = function (e) {
+ let index = -1;
+
+ each(pointers, (i: any, pointer) => {
+ if (!pointerEquals(e, pointer)) {
+ return true;
+ }
+
+ index = i;
+ return false;
+ });
+
+ return index;
+ };
+
+ const addPointer = function (e) {
+ if (getPointerIndex(e) === -1) {
+ onPointerAdding(e);
+ pointers.push(e);
+ }
+ };
+
+ const removePointer = function (e) {
+ const index = getPointerIndex(e);
+ if (index > -1) {
+ pointers.splice(index, 1);
+ }
+ };
+
+ const updatePointer = function (e) {
+ pointers[getPointerIndex(e)] = e;
+ };
+
+ /* eslint-disable spellcheck/spell-checker */
+ addEventsListener(eventMap.dxpointerdown, addPointer);
+ addEventsListener(eventMap.dxpointermove, updatePointer);
+ addEventsListener(eventMap.dxpointerup, removePointer);
+ addEventsListener(eventMap.dxpointercancel, removePointer);
+
+ this.pointers = function () {
+ return pointers;
+ };
+
+ this.reset = function () {
+ pointers = [];
+ };
+};
+
+export default Observer;
diff --git a/packages/devextreme/js/__internal/events/pointer/m_touch.ts b/packages/devextreme/js/__internal/events/pointer/m_touch.ts
new file mode 100644
index 000000000000..102f75060d26
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/pointer/m_touch.ts
@@ -0,0 +1,68 @@
+import devices from '@js/core/devices';
+import { extend } from '@js/core/utils/extend';
+import { each } from '@js/core/utils/iterator';
+import BaseStrategy from '@js/events/pointer/base';
+
+/* eslint-disable spellcheck/spell-checker */
+const eventMap = {
+ dxpointerdown: 'touchstart',
+ dxpointermove: 'touchmove',
+ dxpointerup: 'touchend',
+ dxpointercancel: 'touchcancel',
+ dxpointerover: '',
+ dxpointerout: '',
+ dxpointerenter: '',
+ dxpointerleave: '',
+};
+
+const normalizeTouchEvent = function (e) {
+ const pointers: any = [];
+
+ each(e.touches, (_, touch) => {
+ pointers.push(extend({
+ pointerId: touch.identifier,
+ }, touch));
+ });
+
+ return {
+ pointers,
+ pointerId: e.changedTouches[0].identifier,
+ };
+};
+
+const skipTouchWithSameIdentifier = function (pointerEvent) {
+ return devices.real().platform === 'ios' && (pointerEvent === 'dxpointerdown' || pointerEvent === 'dxpointerup');
+};
+
+const TouchStrategy = BaseStrategy.inherit({
+
+ ctor() {
+ this.callBase.apply(this, arguments);
+ this._pointerId = 0;
+ },
+
+ _handler(e) {
+ if (skipTouchWithSameIdentifier(this._eventName)) {
+ const touch = e.changedTouches[0];
+
+ if (this._pointerId === touch.identifier && this._pointerId !== 0) {
+ return;
+ }
+
+ this._pointerId = touch.identifier;
+ }
+
+ return this.callBase.apply(this, arguments);
+ },
+
+ _fireEvent(args) {
+ return this.callBase(extend(normalizeTouchEvent(args.originalEvent), args));
+ },
+
+});
+// @ts-expect-error
+TouchStrategy.map = eventMap;
+// @ts-expect-error
+TouchStrategy.normalize = normalizeTouchEvent;
+
+export default TouchStrategy;
diff --git a/packages/devextreme/js/__internal/events/utils/index.ts b/packages/devextreme/js/__internal/events/utils/index.ts
new file mode 100644
index 000000000000..407f3dced19d
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/utils/index.ts
@@ -0,0 +1,219 @@
+import $ from '@js/core/renderer';
+import { extend } from '@js/core/utils/extend';
+import { each } from '@js/core/utils/iterator';
+import eventsEngine from '@js/events/core/events_engine';
+import { focused } from '@js/ui/widget/selectors';
+
+import mappedAddNamespace from './m_add_namespace';
+/* eslint-disable spellcheck/spell-checker */
+const KEY_MAP = {
+ backspace: 'backspace',
+ tab: 'tab',
+ enter: 'enter',
+ escape: 'escape',
+ pageup: 'pageUp',
+ pagedown: 'pageDown',
+ end: 'end',
+ home: 'home',
+ arrowleft: 'leftArrow',
+ arrowup: 'upArrow',
+ arrowright: 'rightArrow',
+ arrowdown: 'downArrow',
+ delete: 'del',
+ ' ': 'space',
+ f: 'F',
+ a: 'A',
+ '*': 'asterisk',
+ '-': 'minus',
+ alt: 'alt',
+ control: 'control',
+ shift: 'shift',
+};
+
+const LEGACY_KEY_CODES = {
+ // iOS 10.2 and lower didn't supports KeyboardEvent.key
+ 8: 'backspace',
+ 9: 'tab',
+ 13: 'enter',
+ 27: 'escape',
+ 33: 'pageUp',
+ 34: 'pageDown',
+ 35: 'end',
+ 36: 'home',
+ 37: 'leftArrow',
+ 38: 'upArrow',
+ 39: 'rightArrow',
+ 40: 'downArrow',
+ 46: 'del',
+ 32: 'space',
+ 70: 'F',
+ 65: 'A',
+ 106: 'asterisk',
+ 109: 'minus',
+ 189: 'minus',
+ 173: 'minus',
+ 16: 'shift',
+ 17: 'control',
+ 18: 'alt',
+};
+
+const EVENT_SOURCES_REGEX = {
+ dx: /^dx/i,
+ mouse: /(mouse|wheel)/i,
+ touch: /^touch/i,
+ keyboard: /^key/i,
+ pointer: /^(ms)?pointer/i,
+};
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable @typescript-eslint/no-unsafe-return */
+export const eventSource = ({ type }) => {
+ let result = 'other';
+ /* eslint-disable @typescript-eslint/no-invalid-void-type */
+ // eslint-disable-next-line consistent-return
+ each(EVENT_SOURCES_REGEX, function (key): boolean | void {
+ // eslint-disable-next-line @typescript-eslint/no-invalid-this
+ if (this.test(type)) {
+ result = key;
+
+ return false;
+ }
+ });
+
+ return result;
+};
+
+let fixMethod = (e) => e;
+// @ts-expect-error
+const getEvent = (originalEvent) => eventsEngine.Event(originalEvent, originalEvent);
+// @ts-expect-error
+const copyEvent = (originalEvent) => fixMethod(getEvent(originalEvent), originalEvent);
+
+const isDxEvent = (e) => eventSource(e) === 'dx';
+const isNativeMouseEvent = (e) => eventSource(e) === 'mouse';
+const isNativeTouchEvent = (e) => eventSource(e) === 'touch';
+
+export const isPointerEvent = (e) => eventSource(e) === 'pointer';
+
+export const isMouseEvent = (e) => isNativeMouseEvent(e)
+ || ((isPointerEvent(e) || isDxEvent(e)) && e.pointerType === 'mouse');
+
+export const isDxMouseWheelEvent = (e) => e && e.type === 'dxmousewheel';
+
+export const isTouchEvent = (e) => isNativeTouchEvent(e)
+ || ((isPointerEvent(e) || isDxEvent(e)) && e.pointerType === 'touch');
+
+export const isKeyboardEvent = (e) => eventSource(e) === 'keyboard';
+
+export const isFakeClickEvent = ({
+ screenX,
+ offsetX,
+ pageX,
+}) => screenX === 0 && !offsetX && pageX === 0;
+
+export const eventData = ({ pageX, pageY, timeStamp }) => ({
+ x: pageX,
+ y: pageY,
+ time: timeStamp,
+});
+
+export const eventDelta = (from, to) => ({
+ x: to.x - from.x,
+ y: to.y - from.y,
+ time: to.time - from.time || 1,
+});
+
+export const hasTouches = (e) => {
+ const { originalEvent, pointers } = e;
+
+ if (isNativeTouchEvent(e)) {
+ return (originalEvent.touches || []).length;
+ }
+
+ if (isDxEvent(e)) {
+ return (pointers || []).length;
+ }
+
+ return 0;
+};
+
+// TODO: for tests
+let skipEvents = false;
+export const forceSkipEvents = () => { skipEvents = true; };
+export const stopEventsSkipping = () => { skipEvents = false; };
+// eslint-disable-next-line consistent-return
+export const needSkipEvent = (e) => {
+ // TODO: for tests
+ if (skipEvents) {
+ return true;
+ }
+
+ // TODO: this checking used in swipeable first move handler. is it correct?
+ const { target } = e;
+ const $target = $(target);
+ const isContentEditable = target?.isContentEditable || target?.hasAttribute('contenteditable');
+ const touchInEditable = $target.is('input, textarea, select') || isContentEditable;
+
+ if (isDxMouseWheelEvent(e)) {
+ const isTextArea = $target.is('textarea') && $target.hasClass('dx-texteditor-input');
+
+ if (isTextArea || isContentEditable) {
+ return false;
+ }
+
+ const isInputFocused = $target.is('input[type=\'number\'], textarea, select') && $target.is(':focus');
+
+ return isInputFocused;
+ }
+
+ if (isMouseEvent(e)) {
+ return touchInEditable || e.which > 1; // only left mouse button
+ }
+
+ if (isTouchEvent(e)) {
+ return touchInEditable && focused($target);
+ }
+};
+
+export const setEventFixMethod = (func) => { fixMethod = func; };
+
+export const createEvent = (originalEvent, args) => {
+ const event = copyEvent(originalEvent);
+
+ if (args) {
+ extend(event, args);
+ }
+
+ return event;
+};
+
+export const fireEvent = (props) => {
+ const { originalEvent, delegateTarget } = props;
+ const event = createEvent(originalEvent, props);
+ // @ts-expect-error
+ eventsEngine.trigger(delegateTarget || event.target, event);
+
+ return event;
+};
+
+export const normalizeKeyName = ({ key, which }) => {
+ const normalizedKey = KEY_MAP[key?.toLowerCase()] || key;
+ const normalizedKeyFromWhich = LEGACY_KEY_CODES[which];
+ if (normalizedKeyFromWhich && normalizedKey === key) {
+ return normalizedKeyFromWhich;
+ }
+
+ if (!normalizedKey && which) {
+ return String.fromCharCode(which);
+ }
+
+ return normalizedKey;
+};
+
+export const getChar = ({ key, which }) => key || String.fromCharCode(which);
+
+export const addNamespace = mappedAddNamespace;
+
+export const isCommandKeyPressed = ({ ctrlKey, metaKey }) => ctrlKey || metaKey;
diff --git a/packages/devextreme/js/__internal/events/utils/m_add_namespace.ts b/packages/devextreme/js/__internal/events/utils/m_add_namespace.ts
new file mode 100644
index 000000000000..f1f64eb8702c
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/utils/m_add_namespace.ts
@@ -0,0 +1,21 @@
+import errors from '@js/core/errors';
+
+const addNamespace = (eventNames, namespace) => {
+ if (!namespace) {
+ throw errors.Error('E0017');
+ }
+
+ if (Array.isArray(eventNames)) {
+ return eventNames
+ .map((eventName) => addNamespace(eventName, namespace))
+ .join(' ');
+ }
+
+ if (eventNames.indexOf(' ') !== -1) {
+ return addNamespace(eventNames.split(/\s+/g), namespace);
+ }
+
+ return `${eventNames}.${namespace}`;
+};
+
+export default addNamespace;
diff --git a/packages/devextreme/js/__internal/events/utils/m_event_nodes_disposing.ts b/packages/devextreme/js/__internal/events/utils/m_event_nodes_disposing.ts
new file mode 100644
index 000000000000..6d987c8aed01
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/utils/m_event_nodes_disposing.ts
@@ -0,0 +1,20 @@
+import eventsEngine from '@js/events/core/events_engine';
+import { removeEvent } from '@js/events/remove';
+
+function nodesByEvent(event) {
+ return event && [
+ event.target,
+ event.delegateTarget,
+ event.relatedTarget,
+ event.currentTarget,
+ ].filter((node) => !!node);
+}
+
+export const subscribeNodesDisposing = (event, callback) => {
+ // @ts-expect-error
+ eventsEngine.one(nodesByEvent(event), removeEvent, callback);
+};
+
+export const unsubscribeNodesDisposing = (event, callback) => {
+ eventsEngine.off(nodesByEvent(event), removeEvent, callback);
+};
diff --git a/packages/devextreme/js/__internal/events/utils/m_event_target.ts b/packages/devextreme/js/__internal/events/utils/m_event_target.ts
new file mode 100644
index 000000000000..28224cf5f616
--- /dev/null
+++ b/packages/devextreme/js/__internal/events/utils/m_event_target.ts
@@ -0,0 +1,18 @@
+export const getEventTarget = (event) => {
+ const { originalEvent } = event;
+
+ if (!originalEvent) {
+ return event.target;
+ }
+
+ const isShadowDOMUsed = Boolean(originalEvent.target?.shadowRoot);
+
+ if (!isShadowDOMUsed) {
+ return originalEvent.target;
+ }
+
+ const path = originalEvent.path ?? originalEvent.composedPath?.();
+ const target = path?.[0] ?? event.target;
+
+ return target;
+};
diff --git a/packages/devextreme/js/events/click.js b/packages/devextreme/js/events/click.js
index 155d2e4abbe8..b11d13e812b5 100644
--- a/packages/devextreme/js/events/click.js
+++ b/packages/devextreme/js/events/click.js
@@ -1,128 +1,8 @@
-import $ from '../core/renderer';
-import eventsEngine from '../events/core/events_engine';
-import devices from '../core/devices';
-import domAdapter from '../core/dom_adapter';
-import { resetActiveElement } from '../core/utils/dom';
-import { requestAnimationFrame, cancelAnimationFrame } from '../animation/frame';
-import { addNamespace, fireEvent } from './utils/index';
-import { subscribeNodesDisposing, unsubscribeNodesDisposing } from './utils/event_nodes_disposing';
-import { getEventTarget } from './utils/event_target';
-import pointerEvents from './pointer';
-import Emitter from './core/emitter';
-import registerEmitter from './core/emitter_registrator';
-
-const CLICK_EVENT_NAME = 'dxclick';
-
-const misc = { requestAnimationFrame, cancelAnimationFrame };
-
-let prevented = null;
-let lastFiredEvent = null;
-
-const onNodeRemove = () => {
- lastFiredEvent = null;
-};
-
-const clickHandler = function(e) {
- const originalEvent = e.originalEvent;
- const eventAlreadyFired = lastFiredEvent === originalEvent || originalEvent && originalEvent.DXCLICK_FIRED;
- const leftButton = !e.which || e.which === 1;
-
- if(leftButton && !prevented && !eventAlreadyFired) {
- if(originalEvent) {
- originalEvent.DXCLICK_FIRED = true;
- }
-
- unsubscribeNodesDisposing(lastFiredEvent, onNodeRemove);
- lastFiredEvent = originalEvent;
- subscribeNodesDisposing(lastFiredEvent, onNodeRemove);
-
- fireEvent({
- type: CLICK_EVENT_NAME,
- originalEvent: e
- });
- }
-};
-
-const ClickEmitter = Emitter.inherit({
-
- ctor: function(element) {
- this.callBase(element);
- eventsEngine.on(this.getElement(), 'click', clickHandler);
- },
-
- start: function(e) {
- prevented = null;
- },
-
- cancel: function() {
- prevented = true;
- },
-
- dispose: function() {
- eventsEngine.off(this.getElement(), 'click', clickHandler);
- }
-});
-
-
-// NOTE: fixes native click blur on slow devices
-(function() {
- const desktopDevice = devices.real().generic;
-
- if(!desktopDevice) {
- let startTarget = null;
- let blurPrevented = false;
-
- const isInput = function(element) {
- return $(element).is('input, textarea, select, button ,:focus, :focus *');
- };
-
- const pointerDownHandler = function(e) {
- startTarget = e.target;
- blurPrevented = e.isDefaultPrevented();
- };
-
- const getTarget = function(e) {
- const target = getEventTarget(e);
- return $(target);
- };
-
- const clickHandler = function(e) {
- const $target = getTarget(e);
-
- if(!blurPrevented && startTarget && !$target.is(startTarget) && !$(startTarget).is('label') && isInput($target)) {
- resetActiveElement();
- }
-
- startTarget = null;
- blurPrevented = false;
- };
-
- const NATIVE_CLICK_FIXER_NAMESPACE = 'NATIVE_CLICK_FIXER';
- const document = domAdapter.getDocument();
- eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.down, NATIVE_CLICK_FIXER_NAMESPACE), pointerDownHandler);
- eventsEngine.subscribeGlobal(document, addNamespace('click', NATIVE_CLICK_FIXER_NAMESPACE), clickHandler);
- }
-})();
-
-
/**
* @name UI Events.dxclick
* @type eventType
* @type_function_param1 event:event
* @module events/click
*/
-registerEmitter({
- emitter: ClickEmitter,
- bubble: true,
- events: [
- CLICK_EVENT_NAME
- ]
-});
-
-export { CLICK_EVENT_NAME as name };
-///#DEBUG
-export {
- misc
-};
-///#ENDDEBUG
+export * from '../__internal/events/m_click';
diff --git a/packages/devextreme/js/events/contextmenu.js b/packages/devextreme/js/events/contextmenu.js
index 88dd9290add1..d8c4c5830d05 100644
--- a/packages/devextreme/js/events/contextmenu.js
+++ b/packages/devextreme/js/events/contextmenu.js
@@ -1,57 +1,3 @@
-import $ from '../core/renderer';
-import eventsEngine from '../events/core/events_engine';
-import { touch } from '../core/utils/support';
-import devices from '../core/devices';
-import Class from '../core/class';
-import registerEvent from './core/event_registrator';
-import { addNamespace, fireEvent, isMouseEvent } from './utils/index';
-import holdEvent from './hold';
-
-const CONTEXTMENU_NAMESPACE = 'dxContexMenu';
-
-const CONTEXTMENU_NAMESPACED_EVENT_NAME = addNamespace('contextmenu', CONTEXTMENU_NAMESPACE);
-const HOLD_NAMESPACED_EVENT_NAME = addNamespace(holdEvent.name, CONTEXTMENU_NAMESPACE);
-
-const CONTEXTMENU_EVENT_NAME = 'dxcontextmenu';
-
-
-const ContextMenu = Class.inherit({
-
- setup: function(element) {
- const $element = $(element);
-
- eventsEngine.on($element, CONTEXTMENU_NAMESPACED_EVENT_NAME, this._contextMenuHandler.bind(this));
-
- if(touch || devices.isSimulator()) {
- eventsEngine.on($element, HOLD_NAMESPACED_EVENT_NAME, this._holdHandler.bind(this));
- }
- },
-
- _holdHandler: function(e) {
- if(isMouseEvent(e) && !devices.isSimulator()) {
- return;
- }
-
- this._fireContextMenu(e);
- },
-
- _contextMenuHandler: function(e) {
- this._fireContextMenu(e);
- },
-
- _fireContextMenu: function(e) {
- return fireEvent({
- type: CONTEXTMENU_EVENT_NAME,
- originalEvent: e
- });
- },
-
- teardown: function(element) {
- eventsEngine.off(element, '.' + CONTEXTMENU_NAMESPACE);
- }
-
-});
-
/**
* @name UI Events.dxcontextmenu
* @type eventType
@@ -59,6 +5,4 @@ const ContextMenu = Class.inherit({
* @module events/contextmenu
*/
-registerEvent(CONTEXTMENU_EVENT_NAME, new ContextMenu());
-
-export const name = CONTEXTMENU_EVENT_NAME;
+export * from '../__internal/events/m_contextmenu';
diff --git a/packages/devextreme/js/events/core/emitter.feedback.js b/packages/devextreme/js/events/core/emitter.feedback.js
index 8ec2ab5f0e8d..f086130e30a5 100644
--- a/packages/devextreme/js/events/core/emitter.feedback.js
+++ b/packages/devextreme/js/events/core/emitter.feedback.js
@@ -1,181 +1 @@
-import Class from '../../core/class';
-import { noop, ensureDefined } from '../../core/utils/common';
-import { contains } from '../../core/utils/dom';
-import devices from '../../core/devices';
-import { isMouseEvent } from '../utils/index';
-import pointerEvents from '../pointer';
-import Emitter from './emitter';
-import registerEmitter from './emitter_registrator';
-
-const ACTIVE_EVENT_NAME = 'dxactive';
-const INACTIVE_EVENT_NAME = 'dxinactive';
-
-const ACTIVE_TIMEOUT = 30;
-const INACTIVE_TIMEOUT = 400;
-
-
-const FeedbackEvent = Class.inherit({
-
- ctor: function(timeout, fire) {
- this._timeout = timeout;
- this._fire = fire;
- },
-
- start: function() {
- const that = this;
-
- this._schedule(function() {
- that.force();
- });
- },
-
- _schedule: function(fn) {
- this.stop();
- this._timer = setTimeout(fn, this._timeout);
- },
-
- stop: function() {
- clearTimeout(this._timer);
- },
-
- force: function() {
- if(this._fired) {
- return;
- }
-
- this.stop();
- this._fire();
- this._fired = true;
- },
-
- fired: function() {
- return this._fired;
- }
-
-});
-
-
-let activeFeedback;
-
-const FeedbackEmitter = Emitter.inherit({
-
- ctor: function() {
- this.callBase.apply(this, arguments);
-
- this._active = new FeedbackEvent(0, noop);
- this._inactive = new FeedbackEvent(0, noop);
- },
-
- configure: function(data, eventName) {
- switch(eventName) {
- case ACTIVE_EVENT_NAME:
- data.activeTimeout = data.timeout;
- break;
- case INACTIVE_EVENT_NAME:
- data.inactiveTimeout = data.timeout;
- break;
- }
-
- this.callBase(data);
- },
-
- start: function(e) {
- if(activeFeedback) {
- const activeChildExists = contains(this.getElement().get(0), activeFeedback.getElement().get(0));
- const childJustActivated = !activeFeedback._active.fired();
-
- if(activeChildExists && childJustActivated) {
- this._cancel();
- return;
- }
-
- activeFeedback._inactive.force();
- }
- activeFeedback = this;
-
- this._initEvents(e);
- this._active.start();
- },
-
- _initEvents: function(e) {
- const that = this;
-
- const eventTarget = this._getEmitterTarget(e);
-
- const mouseEvent = isMouseEvent(e);
- const isSimulator = devices.isSimulator();
- const deferFeedback = isSimulator || !mouseEvent;
-
- const activeTimeout = ensureDefined(this.activeTimeout, ACTIVE_TIMEOUT);
- const inactiveTimeout = ensureDefined(this.inactiveTimeout, INACTIVE_TIMEOUT);
-
- this._active = new FeedbackEvent(deferFeedback ? activeTimeout : 0, function() {
- that._fireEvent(ACTIVE_EVENT_NAME, e, { target: eventTarget });
- });
- this._inactive = new FeedbackEvent(deferFeedback ? inactiveTimeout : 0, function() {
- that._fireEvent(INACTIVE_EVENT_NAME, e, { target: eventTarget });
- activeFeedback = null;
- });
- },
-
- cancel: function(e) {
- this.end(e);
- },
-
- end: function(e) {
- const skipTimers = e.type !== pointerEvents.up;
-
- if(skipTimers) {
- this._active.stop();
- } else {
- this._active.force();
- }
-
- this._inactive.start();
-
- if(skipTimers) {
- this._inactive.force();
- }
- },
-
- dispose: function() {
- this._active.stop();
- this._inactive.stop();
-
- if(activeFeedback === this) {
- activeFeedback = null;
- }
-
- this.callBase();
- },
-
- lockInactive: function() {
- this._active.force();
- this._inactive.stop();
- activeFeedback = null;
- this._cancel();
-
- return this._inactive.force.bind(this._inactive);
- }
-
-});
-FeedbackEmitter.lock = function(deferred) {
- const lockInactive = activeFeedback ? activeFeedback.lockInactive() : noop;
-
- deferred.done(lockInactive);
-};
-
-
-registerEmitter({
- emitter: FeedbackEmitter,
- events: [
- ACTIVE_EVENT_NAME,
- INACTIVE_EVENT_NAME
- ]
-});
-
-export const lock = FeedbackEmitter.lock;
-export {
- ACTIVE_EVENT_NAME as active,
- INACTIVE_EVENT_NAME as inactive
-};
+export * from '../../__internal/events/core/m_emitter.feedback';
diff --git a/packages/devextreme/js/events/core/emitter.js b/packages/devextreme/js/events/core/emitter.js
index 5405d560c360..223a042f3077 100644
--- a/packages/devextreme/js/events/core/emitter.js
+++ b/packages/devextreme/js/events/core/emitter.js
@@ -1,106 +1 @@
-import $ from '../../core/renderer';
-import { noop } from '../../core/utils/common';
-import Class from '../../core/class';
-import Callbacks from '../../core/utils/callbacks';
-import { extend } from '../../core/utils/extend';
-import { isDxMouseWheelEvent, hasTouches, fireEvent } from '../utils/index';
-
-const Emitter = Class.inherit({
-
- ctor: function(element) {
- this._$element = $(element);
-
- this._cancelCallback = Callbacks();
- this._acceptCallback = Callbacks();
- },
-
- getElement: function() {
- return this._$element;
- },
-
- validate: function(e) {
- return !isDxMouseWheelEvent(e);
- },
-
- validatePointers: function(e) {
- return hasTouches(e) === 1;
- },
-
- allowInterruptionByMouseWheel: function() {
- return true;
- },
-
- configure: function(data) {
- extend(this, data);
- },
-
- addCancelCallback: function(callback) {
- this._cancelCallback.add(callback);
- },
-
- removeCancelCallback: function() {
- this._cancelCallback.empty();
- },
-
- _cancel: function(e) {
- this._cancelCallback.fire(this, e);
- },
-
- addAcceptCallback: function(callback) {
- this._acceptCallback.add(callback);
- },
-
- removeAcceptCallback: function() {
- this._acceptCallback.empty();
- },
-
- _accept: function(e) {
- this._acceptCallback.fire(this, e);
- },
-
- _requestAccept: function(e) {
- this._acceptRequestEvent = e;
- },
-
- _forgetAccept: function() {
- this._accept(this._acceptRequestEvent);
- this._acceptRequestEvent = null;
- },
-
- start: noop,
- move: noop,
- end: noop,
-
- cancel: noop,
- reset: function() {
- if(this._acceptRequestEvent) {
- this._accept(this._acceptRequestEvent);
- }
- },
-
- _fireEvent: function(eventName, e, params) {
- const eventData = extend({
- type: eventName,
- originalEvent: e,
- target: this._getEmitterTarget(e),
- delegateTarget: this.getElement().get(0)
- }, params);
-
- e = fireEvent(eventData);
-
- if(e.cancel) {
- this._cancel(e);
- }
-
- return e;
- },
-
- _getEmitterTarget: function(e) {
- return (this.delegateSelector ? $(e.target).closest(this.delegateSelector) : this.getElement()).get(0);
- },
-
- dispose: noop
-
-});
-
-export default Emitter;
+export { default } from '../../__internal/events/core/m_emitter';
diff --git a/packages/devextreme/js/events/core/emitter_registrator.js b/packages/devextreme/js/events/core/emitter_registrator.js
index ccfbbfb4797f..c9f061241a98 100644
--- a/packages/devextreme/js/events/core/emitter_registrator.js
+++ b/packages/devextreme/js/events/core/emitter_registrator.js
@@ -1,297 +1 @@
-import $ from '../../core/renderer';
-import readyCallbacks from '../../core/utils/ready_callbacks';
-import domAdapter from '../../core/dom_adapter';
-import eventsEngine from '../../events/core/events_engine';
-import { data as elementData } from '../../core/element_data';
-import Class from '../../core/class';
-import { extend } from '../../core/utils/extend';
-import { each } from '../../core/utils/iterator';
-import registerEvent from './event_registrator';
-import { addNamespace, isMouseEvent } from '../utils/index';
-import pointerEvents from '../pointer';
-import { name as wheelEventName } from './wheel';
-
-const MANAGER_EVENT = 'dxEventManager';
-const EMITTER_DATA = 'dxEmitter';
-
-const EventManager = Class.inherit({
-
- ctor: function() {
- this._attachHandlers();
- this.reset();
-
- this._proxiedCancelHandler = this._cancelHandler.bind(this);
- this._proxiedAcceptHandler = this._acceptHandler.bind(this);
- },
-
- _attachHandlers: function() {
- readyCallbacks.add(function() {
- const document = domAdapter.getDocument();
- eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.down, MANAGER_EVENT), this._pointerDownHandler.bind(this));
- eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.move, MANAGER_EVENT), this._pointerMoveHandler.bind(this));
- eventsEngine.subscribeGlobal(document, addNamespace([pointerEvents.up, pointerEvents.cancel].join(' '), MANAGER_EVENT), this._pointerUpHandler.bind(this));
- eventsEngine.subscribeGlobal(document, addNamespace(wheelEventName, MANAGER_EVENT), this._mouseWheelHandler.bind(this));
- }.bind(this));
- },
-
- _eachEmitter: function(callback) {
- const activeEmitters = this._activeEmitters || [];
- let i = 0;
-
- while(activeEmitters.length > i) {
- const emitter = activeEmitters[i];
- if(callback(emitter) === false) {
- break;
- }
-
- if(activeEmitters[i] === emitter) {
- i++;
- }
- }
- },
-
- _applyToEmitters: function(method, arg) {
- this._eachEmitter(function(emitter) {
- emitter[method].call(emitter, arg);
- });
- },
-
- reset: function() {
- this._eachEmitter(this._proxiedCancelHandler);
- this._activeEmitters = [];
- },
-
- resetEmitter: function(emitter) {
- this._proxiedCancelHandler(emitter);
- },
-
- _pointerDownHandler: function(e) {
- if(isMouseEvent(e) && e.which > 1) {
- return;
- }
-
- this._updateEmitters(e);
- },
-
- _updateEmitters: function(e) {
- if(!this._isSetChanged(e)) {
- return;
- }
-
- this._cleanEmitters(e);
- this._fetchEmitters(e);
- },
-
- _isSetChanged: function(e) {
- const currentSet = this._closestEmitter(e);
- const previousSet = this._emittersSet || [];
-
- let setChanged = currentSet.length !== previousSet.length;
-
- each(currentSet, function(index, emitter) {
- setChanged = setChanged || previousSet[index] !== emitter;
- return !setChanged;
- });
-
- this._emittersSet = currentSet;
-
- return setChanged;
- },
-
- _closestEmitter: function(e) {
- const that = this;
-
- const result = [];
- let $element = $(e.target);
-
- function handleEmitter(_, emitter) {
- if(!!emitter && emitter.validatePointers(e) && emitter.validate(e)) {
- emitter.addCancelCallback(that._proxiedCancelHandler);
- emitter.addAcceptCallback(that._proxiedAcceptHandler);
- result.push(emitter);
- }
- }
-
- while($element.length) {
- const emitters = elementData($element.get(0), EMITTER_DATA) || [];
- each(emitters, handleEmitter);
- $element = $element.parent();
- }
-
- return result;
- },
-
- _acceptHandler: function(acceptedEmitter, e) {
- const that = this;
-
- this._eachEmitter(function(emitter) {
- if(emitter !== acceptedEmitter) {
- that._cancelEmitter(emitter, e);
- }
- });
- },
-
- _cancelHandler: function(canceledEmitter, e) {
- this._cancelEmitter(canceledEmitter, e);
- },
-
- _cancelEmitter: function(emitter, e) {
- const activeEmitters = this._activeEmitters;
-
- if(e) {
- emitter.cancel(e);
- } else {
- emitter.reset();
- }
-
- emitter.removeCancelCallback();
- emitter.removeAcceptCallback();
-
- const emitterIndex = activeEmitters.indexOf(emitter);
- if(emitterIndex > -1) {
- activeEmitters.splice(emitterIndex, 1);
- }
- },
-
- _cleanEmitters: function(e) {
- this._applyToEmitters('end', e);
- this.reset(e);
- },
-
- _fetchEmitters: function(e) {
- this._activeEmitters = this._emittersSet.slice();
- this._applyToEmitters('start', e);
- },
-
- _pointerMoveHandler: function(e) {
- this._applyToEmitters('move', e);
- },
-
- _pointerUpHandler: function(e) {
- this._updateEmitters(e);
- },
-
- _mouseWheelHandler: function(e) {
- if(!this._allowInterruptionByMouseWheel()) {
- return;
- }
-
- e.pointers = [null];
- this._pointerDownHandler(e);
-
- this._adjustWheelEvent(e);
-
- this._pointerMoveHandler(e);
- e.pointers = [];
- this._pointerUpHandler(e);
- },
-
- _allowInterruptionByMouseWheel: function() {
- let allowInterruption = true;
- this._eachEmitter(function(emitter) {
- allowInterruption = emitter.allowInterruptionByMouseWheel() && allowInterruption;
- return allowInterruption;
- });
- return allowInterruption;
- },
-
- _adjustWheelEvent: function(e) {
- let closestGestureEmitter = null;
-
- this._eachEmitter(function(emitter) {
- if(!(emitter.gesture)) {
- return;
- }
-
- const direction = emitter.getDirection(e);
- if(direction !== 'horizontal' && !e.shiftKey || direction !== 'vertical' && e.shiftKey) {
- closestGestureEmitter = emitter;
- return false;
- }
- });
-
- if(!closestGestureEmitter) {
- return;
- }
-
- const direction = closestGestureEmitter.getDirection(e);
- const verticalGestureDirection = direction === 'both' && !e.shiftKey || direction === 'vertical';
- const prop = verticalGestureDirection ? 'pageY' : 'pageX';
-
- e[prop] += e.delta;
- },
-
- isActive: function(element) {
- let result = false;
- this._eachEmitter(function(emitter) {
- result = result || emitter.getElement().is(element);
- });
- return result;
- }
-});
-
-const eventManager = new EventManager();
-
-const EMITTER_SUBSCRIPTION_DATA = 'dxEmitterSubscription';
-
-const registerEmitter = function(emitterConfig) {
- const emitterClass = emitterConfig.emitter;
- const emitterName = emitterConfig.events[0];
- const emitterEvents = emitterConfig.events;
-
- each(emitterEvents, function(_, eventName) {
- registerEvent(eventName, {
-
- noBubble: !emitterConfig.bubble,
-
- setup: function(element) {
- const subscriptions = elementData(element, EMITTER_SUBSCRIPTION_DATA) || {};
-
- const emitters = elementData(element, EMITTER_DATA) || {};
- const emitter = emitters[emitterName] || new emitterClass(element);
-
- subscriptions[eventName] = true;
- emitters[emitterName] = emitter;
-
- elementData(element, EMITTER_DATA, emitters);
- elementData(element, EMITTER_SUBSCRIPTION_DATA, subscriptions);
- },
-
- add: function(element, handleObj) {
- const emitters = elementData(element, EMITTER_DATA);
- const emitter = emitters[emitterName];
-
- emitter.configure(extend({
- delegateSelector: handleObj.selector
- }, handleObj.data), handleObj.type);
- },
-
- teardown: function(element) {
- const subscriptions = elementData(element, EMITTER_SUBSCRIPTION_DATA);
-
- const emitters = elementData(element, EMITTER_DATA);
- const emitter = emitters[emitterName];
-
- delete subscriptions[eventName];
-
- let disposeEmitter = true;
- each(emitterEvents, function(_, eventName) {
- disposeEmitter = disposeEmitter && !subscriptions[eventName];
- return disposeEmitter;
- });
-
- if(disposeEmitter) {
- if(eventManager.isActive(element)) {
- eventManager.resetEmitter(emitter);
- }
-
- emitter && emitter.dispose();
- delete emitters[emitterName];
- }
- }
-
- });
- });
-};
-
-export default registerEmitter;
+export { default } from '../../__internal/events/core/m_emitter_registrator';
diff --git a/packages/devextreme/js/events/core/event_registrator.js b/packages/devextreme/js/events/core/event_registrator.js
index f15717cc1523..4de26caede8d 100644
--- a/packages/devextreme/js/events/core/event_registrator.js
+++ b/packages/devextreme/js/events/core/event_registrator.js
@@ -1,35 +1 @@
-import { each } from '../../core/utils/iterator';
-import callbacks from './event_registrator_callbacks';
-
-const registerEvent = function(name, eventObject) {
- const strategy = {};
-
- if('noBubble' in eventObject) {
- strategy.noBubble = eventObject.noBubble;
- }
-
- if('bindType' in eventObject) {
- strategy.bindType = eventObject.bindType;
- }
-
- if('delegateType' in eventObject) {
- strategy.delegateType = eventObject.delegateType;
- }
-
- each(['setup', 'teardown', 'add', 'remove', 'trigger', 'handle', '_default', 'dispose'], function(_, methodName) {
- if(!eventObject[methodName]) {
- return;
- }
-
- strategy[methodName] = function() {
- const args = [].slice.call(arguments);
- args.unshift(this);
- return eventObject[methodName].apply(eventObject, args);
- };
- });
-
- callbacks.fire(name, strategy);
-};
-registerEvent.callbacks = callbacks;
-
-export default registerEvent;
+export { default } from '../../__internal/events/core/m_event_registrator';
diff --git a/packages/devextreme/js/events/core/events_engine.js b/packages/devextreme/js/events/core/events_engine.js
index 853c9d5cee3b..a8e5d0c5e304 100644
--- a/packages/devextreme/js/events/core/events_engine.js
+++ b/packages/devextreme/js/events/core/events_engine.js
@@ -1,685 +1 @@
-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';
-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'
-};
-const NATIVE_EVENTS_TO_TRIGGER = {
- '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'
-];
-
-function matchesSafe(target, selector) {
- return !isWindow(target) && target.nodeName !== '#document' && domAdapter.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 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++;
- }
- }
-
- if(element.nodeType || isWindow(element)) {
- special.callMethod(eventName, '_default', element, [ event, extraParameters ]);
- callNativeMethod(eventName, element);
- }
- })),
-
- triggerHandler: getHandler(normalizeTriggerArguments(function(element, event, extraParameters) {
- const handlersController = getHandlersController(element, event.type);
- handlersController.callHandlers(event, extraParameters);
- }))
-});
-
-function applyForEach(args, method) {
- const element = args[0];
-
- 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);
-
- Array.prototype.forEach.call(element, function(itemElement) {
- itemArgs[0] = itemElement;
- applyForEach(itemArgs, method);
- });
- } else {
- throw errors.Error('E0025');
- }
-}
-
-function getHandler(method) {
- return function() {
- applyForEach(arguments, method);
- };
-}
-
-function detectPassiveEventHandlersSupport() {
- let isSupported = false;
-
- try {
- const options = Object.defineProperty({ }, 'passive', {
- get: function() {
- isSupported = true;
- return true;
- }
- });
-
- window.addEventListener('test', null, options);
- } catch(e) { }
-
- return isSupported;
-}
-
-const passiveEventHandlersSupported = callOnce(detectPassiveEventHandlersSupport);
-
-const contains = (container, element) => {
- if(isWindow(container)) {
- return contains(container.document, element);
- }
-
- return container.contains
- ? container.contains(element)
- : !!(element.compareDocumentPosition(container) & element.DOCUMENT_POSITION_CONTAINS);
-};
-
-function getHandlersController(element, eventName) {
- let elementData = elementDataMap.get(element);
-
- eventName = eventName || '';
-
- const eventNameParts = eventName.split('.');
- const namespaces = eventNameParts.slice(1);
- const eventNameIsDefined = !!eventNameParts[0];
-
- eventName = eventNameParts[0] || EMPTY_EVENT_NAME;
-
- if(!elementData) {
- elementData = {};
- elementDataMap.set(element, elementData);
- }
-
- 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 ]);
- }
-
- if(shouldAddNativeListener) {
- eventData.nativeHandler = getNativeHandler(eventName);
-
- if(passiveEventHandlersSupported() && forcePassiveFalseEventNames.indexOf(eventName) > -1) {
- nativeListenerOptions = {
- passive: false
- };
- }
-
- eventData.removeListener = domAdapter.listen(element, NATIVE_EVENTS_TO_SUBSCRIBE[eventName] || eventName, eventData.nativeHandler, nativeListenerOptions);
- }
-
- 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);
- }
- }
-
- const elementDataIsEmpty = Object.keys(elementData).length === 0;
-
- if(elementDataIsEmpty) {
- elementDataMap.delete(element);
- }
- },
-
- callHandlers: function(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);
- };
-}
-
-function isSubset(original, checked) {
- 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;
- }
-
- if(!handler && typeof eventName === 'string') {
- handler = data || selector;
- selector = undefined;
- data = undefined;
- }
-
- callback(element, eventName, selector, data, handler);
- };
-}
-
-function normalizeOffArguments(callback) {
- return function(element, eventName, selector, handler) {
- if(typeof selector === 'function') {
- handler = selector;
- selector = undefined;
- }
-
- callback(element, eventName, selector, handler);
- };
-}
-
-function normalizeTriggerArguments(callback) {
- return function(element, src, extraParameters) {
- if(typeof src === 'string') {
- src = {
- type: src
- };
- }
-
- if(!src.target) {
- src.target = element;
- }
-
- src.currentTarget = element;
-
- if(!src.delegateTarget) {
- src.delegateTarget = element;
- }
-
- if(!src.type && src.originalEvent) {
- src.type = src.originalEvent.type;
- }
-
- 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 = {};
- }
-
- if(typeof src === 'string') {
- src = {
- type: src
- };
- }
-
- if(!config) {
- config = {};
- }
-
- 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();
- }
-
- });
- 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);
- }
- };
-
- return function(element, eventName) {
- if(typeof eventName === 'object') {
- const args = 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);
- }
- };
-}
-
-function callNativeMethod(eventName, element) {
- const nativeMethodName = NATIVE_EVENTS_TO_TRIGGER[eventName] || eventName;
-
- const isLinkClickEvent = function(eventName, element) {
- return eventName === 'click' && element.localName === 'a';
- };
-
- if(isLinkClickEvent(eventName, element)) return;
-
- 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 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;
-}
-
-function initEvent(EventClass) {
- 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);
- }
-
- addProperty('which', calculateWhich, this);
-
- if(src.type.indexOf('touch') === 0) {
- delete config.pageX;
- delete config.pageY;
- }
-
- Object.assign(this, config);
-
- this.guid = ++guid;
-}));
-
-function addProperty(propName, hook, eventInstance) {
- Object.defineProperty(eventInstance || eventsEngine.Event.prototype, 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
- });
- }
- });
-}
-
-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.subscribeGlobal = function() {
- applyForEach(arguments, normalizeOnArguments(function() {
- const args = arguments;
-
- 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);
- });
-
- afterSetStrategy.add(function() {
- eventsEngine.on.apply(this, args);
- });
- }));
-};
-
-eventsEngine.forcePassiveFalseEventNames = forcePassiveFalseEventNames;
-eventsEngine.passiveEventHandlersSupported = passiveEventHandlersSupported;
-
-///#DEBUG
-eventsEngine.elementDataMap = elementDataMap;
-eventsEngine.detectPassiveEventHandlersSupport = detectPassiveEventHandlersSupport;
-
-///#ENDDEBUG
-
-export default eventsEngine;
+export { default } from '../../__internal/events/core/m_events_engine';
diff --git a/packages/devextreme/js/events/core/hook_touch_props.js b/packages/devextreme/js/events/core/hook_touch_props.js
index fec9f76a8e75..96daa6e79e09 100644
--- a/packages/devextreme/js/events/core/hook_touch_props.js
+++ b/packages/devextreme/js/events/core/hook_touch_props.js
@@ -1,21 +1 @@
-const touchPropsToHook = ['pageX', 'pageY', 'screenX', 'screenY', 'clientX', 'clientY'];
-const touchPropHook = function(name, event) {
- if(event[name] && !event.touches || !event.touches) {
- return event[name];
- }
-
- const touches = event.touches.length ? event.touches : event.changedTouches;
- if(!touches.length) {
- return;
- }
-
- return touches[0][name];
-};
-
-export default function(callback) {
- touchPropsToHook.forEach(function(name) {
- callback(name, function(event) {
- return touchPropHook(name, event);
- });
- }, this);
-}
+export { default } from '../../__internal/events/core/m_hook_touch_props';
diff --git a/packages/devextreme/js/events/core/keyboard_processor.js b/packages/devextreme/js/events/core/keyboard_processor.js
index ad018beb86c9..d7e367d4c144 100644
--- a/packages/devextreme/js/events/core/keyboard_processor.js
+++ b/packages/devextreme/js/events/core/keyboard_processor.js
@@ -1,82 +1 @@
-import $ from '../../core/renderer';
-import eventsEngine from '../../events/core/events_engine';
-import Class from '../../core/class';
-import { addNamespace, normalizeKeyName } from '../../events/utils/index';
-
-const COMPOSITION_START_EVENT = 'compositionstart';
-const COMPOSITION_END_EVENT = 'compositionend';
-const KEYDOWN_EVENT = 'keydown';
-const NAMESPACE = 'KeyboardProcessor';
-
-const createKeyDownOptions = (e) => {
- return {
- keyName: normalizeKeyName(e),
- key: e.key,
- code: e.code,
- ctrl: e.ctrlKey,
- location: e.location,
- metaKey: e.metaKey,
- shift: e.shiftKey,
- alt: e.altKey,
- which: e.which,
- originalEvent: e
- };
-};
-
-const KeyboardProcessor = Class.inherit({
- _keydown: addNamespace(KEYDOWN_EVENT, NAMESPACE),
- _compositionStart: addNamespace(COMPOSITION_START_EVENT, NAMESPACE),
- _compositionEnd: addNamespace(COMPOSITION_END_EVENT, NAMESPACE),
-
- ctor: function(options) {
- options = options || {};
- if(options.element) {
- this._element = $(options.element);
- }
- if(options.focusTarget) {
- this._focusTarget = options.focusTarget;
- }
- this._handler = options.handler;
-
- if(this._element) {
- this._processFunction = (e) => {
- const focusTargets = $(this._focusTarget).toArray();
- const isNotFocusTarget = this._focusTarget && this._focusTarget !== e.target && !focusTargets.includes(e.target);
- const shouldSkipProcessing = this._isComposingJustFinished && e.which === 229 || this._isComposing || isNotFocusTarget;
-
- this._isComposingJustFinished = false;
- if(!shouldSkipProcessing) {
- this.process(e);
- }
- };
- this._toggleProcessingWithContext = this.toggleProcessing.bind(this);
-
- eventsEngine.on(this._element, this._keydown, this._processFunction);
- eventsEngine.on(this._element, this._compositionStart, this._toggleProcessingWithContext);
- eventsEngine.on(this._element, this._compositionEnd, this._toggleProcessingWithContext);
- }
- },
-
- dispose: function() {
- if(this._element) {
- eventsEngine.off(this._element, this._keydown, this._processFunction);
- eventsEngine.off(this._element, this._compositionStart, this._toggleProcessingWithContext);
- eventsEngine.off(this._element, this._compositionEnd, this._toggleProcessingWithContext);
- }
- this._element = undefined;
- this._handler = undefined;
- },
-
- process: function(e) {
- this._handler(createKeyDownOptions(e));
- },
-
- toggleProcessing: function({ type }) {
- this._isComposing = type === COMPOSITION_START_EVENT;
- this._isComposingJustFinished = !this._isComposing;
- }
-});
-
-KeyboardProcessor.createKeyDownOptions = createKeyDownOptions;
-
-export default KeyboardProcessor;
+export { default } from '../../__internal/events/core/m_keyboard_processor';
diff --git a/packages/devextreme/js/events/core/wheel.js b/packages/devextreme/js/events/core/wheel.js
index 4e99c61d5b6d..c9d2e35c81d2 100644
--- a/packages/devextreme/js/events/core/wheel.js
+++ b/packages/devextreme/js/events/core/wheel.js
@@ -1,54 +1 @@
-import $ from '../../core/renderer';
-import eventsEngine from '../../events/core/events_engine';
-import registerEvent from './event_registrator';
-import { addNamespace, fireEvent } from '../utils/index';
-
-
-const EVENT_NAME = 'dxmousewheel';
-const EVENT_NAMESPACE = 'dxWheel';
-const NATIVE_EVENT_NAME = 'wheel';
-
-const PIXEL_MODE = 0;
-const DELTA_MUTLIPLIER = 30;
-
-const wheel = {
- setup: function(element) {
- const $element = $(element);
- eventsEngine.on($element, addNamespace(NATIVE_EVENT_NAME, EVENT_NAMESPACE), wheel._wheelHandler.bind(wheel));
- },
-
- teardown: function(element) {
- eventsEngine.off(element, `.${EVENT_NAMESPACE}`);
- },
-
- _wheelHandler: function(e) {
- const { deltaMode, deltaY, deltaX, deltaZ } = e.originalEvent;
-
- fireEvent({
- type: EVENT_NAME,
- originalEvent: e,
- delta: this._normalizeDelta(deltaY, deltaMode),
- deltaX,
- deltaY,
- deltaZ,
- deltaMode,
- pointerType: 'mouse'
- });
-
- e.stopPropagation();
- },
-
- _normalizeDelta(delta, deltaMode = PIXEL_MODE) {
- if(deltaMode === PIXEL_MODE) {
- return -delta;
- } else {
- // Use multiplier to get rough delta value in px for the LINE or PAGE mode
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460
- return -DELTA_MUTLIPLIER * delta;
- }
- }
-};
-
-registerEvent(EVENT_NAME, wheel);
-
-export { EVENT_NAME as name };
+export * from '../../__internal/events/core/m_wheel';
diff --git a/packages/devextreme/js/events/double_click.js b/packages/devextreme/js/events/double_click.js
index f095c10cda89..3e0cf4edb96e 100644
--- a/packages/devextreme/js/events/double_click.js
+++ b/packages/devextreme/js/events/double_click.js
@@ -1,4 +1,4 @@
-import { name, dblClick } from '../__internal/events/dblclick';
+import { name, dblClick } from '../__internal/events/m_dblclick';
import registerEvent from './core/event_registrator';
registerEvent(name, dblClick);
diff --git a/packages/devextreme/js/events/drag.js b/packages/devextreme/js/events/drag.js
index ceed272dd460..c03bdb173853 100644
--- a/packages/devextreme/js/events/drag.js
+++ b/packages/devextreme/js/events/drag.js
@@ -1,74 +1,3 @@
-import $ from '../core/renderer';
-import { data as elementData, removeData } from '../core/element_data';
-import { wrapToArray } from '../core/utils/array';
-import * as iteratorUtils from '../core/utils/iterator';
-import { contains } from '../core/utils/dom';
-import registerEvent from './core/event_registrator';
-import { eventData as eData, fireEvent } from './utils/index';
-import GestureEmitter from './gesture/emitter.gesture';
-import registerEmitter from './core/emitter_registrator';
-
-
-const DRAG_START_EVENT = 'dxdragstart';
-const DRAG_EVENT = 'dxdrag';
-const DRAG_END_EVENT = 'dxdragend';
-
-const DRAG_ENTER_EVENT = 'dxdragenter';
-const DRAG_LEAVE_EVENT = 'dxdragleave';
-const DROP_EVENT = 'dxdrop';
-
-const DX_DRAG_EVENTS_COUNT_KEY = 'dxDragEventsCount';
-
-
-const knownDropTargets = [];
-const knownDropTargetSelectors = [];
-const knownDropTargetConfigs = [];
-
-const dropTargetRegistration = {
-
- setup: function(element, data) {
- const knownDropTarget = knownDropTargets.includes(element);
- if(!knownDropTarget) {
- knownDropTargets.push(element);
- knownDropTargetSelectors.push([]);
- knownDropTargetConfigs.push(data || {});
- }
- },
-
- add: function(element, handleObj) {
- const index = knownDropTargets.indexOf(element);
- this.updateEventsCounter(element, handleObj.type, 1);
-
- const selector = handleObj.selector;
- if(!knownDropTargetSelectors[index].includes(selector)) {
- knownDropTargetSelectors[index].push(selector);
- }
- },
-
- updateEventsCounter: function(element, event, value) {
- if([DRAG_ENTER_EVENT, DRAG_LEAVE_EVENT, DROP_EVENT].indexOf(event) > -1) {
- const eventsCount = elementData(element, DX_DRAG_EVENTS_COUNT_KEY) || 0;
- elementData(element, DX_DRAG_EVENTS_COUNT_KEY, Math.max(0, eventsCount + value));
- }
- },
-
- remove: function(element, handleObj) {
- this.updateEventsCounter(element, handleObj.type, -1);
- },
-
- teardown: function(element) {
- const handlersCount = elementData(element, DX_DRAG_EVENTS_COUNT_KEY);
- if(!handlersCount) {
- const index = knownDropTargets.indexOf(element);
- knownDropTargets.splice(index, 1);
- knownDropTargetSelectors.splice(index, 1);
- knownDropTargetConfigs.splice(index, 1);
- removeData(element, DX_DRAG_EVENTS_COUNT_KEY);
- }
- }
-
-};
-
/**
* @name UI Events.dxdragenter
* @type eventType
@@ -90,229 +19,6 @@ const dropTargetRegistration = {
* @type_function_param1_field1 draggingElement:Element
* @module events/drag
*/
-
-registerEvent(DRAG_ENTER_EVENT, dropTargetRegistration);
-registerEvent(DRAG_LEAVE_EVENT, dropTargetRegistration);
-registerEvent(DROP_EVENT, dropTargetRegistration);
-
-const getItemDelegatedTargets = function($element) {
- const dropTargetIndex = knownDropTargets.indexOf($element.get(0));
- const dropTargetSelectors = knownDropTargetSelectors[dropTargetIndex].filter((selector) => selector);
-
- let $delegatedTargets = $element.find(dropTargetSelectors.join(', '));
- if(knownDropTargetSelectors[dropTargetIndex].includes(undefined)) {
- $delegatedTargets = $delegatedTargets.add($element);
- }
- return $delegatedTargets;
-};
-
-const getItemConfig = function($element) {
- const dropTargetIndex = knownDropTargets.indexOf($element.get(0));
- return knownDropTargetConfigs[dropTargetIndex];
-};
-
-const getItemPosition = function(dropTargetConfig, $element) {
- if(dropTargetConfig.itemPositionFunc) {
- return dropTargetConfig.itemPositionFunc($element);
- } else {
- return $element.offset();
- }
-};
-
-const getItemSize = function(dropTargetConfig, $element) {
- if(dropTargetConfig.itemSizeFunc) {
- return dropTargetConfig.itemSizeFunc($element);
- }
-
- return {
- width: $element.get(0).getBoundingClientRect().width,
- height: $element.get(0).getBoundingClientRect().height
- };
-};
-
-const DragEmitter = GestureEmitter.inherit({
-
- ctor: function(element) {
- this.callBase(element);
-
- this.direction = 'both';
- },
-
- _init: function(e) {
- this._initEvent = e;
- },
-
- _start: function(e) {
- e = this._fireEvent(DRAG_START_EVENT, this._initEvent);
-
- this._maxLeftOffset = e.maxLeftOffset;
- this._maxRightOffset = e.maxRightOffset;
- this._maxTopOffset = e.maxTopOffset;
- this._maxBottomOffset = e.maxBottomOffset;
-
- if(e.targetElements || e.targetElements === null) {
- const dropTargets = wrapToArray(e.targetElements || []);
- this._dropTargets = iteratorUtils.map(dropTargets, function(element) { return $(element).get(0); });
- } else {
- this._dropTargets = knownDropTargets;
- }
- },
-
- _move: function(e) {
- const eventData = eData(e);
- const dragOffset = this._calculateOffset(eventData);
-
- e = this._fireEvent(DRAG_EVENT, e, {
- offset: dragOffset
- });
-
- this._processDropTargets(e);
-
- if(!e._cancelPreventDefault) {
- e.preventDefault();
- }
- },
-
- _calculateOffset: function(eventData) {
- return {
- x: this._calculateXOffset(eventData),
- y: this._calculateYOffset(eventData)
- };
- },
-
- _calculateXOffset: function(eventData) {
- if(this.direction !== 'vertical') {
- const offset = eventData.x - this._startEventData.x;
-
- return this._fitOffset(offset, this._maxLeftOffset, this._maxRightOffset);
- }
- return 0;
- },
-
- _calculateYOffset: function(eventData) {
- if(this.direction !== 'horizontal') {
- const offset = eventData.y - this._startEventData.y;
-
- return this._fitOffset(offset, this._maxTopOffset, this._maxBottomOffset);
- }
- return 0;
- },
-
- _fitOffset: function(offset, minOffset, maxOffset) {
- if(minOffset != null) {
- offset = Math.max(offset, -minOffset);
- }
- if(maxOffset != null) {
- offset = Math.min(offset, maxOffset);
- }
-
- return offset;
- },
-
- _processDropTargets: function(e) {
- const target = this._findDropTarget(e);
- const sameTarget = target === this._currentDropTarget;
-
- if(!sameTarget) {
- this._fireDropTargetEvent(e, DRAG_LEAVE_EVENT);
- this._currentDropTarget = target;
- this._fireDropTargetEvent(e, DRAG_ENTER_EVENT);
- }
- },
-
- _fireDropTargetEvent: function(event, eventName) {
- if(!this._currentDropTarget) {
- return;
- }
-
- const eventData = {
- type: eventName,
- originalEvent: event,
- draggingElement: this._$element.get(0),
- target: this._currentDropTarget
- };
-
- fireEvent(eventData);
- },
-
- _findDropTarget: function(e) {
- const that = this;
- let result;
-
- iteratorUtils.each(knownDropTargets, function(_, target) {
- if(!that._checkDropTargetActive(target)) {
- return;
- }
-
- const $target = $(target);
- iteratorUtils.each(getItemDelegatedTargets($target), function(_, delegatedTarget) {
- const $delegatedTarget = $(delegatedTarget);
- if(that._checkDropTarget(getItemConfig($target), $delegatedTarget, $(result), e)) {
- result = delegatedTarget;
- }
- });
- });
-
- return result;
- },
-
- _checkDropTargetActive: function(target) {
- let active = false;
-
- iteratorUtils.each(this._dropTargets, function(_, activeTarget) {
- active = active || activeTarget === target || contains(activeTarget, target);
- return !active;
- });
-
- return active;
- },
-
- _checkDropTarget: function(config, $target, $prevTarget, e) {
- const isDraggingElement = $target.get(0) === $(e.target).get(0);
- if(isDraggingElement) {
- return false;
- }
-
- const targetPosition = getItemPosition(config, $target);
- if(e.pageX < targetPosition.left) {
- return false;
- }
- if(e.pageY < targetPosition.top) {
- return false;
- }
-
- const targetSize = getItemSize(config, $target);
- if(e.pageX > targetPosition.left + targetSize.width) {
- return false;
- }
- if(e.pageY > targetPosition.top + targetSize.height) {
- return false;
- }
-
- if($prevTarget.length && $prevTarget.closest($target).length) {
- return false;
- }
-
- if(config.checkDropTarget && !config.checkDropTarget($target, e)) {
- return false;
- }
-
- return $target;
- },
-
- _end: function(e) {
- const eventData = eData(e);
-
- this._fireEvent(DRAG_END_EVENT, e, {
- offset: this._calculateOffset(eventData)
- });
-
- this._fireDropTargetEvent(e, DROP_EVENT);
- delete this._currentDropTarget;
- }
-
-});
-
/**
* @name UI Events.dxdragstart
* @type eventType
@@ -336,26 +42,4 @@ const DragEmitter = GestureEmitter.inherit({
* @type_function_param1_field2 cancel:boolean
* @module events/drag
*/
-
-registerEmitter({
- emitter: DragEmitter,
- events: [
- DRAG_START_EVENT,
- DRAG_EVENT,
- DRAG_END_EVENT
- ]
-});
-
-
-///#DEBUG
-export { knownDropTargets as dropTargets };
-///#ENDDEBUG
-
-export {
- DRAG_EVENT as move,
- DRAG_START_EVENT as start,
- DRAG_END_EVENT as end,
- DRAG_ENTER_EVENT as enter,
- DRAG_LEAVE_EVENT as leave,
- DROP_EVENT as drop
-};
+export * from '../__internal/events/m_drag';
diff --git a/packages/devextreme/js/events/gesture/emitter.gesture.js b/packages/devextreme/js/events/gesture/emitter.gesture.js
index bbf8c1a2146a..bacdf0ee957e 100644
--- a/packages/devextreme/js/events/gesture/emitter.gesture.js
+++ b/packages/devextreme/js/events/gesture/emitter.gesture.js
@@ -1,236 +1 @@
-import $ from '../../core/renderer';
-import eventsEngine from '../../events/core/events_engine';
-import devices from '../../core/devices';
-import { styleProp } from '../../core/utils/style';
-import callOnce from '../../core/utils/call_once';
-import { resetActiveElement, clearSelection } from '../../core/utils/dom';
-import readyCallbacks from '../../core/utils/ready_callbacks';
-const ready = readyCallbacks.add;
-import { sign } from '../../core/utils/math';
-import { noop } from '../../core/utils/common';
-import { isDefined } from '../../core/utils/type';
-import { needSkipEvent, createEvent, eventData, isDxMouseWheelEvent, eventDelta, isTouchEvent } from '../utils/index';
-import Emitter from '../core/emitter';
-const abs = Math.abs;
-
-const SLEEP = 0;
-const INITED = 1;
-const STARTED = 2;
-
-let TOUCH_BOUNDARY = 10;
-const IMMEDIATE_TOUCH_BOUNDARY = 0;
-const IMMEDIATE_TIMEOUT = 180;
-
-const supportPointerEvents = function() {
- return styleProp('pointer-events');
-};
-
-const setGestureCover = callOnce(function() {
- const GESTURE_COVER_CLASS = 'dx-gesture-cover';
-
- const isDesktop = devices.real().deviceType === 'desktop';
-
- if(!supportPointerEvents() || !isDesktop) {
- return noop;
- }
-
- const $cover = $('')
- .addClass(GESTURE_COVER_CLASS)
- .css('pointerEvents', 'none');
-
- eventsEngine.subscribeGlobal($cover, 'dxmousewheel', function(e) {
- e.preventDefault();
- });
-
- ready(function() {
- $cover.appendTo('body');
- });
-
- return function(toggle, cursor) {
- $cover.css('pointerEvents', toggle ? 'all' : 'none');
- toggle && $cover.css('cursor', cursor);
- };
-});
-
-const gestureCover = function(toggle, cursor) {
- const gestureCoverStrategy = setGestureCover();
- gestureCoverStrategy(toggle, cursor);
-};
-
-const GestureEmitter = Emitter.inherit({
-
- gesture: true,
-
- configure: function(data) {
- this.getElement().css('msTouchAction', data.immediate ? 'pinch-zoom' : '');
-
- this.callBase(data);
- },
-
- allowInterruptionByMouseWheel: function() {
- return this._stage !== STARTED;
- },
-
- getDirection: function() {
- return this.direction;
- },
-
- _cancel: function() {
- this.callBase.apply(this, arguments);
-
- this._toggleGestureCover(false);
- this._stage = SLEEP;
- },
-
- start: function(e) {
- if(e._needSkipEvent || needSkipEvent(e)) {
- this._cancel(e);
- return;
- }
-
- this._startEvent = createEvent(e);
- this._startEventData = eventData(e);
-
- this._stage = INITED;
- this._init(e);
-
- this._setupImmediateTimer();
- },
-
- _setupImmediateTimer: function() {
- clearTimeout(this._immediateTimer);
- this._immediateAccepted = false;
-
- if(!this.immediate) {
- return;
- }
-
- if(this.immediateTimeout === 0) {
- this._immediateAccepted = true;
- return;
- }
-
- this._immediateTimer = setTimeout((function() {
- this._immediateAccepted = true;
- }).bind(this), this.immediateTimeout ?? IMMEDIATE_TIMEOUT);
- },
-
- move: function(e) {
- if(this._stage === INITED && this._directionConfirmed(e)) {
- this._stage = STARTED;
-
- this._resetActiveElement();
- this._toggleGestureCover(true);
- this._clearSelection(e);
-
- this._adjustStartEvent(e);
- this._start(this._startEvent);
-
- if(this._stage === SLEEP) {
- return;
- }
-
- this._requestAccept(e);
- this._move(e);
- this._forgetAccept();
- } else if(this._stage === STARTED) {
- this._clearSelection(e);
- this._move(e);
- }
- },
-
- _directionConfirmed: function(e) {
- const touchBoundary = this._getTouchBoundary(e);
- const delta = eventDelta(this._startEventData, eventData(e));
- const deltaX = abs(delta.x);
- const deltaY = abs(delta.y);
-
- const horizontalMove = this._validateMove(touchBoundary, deltaX, deltaY);
- const verticalMove = this._validateMove(touchBoundary, deltaY, deltaX);
-
- const direction = this.getDirection(e);
- const bothAccepted = direction === 'both' && (horizontalMove || verticalMove);
- const horizontalAccepted = direction === 'horizontal' && horizontalMove;
- const verticalAccepted = direction === 'vertical' && verticalMove;
-
- return bothAccepted || horizontalAccepted || verticalAccepted || this._immediateAccepted;
- },
-
- _validateMove: function(touchBoundary, mainAxis, crossAxis) {
- return mainAxis && mainAxis >= touchBoundary && (this.immediate ? mainAxis >= crossAxis : true);
- },
-
- _getTouchBoundary: function(e) {
- return (this.immediate || isDxMouseWheelEvent(e)) ? IMMEDIATE_TOUCH_BOUNDARY : TOUCH_BOUNDARY;
- },
-
- _adjustStartEvent: function(e) {
- const touchBoundary = this._getTouchBoundary(e);
- const delta = eventDelta(this._startEventData, eventData(e));
-
- this._startEvent.pageX += sign(delta.x) * touchBoundary;
- this._startEvent.pageY += sign(delta.y) * touchBoundary;
- },
-
- _resetActiveElement: function() {
- if(devices.real().platform === 'ios' && this.getElement().find(':focus').length) {
- resetActiveElement();
- }
- },
-
- _toggleGestureCover: function(toggle) {
- this._toggleGestureCoverImpl(toggle);
- },
-
- _toggleGestureCoverImpl: function(toggle) {
- const isStarted = this._stage === STARTED;
-
- if(isStarted) {
- gestureCover(toggle, this.getElement().css('cursor'));
- }
- },
-
- _clearSelection: function(e) {
- if(isDxMouseWheelEvent(e) || isTouchEvent(e)) {
- return;
- }
-
- clearSelection();
- },
-
- end: function(e) {
- this._toggleGestureCover(false);
-
- if(this._stage === STARTED) {
- this._end(e);
- } else if(this._stage === INITED) {
- this._stop(e);
- }
-
- this._stage = SLEEP;
- },
-
- dispose: function() {
- clearTimeout(this._immediateTimer);
- this.callBase.apply(this, arguments);
- this._toggleGestureCover(false);
- },
-
- _init: noop,
- _start: noop,
- _move: noop,
- _stop: noop,
- _end: noop
-
-});
-GestureEmitter.initialTouchBoundary = TOUCH_BOUNDARY;
-GestureEmitter.touchBoundary = function(newBoundary) {
- if(isDefined(newBoundary)) {
- TOUCH_BOUNDARY = newBoundary;
- return;
- }
-
- return TOUCH_BOUNDARY;
-};
-
-export default GestureEmitter;
+export { default } from '../../__internal/events/gesture/m_emitter.gesture';
diff --git a/packages/devextreme/js/events/gesture/emitter.gesture.scroll.js b/packages/devextreme/js/events/gesture/emitter.gesture.scroll.js
index 68848097870c..d3ae4e160f92 100644
--- a/packages/devextreme/js/events/gesture/emitter.gesture.scroll.js
+++ b/packages/devextreme/js/events/gesture/emitter.gesture.scroll.js
@@ -1,355 +1 @@
-import eventsEngine from '../../events/core/events_engine';
-import Class from '../../core/class';
-const abstract = Class.abstract;
-import { addNamespace, isDxMouseWheelEvent, isMouseEvent, eventData, eventDelta } from '../../events/utils/index';
-import GestureEmitter from '../../events/gesture/emitter.gesture';
-import registerEmitter from '../../events/core/emitter_registrator';
-import { requestAnimationFrame, cancelAnimationFrame } from '../../animation/frame';
-import devices from '../../core/devices';
-
-const realDevice = devices.real();
-
-const SCROLL_EVENT = 'scroll';
-const SCROLL_INIT_EVENT = 'dxscrollinit';
-const SCROLL_START_EVENT = 'dxscrollstart';
-const SCROLL_MOVE_EVENT = 'dxscroll';
-const SCROLL_END_EVENT = 'dxscrollend';
-const SCROLL_STOP_EVENT = 'dxscrollstop';
-const SCROLL_CANCEL_EVENT = 'dxscrollcancel';
-
-
-const Locker = Class.inherit((function() {
-
- const NAMESPACED_SCROLL_EVENT = addNamespace(SCROLL_EVENT, 'dxScrollEmitter');
-
- return {
-
- ctor: function(element) {
- this._element = element;
-
- this._locked = false;
-
- this._proxiedScroll = (e) => {
- if(!this._disposed) {
- this._scroll(e);
- }
- };
- eventsEngine.on(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll);
- },
-
- _scroll: abstract,
-
- check: function(e, callback) {
- if(this._locked) {
- callback();
- }
- },
-
- dispose: function() {
- this._disposed = true;
- eventsEngine.off(this._element, NAMESPACED_SCROLL_EVENT, this._proxiedScroll);
- }
-
- };
-
-})());
-
-
-const TimeoutLocker = Locker.inherit((function() {
-
- return {
-
- ctor: function(element, timeout) {
- this.callBase(element);
-
- this._timeout = timeout;
- },
-
- _scroll: function() {
- this._prepare();
- this._forget();
- },
-
- _prepare: function() {
- if(this._timer) {
- this._clearTimer();
- }
- this._locked = true;
- },
-
- _clearTimer: function() {
- clearTimeout(this._timer);
- this._locked = false;
- this._timer = null;
- },
-
- _forget: function() {
- const that = this;
-
- this._timer = setTimeout(function() {
- that._clearTimer();
- }, this._timeout);
- },
-
- dispose: function() {
- this.callBase();
-
- this._clearTimer();
- }
-
- };
-
-})());
-
-
-const WheelLocker = TimeoutLocker.inherit((function() {
-
- const WHEEL_UNLOCK_TIMEOUT = 400;
-
- return {
-
- ctor: function(element) {
- this.callBase(element, WHEEL_UNLOCK_TIMEOUT);
-
- this._lastWheelDirection = null;
- },
-
- check: function(e, callback) {
- this._checkDirectionChanged(e);
-
- this.callBase(e, callback);
- },
-
- _checkDirectionChanged: function(e) {
- if(!isDxMouseWheelEvent(e)) {
- this._lastWheelDirection = null;
- return;
- }
-
- const direction = e.shiftKey || false;
- const directionChange = this._lastWheelDirection !== null && direction !== this._lastWheelDirection;
- this._lastWheelDirection = direction;
-
- this._locked = this._locked && !directionChange;
- }
-
- };
-
-})());
-
-
-let PointerLocker = TimeoutLocker.inherit((function() {
-
- const POINTER_UNLOCK_TIMEOUT = 400;
-
- return {
-
- ctor: function(element) {
- this.callBase(element, POINTER_UNLOCK_TIMEOUT);
- }
-
- };
-
-})());
-
-(function() {
- const { ios: isIos, android: isAndroid } = realDevice;
-
- if(!(isIos || isAndroid)) {
- return;
- }
-
- PointerLocker = Locker.inherit((function() {
-
- return {
-
- _scroll: function() {
- this._locked = true;
-
- const that = this;
- cancelAnimationFrame(this._scrollFrame);
- this._scrollFrame = requestAnimationFrame(function() {
- that._locked = false;
- });
- },
-
- check: function(e, callback) {
- cancelAnimationFrame(this._scrollFrame);
- cancelAnimationFrame(this._checkFrame);
-
- const that = this;
- const callBase = this.callBase;
- this._checkFrame = requestAnimationFrame(function() {
- callBase.call(that, e, callback);
-
- that._locked = false;
- });
- },
-
- dispose: function() {
- this.callBase();
-
- cancelAnimationFrame(this._scrollFrame);
- cancelAnimationFrame(this._checkFrame);
- }
-
- };
-
- })());
-
-})();
-
-
-const ScrollEmitter = GestureEmitter.inherit((function() {
-
- const INERTIA_TIMEOUT = 100;
- const VELOCITY_CALC_TIMEOUT = 200;
- const FRAME_DURATION = Math.round(1000 / 60);
-
- return {
-
- ctor: function(element) {
- this.callBase.apply(this, arguments);
- this.direction = 'both';
-
- this._pointerLocker = new PointerLocker(element);
- this._wheelLocker = new WheelLocker(element);
- },
-
- validate: function() {
- return true;
- },
-
- configure: function(data) {
- if(data.scrollTarget) {
- this._pointerLocker.dispose();
- this._wheelLocker.dispose();
- this._pointerLocker = new PointerLocker(data.scrollTarget);
- this._wheelLocker = new WheelLocker(data.scrollTarget);
- }
-
- this.callBase(data);
- },
-
- _init: function(e) {
- this._wheelLocker.check(e, function() {
- if(isDxMouseWheelEvent(e)) {
- this._accept(e);
- }
- }.bind(this));
-
- this._pointerLocker.check(e, function() {
- const skipCheck = this.isNative && isMouseEvent(e);
- if(!isDxMouseWheelEvent(e) && !skipCheck) {
- this._accept(e);
- }
- }.bind(this));
-
- this._fireEvent(SCROLL_INIT_EVENT, e);
-
- this._prevEventData = eventData(e);
- },
-
- move: function(e) {
- this.callBase.apply(this, arguments);
-
- e.isScrollingEvent = this.isNative || e.isScrollingEvent;
- },
-
- _start: function(e) {
- this._savedEventData = eventData(e);
-
- this._fireEvent(SCROLL_START_EVENT, e);
-
- this._prevEventData = eventData(e);
- },
-
- _move: function(e) {
- const currentEventData = eventData(e);
-
- this._fireEvent(SCROLL_MOVE_EVENT, e, {
- delta: eventDelta(this._prevEventData, currentEventData)
- });
-
- const delta = eventDelta(this._savedEventData, currentEventData);
- if(delta.time > VELOCITY_CALC_TIMEOUT) {
- this._savedEventData = this._prevEventData;
- }
-
- this._prevEventData = eventData(e);
- },
-
- _end: function(e) {
- const endEventDelta = eventDelta(this._prevEventData, eventData(e));
- let velocity = { x: 0, y: 0 };
-
- if(!isDxMouseWheelEvent(e) && endEventDelta.time < INERTIA_TIMEOUT) {
- const delta = eventDelta(this._savedEventData, this._prevEventData);
- const velocityMultiplier = FRAME_DURATION / delta.time;
-
- velocity = { x: delta.x * velocityMultiplier, y: delta.y * velocityMultiplier };
- }
-
- this._fireEvent(SCROLL_END_EVENT, e, {
- velocity: velocity
- });
- },
-
- _stop: function(e) {
- this._fireEvent(SCROLL_STOP_EVENT, e);
- },
-
- cancel: function(e) {
- this.callBase.apply(this, arguments);
-
- this._fireEvent(SCROLL_CANCEL_EVENT, e);
- },
-
- dispose: function() {
- this.callBase.apply(this, arguments);
-
- this._pointerLocker.dispose();
- this._wheelLocker.dispose();
- },
-
- _clearSelection: function() {
- if(this.isNative) {
- return;
- }
-
- return this.callBase.apply(this, arguments);
- },
-
- _toggleGestureCover: function() {
- if(this.isNative) {
- return;
- }
-
- return this.callBase.apply(this, arguments);
- }
-
- };
-
-})());
-
-registerEmitter({
- emitter: ScrollEmitter,
- events: [
- SCROLL_INIT_EVENT,
- SCROLL_START_EVENT,
- SCROLL_MOVE_EVENT,
- SCROLL_END_EVENT,
- SCROLL_STOP_EVENT,
- SCROLL_CANCEL_EVENT
- ]
-});
-
-export default {
- init: SCROLL_INIT_EVENT,
- start: SCROLL_START_EVENT,
- move: SCROLL_MOVE_EVENT,
- end: SCROLL_END_EVENT,
- stop: SCROLL_STOP_EVENT,
- cancel: SCROLL_CANCEL_EVENT,
- scroll: SCROLL_EVENT
-};
+export { default } from '../../__internal/events/gesture/m_emitter.gesture.scroll';
diff --git a/packages/devextreme/js/events/gesture/swipeable.js b/packages/devextreme/js/events/gesture/swipeable.js
index 622880a7168f..e6d44d8d75e9 100644
--- a/packages/devextreme/js/events/gesture/swipeable.js
+++ b/packages/devextreme/js/events/gesture/swipeable.js
@@ -1,113 +1 @@
-import {
- start as swipeEventStart,
- swipe as swipeEventSwipe,
- end as swipeEventEnd
-} from '../swipe';
-import eventsEngine from '../../events/core/events_engine';
-import DOMComponent from '../../core/dom_component';
-import { each } from '../../core/utils/iterator';
-import { addNamespace } from '../utils/index';
-import { extend } from '../../core/utils/extend';
-import { name } from '../../core/utils/public_component';
-
-const DX_SWIPEABLE = 'dxSwipeable';
-const SWIPEABLE_CLASS = 'dx-swipeable';
-
-const ACTION_TO_EVENT_MAP = {
- 'onStart': swipeEventStart,
- 'onUpdated': swipeEventSwipe,
- 'onEnd': swipeEventEnd,
- 'onCancel': 'dxswipecancel'
-};
-
-const IMMEDIATE_TIMEOUT = 180;
-
-const Swipeable = DOMComponent.inherit({
-
- _getDefaultOptions: function() {
- return extend(this.callBase(), {
- elastic: true,
- immediate: false,
- immediateTimeout: IMMEDIATE_TIMEOUT,
- direction: 'horizontal',
- itemSizeFunc: null,
- onStart: null,
- onUpdated: null,
- onEnd: null,
- onCancel: null
- });
- },
-
- _render: function() {
- this.callBase();
-
- this.$element().addClass(SWIPEABLE_CLASS);
- this._attachEventHandlers();
- },
-
- _attachEventHandlers: function() {
- this._detachEventHandlers();
-
- if(this.option('disabled')) {
- return;
- }
-
- const NAME = this.NAME;
-
- this._createEventData();
-
- each(ACTION_TO_EVENT_MAP, (function(actionName, eventName) {
- const action = this._createActionByOption(actionName, { context: this });
-
- eventName = addNamespace(eventName, NAME);
-
- eventsEngine.on(this.$element(), eventName, this._eventData, function(e) {
- return action({ event: e });
- });
- }).bind(this));
- },
-
- _createEventData: function() {
- this._eventData = {
- elastic: this.option('elastic'),
- itemSizeFunc: this.option('itemSizeFunc'),
- direction: this.option('direction'),
- immediate: this.option('immediate'),
- immediateTimeout: this.option('immediateTimeout'),
- };
- },
-
- _detachEventHandlers: function() {
- eventsEngine.off(this.$element(), '.' + DX_SWIPEABLE);
- },
-
- _optionChanged: function(args) {
- switch(args.name) {
- case 'disabled':
- case 'onStart':
- case 'onUpdated':
- case 'onEnd':
- case 'onCancel':
- case 'elastic':
- case 'immediate':
- case 'itemSizeFunc':
- case 'direction':
- this._detachEventHandlers();
- this._attachEventHandlers();
- break;
- case 'rtlEnabled':
- break;
- default:
- this.callBase(args);
- }
-
- },
-
- _useTemplates: function() {
- return false;
- },
-});
-
-name(Swipeable, DX_SWIPEABLE);
-
-export default Swipeable;
+export { default } from '../../__internal/events/gesture/m_swipeable';
diff --git a/packages/devextreme/js/events/hold.js b/packages/devextreme/js/events/hold.js
index 2459cb62976b..2174679ed7e7 100644
--- a/packages/devextreme/js/events/hold.js
+++ b/packages/devextreme/js/events/hold.js
@@ -1,62 +1,3 @@
-import { eventData, eventDelta } from './utils/index';
-import Emitter from './core/emitter';
-import registerEmitter from './core/emitter_registrator';
-const abs = Math.abs;
-
-const HOLD_EVENT_NAME = 'dxhold';
-const HOLD_TIMEOUT = 750;
-const TOUCH_BOUNDARY = 5;
-
-
-const HoldEmitter = Emitter.inherit({
-
- start: function(e) {
- this._startEventData = eventData(e);
-
- this._startTimer(e);
- },
-
- _startTimer: function(e) {
- const holdTimeout = ('timeout' in this) ? this.timeout : HOLD_TIMEOUT;
- this._holdTimer = setTimeout((function() {
- this._requestAccept(e);
- this._fireEvent(HOLD_EVENT_NAME, e, {
- target: e.target
- });
- this._forgetAccept();
- }).bind(this), holdTimeout);
- },
-
- move: function(e) {
- if(this._touchWasMoved(e)) {
- this._cancel(e);
- }
- },
-
- _touchWasMoved: function(e) {
- const delta = eventDelta(this._startEventData, eventData(e));
-
- return abs(delta.x) > TOUCH_BOUNDARY || abs(delta.y) > TOUCH_BOUNDARY;
- },
-
- end: function() {
- this._stopTimer();
- },
-
- _stopTimer: function() {
- clearTimeout(this._holdTimer);
- },
-
- cancel: function() {
- this._stopTimer();
- },
-
- dispose: function() {
- this._stopTimer();
- }
-
-});
-
/**
* @name UI Events.dxhold
* @type eventType
@@ -64,14 +5,4 @@ const HoldEmitter = Emitter.inherit({
* @module events/hold
*/
-registerEmitter({
- emitter: HoldEmitter,
- bubble: true,
- events: [
- HOLD_EVENT_NAME
- ]
-});
-
-export default {
- name: HOLD_EVENT_NAME
-};
+export { default } from '../__internal/events/m_hold';
diff --git a/packages/devextreme/js/events/hover.js b/packages/devextreme/js/events/hover.js
index b75977591040..e603188362d0 100644
--- a/packages/devextreme/js/events/hover.js
+++ b/packages/devextreme/js/events/hover.js
@@ -1,95 +1,3 @@
-import eventsEngine from '../events/core/events_engine';
-import { removeData, data as elementData } from '../core/element_data';
-import Class from '../core/class';
-import devices from '../core/devices';
-import registerEvent from './core/event_registrator';
-import { addNamespace, isTouchEvent, fireEvent } from './utils/index';
-import pointerEvents from './pointer';
-
-const HOVERSTART_NAMESPACE = 'dxHoverStart';
-const HOVERSTART = 'dxhoverstart';
-const POINTERENTER_NAMESPACED_EVENT_NAME = addNamespace(pointerEvents.enter, HOVERSTART_NAMESPACE);
-
-const HOVEREND_NAMESPACE = 'dxHoverEnd';
-const HOVEREND = 'dxhoverend';
-const POINTERLEAVE_NAMESPACED_EVENT_NAME = addNamespace(pointerEvents.leave, HOVEREND_NAMESPACE);
-
-
-const Hover = Class.inherit({
-
- noBubble: true,
-
- ctor: function() {
- this._handlerArrayKeyPath = this._eventNamespace + '_HandlerStore';
- },
-
- setup: function(element) {
- elementData(element, this._handlerArrayKeyPath, {});
- },
-
- add: function(element, handleObj) {
- const that = this;
- const handler = function(e) {
- that._handler(e);
- };
-
- eventsEngine.on(element, this._originalEventName, handleObj.selector, handler);
- elementData(element, this._handlerArrayKeyPath)[handleObj.guid] = handler;
- },
-
- _handler: function(e) {
- if(isTouchEvent(e) || devices.isSimulator()) {
- return;
- }
-
- fireEvent({
- type: this._eventName,
- originalEvent: e,
- delegateTarget: e.delegateTarget
- });
- },
-
- remove: function(element, handleObj) {
- const handler = elementData(element, this._handlerArrayKeyPath)[handleObj.guid];
-
- eventsEngine.off(element, this._originalEventName, handleObj.selector, handler);
- },
-
- teardown: function(element) {
- removeData(element, this._handlerArrayKeyPath);
- }
-
-});
-
-const HoverStart = Hover.inherit({
-
- ctor: function() {
- this._eventNamespace = HOVERSTART_NAMESPACE;
- this._eventName = HOVERSTART;
- this._originalEventName = POINTERENTER_NAMESPACED_EVENT_NAME;
- this.callBase();
- },
-
- _handler: function(e) {
- const pointers = e.pointers || [];
- if(!pointers.length) {
- this.callBase(e);
- }
- }
-
-});
-
-const HoverEnd = Hover.inherit({
-
- ctor: function() {
- this._eventNamespace = HOVEREND_NAMESPACE;
- this._eventName = HOVEREND;
- this._originalEventName = POINTERLEAVE_NAMESPACED_EVENT_NAME;
- this.callBase();
- }
-
-});
-
/**
* @name UI Events.dxhoverstart
* @type eventType
@@ -104,10 +12,4 @@ const HoverEnd = Hover.inherit({
* @module events/hover
*/
-registerEvent(HOVERSTART, new HoverStart());
-registerEvent(HOVEREND, new HoverEnd());
-
-export {
- HOVERSTART as start,
- HOVEREND as end
-};
+export * from '../__internal/events/m_hover';
diff --git a/packages/devextreme/js/events/pointer.js b/packages/devextreme/js/events/pointer.js
index e6839c01cf18..76b7978e98d7 100644
--- a/packages/devextreme/js/events/pointer.js
+++ b/packages/devextreme/js/events/pointer.js
@@ -1,12 +1,3 @@
-import GlobalConfig from '../core/config';
-import * as support from '../core/utils/support';
-import { each } from '../core/utils/iterator';
-import devices from '../core/devices';
-import registerEvent from './core/event_registrator';
-import TouchStrategy from './pointer/touch';
-import MouseStrategy from './pointer/mouse';
-import MouseAndTouchStrategy from './pointer/mouse_and_touch';
-
/**
* @name UI Events.dxpointerdown
* @type eventType
@@ -64,54 +55,4 @@ import MouseAndTouchStrategy from './pointer/mouse_and_touch';
* @module events/pointer
*/
-const getStrategy = (support, { tablet, phone }) => {
- const pointerEventStrategy = getStrategyFromGlobalConfig();
-
- if(pointerEventStrategy) {
- return pointerEventStrategy;
- }
-
- if(support.touch && !(tablet || phone)) {
- return MouseAndTouchStrategy;
- }
-
- if(support.touch) {
- return TouchStrategy;
- }
-
- return MouseStrategy;
-};
-
-const EventStrategy = getStrategy(support, devices.real());
-
-each(EventStrategy.map, (pointerEvent, originalEvents) => {
- registerEvent(pointerEvent, new EventStrategy(pointerEvent, originalEvents));
-});
-
-const pointer = {
- down: 'dxpointerdown',
- up: 'dxpointerup',
- move: 'dxpointermove',
- cancel: 'dxpointercancel',
- enter: 'dxpointerenter',
- leave: 'dxpointerleave',
- over: 'dxpointerover',
- out: 'dxpointerout'
-};
-
-function getStrategyFromGlobalConfig() {
- const eventStrategyName = GlobalConfig().pointerEventStrategy;
-
- return {
- 'mouse-and-touch': MouseAndTouchStrategy,
- 'touch': TouchStrategy,
- 'mouse': MouseStrategy,
- }[eventStrategyName];
-}
-
-///#DEBUG
-pointer.getStrategy = getStrategy;
-
-///#ENDDEBUG
-
-export default pointer;
+export { default } from '../__internal/events/m_pointer';
diff --git a/packages/devextreme/js/events/pointer/base.js b/packages/devextreme/js/events/pointer/base.js
index 75baf7ab8111..305dab9967e0 100644
--- a/packages/devextreme/js/events/pointer/base.js
+++ b/packages/devextreme/js/events/pointer/base.js
@@ -1,114 +1 @@
-import eventsEngine from '../../events/core/events_engine';
-import browser from '../../core/utils/browser';
-import domAdapter from '../../core/dom_adapter';
-import Class from '../../core/class';
-import { addNamespace, eventSource, fireEvent } from '../utils/index';
-import { getEventTarget } from '../utils/event_target';
-
-const POINTER_EVENTS_NAMESPACE = 'dxPointerEvents';
-
-
-const BaseStrategy = Class.inherit({
-
- ctor: function(eventName, originalEvents) {
- this._eventName = eventName;
- this._originalEvents = addNamespace(originalEvents, POINTER_EVENTS_NAMESPACE);
- this._handlerCount = 0;
- this.noBubble = this._isNoBubble();
- },
-
- _isNoBubble: function() {
- const eventName = this._eventName;
-
- return eventName === 'dxpointerenter' ||
- eventName === 'dxpointerleave';
- },
-
- _handler: function(e) {
- const delegateTarget = this._getDelegateTarget(e);
-
- const event = {
- type: this._eventName,
- pointerType: e.pointerType || eventSource(e),
- originalEvent: e,
- delegateTarget: delegateTarget,
- // NOTE: TimeStamp normalization (FF bug #238041) (T277118)
- timeStamp: browser.mozilla ? (new Date()).getTime() : e.timeStamp
- };
-
- const target = getEventTarget(e);
- event.target = target;
-
- return this._fireEvent(event);
- },
-
- _getDelegateTarget: function(e) {
- let delegateTarget;
-
- if(this.noBubble) {
- delegateTarget = e.delegateTarget;
- }
-
- return delegateTarget;
- },
-
- _fireEvent: function(args) {
- return fireEvent(args);
- },
-
- _setSelector: function(handleObj) {
- this._selector = this.noBubble && handleObj ? handleObj.selector : null;
- },
-
- _getSelector: function() {
- return this._selector;
- },
-
- setup: function() {
- return true;
- },
-
- add: function(element, handleObj) {
- if(this._handlerCount <= 0 || this.noBubble) {
- element = this.noBubble ? element : domAdapter.getDocument();
- this._setSelector(handleObj);
-
- const that = this;
- eventsEngine.on(element, this._originalEvents, this._getSelector(), function(e) {
- that._handler(e);
- });
- }
-
- if(!this.noBubble) {
- this._handlerCount++;
- }
- },
-
- remove: function(handleObj) {
- this._setSelector(handleObj);
-
- if(!this.noBubble) {
- this._handlerCount--;
- }
- },
-
- teardown: function(element) {
- if(this._handlerCount && !this.noBubble) {
- return;
- }
-
- element = this.noBubble ? element : domAdapter.getDocument();
-
- if(this._originalEvents !== '.' + POINTER_EVENTS_NAMESPACE) {
- eventsEngine.off(element, this._originalEvents, this._getSelector());
- }
- },
-
- dispose: function(element) {
- element = this.noBubble ? element : domAdapter.getDocument();
-
- eventsEngine.off(element, this._originalEvents);
- }
-});
-
-export default BaseStrategy;
+export { default } from '../../__internal/events/pointer/m_base';
diff --git a/packages/devextreme/js/events/pointer/mouse.js b/packages/devextreme/js/events/pointer/mouse.js
index 895bc0ccadb5..aaded4766988 100644
--- a/packages/devextreme/js/events/pointer/mouse.js
+++ b/packages/devextreme/js/events/pointer/mouse.js
@@ -1,61 +1 @@
-import { extend } from '../../core/utils/extend';
-import BaseStrategy from './base';
-import Observer from './observer';
-
-const eventMap = {
- 'dxpointerdown': 'mousedown',
- 'dxpointermove': 'mousemove',
- 'dxpointerup': 'mouseup',
- 'dxpointercancel': '',
- 'dxpointerover': 'mouseover',
- 'dxpointerout': 'mouseout',
- 'dxpointerenter': 'mouseenter',
- 'dxpointerleave': 'mouseleave'
-};
-
-const normalizeMouseEvent = function(e) {
- e.pointerId = 1;
-
- return {
- pointers: observer.pointers(),
- pointerId: 1
- };
-};
-
-
-let observer;
-let activated = false;
-const activateStrategy = function() {
- if(activated) {
- return;
- }
-
- observer = new Observer(eventMap, function() {
- return true;
- });
-
- activated = true;
-};
-
-const MouseStrategy = BaseStrategy.inherit({
-
- ctor: function() {
- this.callBase.apply(this, arguments);
-
- activateStrategy();
- },
-
- _fireEvent: function(args) {
- return this.callBase(extend(normalizeMouseEvent(args.originalEvent), args));
- }
-
-});
-MouseStrategy.map = eventMap;
-MouseStrategy.normalize = normalizeMouseEvent;
-MouseStrategy.activate = activateStrategy;
-MouseStrategy.resetObserver = function() {
- observer.reset();
-};
-
-
-export default MouseStrategy;
+export { default } from '../../__internal/events/pointer/m_mouse';
diff --git a/packages/devextreme/js/events/pointer/mouse_and_touch.js b/packages/devextreme/js/events/pointer/mouse_and_touch.js
index be242f223fcb..dde0522c0306 100644
--- a/packages/devextreme/js/events/pointer/mouse_and_touch.js
+++ b/packages/devextreme/js/events/pointer/mouse_and_touch.js
@@ -1,85 +1 @@
-import { extend } from '../../core/utils/extend';
-import BaseStrategy from './base';
-import MouseStrategy from './mouse';
-import TouchStrategy from './touch';
-import { isMouseEvent } from '../utils/index';
-
-const eventMap = {
- 'dxpointerdown': 'touchstart mousedown',
- 'dxpointermove': 'touchmove mousemove',
- 'dxpointerup': 'touchend mouseup',
- 'dxpointercancel': 'touchcancel',
- 'dxpointerover': 'mouseover',
- 'dxpointerout': 'mouseout',
- 'dxpointerenter': 'mouseenter',
- 'dxpointerleave': 'mouseleave'
-};
-
-
-let activated = false;
-const activateStrategy = function() {
- if(activated) {
- return;
- }
-
- MouseStrategy.activate();
-
- activated = true;
-};
-
-const MouseAndTouchStrategy = BaseStrategy.inherit({
-
- EVENT_LOCK_TIMEOUT: 100,
-
- ctor: function() {
- this.callBase.apply(this, arguments);
-
- activateStrategy();
- },
-
- _handler: function(e) {
- const isMouse = isMouseEvent(e);
-
- if(!isMouse) {
- this._skipNextEvents = true;
- }
-
- if(isMouse && this._mouseLocked) {
- return;
- }
-
- if(isMouse && this._skipNextEvents) {
- this._skipNextEvents = false;
- this._mouseLocked = true;
-
- clearTimeout(this._unlockMouseTimer);
-
- const that = this;
- this._unlockMouseTimer = setTimeout(function() {
- that._mouseLocked = false;
- }, this.EVENT_LOCK_TIMEOUT);
-
- return;
- }
-
- return this.callBase(e);
- },
-
- _fireEvent: function(args) {
- const normalizer = isMouseEvent(args.originalEvent) ? MouseStrategy.normalize : TouchStrategy.normalize;
-
- return this.callBase(extend(normalizer(args.originalEvent), args));
- },
-
- dispose: function() {
- this.callBase();
- this._skipNextEvents = false;
- this._mouseLocked = false;
- clearTimeout(this._unlockMouseTimer);
- }
-});
-MouseAndTouchStrategy.map = eventMap;
-MouseAndTouchStrategy.resetObserver = MouseStrategy.resetObserver;
-
-
-export default MouseAndTouchStrategy;
+export { default } from '../../__internal/events/pointer/m_mouse_and_touch';
diff --git a/packages/devextreme/js/events/pointer/observer.js b/packages/devextreme/js/events/pointer/observer.js
index 374d4b336a3c..6b5fefe472db 100644
--- a/packages/devextreme/js/events/pointer/observer.js
+++ b/packages/devextreme/js/events/pointer/observer.js
@@ -1,69 +1 @@
-import { each } from '../../core/utils/iterator';
-import readyCallbacks from '../../core/utils/ready_callbacks';
-import domAdapter from '../../core/dom_adapter';
-
-const addEventsListener = function(events, handler) {
- readyCallbacks.add(function() {
- events
- .split(' ')
- .forEach(function(event) {
- domAdapter.listen(domAdapter.getDocument(), event, handler, true);
- });
- });
-};
-
-const Observer = function(eventMap, pointerEquals, onPointerAdding) {
-
- onPointerAdding = onPointerAdding || function() { };
-
- let pointers = [];
-
- const getPointerIndex = function(e) {
- let index = -1;
-
- each(pointers, function(i, pointer) {
- if(!pointerEquals(e, pointer)) {
- return true;
- }
-
- index = i;
- return false;
- });
-
- return index;
- };
-
- const addPointer = function(e) {
- if(getPointerIndex(e) === -1) {
- onPointerAdding(e);
- pointers.push(e);
- }
- };
-
- const removePointer = function(e) {
- const index = getPointerIndex(e);
- if(index > -1) {
- pointers.splice(index, 1);
- }
- };
-
- const updatePointer = function(e) {
- pointers[getPointerIndex(e)] = e;
- };
-
- addEventsListener(eventMap['dxpointerdown'], addPointer);
- addEventsListener(eventMap['dxpointermove'], updatePointer);
- addEventsListener(eventMap['dxpointerup'], removePointer);
- addEventsListener(eventMap['dxpointercancel'], removePointer);
-
- this.pointers = function() {
- return pointers;
- };
-
- this.reset = function() {
- pointers = [];
- };
-
-};
-
-export default Observer;
+export { default } from '../../__internal/events/pointer/m_observer';
diff --git a/packages/devextreme/js/events/pointer/touch.js b/packages/devextreme/js/events/pointer/touch.js
index 6b2969bf8d45..f41aa71ccc75 100644
--- a/packages/devextreme/js/events/pointer/touch.js
+++ b/packages/devextreme/js/events/pointer/touch.js
@@ -1,67 +1 @@
-import devices from '../../core/devices';
-import { extend } from '../../core/utils/extend';
-import { each } from '../../core/utils/iterator';
-import BaseStrategy from './base';
-
-const eventMap = {
- 'dxpointerdown': 'touchstart',
- 'dxpointermove': 'touchmove',
- 'dxpointerup': 'touchend',
- 'dxpointercancel': 'touchcancel',
- 'dxpointerover': '',
- 'dxpointerout': '',
- 'dxpointerenter': '',
- 'dxpointerleave': ''
-};
-
-
-const normalizeTouchEvent = function(e) {
- const pointers = [];
-
- each(e.touches, function(_, touch) {
- pointers.push(extend({
- pointerId: touch.identifier
- }, touch));
- });
-
- return {
- pointers: pointers,
- pointerId: e.changedTouches[0].identifier
- };
-};
-
-const skipTouchWithSameIdentifier = function(pointerEvent) {
- return devices.real().platform === 'ios' && (pointerEvent === 'dxpointerdown' || pointerEvent === 'dxpointerup');
-};
-
-const TouchStrategy = BaseStrategy.inherit({
-
- ctor: function() {
- this.callBase.apply(this, arguments);
- this._pointerId = 0;
- },
-
- _handler: function(e) {
- if(skipTouchWithSameIdentifier(this._eventName)) {
- const touch = e.changedTouches[0];
-
- if(this._pointerId === touch.identifier && this._pointerId !== 0) {
- return;
- }
-
- this._pointerId = touch.identifier;
- }
-
- return this.callBase.apply(this, arguments);
- },
-
- _fireEvent: function(args) {
- return this.callBase(extend(normalizeTouchEvent(args.originalEvent), args));
- }
-
-});
-TouchStrategy.map = eventMap;
-TouchStrategy.normalize = normalizeTouchEvent;
-
-
-export default TouchStrategy;
+export { default } from '../../__internal/events/pointer/m_touch';
diff --git a/packages/devextreme/js/events/remove.js b/packages/devextreme/js/events/remove.js
index ffde4455a3d6..b475e099cbec 100644
--- a/packages/devextreme/js/events/remove.js
+++ b/packages/devextreme/js/events/remove.js
@@ -1,11 +1,3 @@
-import $ from '../core/renderer';
-import { beforeCleanData } from '../core/element_data';
-import eventsEngine from './core/events_engine';
-import registerEvent from './core/event_registrator';
-
-export const removeEvent = 'dxremove';
-const eventPropName = 'dxRemoveEvent';
-
/**
* @name UI Events.dxremove
* @type eventType
@@ -13,20 +5,4 @@ const eventPropName = 'dxRemoveEvent';
* @module events/remove
*/
-beforeCleanData(function(elements) {
- elements = [].slice.call(elements);
- for(let i = 0; i < elements.length; i++) {
- const $element = $(elements[i]);
- if($element.prop(eventPropName)) {
- $element[0][eventPropName] = null;
- eventsEngine.triggerHandler($element, removeEvent);
- }
- }
-});
-
-registerEvent(removeEvent, {
- noBubble: true,
- setup: function(element) {
- $(element).prop(eventPropName, true);
- }
-});
+export * from '../__internal/events/m_remove';
diff --git a/packages/devextreme/js/events/short.js b/packages/devextreme/js/events/short.js
index c47f8aead18b..70e38ebf6b7b 100644
--- a/packages/devextreme/js/events/short.js
+++ b/packages/devextreme/js/events/short.js
@@ -1,119 +1 @@
-import eventsEngine from './core/events_engine';
-import KeyboardProcessor from './core/keyboard_processor';
-import { addNamespace as pureAddNamespace } from './utils/index';
-
-function addNamespace(event, namespace) {
- return namespace ? pureAddNamespace(event, namespace) : event;
-}
-
-function executeAction(action, args) {
- return typeof action === 'function' ? action(args) : action.execute(args);
-}
-
-export const active = {
- on: ($el, active, inactive, opts) => {
- const { selector, showTimeout, hideTimeout, namespace } = opts;
-
- eventsEngine.on($el, addNamespace('dxactive', namespace), selector, { timeout: showTimeout },
- event => executeAction(active, { event, element: event.currentTarget })
- );
- eventsEngine.on($el, addNamespace('dxinactive', namespace), selector, { timeout: hideTimeout },
- event => executeAction(inactive, { event, element: event.currentTarget })
- );
- },
-
- off: ($el, { namespace, selector }) => {
- eventsEngine.off($el, addNamespace('dxactive', namespace), selector);
- eventsEngine.off($el, addNamespace('dxinactive', namespace), selector);
- }
-};
-
-export const resize = {
- on: ($el, resize, { namespace } = {}) => {
- eventsEngine.on($el, addNamespace('dxresize', namespace), resize);
- },
- off: ($el, { namespace } = {}) => {
- eventsEngine.off($el, addNamespace('dxresize', namespace));
- }
-};
-
-export const hover = {
- on: ($el, start, end, { selector, namespace }) => {
- eventsEngine.on($el, addNamespace('dxhoverend', namespace), selector, event => end(event));
- eventsEngine.on($el, addNamespace('dxhoverstart', namespace), selector,
- event => executeAction(start, { element: event.target, event }));
- },
-
- off: ($el, { selector, namespace }) => {
- eventsEngine.off($el, addNamespace('dxhoverstart', namespace), selector);
- eventsEngine.off($el, addNamespace('dxhoverend', namespace), selector);
- }
-};
-
-export const visibility = {
- on: ($el, shown, hiding, { namespace }) => {
- eventsEngine.on($el, addNamespace('dxhiding', namespace), hiding);
- eventsEngine.on($el, addNamespace('dxshown', namespace), shown);
- },
-
- off: ($el, { namespace }) => {
- eventsEngine.off($el, addNamespace('dxhiding', namespace));
- eventsEngine.off($el, addNamespace('dxshown', namespace));
- }
-};
-
-export const focus = {
- on: ($el, focusIn, focusOut, { namespace }) => {
- eventsEngine.on($el, addNamespace('focusin', namespace), focusIn);
- eventsEngine.on($el, addNamespace('focusout', namespace), focusOut);
- },
-
- off: ($el, { namespace }) => {
- eventsEngine.off($el, addNamespace('focusin', namespace));
- eventsEngine.off($el, addNamespace('focusout', namespace));
- },
-
- trigger: $el => eventsEngine.trigger($el, 'focus')
-};
-
-export const dxClick = {
- on: ($el, click, { namespace } = {}) => {
- eventsEngine.on($el, addNamespace('dxclick', namespace), click);
- },
- off: ($el, { namespace } = {}) => {
- eventsEngine.off($el, addNamespace('dxclick', namespace));
- }
-};
-
-export const click = {
- on: ($el, click, { namespace } = {}) => {
- eventsEngine.on($el, addNamespace('click', namespace), click);
- },
- off: ($el, { namespace } = {}) => {
- eventsEngine.off($el, addNamespace('click', namespace));
- }
-};
-
-let index = 0;
-const keyboardProcessors = {};
-const generateListenerId = () => `keyboardProcessorId${index++}`;
-
-export const keyboard = {
- on: (element, focusTarget, handler) => {
- const listenerId = generateListenerId();
-
- keyboardProcessors[listenerId] = new KeyboardProcessor({ element, focusTarget, handler });
-
- return listenerId;
- },
-
- off: listenerId => {
- if(listenerId && keyboardProcessors[listenerId]) {
- keyboardProcessors[listenerId].dispose();
- delete keyboardProcessors[listenerId];
- }
- },
-
- // NOTE: For tests
- _getProcessor: listenerId => keyboardProcessors[listenerId]
-};
+export * from '../__internal/events/m_short';
diff --git a/packages/devextreme/js/events/swipe.js b/packages/devextreme/js/events/swipe.js
index 3f5d8e65fe35..31e61bbd529e 100644
--- a/packages/devextreme/js/events/swipe.js
+++ b/packages/devextreme/js/events/swipe.js
@@ -1,171 +1,3 @@
-import { getWidth, getHeight } from '../core/utils/size';
-import { eventData } from './utils/index';
-import GestureEmitter from './gesture/emitter.gesture';
-import registerEmitter from './core/emitter_registrator';
-
-const SWIPE_START_EVENT = 'dxswipestart';
-const SWIPE_EVENT = 'dxswipe';
-const SWIPE_END_EVENT = 'dxswipeend';
-
-
-const HorizontalStrategy = {
- defaultItemSizeFunc: function() {
- return getWidth(this.getElement());
- },
-
- getBounds: function() {
- return [
- this._maxLeftOffset,
- this._maxRightOffset
- ];
- },
-
- calcOffsetRatio: function(e) {
- const endEventData = eventData(e);
- return (endEventData.x - (this._savedEventData && this._savedEventData.x || 0)) / this._itemSizeFunc().call(this, e);
- },
-
- isFastSwipe: function(e) {
- const endEventData = eventData(e);
- return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.x - this._tickData.x) >= (endEventData.time - this._tickData.time);
- }
-};
-
-const VerticalStrategy = {
- defaultItemSizeFunc: function() {
- return getHeight(this.getElement());
- },
-
- getBounds: function() {
- return [
- this._maxTopOffset,
- this._maxBottomOffset
- ];
- },
-
- calcOffsetRatio: function(e) {
- const endEventData = eventData(e);
- return (endEventData.y - (this._savedEventData && this._savedEventData.y || 0)) / this._itemSizeFunc().call(this, e);
- },
-
- isFastSwipe: function(e) {
- const endEventData = eventData(e);
- return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.y - this._tickData.y) >= (endEventData.time - this._tickData.time);
- }
-};
-
-
-const STRATEGIES = {
- 'horizontal': HorizontalStrategy,
- 'vertical': VerticalStrategy
-};
-
-const SwipeEmitter = GestureEmitter.inherit({
-
- TICK_INTERVAL: 300,
- FAST_SWIPE_SPEED_LIMIT: 10,
-
- ctor: function(element) {
- this.callBase(element);
-
- this.direction = 'horizontal';
- this.elastic = true;
- },
-
- _getStrategy: function() {
- return STRATEGIES[this.direction];
- },
-
- _defaultItemSizeFunc: function() {
- return this._getStrategy().defaultItemSizeFunc.call(this);
- },
-
- _itemSizeFunc: function() {
- return this.itemSizeFunc || this._defaultItemSizeFunc;
- },
-
- _init: function(e) {
- this._tickData = eventData(e);
- },
-
- _start: function(e) {
- this._savedEventData = eventData(e);
-
- e = this._fireEvent(SWIPE_START_EVENT, e);
-
- if(!e.cancel) {
- this._maxLeftOffset = e.maxLeftOffset;
- this._maxRightOffset = e.maxRightOffset;
- this._maxTopOffset = e.maxTopOffset;
- this._maxBottomOffset = e.maxBottomOffset;
- }
- },
-
- _move: function(e) {
- const strategy = this._getStrategy();
- const moveEventData = eventData(e);
- let offset = strategy.calcOffsetRatio.call(this, e);
-
- offset = this._fitOffset(offset, this.elastic);
-
- if(moveEventData.time - this._tickData.time > this.TICK_INTERVAL) {
- this._tickData = moveEventData;
- }
-
- this._fireEvent(SWIPE_EVENT, e, {
- offset: offset,
- });
-
- if(e.cancelable !== false) {
- e.preventDefault();
- }
- },
-
- _end: function(e) {
- const strategy = this._getStrategy();
- const offsetRatio = strategy.calcOffsetRatio.call(this, e);
- const isFast = strategy.isFastSwipe.call(this, e);
- let startOffset = offsetRatio;
- let targetOffset = this._calcTargetOffset(offsetRatio, isFast);
-
- startOffset = this._fitOffset(startOffset, this.elastic);
- targetOffset = this._fitOffset(targetOffset, false);
-
- this._fireEvent(SWIPE_END_EVENT, e, {
- offset: startOffset,
- targetOffset: targetOffset
- });
- },
-
- _fitOffset: function(offset, elastic) {
- const strategy = this._getStrategy();
- const bounds = strategy.getBounds.call(this);
-
- if(offset < -bounds[0]) {
- return elastic ? (-2 * bounds[0] + offset) / 3 : -bounds[0];
- }
-
- if(offset > bounds[1]) {
- return elastic ? (2 * bounds[1] + offset) / 3 : bounds[1];
- }
-
- return offset;
- },
-
- _calcTargetOffset: function(offsetRatio, isFast) {
- let result;
- if(isFast) {
- result = Math.ceil(Math.abs(offsetRatio));
- if(offsetRatio < 0) {
- result = -result;
- }
- } else {
- result = Math.round(offsetRatio);
- }
- return result;
- }
-});
-
/**
* @name UI Events.dxswipestart
* @type eventType
@@ -190,17 +22,4 @@ const SwipeEmitter = GestureEmitter.inherit({
* @module events/swipe
*/
-registerEmitter({
- emitter: SwipeEmitter,
- events: [
- SWIPE_START_EVENT,
- SWIPE_EVENT,
- SWIPE_END_EVENT
- ]
-});
-
-export {
- SWIPE_EVENT as swipe,
- SWIPE_START_EVENT as start,
- SWIPE_END_EVENT as end
-};
+export * from '../__internal/events/m_swipe';
diff --git a/packages/devextreme/js/events/transform.js b/packages/devextreme/js/events/transform.js
index 9e34d9c39b3f..db22a4cec363 100644
--- a/packages/devextreme/js/events/transform.js
+++ b/packages/devextreme/js/events/transform.js
@@ -1,154 +1,4 @@
-import { sign as mathSign, fitIntoRange } from '../core/utils/math';
-import * as iteratorUtils from '../core/utils/iterator';
-import { hasTouches } from './utils/index';
-import Emitter from './core/emitter';
-import registerEmitter from './core/emitter_registrator';
-
-const DX_PREFIX = 'dx';
-
-const TRANSFORM = 'transform';
-const TRANSLATE = 'translate';
-const PINCH = 'pinch';
-const ROTATE = 'rotate';
-
-const START_POSTFIX = 'start';
-const UPDATE_POSTFIX = '';
-const END_POSTFIX = 'end';
-
-const eventAliases = [];
-const addAlias = function(eventName, eventArgs) {
- eventAliases.push({
- name: eventName,
- args: eventArgs
- });
-};
-
-addAlias(TRANSFORM, {
- scale: true,
- deltaScale: true,
- rotation: true,
- deltaRotation: true,
- translation: true,
- deltaTranslation: true
-});
-
-addAlias(TRANSLATE, {
- translation: true,
- deltaTranslation: true
-});
-
-addAlias(PINCH, {
- scale: true,
- deltaScale: true
-});
-
-addAlias(ROTATE, {
- rotation: true,
- deltaRotation: true
-});
-
-
-const getVector = function(first, second) {
- return {
- x: second.pageX - first.pageX,
- y: -second.pageY + first.pageY,
- centerX: (second.pageX + first.pageX) * 0.5,
- centerY: (second.pageY + first.pageY) * 0.5
- };
-};
-
-const getEventVector = function(e) {
- const pointers = e.pointers;
-
- return getVector(pointers[0], pointers[1]);
-};
-
-const getDistance = function(vector) {
- return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
-};
-
-const getScale = function(firstVector, secondVector) {
- return getDistance(firstVector) / getDistance(secondVector);
-};
-
-const getRotation = function(firstVector, secondVector) {
- const scalarProduct = firstVector.x * secondVector.x + firstVector.y * secondVector.y;
- const distanceProduct = getDistance(firstVector) * getDistance(secondVector);
-
- if(distanceProduct === 0) {
- return 0;
- }
-
- const sign = mathSign(firstVector.x * secondVector.y - secondVector.x * firstVector.y);
- const angle = Math.acos(fitIntoRange(scalarProduct / distanceProduct, -1, 1));
-
- return sign * angle;
-};
-
-const getTranslation = function(firstVector, secondVector) {
- return {
- x: firstVector.centerX - secondVector.centerX,
- y: firstVector.centerY - secondVector.centerY
- };
-};
-
-const TransformEmitter = Emitter.inherit({
-
- validatePointers: function(e) {
- return hasTouches(e) > 1;
- },
-
- start: function(e) {
- this._accept(e);
-
- const startVector = getEventVector(e);
- this._startVector = startVector;
- this._prevVector = startVector;
-
- this._fireEventAliases(START_POSTFIX, e);
- },
-
- move: function(e) {
- const currentVector = getEventVector(e);
- const eventArgs = this._getEventArgs(currentVector);
-
- this._fireEventAliases(UPDATE_POSTFIX, e, eventArgs);
- this._prevVector = currentVector;
- },
-
- end: function(e) {
- const eventArgs = this._getEventArgs(this._prevVector);
- this._fireEventAliases(END_POSTFIX, e, eventArgs);
- },
-
- _getEventArgs: function(vector) {
- return {
- scale: getScale(vector, this._startVector),
- deltaScale: getScale(vector, this._prevVector),
- rotation: getRotation(vector, this._startVector),
- deltaRotation: getRotation(vector, this._prevVector),
- translation: getTranslation(vector, this._startVector),
- deltaTranslation: getTranslation(vector, this._prevVector)
- };
- },
-
- _fireEventAliases: function(eventPostfix, originalEvent, eventArgs) {
- eventArgs = eventArgs || {};
-
- iteratorUtils.each(eventAliases, (function(_, eventAlias) {
- const args = {};
- iteratorUtils.each(eventAlias.args, function(name) {
- if(name in eventArgs) {
- args[name] = eventArgs[name];
- }
- });
-
- this._fireEvent(DX_PREFIX + eventAlias.name + eventPostfix, originalEvent, args);
- }).bind(this));
- }
-
-});
-
+import { exportNames } from '../__internal/events/m_transform';
/**
* @name UI Events.dxtransformstart
@@ -262,21 +112,6 @@ const TransformEmitter = Emitter.inherit({
* @module events/transform
*/
-const eventNames = eventAliases.reduce((result, eventAlias) => {
- [START_POSTFIX, UPDATE_POSTFIX, END_POSTFIX].forEach(eventPostfix => {
- result.push(DX_PREFIX + eventAlias.name + eventPostfix);
- });
- return result;
-}, []);
-
-registerEmitter({
- emitter: TransformEmitter,
- events: eventNames
-});
-const exportNames = {};
-iteratorUtils.each(eventNames, function(_, eventName) {
- exportNames[eventName.substring(DX_PREFIX.length)] = eventName;
-});
/* eslint-disable spellcheck/spell-checker */
export const {
transformstart,
@@ -293,5 +128,6 @@ export const {
pinchend,
rotatestart,
rotate,
- rotateend
+ rotateend,
} = exportNames;
+
diff --git a/packages/devextreme/js/events/utils/add_namespace.js b/packages/devextreme/js/events/utils/add_namespace.js
index c41b78ce9a03..ffa6a046fa06 100644
--- a/packages/devextreme/js/events/utils/add_namespace.js
+++ b/packages/devextreme/js/events/utils/add_namespace.js
@@ -1,21 +1 @@
-import errors from '../../core/errors';
-
-const addNamespace = (eventNames, namespace) => {
- if(!namespace) {
- throw errors.Error('E0017');
- }
-
- if(Array.isArray(eventNames)) {
- return eventNames
- .map(eventName => addNamespace(eventName, namespace))
- .join(' ');
- }
-
- if(eventNames.indexOf(' ') !== -1) {
- return addNamespace(eventNames.split(/\s+/g), namespace);
- }
-
- return `${eventNames}.${namespace}`;
-};
-
-export default addNamespace;
+export { default } from '../../__internal/events/utils/m_add_namespace';
diff --git a/packages/devextreme/js/events/utils/event_nodes_disposing.js b/packages/devextreme/js/events/utils/event_nodes_disposing.js
index ae6513a267ba..0dd3c94270d2 100644
--- a/packages/devextreme/js/events/utils/event_nodes_disposing.js
+++ b/packages/devextreme/js/events/utils/event_nodes_disposing.js
@@ -1,19 +1 @@
-import eventsEngine from '../core/events_engine';
-import { removeEvent } from '../remove';
-
-function nodesByEvent(event) {
- return event && [
- event.target,
- event.delegateTarget,
- event.relatedTarget,
- event.currentTarget
- ].filter(node => !!node);
-}
-
-export const subscribeNodesDisposing = (event, callback) => {
- eventsEngine.one(nodesByEvent(event), removeEvent, callback);
-};
-
-export const unsubscribeNodesDisposing = (event, callback) => {
- eventsEngine.off(nodesByEvent(event), removeEvent, callback);
-};
+export * from '../../__internal/events/utils/m_event_nodes_disposing';
diff --git a/packages/devextreme/js/events/utils/event_target.js b/packages/devextreme/js/events/utils/event_target.js
index cb8c63726e6b..6b0f3d4dd2a0 100644
--- a/packages/devextreme/js/events/utils/event_target.js
+++ b/packages/devextreme/js/events/utils/event_target.js
@@ -1,18 +1 @@
-export const getEventTarget = (event) => {
- const originalEvent = event.originalEvent;
-
- if(!originalEvent) {
- return event.target;
- }
-
- const isShadowDOMUsed = Boolean(originalEvent.target?.shadowRoot);
-
- if(!isShadowDOMUsed) {
- return originalEvent.target;
- }
-
- const path = originalEvent.path ?? originalEvent.composedPath?.();
- const target = path?.[0] ?? event.target;
-
- return target;
-};
+export * from '../../__internal/events/utils/m_event_target';
diff --git a/packages/devextreme/js/events/utils/index.js b/packages/devextreme/js/events/utils/index.js
index 3b24393d0fa5..4e21a47cee31 100644
--- a/packages/devextreme/js/events/utils/index.js
+++ b/packages/devextreme/js/events/utils/index.js
@@ -1,200 +1 @@
-import $ from '../../core/renderer';
-import mappedAddNamespace from './add_namespace';
-import eventsEngine from '../core/events_engine';
-import { each } from '../../core/utils/iterator';
-import { extend } from '../../core/utils/extend';
-import { focused } from '../../ui/widget/selectors';
-
-const KEY_MAP = {
- 'backspace': 'backspace',
- 'tab': 'tab',
- 'enter': 'enter',
- 'escape': 'escape',
- 'pageup': 'pageUp',
- 'pagedown': 'pageDown',
- 'end': 'end',
- 'home': 'home',
- 'arrowleft': 'leftArrow',
- 'arrowup': 'upArrow',
- 'arrowright': 'rightArrow',
- 'arrowdown': 'downArrow',
- 'delete': 'del',
- ' ': 'space',
- 'f': 'F',
- 'a': 'A',
- '*': 'asterisk',
- '-': 'minus',
- 'alt': 'alt',
- 'control': 'control',
- 'shift': 'shift',
-};
-
-const LEGACY_KEY_CODES = {
- // iOS 10.2 and lower didn't supports KeyboardEvent.key
- '8': 'backspace',
- '9': 'tab',
- '13': 'enter',
- '27': 'escape',
- '33': 'pageUp',
- '34': 'pageDown',
- '35': 'end',
- '36': 'home',
- '37': 'leftArrow',
- '38': 'upArrow',
- '39': 'rightArrow',
- '40': 'downArrow',
- '46': 'del',
- '32': 'space',
- '70': 'F',
- '65': 'A',
- '106': 'asterisk',
- '109': 'minus',
- '189': 'minus',
- '173': 'minus',
- '16': 'shift',
- '17': 'control',
- '18': 'alt'
-};
-
-const EVENT_SOURCES_REGEX = {
- dx: /^dx/i,
- mouse: /(mouse|wheel)/i,
- touch: /^touch/i,
- keyboard: /^key/i,
- pointer: /^(ms)?pointer/i
-};
-
-let fixMethod = e => e;
-const copyEvent = originalEvent => fixMethod(eventsEngine.Event(originalEvent, originalEvent), originalEvent);
-const isDxEvent = e => eventSource(e) === 'dx';
-const isNativeMouseEvent = e => eventSource(e) === 'mouse';
-const isNativeTouchEvent = e => eventSource(e) === 'touch';
-
-export const eventSource = ({ type }) => {
- let result = 'other';
-
- each(EVENT_SOURCES_REGEX, function(key) {
- if(this.test(type)) {
- result = key;
-
- return false;
- }
- });
-
- return result;
-};
-
-export const isPointerEvent = e => eventSource(e) === 'pointer';
-
-export const isMouseEvent = e => isNativeMouseEvent(e) ||
- ((isPointerEvent(e) || isDxEvent(e)) && e.pointerType === 'mouse');
-
-export const isDxMouseWheelEvent = e => e && e.type === 'dxmousewheel';
-
-export const isTouchEvent = e => isNativeTouchEvent(e) ||
- ((isPointerEvent(e) || isDxEvent(e)) && e.pointerType === 'touch');
-
-export const isKeyboardEvent = e => eventSource(e) === 'keyboard';
-
-export const isFakeClickEvent = ({ screenX, offsetX, pageX }) => screenX === 0 && !offsetX && pageX === 0;
-
-export const eventData = ({ pageX, pageY, timeStamp }) => ({
- x: pageX,
- y: pageY,
- time: timeStamp
-});
-
-export const eventDelta = (from, to) => ({
- x: to.x - from.x,
- y: to.y - from.y,
- time: to.time - from.time || 1
-});
-
-export const hasTouches = e => {
- const { originalEvent, pointers } = e;
-
- if(isNativeTouchEvent(e)) {
- return (originalEvent.touches || []).length;
- }
-
- if(isDxEvent(e)) {
- return (pointers || []).length;
- }
-
- return 0;
-};
-
-// TODO: for tests
-let skipEvents = false;
-export const forceSkipEvents = () => skipEvents = true;
-export const stopEventsSkipping = () => skipEvents = false;
-
-export const needSkipEvent = e => {
- // TODO: for tests
- if(skipEvents) {
- return true;
- }
-
- // TODO: this checking used in swipeable first move handler. is it correct?
- const { target } = e;
- const $target = $(target);
- const isContentEditable = target?.isContentEditable || target?.hasAttribute('contenteditable');
- const touchInEditable = $target.is('input, textarea, select') || isContentEditable;
-
- if(isDxMouseWheelEvent(e)) {
- const isTextArea = $target.is('textarea') && $target.hasClass('dx-texteditor-input');
-
- if(isTextArea || isContentEditable) {
- return false;
- }
-
- const isInputFocused = $target.is('input[type=\'number\'], textarea, select') && $target.is(':focus');
-
- return isInputFocused;
- }
-
- if(isMouseEvent(e)) {
- return touchInEditable || e.which > 1; // only left mouse button
- }
-
- if(isTouchEvent(e)) {
- return touchInEditable && focused($target);
- }
-};
-
-export const setEventFixMethod = func => fixMethod = func;
-
-export const createEvent = (originalEvent, args) => {
- const event = copyEvent(originalEvent);
-
- args && extend(event, args);
-
- return event;
-};
-
-export const fireEvent = props => {
- const { originalEvent, delegateTarget } = props;
- const event = createEvent(originalEvent, props);
-
- eventsEngine.trigger(delegateTarget || event.target, event);
-
- return event;
-};
-
-export const normalizeKeyName = ({ key, which }) => {
- const normalizedKey = KEY_MAP[key?.toLowerCase()] || key;
- const normalizedKeyFromWhich = LEGACY_KEY_CODES[which];
- if(normalizedKeyFromWhich && normalizedKey === key) {
- return normalizedKeyFromWhich;
- } else if(!normalizedKey && which) {
- return String.fromCharCode(which);
- }
-
- return normalizedKey;
-};
-
-export const getChar = ({ key, which }) => key || String.fromCharCode(which);
-
-export const addNamespace = mappedAddNamespace;
-
-export const isCommandKeyPressed = ({ ctrlKey, metaKey }) => ctrlKey || metaKey;
+export * from '../../__internal/events/utils/index';
diff --git a/packages/devextreme/js/events/visibility_change.js b/packages/devextreme/js/events/visibility_change.js
index 623329c76d45..eae6f20c886a 100644
--- a/packages/devextreme/js/events/visibility_change.js
+++ b/packages/devextreme/js/events/visibility_change.js
@@ -1,22 +1,7 @@
-import $ from '../core/renderer';
-import eventsEngine from './core/events_engine';
+import VisibilityChangeModule from '../__internal/events/m_visibility_change';
-const triggerVisibilityChangeEvent = function(eventName) {
- const VISIBILITY_CHANGE_SELECTOR = '.dx-visibility-change-handler';
+export const triggerShownEvent = VisibilityChangeModule.triggerShownEvent;
+export const triggerHidingEvent = VisibilityChangeModule.triggerHidingEvent;
+export const triggerResizeEvent = VisibilityChangeModule.triggerResizeEvent;
- return function(element) {
- const $element = $(element || 'body');
-
- const changeHandlers = $element.filter(VISIBILITY_CHANGE_SELECTOR).
- add($element.find(VISIBILITY_CHANGE_SELECTOR));
-
- for(let i = 0; i < changeHandlers.length; i++) {
- eventsEngine.triggerHandler(changeHandlers[i], eventName);
- }
- };
-};
-
-
-export const triggerShownEvent = triggerVisibilityChangeEvent('dxshown');
-export const triggerHidingEvent = triggerVisibilityChangeEvent('dxhiding');
-export const triggerResizeEvent = triggerVisibilityChangeEvent('dxresize');
+export default VisibilityChangeModule;
diff --git a/packages/devextreme/testing/tests/DevExpress.ui.events/dblclick.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.events/dblclick.tests.js
index 8178c3e8966d..0d6d62db4230 100644
--- a/packages/devextreme/testing/tests/DevExpress.ui.events/dblclick.tests.js
+++ b/packages/devextreme/testing/tests/DevExpress.ui.events/dblclick.tests.js
@@ -1,6 +1,6 @@
const $ = require('jquery');
const dblclickEvent = require('events/dblclick');
-const { dblClick } = require('__internal/events/dblclick');
+const { dblClick } = require('__internal/events/m_dblclick');
const pointerMock = require('../../helpers/pointerMock.js');
QUnit.testStart(function() {
@@ -44,7 +44,7 @@ QUnit.test('dxdblclick should not be handled on a usual dxclick even if dblClick
el.off(dblclickEvent.name);
el.on(dblclickEvent.name, handler);
- el.on(dblclickEvent.name, () => {});
+ el.on(dblclickEvent.name, () => { });
el.trigger('dxclick');