Skip to content

Commit

Permalink
Fix listenTo for ElementView
Browse files Browse the repository at this point in the history
  • Loading branch information
jcbrand committed Oct 16, 2023
1 parent 4e4be85 commit c845797
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 10 deletions.
50 changes: 44 additions & 6 deletions src/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.<string, any>} 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<string, any>} 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() {
Expand Down Expand Up @@ -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;
4 changes: 2 additions & 2 deletions src/eventemitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down
24 changes: 23 additions & 1 deletion src/listening.js
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/utils/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down

0 comments on commit c845797

Please sign in to comment.