Skip to content

Commit d323672

Browse files
authored
fix(core): handle GestureObservers same as event listeners (#10538)
1 parent 3b77fff commit d323672

File tree

3 files changed

+39
-23
lines changed

3 files changed

+39
-23
lines changed

packages/core/ui/core/view/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ export abstract class View extends ViewCommon {
587587
*/
588588
public focus(): boolean;
589589

590-
public getGestureObservers(type: GestureTypes): Array<GesturesObserver>;
590+
public getGestureObservers(type: GestureTypes): Array<GesturesObserver> | undefined;
591591

592592
/**
593593
* Removes listener(s) for the specified event name.

packages/core/ui/core/view/view-common.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
278278
}
279279
}
280280

281-
_observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void {
281+
protected _observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void {
282+
thisArg = thisArg || undefined;
283+
284+
if (this._gestureObservers[type]?.find((observer) => observer.callback === callback && observer.context === thisArg)) {
285+
// Already added.
286+
return;
287+
}
288+
282289
if (!this._gestureObservers[type]) {
283290
this._gestureObservers[type] = [];
284291
}
@@ -291,6 +298,8 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
291298
}
292299

293300
public addEventListener(eventNames: string, callback: (data: EventData) => void, thisArg?: any) {
301+
thisArg = thisArg || undefined;
302+
294303
// Normalize "ontap" -> "tap"
295304
const normalizedName = getEventOrGestureName(eventNames);
296305

@@ -300,14 +309,16 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
300309

301310
// If it's a gesture (and this Observable declares e.g. `static tapEvent`)
302311
if (gesture && !this._isEvent(normalizedName)) {
303-
this._observe(gesture, callback as unknown as (data: GestureEventData) => void, thisArg);
312+
this._observe(gesture, callback, thisArg);
304313
return;
305314
}
306315

307316
super.addEventListener(normalizedName, callback, thisArg);
308317
}
309318

310319
public removeEventListener(eventNames: string, callback?: (data: EventData) => void, thisArg?: any) {
320+
thisArg = thisArg || undefined;
321+
311322
// Normalize "ontap" -> "tap"
312323
const normalizedName = getEventOrGestureName(eventNames);
313324

@@ -317,7 +328,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
317328

318329
// If it's a gesture (and this Observable declares e.g. `static tapEvent`)
319330
if (gesture && !this._isEvent(normalizedName)) {
320-
this._disconnectGestureObservers(gesture);
331+
this._disconnectGestureObservers(gesture, callback, thisArg);
321332
return;
322333
}
323334

@@ -479,14 +490,34 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
479490
return this.constructor && `${name}Event` in this.constructor;
480491
}
481492

482-
private _disconnectGestureObservers(type: GestureTypes): void {
493+
private _disconnectGestureObservers(type: GestureTypes, callback?: (data: EventData) => void, thisArg?: any): void {
494+
// Largely mirrors the implementation of Observable.innerRemoveEventListener().
495+
483496
const observers = this.getGestureObservers(type);
484497
if (!observers) {
485498
return;
486499
}
487500

488-
for (const observer of observers) {
501+
for (let i = 0; i < observers.length; i++) {
502+
const observer = observers[i];
503+
504+
// If we have a `thisArg`, refine on both `callback` and `thisArg`.
505+
if (thisArg && (observer.callback !== callback || observer.context !== thisArg)) {
506+
continue;
507+
}
508+
509+
// If we don't have a `thisArg`, refine only on `callback`.
510+
if (callback && observer.callback !== callback) {
511+
continue;
512+
}
513+
489514
observer.disconnect();
515+
observers.splice(i, 1);
516+
i--;
517+
}
518+
519+
if (!observers.length) {
520+
delete this._gestureObservers[type];
490521
}
491522
}
492523

packages/core/ui/gestures/gestures-common.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ export function fromString(type: string): GestureTypes | undefined {
338338
export abstract class GesturesObserverBase implements GesturesObserverDefinition {
339339
private _callback: (args: GestureEventData) => void;
340340
private _target: View;
341-
private _context: any;
341+
private _context?: any;
342342

343343
public type: GestureTypes;
344344

@@ -354,7 +354,7 @@ export abstract class GesturesObserverBase implements GesturesObserverDefinition
354354
return this._context;
355355
}
356356

357-
constructor(target: View, callback: (args: GestureEventData) => void, context: any) {
357+
constructor(target: View, callback: (args: GestureEventData) => void, context?: any) {
358358
this._target = target;
359359
this._callback = callback;
360360
this._context = context;
@@ -364,21 +364,6 @@ export abstract class GesturesObserverBase implements GesturesObserverDefinition
364364
public abstract observe(type: GestureTypes);
365365

366366
public disconnect() {
367-
// remove gesture observer from map
368-
if (this.target) {
369-
const list = this.target.getGestureObservers(this.type);
370-
if (list && list.length > 0) {
371-
for (let i = 0; i < list.length; i++) {
372-
if (list[i].callback === this.callback) {
373-
break;
374-
}
375-
}
376-
list.length = 0;
377-
378-
this.target._gestureObservers[this.type] = undefined;
379-
delete this.target._gestureObservers[this.type];
380-
}
381-
}
382367
this._target = null;
383368
this._callback = null;
384369
this._context = null;

0 commit comments

Comments
 (0)