diff --git a/src/collection.js b/src/collection.js new file mode 100644 index 000000000..4a980f37f --- /dev/null +++ b/src/collection.js @@ -0,0 +1,116 @@ +// @todo Add events. + +var Collection = function (items) { + this.items = []; + + this.next_id = 0; + + if (items) + { + this.add(items); + } +}; +util.inherits(Collection, EventEmitter); + +Collection.prototype.model = require('model'); + +/** + * Adds new items to this collection. + */ +Collection.prototype.add = function (items) { + if (!_.isArray(items)) + { + items = [items]; + } + + _.each(items, function (item) { + if ( !(item instanceof this.model) ) + { + item = new this.model(item); + } + + var error = item.validate(); + if (undefined !== error) + { + // @todo Better system inspired by Backbone.js. + throw error; + } + + var id = item.get('id'); + + if (undefined === id) + { + id = this.next_id++; + item.set('id', id); + } + + // Existing items are ignored. + if (!this.items[id]) + { + this.items[id] = item; + } + }); +}; + +/** + * Removes items from this collection. + */ +Collection.prototype.remove = function (ids) { + if (!_.isArray(ids)) + { + ids = [ids]; + } + + _.each(ids, function (id) { + delete this.items[id]; + }); +}; + +/** + * Updates existing items. + */ +Collection.prototype.update = function (items) { + if (!_.isArray(items)) + { + items = [items]; + } + + _.each(items, function (item) { + if (item instanceof this.model) + { + item = item.properties; + } + + // @todo + // var error = item.validate(); + // if (undefined !== error) + // { + // // @todo Better system inspired by Backbone.js. + // throw error; + // } + + var id = item.id; + + // Missing items are ignored. + if (this.items[id]) + { + this.items[id].set(item); + } + }); +}; + +/** + * Smartly updates the collection. + * + * - Adds new items. + * - Updates existing items. + * - Removes missing items. + */ +Collection.prototype.set = function (items) { + throw 'not implemented'; +}; + +Model.extend = require('extendable'); + +// Export. +module.exports = Model; diff --git a/src/event-emitter.js b/src/event-emitter.js new file mode 100644 index 000000000..60c6ed983 --- /dev/null +++ b/src/event-emitter.js @@ -0,0 +1,3 @@ +module.exports = require('events').EventEmitter; + +module.exports.extend = require('extendable'); diff --git a/src/model.js b/src/model.js new file mode 100644 index 000000000..7ef7f0652 --- /dev/null +++ b/src/model.js @@ -0,0 +1,83 @@ +// @todo Add events. + +var Model = function (properties) { + this.properties = {}; + + if (properties) + { + this.set(properties); + } +}; +util.inherits(Model, require('events').EventEmitter); + +/** + * Initializes the model after construction. + */ +Model.prototype.initialize = function () {}; + +/** + * Validates the model. + * + * @returns {undefined|mixed} Returns something else than undefined if + * there was an error. + */ +Model.prototype.validate = function (properties) {}; + +/** + * Gets property. + */ +Model.prototype.get = function (property, def) { + var prop = this.properties[property]; + if (undefined !== prop) + { + return prop; + } + + prop = this['default'][property]; + if (undefined !== prop) + { + return prop; + } + + return def; +}; + +/** + * Checks if a property exists. + */ +Model.prototype.has = function (property) { + return (undefined !== this.get(property)); +}; + +/** + * Sets properties. + */ +Model.prototype.set = function (properties, value) { + if (undefined !== value) + { + var property = properties; + properties = {}; + properties[property] = value; + } + + _.extend(this.properties, properties); +}; + +/** + * Unsets properties. + */ +Model.prototype.unset = function (properties) { + this.properties = _.omit(this.properties, properties); +}; + +/** + * Default properties. + * + * @type {Object} + */ +Model.prototype['default'] = {}; + +Model.extend = require('extendable'); + +// Export. +module.exports = Model; diff --git a/src/session.js b/src/session.js new file mode 100644 index 000000000..c2502d600 --- /dev/null +++ b/src/session.js @@ -0,0 +1,5 @@ +module.exports = require('model').extend({ + 'close': function () { + session.emit('close'); + }, +});