Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the EventEmitter a mixin class... #41

Merged
merged 3 commits into from
Oct 26, 2023
Merged
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
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ node_modules: package.json package-lock.json
npm install

build: node_modules
npm run types
npm run build

dist: build

check: node_modules build eslint
npm run types
npm run test

.PHONY: eslint
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "Modernized Backbone with web components",
"url": "https://github.com/conversejs/skeletor",
"main": "src/index.js",
"types": "src/types/index.d.ts",
"browser": "dist/skeletor.js",
"keywords": [
"model",
Expand Down
105 changes: 50 additions & 55 deletions src/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const addOptions = { add: true, remove: false };
* belonging to this particular author, and so on. Collections maintain
* indexes of their models, both in order, and for lookup by `id`.
*/
class Collection extends EventEmitter {
class Collection extends EventEmitter(Object) {
/**
* Create a new **Collection**, perhaps to contain a specific type of `model`.
* If a `comparator` is specified, the Collection will maintain
Expand All @@ -51,6 +51,8 @@ class Collection extends EventEmitter {
this._reset();
this.initialize.apply(this, arguments);
if (models) this.reset(models, Object.assign({ silent: true }, options));

this[Symbol.iterator] = this.values;
}

/**
Expand Down Expand Up @@ -280,10 +282,10 @@ class Collection extends EventEmitter {
console.error(e);
resolve();
},
})
}),
);
});
})
}),
);
await this.browserStorage.clear();
this.reset();
Expand Down Expand Up @@ -402,7 +404,7 @@ class Collection extends EventEmitter {
sortBy(iteratee) {
return sortBy(
this.models,
isFunction(iteratee) ? iteratee : (m) => (isString(iteratee) ? m.get(iteratee) : m.matches(iteratee))
isFunction(iteratee) ? iteratee : (m) => (isString(iteratee) ? m.get(iteratee) : m.matches(iteratee)),
);
}

Expand Down Expand Up @@ -452,7 +454,7 @@ class Collection extends EventEmitter {
findLastIndex(pred, fromIndex) {
return this.models.findLastIndex(
isFunction(pred) ? pred : (m) => (isString(pred) ? m.get(pred) : m.matches(pred)),
fromIndex
fromIndex,
);
}

Expand Down Expand Up @@ -718,7 +720,7 @@ class Collection extends EventEmitter {
_prepareModel(attrs, options) {
if (this._isModel(attrs)) {
if (!attrs.collection) attrs.collection = this;
return /** @type {Model} */(attrs);
return /** @type {Model} */ (attrs);
}
options = options ? clone(options) : {};
options.collection = this;
Expand Down Expand Up @@ -822,69 +824,62 @@ class Collection extends EventEmitter {
}
}

// Defining an @@iterator method implements JavaScript's Iterable protocol.
// In modern ES2015 browsers, this value is found at Symbol.iterator.
const $$iterator = typeof Symbol === 'function' && Symbol.iterator;
if ($$iterator) {
Collection.prototype[$$iterator] = Collection.prototype.values;
}

// CollectionIterator
// ------------------

// A CollectionIterator implements JavaScript's Iterator protocol, allowing the
// use of `for of` loops in modern browsers and interoperation between
// Collection and other JavaScript functions and third-party libraries
// which can operate on Iterables.
const CollectionIterator = function (collection, kind) {
this._collection = collection;
this._kind = kind;
this._index = 0;
};

// This "enum" defines the three possible kinds of values which can be emitted
// by a CollectionIterator that correspond to the values(), keys() and entries()
// methods on Collection, respectively.
const ITERATOR_VALUES = 1;
const ITERATOR_KEYS = 2;
const ITERATOR_KEYSVALUES = 3;

// All Iterators should themselves be Iterable.
if ($$iterator) {
CollectionIterator.prototype[$$iterator] = function () {
return this;
};
}
class CollectionIterator {
/**
* A CollectionIterator implements JavaScript's Iterator protocol, allowing the
* use of `for of` loops in modern browsers and interoperation between
* Collection and other JavaScript functions and third-party libraries
* which can operate on Iterables.
* @param {Collection} collection
* @param {Number} kind
*/
constructor(collection, kind) {
this._collection = collection;
this._kind = kind;
this._index = 0;
}

next() {
if (this._collection) {
// Only continue iterating if the iterated collection is long enough.
if (this._index < this._collection.length) {
const model = this._collection.at(this._index);
this._index++;

CollectionIterator.prototype.next = function () {
if (this._collection) {
// Only continue iterating if the iterated collection is long enough.
if (this._index < this._collection.length) {
const model = this._collection.at(this._index);
this._index++;

// Construct a value depending on what kind of values should be iterated.
let value;
if (this._kind === ITERATOR_VALUES) {
value = model;
} else {
const id = this._collection.modelId(model.attributes);
if (this._kind === ITERATOR_KEYS) {
value = id;
// Construct a value depending on what kind of values should be iterated.
let value;
if (this._kind === ITERATOR_VALUES) {
value = model;
} else {
// ITERATOR_KEYSVALUES
value = [id, model];
const id = this._collection.modelId(model.attributes);
if (this._kind === ITERATOR_KEYS) {
value = id;
} else {
// ITERATOR_KEYSVALUES
value = [id, model];
}
}
return { value: value, done: false };
}
return { value: value, done: false };

// Once exhausted, remove the reference to the collection so future
// calls to the next method always return done.
this._collection = undefined;
}

// Once exhausted, remove the reference to the collection so future
// calls to the next method always return done.
this._collection = undefined;
return { value: undefined, done: true };
}

return { value: undefined, done: true };
};
[Symbol.iterator]() {
return this;
}
}

export { Collection };
24 changes: 1 addition & 23 deletions src/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import EventEmitter from './eventemitter.js';
// Cached regex to split keys for `delegate`.
const delegateEventSplitter = /^(\S+)\s*(.*)$/;

class ElementView extends HTMLElement {
class ElementView extends EventEmitter(HTMLElement) {

/**
* @typedef {import('./model.js').Model} Model
Expand Down Expand Up @@ -33,8 +33,6 @@ class ElementView extends HTMLElement {
constructor(options={}) {
super();

this.emitter = new EventEmitter();

// Will be assigned to from Events
this.stopListening = null;

Expand Down Expand Up @@ -228,26 +226,6 @@ class ElementView extends HTMLElement {
}
return this;
}

/**
* @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;
Loading
Loading