StructureJS
0.14.6A class based utility library for building modular and scalable web platform applications. Features opt-in classes and utilities which provide a solid foundation and toolset to build your next project.
var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; (function (factory) { if (typeof module === 'object' && typeof module.exports === 'object') { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === 'function' && define.amd) { define(["require", "exports", '../event/EventDispatcher', '../event/BaseEvent', '../util/Util'], factory); } })(function (require, exports) { "use strict"; var EventDispatcher_1 = require('../event/EventDispatcher'); var BaseEvent_1 = require('../event/BaseEvent'); var Util_1 = require('../util/Util'); /** * The Collection class provides a way for you to manage your models. * * @class Collection * @extends EventDispatcher * @module StructureJS * @submodule model * @requires Extend * @requires EventDispatcher * @requires BaseEvent * @constructor * @param baseModelType {BaseModel} Pass a class that extends BaseModel and the data added to the collection will be created as that type. * @author Robert S. (www.codeBelt.com) * @example * let data = [{ make: 'Tesla', model: 'Model S', year: 2014 }, { make: 'Tesla', model: 'Model X', year: 2016 }]; * * // Example of adding data to a collection * let collection = new Collection(); * collection.add(data); * * // Example of adding data to a collection that will create a CarModel model for each data object passed in. * let collection = new Collection(CarModel); * collection.add(data); */ var Collection = (function (_super) { __extends(Collection, _super); function Collection(baseModelType) { if (baseModelType === void 0) { baseModelType = null; } _super.call(this); /** * The list of models in the collection. * * @property models * @type {Array.<any>} * @readOnly */ this.models = []; /** * The count of how many models are in the collection. * * @property length * @type {int} * @default 0 * @readOnly * @public */ this.length = 0; /** * A reference to a BaseModel type that will be used in the collection. * * @property _modelType * @type {any} * @protected */ this._modelType = null; this._modelType = baseModelType; } /** * Adds model or an array of models to the collection. * * @method add * @param model {Any|Array} Single or an array of models to add to the current collection. * @param [silent=false] {boolean} If you'd like to prevent the event from being dispatched. * @public * @chainable * @example * collection.add(model); * * collection.add([model, model, model, model]); * * collection.add(model, true); */ Collection.prototype.add = function (model, silent) { if (silent === void 0) { silent = false; } if (model == null) { return; } // If the model passed in is not an array then make it. var models = (model instanceof Array) ? model : [model]; var len = models.length; for (var i = 0; i < len; i++) { // Only add the model if it does not exist in the the collection. if (this.has(models[i]) === false) { if (this._modelType !== null && (models[i] instanceof this._modelType) === false) { // If the modelType is set and the data is not already a instance of the modelType // then instantiate it and pass the data into the constructor. this.models.push(new this._modelType(models[i])); } else { // Pass the data object to the array. this.models.push(models[i]); } this.length = this.models.length; } } if (silent === false) { this.dispatchEvent(new BaseEvent_1.default(BaseEvent_1.default.ADDED)); } return this; }; /** * Removes a model or an array of models from the collection. * * @method remove * @param model {Object|Array} Model(s) to remove * @param [silent=false] {boolean} If you'd like to prevent the event from being dispatched. * @public * @chainable * @example * collection.remove(model); * * collection.remove([model, model, model, model]); * * collection.remove(model, true); */ Collection.prototype.remove = function (model, silent) { if (silent === void 0) { silent = false; } // If the model passed in is not an array then make it. var models = (model instanceof Array) ? model : [model]; for (var i = models.length - 1; i >= 0; i--) { // Only remove the model if it exists in the the collection. if (this.has(models[i]) === true) { this.models.splice(this.indexOf(models[i]), 1); this.length = this.models.length; } } if (silent === false) { this.dispatchEvent(new BaseEvent_1.default(BaseEvent_1.default.REMOVED)); } return this; }; /** * Checks if a collection has an model. * * @method has * @param model {Object} Item to check * @return {boolean} * @public * @example * collection.has(model); */ Collection.prototype.has = function (model) { return this.indexOf(model) > -1; }; /** * Returns the array index position of the Base Model. * * @method indexOf * @param model {Object} get the index of. * @return {int} * @public * @example * collection.indexOf(model); */ Collection.prototype.indexOf = function (model) { return this.models.indexOf(model); }; /** * Finds an object by an index value. * * @method get * @param index {int} The index integer of the model to get * @return {Object} the model * @public * @example * let model = collection.get(1); */ Collection.prototype.get = function (index) { return this.models[index] || null; }; /** * Examines each element in a collection, returning an array of all elements that have the given properties. * When checking properties, this method performs a deep comparison between values to determine if they are equivalent to each other. * @method findBy * @param arg {Object|Array} * @return {Array.<any>} Returns a list of found object's. * @public * @example * // Finds all Base Model that has 'Robert' in it. * collection.findBy("Robert"); * // Finds any Base Model that has 'Robert' or 'Heater' or 23 in it. * collection.findBy(["Robert", "Heather", 32]); * * // Finds all Base Models that same key and value you are searching for. * collection.findBy({ name: 'apple', organic: false, type: 'fruit' }); * collection.findBy([{ type: 'vegetable' }, { name: 'apple', 'organic: false, type': 'fruit' }]); */ Collection.prototype.findBy = function (arg) { // If properties is not an array then make it an array object. var list = (arg instanceof Array) ? arg : [arg]; var foundItems = []; var len = list.length; var prop; for (var i = 0; i < len; i++) { prop = list[i]; // Adds found Base Model to the foundItems array. if ((typeof prop === 'string') || (typeof prop === 'number') || (typeof prop === 'boolean')) { // If the model is not an object. foundItems = foundItems.concat(this._findPropertyValue(prop)); } else { // If the model is an object. foundItems = foundItems.concat(this._where(prop)); } } // Removes all duplicated objects found in the temp array. return Util_1.default.unique(foundItems); }; /** * Loops through the models array and creates a new array of models that match all the properties on the object passed in. * * @method _where * @param propList {Object|Array} * @return {Array.<any>} Returns a list of found object's. * @protected */ Collection.prototype._where = function (propList) { // If properties is not an array then make it an array object. var list = (propList instanceof Array) ? propList : [propList]; var foundItems = []; var itemsLength = this.models.length; var itemsToFindLength = list.length; var hasMatchingProperty = false; var doesModelMatch = false; var model; var obj; var key; var j; for (var i = 0; i < itemsToFindLength; i++) { obj = list[i]; for (j = 0; j < itemsLength; j++) { hasMatchingProperty = false; doesModelMatch = true; model = this.models[j]; for (key in obj) { // Check if the key value is a property. if (obj.hasOwnProperty(key) && model.hasOwnProperty(key)) { hasMatchingProperty = true; if (obj[key] !== model[key]) { doesModelMatch = false; break; } } } if (doesModelMatch === true && hasMatchingProperty === true) { foundItems.push(model); } } } return foundItems; }; /** * Loops through all properties of an object and check to see if the value matches the argument passed in. * * @method _findPropertyValue * @param arg {String|Number|Boolean>} * @return {Array.<any>} Returns a list of found object's. * @protected */ Collection.prototype._findPropertyValue = function (arg) { // If properties is not an array then make it an array object. var list = (arg instanceof Array) ? arg : [arg]; var foundItems = []; var itemsLength = this.models.length; var itemsToFindLength = list.length; var propertyValue; var value; var model; var key; var j; for (var i = 0; i < itemsLength; i++) { model = this.models[i]; for (key in model) { // Check if the key value is a property. if (model.hasOwnProperty(key)) { propertyValue = model[key]; for (j = 0; j < itemsToFindLength; j++) { value = list[j]; // If the Base Model property equals the string value then keep a reference to that Base Model. if (propertyValue === value) { // Add found Base Model to the foundItems array. foundItems.push(model); break; } } } } } return foundItems; }; /** * Clears or remove all the models from the collection. * * @method clear * @param [silent=false] {boolean} If you'd like to prevent the event from being dispatched. * @public * @chainable * @example * collection.clear(); */ Collection.prototype.clear = function (silent) { if (silent === void 0) { silent = false; } this.models = []; this.length = 0; if (silent === false) { this.dispatchEvent(new BaseEvent_1.default(BaseEvent_1.default.CLEAR)); } return this; }; /** * Creates and returns a new collection object that contains a reference to the models in the collection cloned from. * * @method clone * @returns {Collection} * @public * @example * let clone = collection.clone(); */ Collection.prototype.clone = function () { var clonedBaseModel = new this.constructor(this._modelType); clonedBaseModel.add(this.models.slice(0)); return clonedBaseModel; }; /** * Creates a JSON object of the collection. * * @method toJSON * @returns {Array.<any>} * @public * @example * let arrayOfObjects = collection.toJSON(); */ Collection.prototype.toJSON = function () { if (this._modelType !== null) { var list = []; var len = this.length; for (var i = 0; i < len; i++) { list[i] = this.models[i].toJSON(); } return list; } else { return Util_1.default.clone(this.models); } }; /** * Creates a JSON string of the collection. * * @method toJSONString * @returns {string} * @public * @example * let str = collection.toJSONString(); */ Collection.prototype.toJSONString = function () { return JSON.stringify(this.toJSON()); }; /** * Converts the string json data into an Objects and calls the {{#crossLink "Collection/add:method"}}{{/crossLink}} method to add the objects to the collection. * * @method fromJSON * @param json {string} * @public * @chainable * @example * collection.fromJSON(str); */ Collection.prototype.fromJSON = function (json) { var parsedData = JSON.parse(json); this.add(parsedData); return this; }; /** * Allows you to sort models that have one or more common properties, specifying the property or properties to use as the sort keys * * @method sortOn * @param propertyName {string} * @param [sortAscending=true] {boolean} * @public * @return {Array<any>} Returns the list of models in the collection. * @example * collection.sortOn('name'); * collection.sortOn('name', false); */ Collection.prototype.sortOn = function (propertyName, sortAscending) { if (sortAscending === void 0) { sortAscending = true; } if (sortAscending === false) { return this.sort(function (a, b) { if (a[propertyName] < b[propertyName]) { return 1; } if (a[propertyName] > b[propertyName]) { return -1; } return 0; }); } else { return this.sort(function (a, b) { if (a[propertyName] > b[propertyName]) { return 1; } if (a[propertyName] < b[propertyName]) { return -1; } return 0; }); } }; /** * Specifies a function that defines the sort order. If omitted, the array is sorted according to each character's Unicode code * point value, according to the string conversion of each element. * * @method sort * @param [sortFunction=null] {Function} * @public * @return {Array.<any>} Returns the list of models in the collection. * @example * let sortByDate = function(a, b){ * return new Date(a.date) - new Date(b.date) * } * * collection.sort(sortByDate); */ Collection.prototype.sort = function (sortFunction) { if (sortFunction === void 0) { sortFunction = null; } this.models.sort(sortFunction); return this.models; }; /** * The filter method creates a new array with all elements that pass the test implemented by the provided function. * * @method filter * @param callback {Function} Function to test each element of the array. Invoked with arguments (element, index, array). Return true to keep the element, false otherwise. * @param [callbackScope=null] Optional. Value to use as this when executing callback. * @public * @return {Array.<any>} Returns the list of models in the collection. * @example * let isOldEnough = function(model){ * return model.age >= 21; * } * * let list = collection.filter(isOldEnough); */ Collection.prototype.filter = function (callback, callbackScope) { if (callbackScope === void 0) { callbackScope = null; } return this.models.filter(callback, callbackScope); }; /** * Convenient way to get a list of property values. * * @method pluck * @param propertyName {string} The property name you want the values from. * @param [unique=false] {string} Pass in true to remove duplicates. * @return {Array.<any>} * @public * @example * collection.add([{name: 'Robert'}, {name: 'Robert'}, {name: 'Chris'}]); * * let list = collection.pluck('name'); * // ['Robert', 'Robert', 'Chris'] * * let list = collection.pluck('name', true); * // ['Robert', 'Chris'] */ Collection.prototype.pluck = function (propertyName, unique) { if (unique === void 0) { unique = false; } var list = []; for (var i = 0; i < this.length; i++) { if (this.models[i].hasOwnProperty(propertyName) === true) { list[i] = this.models[i][propertyName]; } } if (unique === true) { list = Util_1.default.unique(list); } return list; }; /** * Convenient way to group models into categories/groups by a property name. * * @method groupBy * @param propertyName {string} The string value of the property you want to group with. * @return {any} Returns an object that is categorized by the property name. * @public * @example * collection.add([{name: 'Robert', id: 0}, {name: 'Robert', id: 1}, {name: 'Chris', id: 2}]); * * let list = collection.groupBy('name'); * * // { * // Robert: [{name: 'Robert', id: 0}, {name: 'Robert', id: 1}] * // Chris: [{name: 'Chris', id: 2}] * // } */ Collection.prototype.groupBy = function (propertyName) { var model; var groupName; var groupList = {}; // Loop through all the models in this collection. for (var i = 0; i < this.length; i++) { model = this.models[i]; // Get the value from the property name passed in and uses that as the group name. groupName = model[propertyName]; if (groupList[groupName] == null) { groupList[groupName] = []; } groupList[groupName].push(model); } return groupList; }; /** * Changes the order of the models so that the last model becomes the first model, the penultimate model becomes the second, and so on. * * @method reverse * @public * @return {Array.<any>} Returns the list of models in the collection. * @example * collection.reverse(); */ Collection.prototype.reverse = function () { return this.models.reverse(); }; return Collection; }(EventDispatcher_1.default)); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Collection; });