Created
May 3, 2012 19:49
-
-
Save jsocol/2588776 to your computer and use it in GitHub Desktop.
EventArray.js - Arrays you can watch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * EventArray.js - Arrays you can watch. | |
| * Copyright 2012, James Socol <me@jamessocol.com> | |
| * | |
| * Released under the MIT X11 and BSD 2-clause Licenses. | |
| * | |
| * EventArray.js is a simple wrapper around JS arrays that makes it | |
| * easier to use them for data-driven UIs by providing a way to watch | |
| * them for mutations. Think of the lovechild of an Array and an | |
| * EventEmitter. | |
| * | |
| * var arr = new EventArray(); | |
| * arr.on('push', function(newElement) { | |
| * console.log("you added:", newElement); | |
| * console.log("the array is now this long:", this.length); | |
| * }); | |
| * arr.push('foo'); | |
| * >>> you added: foo | |
| * >>> the array is now this long: 1 | |
| * | |
| * All the mutator methods emit events you can listen to, for example, | |
| * calling `(new EventArray()).push(1)` emits 'push' event. | |
| * | |
| * Depending on the event, registered callbacks will receive different | |
| * arguments. All callbacks have access to the EventArray itself as the | |
| * 'this' object. | |
| * | |
| * Events, with arguments: | |
| * 'change' - no arguments - fired on any mutation. | |
| * 'push' - the element pushed - if multiple values are pushed, multiple | |
| * push events will be fired. | |
| * 'pop' - the element popped. | |
| * '... these docs need to live elsewhere. | |
| */ | |
| function EventArray() { | |
| this.callbacks = { | |
| 'change': [], | |
| 'push': [], | |
| 'pop': [], | |
| 'shift': [], | |
| 'unshift': [], | |
| 'sort': [], | |
| 'reverse': [], | |
| 'splice': [] | |
| }; | |
| return this; | |
| } | |
| EventArray.prototype = Object.create(Array.prototype); | |
| EventArray.prototype.emit = function (type) { | |
| var args = Array.prototype.slice.call(arguments, 1), | |
| self = this; | |
| if (type in this.callbacks) { | |
| this.callbacks[type].forEach(function(fn) { | |
| fn.apply(self, args); | |
| }, self); | |
| } | |
| return this; | |
| }; | |
| EventArray.prototype.on = function (type, callback) { | |
| if (!(type in this.callbacks)) { | |
| this.callbacks[type] = [callback]; | |
| } else { | |
| this.callbacks[type].push(callback); | |
| } | |
| return this; | |
| }; | |
| EventArray.prototype.push = function () { | |
| var self = this; | |
| Array.prototype.forEach.call(arguments, function(el) { | |
| Array.prototype.push.call(self, el); | |
| self.emit('push', el); | |
| }); | |
| this.emit('change'); | |
| return this.length; | |
| }; | |
| EventArray.prototype.pop = function() { | |
| var el = Array.prototype.pop.call(this); | |
| this.emit('pop', el); | |
| this.emit('change'); | |
| return el; | |
| }; | |
| EventArray.prototype.shift = function() { | |
| var el = Array.prototype.shift.call(this); | |
| this.emit('shift', el); | |
| this.emit('change'); | |
| return el; | |
| }; | |
| EventArray.prototype.unshift = function() { | |
| var self = this; | |
| // Unshift adds in the order of the arguments, so we need to reverse them | |
| // to add one at a time. | |
| Array.prototype.reverse.call(arguments); | |
| Array.prototype.forEach.call(arguments, function(el) { | |
| Array.prototype.unshift.call(self, el); | |
| self.emit('unshift', el); | |
| }); | |
| this.emit('change'); | |
| return this.length; | |
| }; | |
| EventArray.prototype.sort = function(cmp) { | |
| Array.prototype.sort.call(this, cmp); | |
| this.emit('sort'); | |
| this.emit('change'); | |
| return this; | |
| }; | |
| EventArray.prototype.reverse = function() { | |
| Array.prototype.reverse.call(this); | |
| this.emit('reverse'); | |
| this.emit('change'); | |
| return this; | |
| }; | |
| EventArray.prototype.splice = function() { | |
| var removed = Array.prototype.splice.apply(this, arguments); | |
| this.emit('splice', removed); | |
| this.emit('change'); | |
| return removed; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment