Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- Fixed issue where `BrowserComponent.off()` could never remove event listeners because it passed the raw handler to `removeEventListener` instead of the decorated wrapper registered with `addEventListener`. This caused permanent listener leaks on resize handlers in Screen and Loader.
- Fixed issue where `scaleTo({…})` and `scaleBy({…})` actions would cause entities to keep scaling indefinitely after the action completed, due to a copy-paste bug that zeroed `angularVelocity` instead of `scaleFactor`
- Fixed issue where `scaleTo({…})` and `scaleBy({…})` actions used a live reference to the entity's scale vector as the interpolation start point, causing the easing curve to be corrupted if the entity's scale changed during the action
- Fixed issue where the first action in a sequence would not execute after calling `clearActions()` mid-execution. All action types now properly reset their initialization state when stopped, resolving issue #3468
Expand Down
27 changes: 16 additions & 11 deletions src/engine/util/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@ export interface NativeEventable {

export class BrowserComponent<T extends NativeEventable> {
private _paused = false;
private _nativeHandlers: { [key: string]: (handler: any) => void } = {};
private _handlers = new Map<string, { handler: (evt: any) => void; wrapper: (evt: any) => void }>();

on(eventName: string, handler: (evt: any) => void): void {
if (this._nativeHandlers[eventName]) {
this.off(eventName, this._nativeHandlers[eventName]);
const existing = this._handlers.get(eventName);
if (existing) {
this.nativeComponent.removeEventListener(eventName, existing.wrapper);
}
this._nativeHandlers[eventName] = this._decorate(handler);
this.nativeComponent.addEventListener(eventName, this._nativeHandlers[eventName]);
const wrapper = this._decorate(handler);
this._handlers.set(eventName, { handler, wrapper });
this.nativeComponent.addEventListener(eventName, wrapper);
}
off(eventName: string, handler?: (event: any) => void): void {
if (!handler) {
handler = this._nativeHandlers[eventName];
const entry = this._handlers.get(eventName);
if (!entry) {
return;
}
if (!handler || entry.handler === handler) {
this.nativeComponent.removeEventListener(eventName, entry.wrapper);
this._handlers.delete(eventName);
}
this.nativeComponent.removeEventListener(eventName, handler);
this._nativeHandlers[eventName] = null;
}

private _decorate(handler: (evt: any) => void): (evt: any) => void {
Expand All @@ -39,8 +44,8 @@ export class BrowserComponent<T extends NativeEventable> {
}

public clear() {
for (const event in this._nativeHandlers) {
this.off(event);
for (const eventName of this._handlers.keys()) {
this.off(eventName);
}
}

Expand Down
Loading