fix(core): handle GestureObservers same as event listeners (#10538)

This commit is contained in:
Jamie Birch
2024-05-07 09:50:01 +09:00
committed by GitHub
parent 3b77fffad5
commit d323672b29
3 changed files with 39 additions and 23 deletions

View File

@ -587,7 +587,7 @@ export abstract class View extends ViewCommon {
*/ */
public focus(): boolean; public focus(): boolean;
public getGestureObservers(type: GestureTypes): Array<GesturesObserver>; public getGestureObservers(type: GestureTypes): Array<GesturesObserver> | undefined;
/** /**
* Removes listener(s) for the specified event name. * Removes listener(s) for the specified event name.

View File

@ -278,7 +278,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
} }
} }
_observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void { protected _observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void {
thisArg = thisArg || undefined;
if (this._gestureObservers[type]?.find((observer) => observer.callback === callback && observer.context === thisArg)) {
// Already added.
return;
}
if (!this._gestureObservers[type]) { if (!this._gestureObservers[type]) {
this._gestureObservers[type] = []; this._gestureObservers[type] = [];
} }
@ -291,6 +298,8 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
} }
public addEventListener(eventNames: string, callback: (data: EventData) => void, thisArg?: any) { public addEventListener(eventNames: string, callback: (data: EventData) => void, thisArg?: any) {
thisArg = thisArg || undefined;
// Normalize "ontap" -> "tap" // Normalize "ontap" -> "tap"
const normalizedName = getEventOrGestureName(eventNames); const normalizedName = getEventOrGestureName(eventNames);
@ -300,7 +309,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
// If it's a gesture (and this Observable declares e.g. `static tapEvent`) // If it's a gesture (and this Observable declares e.g. `static tapEvent`)
if (gesture && !this._isEvent(normalizedName)) { if (gesture && !this._isEvent(normalizedName)) {
this._observe(gesture, callback as unknown as (data: GestureEventData) => void, thisArg); this._observe(gesture, callback, thisArg);
return; return;
} }
@ -308,6 +317,8 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
} }
public removeEventListener(eventNames: string, callback?: (data: EventData) => void, thisArg?: any) { public removeEventListener(eventNames: string, callback?: (data: EventData) => void, thisArg?: any) {
thisArg = thisArg || undefined;
// Normalize "ontap" -> "tap" // Normalize "ontap" -> "tap"
const normalizedName = getEventOrGestureName(eventNames); const normalizedName = getEventOrGestureName(eventNames);
@ -317,7 +328,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
// If it's a gesture (and this Observable declares e.g. `static tapEvent`) // If it's a gesture (and this Observable declares e.g. `static tapEvent`)
if (gesture && !this._isEvent(normalizedName)) { if (gesture && !this._isEvent(normalizedName)) {
this._disconnectGestureObservers(gesture); this._disconnectGestureObservers(gesture, callback, thisArg);
return; return;
} }
@ -479,14 +490,34 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
return this.constructor && `${name}Event` in this.constructor; return this.constructor && `${name}Event` in this.constructor;
} }
private _disconnectGestureObservers(type: GestureTypes): void { private _disconnectGestureObservers(type: GestureTypes, callback?: (data: EventData) => void, thisArg?: any): void {
// Largely mirrors the implementation of Observable.innerRemoveEventListener().
const observers = this.getGestureObservers(type); const observers = this.getGestureObservers(type);
if (!observers) { if (!observers) {
return; return;
} }
for (const observer of observers) { for (let i = 0; i < observers.length; i++) {
const observer = observers[i];
// If we have a `thisArg`, refine on both `callback` and `thisArg`.
if (thisArg && (observer.callback !== callback || observer.context !== thisArg)) {
continue;
}
// If we don't have a `thisArg`, refine only on `callback`.
if (callback && observer.callback !== callback) {
continue;
}
observer.disconnect(); observer.disconnect();
observers.splice(i, 1);
i--;
}
if (!observers.length) {
delete this._gestureObservers[type];
} }
} }

View File

@ -338,7 +338,7 @@ export function fromString(type: string): GestureTypes | undefined {
export abstract class GesturesObserverBase implements GesturesObserverDefinition { export abstract class GesturesObserverBase implements GesturesObserverDefinition {
private _callback: (args: GestureEventData) => void; private _callback: (args: GestureEventData) => void;
private _target: View; private _target: View;
private _context: any; private _context?: any;
public type: GestureTypes; public type: GestureTypes;
@ -354,7 +354,7 @@ export abstract class GesturesObserverBase implements GesturesObserverDefinition
return this._context; return this._context;
} }
constructor(target: View, callback: (args: GestureEventData) => void, context: any) { constructor(target: View, callback: (args: GestureEventData) => void, context?: any) {
this._target = target; this._target = target;
this._callback = callback; this._callback = callback;
this._context = context; this._context = context;
@ -364,21 +364,6 @@ export abstract class GesturesObserverBase implements GesturesObserverDefinition
public abstract observe(type: GestureTypes); public abstract observe(type: GestureTypes);
public disconnect() { public disconnect() {
// remove gesture observer from map
if (this.target) {
const list = this.target.getGestureObservers(this.type);
if (list && list.length > 0) {
for (let i = 0; i < list.length; i++) {
if (list[i].callback === this.callback) {
break;
}
}
list.length = 0;
this.target._gestureObservers[this.type] = undefined;
delete this.target._gestureObservers[this.type];
}
}
this._target = null; this._target = null;
this._callback = null; this._callback = null;
this._context = null; this._context = null;