FormView.extend = function (obj) { var child = function () { FormView.apply(this, arguments); }; extend(child.prototype, FormView.prototype); extend(child.prototype, obj); return child; };
load: function(video, callback) { if (api.error || api.loading) return; api.video = {}; api.finished = false; video = video || conf.clip; // resolve URL video = extend({}, urlResolver.resolve(video, conf.clip.sources)); if (api.playing || api.engine) video.autoplay = true; var engineImpl = selectEngine(video); if (!engineImpl) return setTimeout(function() { api.trigger("error", [api, { code: flowplayer.support.flashVideo ? 5 : 10 }]); }) && api; if (!engineImpl.engineName) throw new Error('engineName property of factory should be exposed'); if (!api.engine || engineImpl.engineName !== api.engine.engineName) { api.ready = false; if (api.engine) { api.engine.unload(); api.conf.autoplay = true; } engine = api.engine = engineImpl(api, root); api.one('ready', function() { setTimeout(function() { if (api.muted) api.mute(true, true); else engine.volume(api.volumeLevel); }); }); } extend(video, engine.pick(video.sources.filter(function(source) { // Filter out sources explicitly configured for some other engine if (!source.engine) return true; return source.engine === engine.engineName; }))); if (video.src) { var e = api.trigger('load', [api, video, engine], true); if (!e.defaultPrevented) { api.ready = false; engine.load(video); // callback if (isFunction(video)) callback = video; if (callback) api.one("ready", callback); } else { api.loading = false; } } return api; },
exports.request = function (method, url, params) { var options = extend({ url: url, method: method, json: true, jar: request.jar() }, params || {} ); var deferred = Q.defer(); var reqObj = defaultedRequestObj || request; reqObj(options, function (error, response, body) { /** Chakram Response Object @desc Encapsulates the results of a HTTP call into a single object @typedef {Object} ChakramResponse @property {Error} error - An error when applicable @property {Object} response - An {@link http://nodejs.org/api/http.html#http_http_incomingmessage http.IncomingMessage} object @property {String|Buffer|Object} body - The response body. Typically a JSON object unless the json option has been set to false, in which case will be either a String or Buffer @property {Object} jar - A {@link https://github.com/goinstant/tough-cookie tough cookie} jar @property {String} url - The request's original URL */ deferred.resolve({ error : error, response: response, body: body, jar: options.jar, url: url }); }); return deferred.promise; };
'root element handling': function (t) { var container = document.createElement('div'); var viewRoot = document.createElement('div'); container.appendChild(viewRoot); var view = new ViewClass(extend(requiredOptions || {}, {el: viewRoot})); // note it's possible this isn't the same element as passed in, it's ok to autorender // and replace the element you were passed. t.ok(view.el.nodeName, 'should have a `this.el` that is an element if passed into constructor'); t.equal(view.el.parentNode, container, 'parent container should be the same'); // these should still be true, post-`render()` t.doesNotThrow(function () { view.render(); }, 'should not error when calling render'); t.ok(view.el.nodeName, 'should have a `this.el` that is an element if passed into constructor'); t.equal(view.el.parentNode, container, 'parent container should be the same'); // calling remove should remove itself from the DOM view.remove(); t.ok(!view.el.parentNode, 'after calling remove should no longer have a parent node'); t.ok(container.children.length === 0, 'container should have no children'); t.end(); }
module.exports = function(source) { var filename = loaderUtils.getRemainingRequest(this) var content = source; var map; var options = {}; var result; this.cacheable && this.cacheable(); // Process query and setup options/defaults/forced for Traceur extend(options, defaults, loaderUtils.parseQuery(this.query), { sourceMaps: true }); Object.keys(options).forEach(function(key) { switch(options[key]) { case 'true': options[key] = true; break; case 'false': options[key] = false; break; case 'undefined': options[key] = undefined; break; case 'null': options[key] = null; break; } }); // Handle Traceur runtime if(options.filename === traceur.RUNTIME_PATH) { return content; } if(options.runtime) { content = 'require("' + traceur.RUNTIME_PATH + '");' + content; } // Parse code through Traceur try { delete options.runtime; var compiler = new traceur.Compiler(options); result = compiler.compile(content); // Process source map (if available) and return result if(options.sourceMaps) { map = JSON.parse(compiler.getSourceMap()); map.sourcesContent = [source]; this.callback(null, result, map); } else { return result.js; } } catch(errors) { throw new Error(errors.join(os.EOL)); } };
constructor: function (attrs) { extend(this, attrs); Object.defineProperty(this, '_groups', { writable: true, enumerable: false }); },
els().forEach(function(el) { var src = el.href; el.setAttribute('data-index', player.conf.playlist.length); var itm = resolver.resolve(src, player.conf.clip.sources); if ($) { extend(itm, $(el).data()); } player.conf.playlist.push(itm); });
return this.map(function (model) { if (model.serialize) { return model.serialize(); } else { var out = {}; extend(out, model); delete out.collection; return out; } });
reset: function (models, options) { options || (options = {}); for (var i = 0, length = this.models.length; i < length; i++) { this._removeReference(this.models[i], options); } options.previousModels = this.models; this._reset(); models = this.add(models, extend({silent: true}, options)); if (!options.silent) this.trigger('reset', this, options); return models; },
api.shareUrl = function(directEmbed) { if (directEmbed && c.embed && c.embed.iframe) return c.embed.iframe; if (typeof api.conf.share === 'string') return api.conf.share; var title = encodeURIComponent(api.video.title || (common.find('title')[0] || {}).innerHTML || 'Flowplayer video') , conf = encodeURIComponent(btoa(JSON.stringify(extend({}, api.conf, api.extensions)).replace(/[\u007F-\uFFFF]/g, function(chr) { return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) }))) , redirect = encodeURIComponent(window.location.toString()) , baseUrl = directEmbed ? 'https://flowplayer.com/e/' : 'https://flowplayer.com/s/'; return baseUrl + '?t=' + title + '&c=' + conf + '&r=' + redirect; };
player.play = function(i) { if (i === undefined) return player.resume(); if (typeof i === 'number' && !player.conf.playlist[i]) return player; else if (typeof i != 'number') return player.load.apply(null, arguments); var arg = extend({index: i}, player.conf.playlist[i]); if (i === player.video.index) return player.load(arg, function() { player.resume(); }); player.off('resume.fromfirst'); // Don't start from beginning if clip explicitely chosen player.load(arg, function() { player.video.index = i; }); return player; };
function Collection(models, options) { options || (options = {}); if (options.model) this.model = options.model; if (options.comparator) this.comparator = options.comparator; if (options.parent) this.parent = options.parent; if (!this.mainIndex) { var idAttribute = this.model && this.model.prototype && this.model.prototype.idAttribute; this.mainIndex = idAttribute || 'id'; } this._reset(); this.initialize.apply(this, arguments); if (models) this.reset(models, extend({silent: true}, options)); }
this.middleware.push(function*(upstream) { if(!prefix_regex.test(this.path)) return yield* upstream var old_ctx = { mount: this.mount , path: this.path } , new_ctx = { mount: (this.mount || '') + prefix , path: this.path.replace(prefix_regex, '/') } extend(this, new_ctx) yield* downstream.call(this, function*() { extend(this, old_ctx) yield* upstream extend(this, new_ctx) }.call(this)) extend(this, old_ctx) })
module.exports = function(file, opts) { var data = '', config = extend({ compress: false, paths: [] }, opts); if (!/\.css$|\.less$/.test(file)) { return through(); } return through(write, end); function write(buf) { data += buf; } function end() { var self = this; var fileConfig = extend({}, config); // Injects the path of the current file. fileConfig.filename = file; less.render(data, fileConfig, function (err, output) { if (err) { self.emit('error', new Error(getErrorMessage(err), file, err.line)); } else { self.queue(output.css); } self.queue(null); }); } function getErrorMessage(err) { var msg = err.message; if (err.line) { msg += ", line " + err.line; } if (err.column) { msg += ", column " + err.column; } if (err.extract) { msg += ": \"" + err.extract + "\""; } return msg; } };
'handling values passed in instantiation': function (t) { var parent = {update: function () {}}; var view = new ViewClass(extend(requiredOptions || {}, { value: validValue, parent: parent, name: 'awesome name' })); t.equal(view.value, validValue, 'should have maintained its value'); t.strictEqual(view.valid, true, 'should be `valid` at init when passed valid value'); t.equal(view.parent, parent, 'should have kept its `parent`'); t.equal(view.name, 'awesome name', 'should have kepts its `name`'); t.end(); }
/** * Configure text-files-loader * @param {Object} options check defaultOptions * @return {[type]} [description] */ function setup(options) { var key var config = extend({}, defaultOptions) for (key in options) { if (config.hasOwnProperty(key)) { config[key] = options[key] } else { throw new Error('Invalid option "' + key + '"') } } module.exports.config = config }
module.exports = function (phrase, inject, callback) { // Parse arguments if (typeof phrase === 'undefined') phrase = ''; if (typeof inject === 'undefined') inject = null; if (typeof inject === 'function') callback = inject; if (typeof callback === 'undefined') callback = null; // Merge if (inject !== null) { afinn = extend(afinn, inject); } // Storage objects var tokens = tokenize(phrase), score = 0, words = [], positive = [], negative = []; // Iterate over tokens var len = tokens.length; while (len--) { var obj = tokens[len]; var item = afinn[obj]; if (typeof item === 'undefined') continue; words.push(obj); if (item > 0) positive.push(obj); if (item < 0) negative.push(obj); score += item; } // Handle optional async interface var result = { score: score, comparative: score / tokens.length, tokens: tokens, words: words, positive: positive, negative: negative }; if (callback === null) return result; process.nextTick(function () { callback(null, result); }); };
_prepareModel: function (attrs, options) { // if we haven't defined a constructor, skip this if (!this.model) return attrs; if (this.isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; } else { options = options ? extend({}, options) : {}; options.collection = this; var model = new this.model(attrs, options); if (!model.validationError) return model; this.trigger('invalid', this, model.validationError, options); return false; } },
_handleWorkQueueStep: function(resolve) { if (this._pathSamplingQueue.length > 0) { var item = this._pathSamplingQueue.pop(); if (item.samplesLeft > 0) { var startIndex = (numSamples - item.samplesLeft); for (var i = startIndex; i < startIndex + batchSize; i++) { var point = item.element.getPointAtLength((i / numSamples) * item.totalLength); item.sampleArray[i * 2 + 0] = point.x; item.sampleArray[i * 2 + 1] = point.y; } this._pathSamplingQueue.push(extend(item, {samplesLeft: item.samplesLeft - batchSize})); } } else { resolve(); } },
function end() { var self = this; var fileConfig = extend({}, config); // Injects the path of the current file. fileConfig.filename = file; less.render(data, fileConfig, function (err, output) { if (err) { self.emit('error', new Error(getErrorMessage(err), file, err.line)); } else { self.queue(output.css); } self.queue(null); }); }
'basics': function (t) { var counter; var parent = { update: function (field) { counter++; this.passedField = field; } }; var view = new ViewClass(extend(requiredOptions || {}, {parent: parent})); // helper we can call function ensureProperties(str) { str = str || ''; t.ok(hasPropertyDefinition(view, 'value'), 'has `value` property' + str); t.equal(typeof view.name, 'string', 'has `name` property that is a string' + str); t.notEqual(view.name, '', '`name` property should not be empty string' + str); t.ok(isFunction(view.setValue), 'has `setValue` method' + str); t.equal(typeof view.valid, 'boolean', 'has `valid` property that is a boolean' + str); t.equal(parent, view.parent, 'has same `parent` property' + str); } t.ok(view, 'should init with `new`'); ensureProperties(); counter = 0; t.doesNotThrow(function () { view.setValue(validValue); }, 'should not error when setting valid value'); t.notEqual(counter, 0, 'should have called `update` on parent when value changed'); t.equal(parent.passedField, view, 'should have passed itself to the parent when changed'); // all this should still be true after setting a value ensureProperties(' after setting a value'); // all this should be true after calling `beforeSubmit`, if present. if (isFunction(view.beforeSubmit)) { view.beforeSubmit(); ensureProperties(' after `beforeSubmit`'); } t.end(); },
window[callbackId] = function(type, arg) { var video = loadVideo; if (conf.debug) console.log("--", type, arg); var event = { type: type }; switch (type) { // RTMP sends a lot of finish events in vain // case "finish": if (conf.rtmp) return; case "ready": arg = extend(video, arg); break; case "click": event.flash = true; break; case "keydown": event.which = arg; break; case "seek": video.time = arg; break; case "status": player.trigger("progress", [player, arg.time]); if (arg.buffer < video.bytes && !video.buffered) { video.buffer = arg.buffer / video.bytes * video.duration; player.trigger("buffer", video.buffer); } else if (!video.buffered) { video.buffered = true; player.trigger("buffered"); } break; } if (type === 'click' || type === 'keydown') { event.target = root; bean.fire(root, type, [event]); } else if (type != 'buffered' && type !== 'unload') { // add some delay so that player is truly ready after an event setTimeout(function() { player.trigger(event, [player, arg]); }, 1); } else if (type === 'unload') { player.trigger(event, [player, arg]); } };
function Builder (opts) { opts = opts || {} // we delete from opts for stylus' sake this.root = opts.root || process.cwd() this.out = opts.out || process.cwd() + '/build' delete opts.root delete opts.out // defaults this.opts = extend({ install: true, require: true, runtime: true, string: false, linenos: dev, destination: this.out, path: 'app', }, opts) }
var videoTagConfig = function(videoTag) { var clip = videoTag.data() || {}, conf = {}; $.each(['autoplay', 'loop', 'preload', 'poster'], function(i, key) { var val = videoTag.attr(key); if (val !== undefined && ['autoplay', 'poster'].indexOf(key) !== -1) conf[key] = val ? val : true; else if (val !== undefined) clip[key] = val ? val : true; }); clip.subtitles = videoTag.find('track').map(function() { var tr = $(this); return { src: tr.attr('src'), kind: tr.attr('kind'), label: tr.attr('label'), srclang: tr.attr('srclang'), 'default': tr.prop('default') }; }).get(); clip.sources = (new URLResolver()).sourcesFromVideoTag(videoTag, $); return extend(conf, {clip: clip}); };
exports.request = function (method, url, params) { var options = extend({ url: url, method: method, json: true }, params || {} ); // options.jar is either a jar object or true // In case user passes {jar: true} option to request, we need reference to global jar to do assertions. options.jar = options.jar || defaultsJar; if (options.jar === true) { options.jar = globalRequestJar; } else if (options.jar === undefined) { // Create new jar for this request for backwards compatibility options.jar = request.jar(); } var deferred = Q.defer(); var reqObj = defaultedRequestObj || request; reqObj(options, function (error, response, body) { /** Chakram Response Object @desc Encapsulates the results of a HTTP call into a single object @typedef {Object} ChakramResponse @property {Error} error - An error when applicable @property {Object} response - An {@link http://nodejs.org/api/http.html#http_http_incomingmessage http.IncomingMessage} object @property {String|Buffer|Object} body - The response body. Typically a JSON object unless the json option has been set to false, in which case will be either a String or Buffer @property {Object} jar - A {@link https://github.com/goinstant/tough-cookie tough cookie} jar @property {String} url - The request's original URL */ deferred.resolve({ error : error, response: response, body: body, jar: options.jar, url: url }); }); return deferred.promise; };
router.get('/',function(req,res){ console.log(req.query); var params = { 'nonce':1, 'from':'yintai', 'ts':parseInt(new Date().getTime()/1000), 'data':JSON.stringify(req.query) }; extend(params,{ 'sign':sign(params) }); console.log(params); // 请求参数 var args = { headers:{'Content-type':'application/x-www-form-urlencoded'}, data: param(params) }; //请求地址 var path = util.format('%s%s',remote,url.parse(req.originalUrl).pathname.replace('/proxy/','')); console.log('请求地址:'+path); console.log(args); // 请求远程 client.post(path,args,function(data,response){ res.send(data); }).on('error',function(err){ res.send(err); }); });
var AnswersStore = extend({}, EventEmitter.prototype, { getAnswers: function() { return _answers; }, setAnswers: function(answers){ _answers = answers; }, setQuestionType: function(qType){ _questionType = qType; }, resetSelected: function() { _answers.forEach(function(item){ item.selected = false; }); }, getAnswersCount: function() { return _answers.length; }, getAnswerIndex: function(uuid){ var ans = getAnswerWithIndex(uuid); return ans ? ans.index : null; }, getConditions: function(uuid) { var ans = _answers.find(function(item){ return item.uuid == uuid; }); if (ans) return ans.conditions || []; return []; }, getConditionsText: function(uuid) { var ans = _answers.find(function(item){ return item.uuid == uuid; }); if (ans) return ans.conditionsText || []; return []; }, getConformities: function(uuid) { var ans = _answers.find(function(item){ return item.uuid == uuid; }); if (ans) return ans.conformities || []; return []; }, getAnswerImg: function(uuid) { var ans = _answers.find(function(item){ return item.uuid == uuid; }); if (ans) return ans.img; }, emitChange: function() { this.emit('change'); }, addChangeListener: function(callBack) { this.on('change', callBack); }, removeChangeListener: function(callBack) { this.removeListener('change', callBack); } });
set: function (models, options) { options = extend({add: true, remove: true, merge: true}, options); if (options.parse) models = this.parse(models, options); var singular = !isArray(models); models = singular ? (models ? [models] : []) : models.slice(); var id, model, attrs, existing, sort, i, length; var at = options.at; var sortable = this.comparator && (at == null) && options.sort !== false; var sortAttr = ('string' === typeof this.comparator) ? this.comparator : null; var toAdd = [], toRemove = [], modelMap = {}; var add = options.add, merge = options.merge, remove = options.remove; var order = !sortable && add && remove ? [] : false; var targetProto = this.model && this.model.prototype || Object.prototype; // Turn bare objects into model references, and prevent invalid models // from being added. for (i = 0, length = models.length; i < length; i++) { attrs = models[i] || {}; if (this.isModel(attrs)) { id = model = attrs; } else if (targetProto.generateId) { id = targetProto.generateId(attrs); } else { id = attrs[this.mainIndex]; } // If a duplicate is found, prevent it from being added and // optionally merge it into the existing model. if (existing = this.get(id)) { if (remove) modelMap[existing.cid || existing[this.mainIndex]] = true; if (merge) { attrs = attrs === model ? model.attributes : attrs; if (options.parse) attrs = existing.parse(attrs, options); // if this is model if (existing.set) { existing.set(attrs, options); if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; } else { // if not just update the properties extend(existing, attrs); } } models[i] = existing; // If this is a new, valid model, push it to the `toAdd` list. } else if (add) { model = models[i] = this._prepareModel(attrs, options); if (!model) continue; toAdd.push(model); this._addReference(model, options); } // Do not add multiple models with the same `id`. model = existing || model; if (!model) continue; if (order && ((model.isNew && model.isNew() || !model[this.mainIndex]) || !modelMap[model.cid || model[this.mainIndex]])) order.push(model); modelMap[model[this.mainIndex]] = true; } // Remove nonexistent models if appropriate. if (remove) { for (i = 0, length = this.length; i < length; i++) { model = this.models[i]; if (!modelMap[model.cid || model[this.mainIndex]]) toRemove.push(model); } if (toRemove.length) this.remove(toRemove, options); } // See if sorting is needed, update `length` and splice in new models. if (toAdd.length || (order && order.length)) { if (sortable) sort = true; if (at != null) { for (i = 0, length = toAdd.length; i < length; i++) { this.models.splice(at + i, 0, toAdd[i]); } } else { var orderedModels = order || toAdd; for (i = 0, length = orderedModels.length; i < length; i++) { this.models.push(orderedModels[i]); } } } // Silently sort the collection if appropriate. if (sort) this.sort({silent: true}); // Unless silenced, it's time to fire all appropriate add/sort events. if (!options.silent) { for (i = 0, length = toAdd.length; i < length; i++) { model = toAdd[i]; if (model.trigger) { model.trigger('add', model, this, options); } else { this.trigger('add', model, this, options); } } if (sort || (order && order.length)) this.trigger('sort', this, options); } // Return the added (or merged) model (or models). return singular ? models[0] : models; },
add: function (models, options) { return this.set(models, extend({merge: false, add: true, remove: false}, options)); },
extend(Collection.prototype, BackboneEvents, { initialize: function () {}, isModel: function (model) { return this.model && model instanceof this.model; }, add: function (models, options) { return this.set(models, extend({merge: false, add: true, remove: false}, options)); }, // overridable parse method parse: function (res, options) { return res; }, // overridable serialize method serialize: function () { return this.map(function (model) { if (model.serialize) { return model.serialize(); } else { var out = {}; extend(out, model); delete out.collection; return out; } }); }, toJSON: function () { return this.serialize(); }, set: function (models, options) { options = extend({add: true, remove: true, merge: true}, options); if (options.parse) models = this.parse(models, options); var singular = !isArray(models); models = singular ? (models ? [models] : []) : models.slice(); var id, model, attrs, existing, sort, i, length; var at = options.at; var sortable = this.comparator && (at == null) && options.sort !== false; var sortAttr = ('string' === typeof this.comparator) ? this.comparator : null; var toAdd = [], toRemove = [], modelMap = {}; var add = options.add, merge = options.merge, remove = options.remove; var order = !sortable && add && remove ? [] : false; var targetProto = this.model && this.model.prototype || Object.prototype; // Turn bare objects into model references, and prevent invalid models // from being added. for (i = 0, length = models.length; i < length; i++) { attrs = models[i] || {}; if (this.isModel(attrs)) { id = model = attrs; } else if (targetProto.generateId) { id = targetProto.generateId(attrs); } else { id = attrs[this.mainIndex]; } // If a duplicate is found, prevent it from being added and // optionally merge it into the existing model. if (existing = this.get(id)) { if (remove) modelMap[existing.cid || existing[this.mainIndex]] = true; if (merge) { attrs = attrs === model ? model.attributes : attrs; if (options.parse) attrs = existing.parse(attrs, options); // if this is model if (existing.set) { existing.set(attrs, options); if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; } else { // if not just update the properties extend(existing, attrs); } } models[i] = existing; // If this is a new, valid model, push it to the `toAdd` list. } else if (add) { model = models[i] = this._prepareModel(attrs, options); if (!model) continue; toAdd.push(model); this._addReference(model, options); } // Do not add multiple models with the same `id`. model = existing || model; if (!model) continue; if (order && ((model.isNew && model.isNew() || !model[this.mainIndex]) || !modelMap[model.cid || model[this.mainIndex]])) order.push(model); modelMap[model[this.mainIndex]] = true; } // Remove nonexistent models if appropriate. if (remove) { for (i = 0, length = this.length; i < length; i++) { model = this.models[i]; if (!modelMap[model.cid || model[this.mainIndex]]) toRemove.push(model); } if (toRemove.length) this.remove(toRemove, options); } // See if sorting is needed, update `length` and splice in new models. if (toAdd.length || (order && order.length)) { if (sortable) sort = true; if (at != null) { for (i = 0, length = toAdd.length; i < length; i++) { this.models.splice(at + i, 0, toAdd[i]); } } else { var orderedModels = order || toAdd; for (i = 0, length = orderedModels.length; i < length; i++) { this.models.push(orderedModels[i]); } } } // Silently sort the collection if appropriate. if (sort) this.sort({silent: true}); // Unless silenced, it's time to fire all appropriate add/sort events. if (!options.silent) { for (i = 0, length = toAdd.length; i < length; i++) { model = toAdd[i]; if (model.trigger) { model.trigger('add', model, this, options); } else { this.trigger('add', model, this, options); } } if (sort || (order && order.length)) this.trigger('sort', this, options); } // Return the added (or merged) model (or models). return singular ? models[0] : models; }, get: function (query, indexName) { if (query == null) return; var index = this._indexes[indexName || this.mainIndex]; return (index && (index[query] || index[query[this.mainIndex]])) || this._indexes.cid[query] || this._indexes.cid[query.cid]; }, // Get the model at the given index. at: function (index) { return this.models[index]; }, remove: function (models, options) { var singular = !isArray(models); var i, length, model, index; models = singular ? [models] : slice.call(models); options || (options = {}); for (i = 0, length = models.length; i < length; i++) { model = models[i] = this.get(models[i]); if (!model) continue; this._deIndex(model); index = this.models.indexOf(model); this.models.splice(index, 1); if (!options.silent) { options.index = index; if (model.trigger) { model.trigger('remove', model, this, options); } else { this.trigger('remove', model, this, options); } } this._removeReference(model, options); } return singular ? models[0] : models; }, // When you have more items than you want to add or remove individually, // you can reset the entire set with a new list of models, without firing // any granular `add` or `remove` events. Fires `reset` when finished. // Useful for bulk operations and optimizations. reset: function (models, options) { options || (options = {}); for (var i = 0, length = this.models.length; i < length; i++) { this._removeReference(this.models[i], options); } options.previousModels = this.models; this._reset(); models = this.add(models, extend({silent: true}, options)); if (!options.silent) this.trigger('reset', this, options); return models; }, sort: function (options) { var self = this; if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); options || (options = {}); if (typeof this.comparator === 'string') { this.models.sort(function (left, right) { if (left.get) { left = left.get(self.comparator); right = right.get(self.comparator); } else { left = left[self.comparator]; right = right[self.comparator]; } if (left > right || left === void 0) return 1; if (left < right || right === void 0) return -1; return 0; }); } else if (this.comparator.length === 1) { this.models.sort(function (left, right) { left = self.comparator(left); right = self.comparator(right); if (left > right || left === void 0) return 1; if (left < right || right === void 0) return -1; return 0; }); } else { this.models.sort(bind(this.comparator,this)); } if (!options.silent) this.trigger('sort', this, options); return this; }, // Private method to reset all internal state. Called when the collection // is first initialized or reset. _reset: function () { var list = slice.call(this.indexes || []); var i = 0; list.push(this.mainIndex); list.push('cid'); var l = list.length; this.models = []; this._indexes = {}; for (; i < l; i++) { this._indexes[list[i]] = {}; } }, _prepareModel: function (attrs, options) { // if we haven't defined a constructor, skip this if (!this.model) return attrs; if (this.isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; } else { options = options ? extend({}, options) : {}; options.collection = this; var model = new this.model(attrs, options); if (!model.validationError) return model; this.trigger('invalid', this, model.validationError, options); return false; } }, _deIndex: function (model) { for (var name in this._indexes) { delete this._indexes[name][model.hasOwnProperty(name) ? model[name] : (model.get && model.get(name))]; } }, _index: function (model) { for (var name in this._indexes) { var indexVal = model.hasOwnProperty(name) ? model[name] : (model.get && model.get(name)); if (indexVal != null) this._indexes[name][indexVal] = model; } }, // Internal method to create a model's ties to a collection. _addReference: function (model, options) { this._index(model); if (!model.collection) model.collection = this; if (model.on) model.on('all', this._onModelEvent, this); }, // Internal method to sever a model's ties to a collection. _removeReference: function (model, options) { if (this === model.collection) delete model.collection; this._deIndex(model); if (model.off) model.off('all', this._onModelEvent, this); }, _onModelEvent: function (event, model, collection, options) { if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options); if (model && event === 'change:' + this.mainIndex) { this._deIndex(model); this._index(model); } this.trigger.apply(this, arguments); } });