Skip to content

Commit 8c821c2

Browse files
fix: jQuery event types contain excessive props but lack originalEvent (DevExpress#30009)
1 parent bdc6b3f commit 8c821c2

File tree

9 files changed

+205
-57
lines changed

9 files changed

+205
-57
lines changed

e2e/compilation-cases/T1282141.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { CutEvent } from 'devextreme/js/ui/color_box';
2+
import { EVENT_PROPERTIES } from 'devextreme/js/__internal/events/core/m_consts';
3+
4+
type NATIVE_EVENT_ARGS = KeyboardEvent
5+
& PointerEvent
6+
& TouchEvent
7+
& FocusEvent
8+
& WheelEvent
9+
& ClipboardEvent;
10+
11+
type NATIVE_EVENT_ARG_NON_PROPS = Pick<KeyboardEvent,
12+
'getModifierState'
13+
| 'initKeyboardEvent'
14+
| 'DOM_KEY_LOCATION_STANDARD'
15+
| 'DOM_KEY_LOCATION_LEFT'
16+
| 'DOM_KEY_LOCATION_RIGHT'
17+
| 'DOM_KEY_LOCATION_NUMPAD'>
18+
& Pick<UIEvent, 'initUIEvent'>
19+
& Pick<Event,
20+
'composedPath'
21+
| 'initEvent'
22+
| 'preventDefault'
23+
| 'stopImmediatePropagation'
24+
| 'stopPropagation'
25+
| 'NONE'
26+
| 'CAPTURING_PHASE'
27+
| 'AT_TARGET'
28+
| 'BUBBLING_PHASE'>
29+
& Pick<PointerEvent, 'getCoalescedEvents' | 'getPredictedEvents'>
30+
& Pick<MouseEvent, 'initMouseEvent'>
31+
& Pick<WheelEvent, 'DOM_DELTA_PIXEL' | 'DOM_DELTA_LINE' | 'DOM_DELTA_PAGE'>;
32+
33+
type PROPS_ASSIGNED_ELSEWHERE = {
34+
type: string;
35+
isTrusted: boolean;
36+
timeStamp: number;
37+
which: number;
38+
currentTarget: EventTarget | null;
39+
40+
// touch hooks
41+
clientX: number;
42+
clientY: number;
43+
pageX: number;
44+
pageY: number;
45+
screenX: number;
46+
screenY: number;
47+
}
48+
49+
type IGNORED_MEMBERS = NATIVE_EVENT_ARG_NON_PROPS & PROPS_ASSIGNED_ELSEWHERE;
50+
51+
type ASSIGNED_EVENT_ARG_GETTERS = {
52+
[Property in typeof EVENT_PROPERTIES[number]]
53+
};
54+
55+
function fn(): void {
56+
let e: CutEvent = undefined as unknown as CutEvent;
57+
58+
e.event?.originalEvent.clipboardData?.clearData();
59+
60+
let dxGetters = undefined as unknown as ASSIGNED_EVENT_ARG_GETTERS & IGNORED_MEMBERS;
61+
let nativeArgs = undefined as unknown as NATIVE_EVENT_ARGS;
62+
63+
nativeArgs = dxGetters;
64+
}
65+
66+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* eslint-disable spellcheck/spell-checker */
2+
export const EMPTY_EVENT_NAME = 'dxEmptyEventType';
3+
export const NATIVE_EVENTS_TO_SUBSCRIBE = {
4+
mouseenter: 'mouseover',
5+
mouseleave: 'mouseout',
6+
pointerenter: 'pointerover',
7+
pointerleave: 'pointerout',
8+
};
9+
export const NATIVE_EVENTS_TO_TRIGGER = {
10+
focusin: 'focus',
11+
focusout: 'blur',
12+
};
13+
export const NO_BUBBLE_EVENTS = ['blur', 'focus', 'load'];
14+
15+
export const forcePassiveFalseEventNames = ['touchmove', 'wheel', 'mousewheel', 'touchstart'];
16+
17+
export const EVENT_PROPERTIES = [
18+
'altKey',
19+
'altitudeAngle',
20+
'azimuthAngle',
21+
'bubbles',
22+
'button',
23+
'buttons',
24+
'cancelable',
25+
'cancelBubble',
26+
'changedTouches',
27+
'char',
28+
'charCode',
29+
'clipboardData',
30+
'code',
31+
'composed',
32+
'ctrlKey',
33+
'defaultPrevented',
34+
'delegateTarget',
35+
'deltaMode',
36+
'deltaX',
37+
'deltaY',
38+
'deltaZ',
39+
'detail',
40+
'eventPhase',
41+
'height',
42+
'isComposing',
43+
'isPrimary',
44+
'key',
45+
'keyCode',
46+
'layerX',
47+
'layerY',
48+
'location',
49+
'metaKey',
50+
'movementX',
51+
'movementY',
52+
'offsetX',
53+
'offsetY',
54+
'pointerId',
55+
'pointerType',
56+
'pressure',
57+
'relatedTarget',
58+
'repeat',
59+
'returnValue',
60+
'srcElement',
61+
'shiftKey',
62+
'tangentialPressure',
63+
'target',
64+
'targetTouches',
65+
'tiltX',
66+
'tiltY',
67+
'toElement',
68+
'touches',
69+
'twist',
70+
'view',
71+
'width',
72+
'x',
73+
'y',
74+
] as const;

packages/devextreme/js/__internal/events/core/m_events_engine.ts

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,55 +11,17 @@ import {
1111
isFunction, isObject, isString, isWindow,
1212
} from '@js/core/utils/type';
1313
import { getWindow, hasWindow } from '@js/core/utils/window';
14+
import {
15+
EMPTY_EVENT_NAME,
16+
EVENT_PROPERTIES,
17+
forcePassiveFalseEventNames,
18+
NATIVE_EVENTS_TO_SUBSCRIBE,
19+
NATIVE_EVENTS_TO_TRIGGER,
20+
NO_BUBBLE_EVENTS,
21+
} from '@ts/events/core/m_consts';
1422

1523
const window = getWindow();
1624

17-
/* eslint-disable spellcheck/spell-checker */
18-
const EMPTY_EVENT_NAME = 'dxEmptyEventType';
19-
const NATIVE_EVENTS_TO_SUBSCRIBE = {
20-
mouseenter: 'mouseover',
21-
mouseleave: 'mouseout',
22-
pointerenter: 'pointerover',
23-
pointerleave: 'pointerout',
24-
};
25-
const NATIVE_EVENTS_TO_TRIGGER = {
26-
focusin: 'focus',
27-
focusout: 'blur',
28-
};
29-
const NO_BUBBLE_EVENTS = ['blur', 'focus', 'load'];
30-
31-
const forcePassiveFalseEventNames = ['touchmove', 'wheel', 'mousewheel', 'touchstart'];
32-
33-
const EVENT_PROPERTIES = [
34-
'target',
35-
'relatedTarget',
36-
'delegateTarget',
37-
'altKey',
38-
'bubbles',
39-
'cancelable',
40-
'changedTouches',
41-
'ctrlKey',
42-
'detail',
43-
'eventPhase',
44-
'metaKey',
45-
'shiftKey',
46-
'view',
47-
'char',
48-
'code',
49-
'charCode',
50-
'key',
51-
'keyCode',
52-
'button',
53-
'buttons',
54-
'offsetX',
55-
'offsetY',
56-
'pointerId',
57-
'pointerType',
58-
'targetTouches',
59-
'toElement',
60-
'touches',
61-
];
62-
6325
function matchesSafe(target, selector) {
6426
return !isWindow(target) && target.nodeName !== '#document' && domAdapter.elementMatches(target, selector);
6527
}

packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/header.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ import messageLocalization from '@js/localization/message';
33
import type { ValueChangedEvent } from '@js/ui/check_box';
44
import type * as dxToolbar from '@js/ui/toolbar';
55
import { isDefined } from '@ts/core/utils/m_type';
6+
import type { SelectCardOptions } from '@ts/grids/new/card_view/content_view/types';
67
import type { CardInfo } from '@ts/grids/new/grid_core/columns_controller/types';
78
import { Toolbar } from '@ts/grids/new/grid_core/inferno_wrappers/toolbar';
89
import type { DefaultToolbarItem } from '@ts/grids/new/grid_core/toolbar/types';
910
import { normalizeToolbarItems } from '@ts/grids/new/grid_core/toolbar/utils';
1011
import type { ComponentType } from 'inferno';
1112
import { Component } from 'inferno';
1213

13-
import type { SelectCardOptions } from '../../types';
14-
1514
export const CLASSES = {
1615
cardHeader: 'dx-cardview-card-header',
1716
cardSelectCheckBox: 'dx-cardview-select-checkbox',

packages/devextreme/js/__internal/ui/context_menu/context_menu.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ class ContextMenu<
588588
}
589589
}
590590

591-
_hoverEndHandler(e: DxEvent<HoverEvent>): void {
591+
_hoverEndHandler(e: HoverEvent): void {
592592
super._hoverEndHandler(e);
593593
e.stopPropagation();
594594
}
@@ -1181,7 +1181,6 @@ class ContextMenu<
11811181
this._setAriaAttributes();
11821182

11831183
// T983617. Prevent the browser's context menu appears on desktop touch screens.
1184-
// @ts-expect-error ts-error
11851184
if (event?.originalEvent?.type === holdEvent.name) {
11861185
this.preventShowingDefaultContextMenuAboveOverlay();
11871186
}

packages/devextreme/js/__internal/ui/context_menu/menu_base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ class MenuBase<
353353
}
354354
}
355355

356-
_hoverStartHandler(e: DxEvent<HoverEvent>): void {
356+
_hoverStartHandler(e: HoverEvent): void {
357357
const $itemElement = this._getItemElementByEventArgs(e);
358358

359359
if (!$itemElement || this._isItemDisabled($itemElement)) return;
@@ -434,7 +434,7 @@ class MenuBase<
434434
}
435435

436436
// eslint-disable-next-line @typescript-eslint/no-unused-vars
437-
_hoverEndHandler(event: DxEvent<HoverEvent>): void {
437+
_hoverEndHandler(event: HoverEvent): void {
438438
clearTimeout(this._showSubmenusTimeout);
439439
}
440440

packages/devextreme/js/events/events.types.d.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @namespace DevExpress.events
33
*/
4-
export type EventObject = {
4+
export type EventObject<TNativeEvent = Event> = {
55
/**
66
* @docid
77
* @public
@@ -20,6 +20,13 @@ export type EventObject = {
2020
*/
2121
delegateTarget: Element;
2222

23+
/**
24+
* @docid
25+
* @public
26+
* @type event
27+
*/
28+
originalEvent: TNativeEvent;
29+
2330
/**
2431
* @docid
2532
* @public
@@ -79,7 +86,16 @@ export interface EventType { }
7986
* @type EventObject|jQuery.Event
8087
*
8188
*/
82-
export type DxEvent<TNativeEvent = Event> = {} extends EventType ? (EventObject & TNativeEvent) : EventType;
89+
export type DxEvent<TNativeEvent = Event> = {} extends EventType
90+
? (EventObject<TNativeEvent> & TNativeEvent)
91+
: (Omit<EventType, 'originalEvent'> & {
92+
/**
93+
* @docid
94+
* @public
95+
* @type event
96+
*/
97+
originalEvent: TNativeEvent;
98+
});
8399

84100
/** @deprecated EventObject */
85101
export type dxEvent = EventObject;

packages/devextreme/testing/tests/DevExpress.ui.events/eventsEngine.tests.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import eventsEngine from 'common/core/events/core/events_engine';
33
import keyboardMock from '../../helpers/keyboardMock.js';
44
import registerEvent from 'common/core/events/core/event_registrator';
55
import { compare as compareVersion } from 'core/utils/version';
6+
import { EVENT_PROPERTIES } from '__internal/events/core/m_consts';
7+
import config from 'core/config';
68

79
QUnit.module('base');
810

@@ -258,6 +260,26 @@ QUnit.test('Simulate clicks, check which property', function(assert) {
258260
}
259261
});
260262

263+
QUnit.test('Check getters attached to event wrappers', function(assert) {
264+
const done = assert.async();
265+
const useJQuery = config().useJQuery;
266+
const div = document.createElement('div');
267+
const handler = function(e) {
268+
if(e instanceof eventsEngine.Event && !useJQuery) {
269+
EVENT_PROPERTIES.forEach(prop => { assert.ok(prop in e, `getter for the '${prop}' prop found in the event arg`); });
270+
} else {
271+
assert.ok(true);
272+
}
273+
done();
274+
};
275+
276+
document.body.appendChild(div);
277+
eventsEngine.on(div, 'click', handler);
278+
const event = div.ownerDocument.createEvent('MouseEvents');
279+
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
280+
div.dispatchEvent(event);
281+
});
282+
261283
QUnit.test('Simulate tab press, check key property', function(assert) {
262284
const done = assert.async();
263285
const input = document.createElement('input');

packages/devextreme/ts/dx.all.d.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7790,8 +7790,13 @@ declare module DevExpress.events {
77907790
* @deprecated Attention! This type is for internal purposes only. If you used it previously, please submit a ticket to our {@link https://supportcenter.devexpress.com/ticket/create Support Center}. We will check if there is an alternative solution.
77917791
*/
77927792
export type DxEvent<TNativeEvent = Event> = {} extends EventType
7793-
? EventObject & TNativeEvent
7794-
: EventType;
7793+
? EventObject<TNativeEvent> & TNativeEvent
7794+
: Omit<EventType, 'originalEvent'> & {
7795+
/**
7796+
* [descr:DxEvent.originalEvent]
7797+
*/
7798+
originalEvent: TNativeEvent;
7799+
};
77957800
/**
77967801
* [descr:event]
77977802
* @deprecated [depNote:event]
@@ -7801,7 +7806,7 @@ declare module DevExpress.events {
78017806
/**
78027807
* @deprecated Attention! This type is for internal purposes only. If you used it previously, please submit a ticket to our {@link https://supportcenter.devexpress.com/ticket/create Support Center}. We will check if there is an alternative solution.
78037808
*/
7804-
export type EventObject = {
7809+
export type EventObject<TNativeEvent = Event> = {
78057810
/**
78067811
* [descr:EventObject.currentTarget]
78077812
*/
@@ -7817,6 +7822,11 @@ declare module DevExpress.events {
78177822
*/
78187823
delegateTarget: Element;
78197824

7825+
/**
7826+
* [descr:EventObject.originalEvent]
7827+
*/
7828+
originalEvent: TNativeEvent;
7829+
78207830
/**
78217831
* [descr:EventObject.target]
78227832
*/

0 commit comments

Comments
 (0)