From c845797101e21a163ac403fc65eac6db069a16b1 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Fri, 6 Oct 2023 15:18:43 +0200 Subject: [PATCH] Fix `listenTo` for ElementView --- src/element.js | 50 +++++++++++++++++++++++++++++++++++++++------ src/eventemitter.js | 4 ++-- src/listening.js | 24 +++++++++++++++++++++- src/utils/events.js | 2 +- 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/element.js b/src/element.js index 4b5115c..f06a876 100644 --- a/src/element.js +++ b/src/element.js @@ -6,27 +6,47 @@ import EventEmitter from './eventemitter.js'; const delegateEventSplitter = /^(\S+)\s*(.*)$/; class ElementView extends HTMLElement { + + /** + * @typedef {import('./model.js').Model} Model + * @typedef {import('./collection.js').Collection} Collection + * @typedef {Record.} Options + * + * @callback EventCallback + * @param {any} event + * @param {Model} model + * @param {Collection} collection + * @param {Options} [options] + */ + + set events (events) { + this._declarativeEvents = events; + } + get events() { - return {}; + return this._declarativeEvents; } /** - * @param {Record} options + * @param {Options} options */ - constructor(options) { + constructor(options={}) { super(); + this.emitter = new EventEmitter(); + // Will be assigned to from Events this.stopListening = null; // Creating a View creates its initial element outside of the DOM, // if an existing element is not provided... this.cid = uniqueId('view'); + this._declarativeEvents = {}; this._domEvents = []; const { model, collection, events } = options; - Object.assign(this, { model, collection, events }); + Object.assign(this, { model: model, collection, events }); } createRenderRoot() { @@ -208,8 +228,26 @@ class ElementView extends HTMLElement { } return this; } -} -Object.assign(ElementView.prototype, EventEmitter.prototype); + /** + * @param {any} obj + * @param {string} name + * @param {EventCallback} [callback] + * @return {EventEmitter} + */ + listenTo(obj, name, callback) { + return this.emitter.listenTo.call(this, obj, name, callback); + } + + /** + * @param {any} [obj] + * @param {string} [name] + * @param {EventCallback} [callback] + * @return {EventEmitter} + */ + stopListening(obj, name, callback) { + return this.emitter.stopListening.call(this, obj, name, callback); + } +} export default ElementView; diff --git a/src/eventemitter.js b/src/eventemitter.js index facb045..aff1fd6 100644 --- a/src/eventemitter.js +++ b/src/eventemitter.js @@ -78,7 +78,7 @@ class EventEmitter { if (error) throw error; // If the target obj is not Backbone.Events, track events manually. - if (listening.interop) listening.on(name, callback); + if (listening.interop) listening.start(name, callback, this); return this; } @@ -124,7 +124,7 @@ class EventEmitter { if (!listening) break; listening.obj.off(name, callback, this); - if (listening.interop) listening.off(name, callback); + if (listening.interop) listening.stop(name, callback); } if (isEmpty(listeningTo)) this._listeningTo = undefined; diff --git a/src/listening.js b/src/listening.js index 2021a57..73e3088 100644 --- a/src/listening.js +++ b/src/listening.js @@ -1,4 +1,4 @@ -import { eventsApi, offApi } from './utils/events.js'; +import { eventsApi, onApi, offApi } from './utils/events.js'; /** * A listening class that tracks and cleans up memory bindings @@ -21,6 +21,28 @@ class Listening { this._events = undefined; } + /** + * @param {string} name + * @param {Function} callback + * @param {any} context + */ + start(name, callback, context) { + this._events = eventsApi(onApi, this._events || {}, name, callback, { + context: this.obj, + ctx: context, + listening: this, + }); + + const listeners = this.obj._listeners || (this.obj._listeners = {}); + listeners[this.id] = this; + + // Allow the listening to use a counter, instead of tracking + // callbacks for library interop + this.interop = false; + + return this; + } + /** * Stop's listening to a callback (or several). * Uses an optimized counter if the listenee uses Backbone.Events. diff --git a/src/utils/events.js b/src/utils/events.js index 9b67b84..35dcc6c 100644 --- a/src/utils/events.js +++ b/src/utils/events.js @@ -100,7 +100,7 @@ export function offApi(events, name, callback, options) { remaining.push(handler); } else { const listening = handler.listening; - if (listening) listening.off(name, callback); + if (listening) listening.stop(name, callback); } }