From 783ab0b6111f127aa1b15f4f6e891bd35ed7013d Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 13 Apr 2015 20:23:43 +0200 Subject: [PATCH] Initial view implementation (fix #3). --- packages/xo-collection/package.json | 2 + packages/xo-collection/src/view.example.js | 40 +++++++++++ packages/xo-collection/src/view.js | 78 ++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 packages/xo-collection/src/view.example.js create mode 100644 packages/xo-collection/src/view.js diff --git a/packages/xo-collection/package.json b/packages/xo-collection/package.json index e26e98785..ebe452ed7 100644 --- a/packages/xo-collection/package.json +++ b/packages/xo-collection/package.json @@ -21,6 +21,8 @@ ], "dependencies": { "babel-runtime": "^5", + "lodash.bind": "^3.1.0", + "lodash.callback": "^3.1.1", "lodash.foreach": "^3.0.2", "make-error": "^1.0.0" }, diff --git a/packages/xo-collection/src/view.example.js b/packages/xo-collection/src/view.example.js new file mode 100644 index 000000000..ddc8e8b92 --- /dev/null +++ b/packages/xo-collection/src/view.example.js @@ -0,0 +1,40 @@ +import Collection from './' +import View from './view' + +const users = new Collection() +users.getId = (user) => user.name + +const activeUsers = new View(users, 'active') +activeUsers.on('add', console.log) +activeUsers.on('update', console.log) +activeUsers.on('remove', console.log) + +users.add({ + name: 'bob' +}) + +users.add({ + name: 'clara', + active: true +}) + +users.add({ + name: 'ophelia' +}) + +users.add({ + name: 'Steve', + active: true +}) + +setTimeout(function () { + console.log('-----') + + users.set({ + name: 'ophelia', + active: true + }) + users.set({ + name: 'Steve' + }) +}, 10) diff --git a/packages/xo-collection/src/view.js b/packages/xo-collection/src/view.js new file mode 100644 index 000000000..22a4935f3 --- /dev/null +++ b/packages/xo-collection/src/view.js @@ -0,0 +1,78 @@ +import bind from 'lodash.bind' +import createCallback from 'lodash.callback' +import forEach from 'lodash.foreach' + +import Collection from './' + +// =================================================================== + +export default class View extends Collection { + constructor (collection, predicate, thisArg) { + super() + + this._collection = collection + this._predicate = createCallback(predicate, thisArg) + + // Bound versions of listeners. + this._onAdd = bind(this._onAdd, this) + this._onUpdate = bind(this._onUpdate, this) + this._onRemove = bind(this._onRemove, this) + + // Register listeners. + this._collection.on('add', this._onAdd) + this._collection.on('update', this._onUpdate) + this._collection.on('remove', this._onRemove) + } + + destroy () { + this._collection.removeListener('add', this._onAdd) + this._collection.removeListener('update', this._onUpdate) + this._collection.removeListener('remove', this._onRemove) + } + + add () { + throw new Error('a view is read only') + } + + clear () { + throw new Error('a view is read only') + } + + set () { + throw new Error('a view is read only') + } + + update () { + throw new Error('a view is read only') + } + + _onAdd (items) { + const {_predicate: predicate} = this + + forEach(items, (value, key) => { + if (predicate(value, key, this)) { + super.add(key, value) + } + }) + } + + _onUpdate (items) { + const {_predicate: predicate} = this + + forEach(items, (value, key) => { + if (predicate(value, key, this)) { + super.set(key, value) + } else if (super.has(key)) { + super.remove(key) + } + }) + } + + _onRemove (items) { + forEach(items, (value, key) => { + if (super.has(key)) { + super.remove(key) + } + }) + } +}