Skip to content

Commit 2c402d5

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(zone.js): handle MSPointer event correctly (#31722)
Close #31699 PR Close #31722
1 parent 35a025f commit 2c402d5

3 files changed

Lines changed: 164 additions & 5 deletions

File tree

packages/zone.js/lib/browser/event-target-legacy.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ export function eventTargetLegacyPatch(_global: any, api: _ZonePrivate) {
3939
const FUNCTION_WRAPPER = '[object FunctionWrapper]';
4040
const BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }';
4141

42+
const pointerEventsMap: {[key: string]: string} = {
43+
'MSPointerCancel': 'pointercancel',
44+
'MSPointerDown': 'pointerdown',
45+
'MSPointerEnter': 'pointerenter',
46+
'MSPointerHover': 'pointerhover',
47+
'MSPointerLeave': 'pointerleave',
48+
'MSPointerMove': 'pointermove',
49+
'MSPointerOut': 'pointerout',
50+
'MSPointerOver': 'pointerover',
51+
'MSPointerUp': 'pointerup'
52+
};
53+
4254
// predefine all __zone_symbol__ + eventName + true/false string
4355
for (let i = 0; i < eventNames.length; i++) {
4456
const eventName = eventNames[i];
@@ -100,7 +112,13 @@ export function eventTargetLegacyPatch(_global: any, api: _ZonePrivate) {
100112
}
101113
// vh is validateHandler to check event handler
102114
// is valid or not(for security check)
103-
api.patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});
115+
api.patchEventTarget(_global, apiTypes, {
116+
vh: checkIEAndCrossContext,
117+
transferEventName: (eventName: string) => {
118+
const pointerEventName = pointerEventsMap[eventName];
119+
return pointerEventName || eventName;
120+
}
121+
});
104122
(Zone as any)[api.symbol('patchEventTarget')] = !!_global[EVENT_TARGET];
105123
return true;
106124
}

packages/zone.js/lib/common/events.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ export interface PatchEventTargetOptions {
6969
supportPassive?: boolean;
7070
// get string from eventName (in nodejs, eventName maybe Symbol)
7171
eventNameToString?: (eventName: any) => string;
72+
// transfer eventName
73+
transferEventName?: (eventName: string) => string;
7274
}
7375

7476
export function patchEventTarget(
@@ -332,7 +334,10 @@ export function patchEventTarget(
332334
returnTarget = false, prepend = false) {
333335
return function(this: unknown) {
334336
const target = this || _global;
335-
const eventName = arguments[0];
337+
let eventName = arguments[0];
338+
if (patchOptions && patchOptions.transferEventName) {
339+
eventName = patchOptions.transferEventName(eventName);
340+
}
336341
let delegate = arguments[1];
337342
if (!delegate) {
338343
return nativeListener.apply(this, arguments);
@@ -498,7 +503,10 @@ export function patchEventTarget(
498503

499504
proto[REMOVE_EVENT_LISTENER] = function() {
500505
const target = this || _global;
501-
const eventName = arguments[0];
506+
let eventName = arguments[0];
507+
if (patchOptions && patchOptions.transferEventName) {
508+
eventName = patchOptions.transferEventName(eventName);
509+
}
502510
const options = arguments[2];
503511

504512
let capture;
@@ -565,7 +573,10 @@ export function patchEventTarget(
565573

566574
proto[LISTENERS_EVENT_LISTENER] = function() {
567575
const target = this || _global;
568-
const eventName = arguments[0];
576+
let eventName = arguments[0];
577+
if (patchOptions && patchOptions.transferEventName) {
578+
eventName = patchOptions.transferEventName(eventName);
579+
}
569580

570581
const listeners: any[] = [];
571582
const tasks =
@@ -582,7 +593,7 @@ export function patchEventTarget(
582593
proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function() {
583594
const target = this || _global;
584595

585-
const eventName = arguments[0];
596+
let eventName = arguments[0];
586597
if (!eventName) {
587598
const keys = Object.keys(target);
588599
for (let i = 0; i < keys.length; i++) {
@@ -600,6 +611,9 @@ export function patchEventTarget(
600611
// remove removeListener listener finally
601612
this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
602613
} else {
614+
if (patchOptions && patchOptions.transferEventName) {
615+
eventName = patchOptions.transferEventName(eventName);
616+
}
603617
const symbolEventNames = zoneSymbolEventNames[eventName];
604618
if (symbolEventNames) {
605619
const symbolEventName = symbolEventNames[FALSE_STR];

packages/zone.js/test/browser/browser.spec.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,4 +2381,131 @@ describe('Zone', function() {
23812381
}));
23822382
});
23832383
});
2384+
2385+
2386+
describe(
2387+
'pointer event in IE',
2388+
ifEnvSupports(
2389+
() => { return getIEVersion() === 11; },
2390+
() => {
2391+
const pointerEventsMap: {[key: string]: string} = {
2392+
'MSPointerCancel': 'pointercancel',
2393+
'MSPointerDown': 'pointerdown',
2394+
'MSPointerEnter': 'pointerenter',
2395+
'MSPointerHover': 'pointerhover',
2396+
'MSPointerLeave': 'pointerleave',
2397+
'MSPointerMove': 'pointermove',
2398+
'MSPointerOut': 'pointerout',
2399+
'MSPointerOver': 'pointerover',
2400+
'MSPointerUp': 'pointerup'
2401+
};
2402+
2403+
let div: HTMLDivElement;
2404+
beforeEach(() => {
2405+
div = document.createElement('div');
2406+
document.body.appendChild(div);
2407+
});
2408+
afterEach(() => { document.body.removeChild(div); });
2409+
Object.keys(pointerEventsMap).forEach(key => {
2410+
it(`${key} and ${pointerEventsMap[key]} should both be triggered`, (done: DoneFn) => {
2411+
const logs: string[] = [];
2412+
div.addEventListener(key, (event: any) => {
2413+
expect(event.type).toEqual(pointerEventsMap[key]);
2414+
logs.push(`${key} triggered`);
2415+
});
2416+
div.addEventListener(pointerEventsMap[key], (event: any) => {
2417+
expect(event.type).toEqual(pointerEventsMap[key]);
2418+
logs.push(`${pointerEventsMap[key]} triggered`);
2419+
});
2420+
const evt1 = document.createEvent('Event');
2421+
evt1.initEvent(key, true, true);
2422+
div.dispatchEvent(evt1);
2423+
2424+
setTimeout(() => {
2425+
expect(logs).toEqual([`${key} triggered`, `${pointerEventsMap[key]} triggered`]);
2426+
});
2427+
2428+
const evt2 = document.createEvent('Event');
2429+
evt2.initEvent(pointerEventsMap[key], true, true);
2430+
div.dispatchEvent(evt2);
2431+
2432+
setTimeout(() => {
2433+
expect(logs).toEqual([`${key} triggered`, `${pointerEventsMap[key]} triggered`]);
2434+
});
2435+
2436+
setTimeout(done);
2437+
});
2438+
2439+
it(`${key} and ${
2440+
pointerEventsMap[key]} with same listener should not be triggered twice`,
2441+
(done: DoneFn) => {
2442+
const logs: string[] = [];
2443+
const listener = function(event: any) {
2444+
expect(event.type).toEqual(pointerEventsMap[key]);
2445+
logs.push(`${key} triggered`);
2446+
};
2447+
div.addEventListener(key, listener);
2448+
div.addEventListener(pointerEventsMap[key], listener);
2449+
2450+
const evt1 = document.createEvent('Event');
2451+
evt1.initEvent(key, true, true);
2452+
div.dispatchEvent(evt1);
2453+
2454+
setTimeout(() => { expect(logs).toEqual([`${key} triggered`]); });
2455+
2456+
const evt2 = document.createEvent('Event');
2457+
evt2.initEvent(pointerEventsMap[key], true, true);
2458+
div.dispatchEvent(evt2);
2459+
2460+
setTimeout(
2461+
() => { expect(logs).toEqual([`${pointerEventsMap[key]} triggered`]); });
2462+
2463+
setTimeout(done);
2464+
});
2465+
2466+
it(`${key} and ${
2467+
pointerEventsMap
2468+
[key]} should be able to be removed with removeEventListener`,
2469+
(done: DoneFn) => {
2470+
const logs: string[] = [];
2471+
const listener1 = function(event: any) { logs.push(`${key} triggered`); };
2472+
const listener2 = function(event: any) {
2473+
logs.push(`${pointerEventsMap[key]} triggered`);
2474+
};
2475+
div.addEventListener(key, listener1);
2476+
div.addEventListener(pointerEventsMap[key], listener2);
2477+
2478+
div.removeEventListener(key, listener1);
2479+
div.removeEventListener(key, listener2);
2480+
2481+
const evt1 = document.createEvent('Event');
2482+
evt1.initEvent(key, true, true);
2483+
div.dispatchEvent(evt1);
2484+
2485+
setTimeout(() => { expect(logs).toEqual([]); });
2486+
2487+
const evt2 = document.createEvent('Event');
2488+
evt2.initEvent(pointerEventsMap[key], true, true);
2489+
div.dispatchEvent(evt2);
2490+
2491+
setTimeout(() => { expect(logs).toEqual([]); });
2492+
2493+
div.addEventListener(key, listener1);
2494+
div.addEventListener(pointerEventsMap[key], listener2);
2495+
2496+
div.removeEventListener(pointerEventsMap[key], listener1);
2497+
div.removeEventListener(pointerEventsMap[key], listener2);
2498+
2499+
div.dispatchEvent(evt1);
2500+
2501+
setTimeout(() => { expect(logs).toEqual([]); });
2502+
2503+
div.dispatchEvent(evt2);
2504+
2505+
setTimeout(() => { expect(logs).toEqual([]); });
2506+
2507+
setTimeout(done);
2508+
});
2509+
});
2510+
}));
23842511
});

0 commit comments

Comments
 (0)