mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-11 11:27:50 +00:00
Update vendor/backbone to 1.2.1.
This commit is contained in:
237
vendor/backbone/backbone.js
vendored
237
vendor/backbone/backbone.js
vendored
@@ -1,4 +1,4 @@
|
|||||||
// Backbone.js 1.2.0
|
// Backbone.js 1.2.1
|
||||||
|
|
||||||
// (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
// (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
// Backbone may be freely distributed under the MIT license.
|
// Backbone may be freely distributed under the MIT license.
|
||||||
@@ -40,12 +40,11 @@
|
|||||||
// restored later on, if `noConflict` is used.
|
// restored later on, if `noConflict` is used.
|
||||||
var previousBackbone = root.Backbone;
|
var previousBackbone = root.Backbone;
|
||||||
|
|
||||||
// Create local references to array methods we'll want to use later.
|
// Create a local reference to a common array method we'll want to use later.
|
||||||
var array = [];
|
var slice = [].slice;
|
||||||
var slice = array.slice;
|
|
||||||
|
|
||||||
// Current version of the library. Keep in sync with `package.json`.
|
// Current version of the library. Keep in sync with `package.json`.
|
||||||
Backbone.VERSION = '1.2.0';
|
Backbone.VERSION = '1.2.1';
|
||||||
|
|
||||||
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
|
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
|
||||||
// the `$` variable.
|
// the `$` variable.
|
||||||
@@ -69,6 +68,35 @@
|
|||||||
// form param named `model`.
|
// form param named `model`.
|
||||||
Backbone.emulateJSON = false;
|
Backbone.emulateJSON = false;
|
||||||
|
|
||||||
|
// Proxy Underscore methods to a Backbone class' prototype using a
|
||||||
|
// particular attribute as the data argument
|
||||||
|
var addMethod = function(length, method, attribute) {
|
||||||
|
switch (length) {
|
||||||
|
case 1: return function() {
|
||||||
|
return _[method](this[attribute]);
|
||||||
|
};
|
||||||
|
case 2: return function(value) {
|
||||||
|
return _[method](this[attribute], value);
|
||||||
|
};
|
||||||
|
case 3: return function(iteratee, context) {
|
||||||
|
return _[method](this[attribute], iteratee, context);
|
||||||
|
};
|
||||||
|
case 4: return function(iteratee, defaultVal, context) {
|
||||||
|
return _[method](this[attribute], iteratee, defaultVal, context);
|
||||||
|
};
|
||||||
|
default: return function() {
|
||||||
|
var args = slice.call(arguments);
|
||||||
|
args.unshift(this[attribute]);
|
||||||
|
return _[method].apply(_, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var addUnderscoreMethods = function(Class, methods, attribute) {
|
||||||
|
_.each(methods, function(length, method) {
|
||||||
|
if (_[method]) Class.prototype[method] = addMethod(length, method, attribute);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Backbone.Events
|
// Backbone.Events
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
@@ -96,6 +124,7 @@
|
|||||||
var i = 0, names;
|
var i = 0, names;
|
||||||
if (name && typeof name === 'object') {
|
if (name && typeof name === 'object') {
|
||||||
// Handle event maps.
|
// Handle event maps.
|
||||||
|
if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
|
||||||
for (names = _.keys(name); i < names.length ; i++) {
|
for (names = _.keys(name); i < names.length ; i++) {
|
||||||
memo = iteratee(memo, names[i], name[names[i]], opts);
|
memo = iteratee(memo, names[i], name[names[i]], opts);
|
||||||
}
|
}
|
||||||
@@ -205,7 +234,7 @@
|
|||||||
// No events to consider.
|
// No events to consider.
|
||||||
if (!events) return;
|
if (!events) return;
|
||||||
|
|
||||||
var i = 0, length, listening;
|
var i = 0, listening;
|
||||||
var context = options.context, listeners = options.listeners;
|
var context = options.context, listeners = options.listeners;
|
||||||
|
|
||||||
// Delete all events listeners and "drop" events.
|
// Delete all events listeners and "drop" events.
|
||||||
@@ -274,7 +303,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Reduces the event callbacks into a map of `{event: onceWrapper}`.
|
// Reduces the event callbacks into a map of `{event: onceWrapper}`.
|
||||||
// `offer` unbinds the `onceWrapper` after it as been called.
|
// `offer` unbinds the `onceWrapper` after it has been called.
|
||||||
var onceMap = function(map, name, callback, offer) {
|
var onceMap = function(map, name, callback, offer) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
var once = map[name] = _.once(function() {
|
var once = map[name] = _.once(function() {
|
||||||
@@ -327,35 +356,6 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Proxy Underscore methods to a Backbone class' prototype using a
|
|
||||||
// particular attribute as the data argument
|
|
||||||
var addMethod = function(length, method, attribute) {
|
|
||||||
switch (length) {
|
|
||||||
case 1: return function() {
|
|
||||||
return _[method](this[attribute]);
|
|
||||||
};
|
|
||||||
case 2: return function(value) {
|
|
||||||
return _[method](this[attribute], value);
|
|
||||||
};
|
|
||||||
case 3: return function(iteratee, context) {
|
|
||||||
return _[method](this[attribute], iteratee, context);
|
|
||||||
};
|
|
||||||
case 4: return function(iteratee, defaultVal, context) {
|
|
||||||
return _[method](this[attribute], iteratee, defaultVal, context);
|
|
||||||
};
|
|
||||||
default: return function() {
|
|
||||||
var args = slice.call(arguments);
|
|
||||||
args.unshift(this[attribute]);
|
|
||||||
return _[method].apply(_, args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var addUnderscoreMethods = function(Class, methods, attribute) {
|
|
||||||
_.each(methods, function(length, method) {
|
|
||||||
if (_[method]) Class.prototype[method] = addMethod(length, method, attribute);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Aliases for backwards compatibility.
|
// Aliases for backwards compatibility.
|
||||||
Events.bind = Events.on;
|
Events.bind = Events.on;
|
||||||
Events.unbind = Events.off;
|
Events.unbind = Events.off;
|
||||||
@@ -444,10 +444,10 @@
|
|||||||
// the core primitive operation of a model, updating the data and notifying
|
// the core primitive operation of a model, updating the data and notifying
|
||||||
// anyone who needs to know about the change in state. The heart of the beast.
|
// anyone who needs to know about the change in state. The heart of the beast.
|
||||||
set: function(key, val, options) {
|
set: function(key, val, options) {
|
||||||
var attr, attrs, unset, changes, silent, changing, prev, current;
|
|
||||||
if (key == null) return this;
|
if (key == null) return this;
|
||||||
|
|
||||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||||
|
var attrs;
|
||||||
if (typeof key === 'object') {
|
if (typeof key === 'object') {
|
||||||
attrs = key;
|
attrs = key;
|
||||||
options = val;
|
options = val;
|
||||||
@@ -461,29 +461,32 @@
|
|||||||
if (!this._validate(attrs, options)) return false;
|
if (!this._validate(attrs, options)) return false;
|
||||||
|
|
||||||
// Extract attributes and options.
|
// Extract attributes and options.
|
||||||
unset = options.unset;
|
var unset = options.unset;
|
||||||
silent = options.silent;
|
var silent = options.silent;
|
||||||
changes = [];
|
var changes = [];
|
||||||
changing = this._changing;
|
var changing = this._changing;
|
||||||
this._changing = true;
|
this._changing = true;
|
||||||
|
|
||||||
if (!changing) {
|
if (!changing) {
|
||||||
this._previousAttributes = _.clone(this.attributes);
|
this._previousAttributes = _.clone(this.attributes);
|
||||||
this.changed = {};
|
this.changed = {};
|
||||||
}
|
}
|
||||||
current = this.attributes, prev = this._previousAttributes;
|
|
||||||
|
var current = this.attributes;
|
||||||
|
var changed = this.changed;
|
||||||
|
var prev = this._previousAttributes;
|
||||||
|
|
||||||
// Check for changes of `id`.
|
// Check for changes of `id`.
|
||||||
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
||||||
|
|
||||||
// For each `set` attribute, update or delete the current value.
|
// For each `set` attribute, update or delete the current value.
|
||||||
for (attr in attrs) {
|
for (var attr in attrs) {
|
||||||
val = attrs[attr];
|
val = attrs[attr];
|
||||||
if (!_.isEqual(current[attr], val)) changes.push(attr);
|
if (!_.isEqual(current[attr], val)) changes.push(attr);
|
||||||
if (!_.isEqual(prev[attr], val)) {
|
if (!_.isEqual(prev[attr], val)) {
|
||||||
this.changed[attr] = val;
|
changed[attr] = val;
|
||||||
} else {
|
} else {
|
||||||
delete this.changed[attr];
|
delete changed[attr];
|
||||||
}
|
}
|
||||||
unset ? delete current[attr] : current[attr] = val;
|
unset ? delete current[attr] : current[attr] = val;
|
||||||
}
|
}
|
||||||
@@ -539,13 +542,14 @@
|
|||||||
// determining if there *would be* a change.
|
// determining if there *would be* a change.
|
||||||
changedAttributes: function(diff) {
|
changedAttributes: function(diff) {
|
||||||
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
|
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
|
||||||
var val, changed = false;
|
|
||||||
var old = this._changing ? this._previousAttributes : this.attributes;
|
var old = this._changing ? this._previousAttributes : this.attributes;
|
||||||
|
var changed = {};
|
||||||
for (var attr in diff) {
|
for (var attr in diff) {
|
||||||
if (_.isEqual(old[attr], (val = diff[attr]))) continue;
|
var val = diff[attr];
|
||||||
(changed || (changed = {}))[attr] = val;
|
if (_.isEqual(old[attr], val)) continue;
|
||||||
|
changed[attr] = val;
|
||||||
}
|
}
|
||||||
return changed;
|
return _.size(changed) ? changed : false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Get the previous value of an attribute, recorded at the time the last
|
// Get the previous value of an attribute, recorded at the time the last
|
||||||
@@ -564,12 +568,12 @@
|
|||||||
// Fetch the model from the server, merging the response with the model's
|
// Fetch the model from the server, merging the response with the model's
|
||||||
// local attributes. Any changed attributes will trigger a "change" event.
|
// local attributes. Any changed attributes will trigger a "change" event.
|
||||||
fetch: function(options) {
|
fetch: function(options) {
|
||||||
options = options ? _.clone(options) : {};
|
options = _.extend({parse: true}, options);
|
||||||
if (options.parse === void 0) options.parse = true;
|
|
||||||
var model = this;
|
var model = this;
|
||||||
var success = options.success;
|
var success = options.success;
|
||||||
options.success = function(resp) {
|
options.success = function(resp) {
|
||||||
if (!model.set(model.parse(resp, options), options)) return false;
|
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
|
||||||
|
if (!model.set(serverAttrs, options)) return false;
|
||||||
if (success) success.call(options.context, model, resp, options);
|
if (success) success.call(options.context, model, resp, options);
|
||||||
model.trigger('sync', model, resp, options);
|
model.trigger('sync', model, resp, options);
|
||||||
};
|
};
|
||||||
@@ -581,9 +585,8 @@
|
|||||||
// If the server returns an attributes hash that differs, the model's
|
// If the server returns an attributes hash that differs, the model's
|
||||||
// state will be `set` again.
|
// state will be `set` again.
|
||||||
save: function(key, val, options) {
|
save: function(key, val, options) {
|
||||||
var attrs, method, xhr, attributes = this.attributes, wait;
|
|
||||||
|
|
||||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||||
|
var attrs;
|
||||||
if (key == null || typeof key === 'object') {
|
if (key == null || typeof key === 'object') {
|
||||||
attrs = key;
|
attrs = key;
|
||||||
options = val;
|
options = val;
|
||||||
@@ -591,8 +594,8 @@
|
|||||||
(attrs = {})[key] = val;
|
(attrs = {})[key] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
options = _.extend({validate: true}, options);
|
options = _.extend({validate: true, parse: true}, options);
|
||||||
wait = options.wait;
|
var wait = options.wait;
|
||||||
|
|
||||||
// If we're not waiting and attributes exist, save acts as
|
// If we're not waiting and attributes exist, save acts as
|
||||||
// `set(attr).save(null, opts)` with validation. Otherwise, check if
|
// `set(attr).save(null, opts)` with validation. Otherwise, check if
|
||||||
@@ -603,35 +606,31 @@
|
|||||||
if (!this._validate(attrs, options)) return false;
|
if (!this._validate(attrs, options)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set temporary attributes if `{wait: true}`.
|
|
||||||
if (attrs && wait) {
|
|
||||||
this.attributes = _.extend({}, attributes, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// After a successful server-side save, the client is (optionally)
|
// After a successful server-side save, the client is (optionally)
|
||||||
// updated with the server-side state.
|
// updated with the server-side state.
|
||||||
if (options.parse === void 0) options.parse = true;
|
|
||||||
var model = this;
|
var model = this;
|
||||||
var success = options.success;
|
var success = options.success;
|
||||||
|
var attributes = this.attributes;
|
||||||
options.success = function(resp) {
|
options.success = function(resp) {
|
||||||
// Ensure attributes are restored during synchronous saves.
|
// Ensure attributes are restored during synchronous saves.
|
||||||
model.attributes = attributes;
|
model.attributes = attributes;
|
||||||
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
|
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
|
||||||
if (wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
|
if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
|
||||||
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
|
if (serverAttrs && !model.set(serverAttrs, options)) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (success) success.call(options.context, model, resp, options);
|
if (success) success.call(options.context, model, resp, options);
|
||||||
model.trigger('sync', model, resp, options);
|
model.trigger('sync', model, resp, options);
|
||||||
};
|
};
|
||||||
wrapError(this, options);
|
wrapError(this, options);
|
||||||
|
|
||||||
method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
|
// Set temporary attributes if `{wait: true}` to properly find new ids.
|
||||||
|
if (attrs && wait) this.attributes = _.extend({}, attributes, attrs);
|
||||||
|
|
||||||
|
var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
|
||||||
if (method === 'patch' && !options.attrs) options.attrs = attrs;
|
if (method === 'patch' && !options.attrs) options.attrs = attrs;
|
||||||
xhr = this.sync(method, this, options);
|
var xhr = this.sync(method, this, options);
|
||||||
|
|
||||||
// Restore attributes.
|
// Restore attributes.
|
||||||
if (attrs && wait) this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
|
|
||||||
return xhr;
|
return xhr;
|
||||||
},
|
},
|
||||||
@@ -676,8 +675,8 @@
|
|||||||
_.result(this.collection, 'url') ||
|
_.result(this.collection, 'url') ||
|
||||||
urlError();
|
urlError();
|
||||||
if (this.isNew()) return base;
|
if (this.isNew()) return base;
|
||||||
var id = this.id || this.attributes[this.idAttribute];
|
var id = this.get(this.idAttribute);
|
||||||
return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(id);
|
return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
|
||||||
},
|
},
|
||||||
|
|
||||||
// **parse** converts a response into the hash of attributes to be `set` on
|
// **parse** converts a response into the hash of attributes to be `set` on
|
||||||
@@ -698,7 +697,7 @@
|
|||||||
|
|
||||||
// Check if the model is currently in a valid state.
|
// Check if the model is currently in a valid state.
|
||||||
isValid: function(options) {
|
isValid: function(options) {
|
||||||
return this._validate({}, _.extend(options || {}, { validate: true }));
|
return this._validate({}, _.defaults({validate: true}, options));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Run validation against the next complete set of model attributes,
|
// Run validation against the next complete set of model attributes,
|
||||||
@@ -761,7 +760,7 @@
|
|||||||
// The JSON representation of a Collection is an array of the
|
// The JSON representation of a Collection is an array of the
|
||||||
// models' attributes.
|
// models' attributes.
|
||||||
toJSON: function(options) {
|
toJSON: function(options) {
|
||||||
return this.map(function(model){ return model.toJSON(options); });
|
return this.map(function(model) { return model.toJSON(options); });
|
||||||
},
|
},
|
||||||
|
|
||||||
// Proxy `Backbone.sync` by default.
|
// Proxy `Backbone.sync` by default.
|
||||||
@@ -776,12 +775,12 @@
|
|||||||
|
|
||||||
// Remove a model, or a list of models from the set.
|
// Remove a model, or a list of models from the set.
|
||||||
remove: function(models, options) {
|
remove: function(models, options) {
|
||||||
var singular = !_.isArray(models), removed;
|
options = _.extend({}, options);
|
||||||
|
var singular = !_.isArray(models);
|
||||||
models = singular ? [models] : _.clone(models);
|
models = singular ? [models] : _.clone(models);
|
||||||
options || (options = {});
|
var removed = this._removeModels(models, options);
|
||||||
removed = this._removeModels(models, options);
|
|
||||||
if (!options.silent && removed) this.trigger('update', this, options);
|
if (!options.silent && removed) this.trigger('update', this, options);
|
||||||
return singular ? models[0] : models;
|
return singular ? removed[0] : removed;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Update a collection by `set`-ing a new list of models, adding new ones,
|
// Update a collection by `set`-ing a new list of models, adding new ones,
|
||||||
@@ -790,7 +789,7 @@
|
|||||||
// the core operation for updating the data contained by the collection.
|
// the core operation for updating the data contained by the collection.
|
||||||
set: function(models, options) {
|
set: function(models, options) {
|
||||||
options = _.defaults({}, options, setOptions);
|
options = _.defaults({}, options, setOptions);
|
||||||
if (options.parse) models = this.parse(models, options);
|
if (options.parse && !this._isModel(models)) models = this.parse(models, options);
|
||||||
var singular = !_.isArray(models);
|
var singular = !_.isArray(models);
|
||||||
models = singular ? (models ? [models] : []) : models.slice();
|
models = singular ? (models ? [models] : []) : models.slice();
|
||||||
var id, model, attrs, existing, sort;
|
var id, model, attrs, existing, sort;
|
||||||
@@ -910,8 +909,7 @@
|
|||||||
// Remove a model from the end of the collection.
|
// Remove a model from the end of the collection.
|
||||||
pop: function(options) {
|
pop: function(options) {
|
||||||
var model = this.at(this.length - 1);
|
var model = this.at(this.length - 1);
|
||||||
this.remove(model, options);
|
return this.remove(model, options);
|
||||||
return model;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Add a model to the beginning of the collection.
|
// Add a model to the beginning of the collection.
|
||||||
@@ -922,8 +920,7 @@
|
|||||||
// Remove a model from the beginning of the collection.
|
// Remove a model from the beginning of the collection.
|
||||||
shift: function(options) {
|
shift: function(options) {
|
||||||
var model = this.at(0);
|
var model = this.at(0);
|
||||||
this.remove(model, options);
|
return this.remove(model, options);
|
||||||
return model;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Slice out a sub-array of models from the collection.
|
// Slice out a sub-array of models from the collection.
|
||||||
@@ -986,8 +983,7 @@
|
|||||||
// collection when they arrive. If `reset: true` is passed, the response
|
// collection when they arrive. If `reset: true` is passed, the response
|
||||||
// data will be passed through the `reset` method instead of `set`.
|
// data will be passed through the `reset` method instead of `set`.
|
||||||
fetch: function(options) {
|
fetch: function(options) {
|
||||||
options = options ? _.clone(options) : {};
|
options = _.extend({parse: true}, options);
|
||||||
if (options.parse === void 0) options.parse = true;
|
|
||||||
var success = options.success;
|
var success = options.success;
|
||||||
var collection = this;
|
var collection = this;
|
||||||
options.success = function(resp) {
|
options.success = function(resp) {
|
||||||
@@ -1006,7 +1002,8 @@
|
|||||||
create: function(model, options) {
|
create: function(model, options) {
|
||||||
options = options ? _.clone(options) : {};
|
options = options ? _.clone(options) : {};
|
||||||
var wait = options.wait;
|
var wait = options.wait;
|
||||||
if (!(model = this._prepareModel(model, options))) return false;
|
model = this._prepareModel(model, options);
|
||||||
|
if (!model) return false;
|
||||||
if (!wait) this.add(model, options);
|
if (!wait) this.add(model, options);
|
||||||
var collection = this;
|
var collection = this;
|
||||||
var success = options.success;
|
var success = options.success;
|
||||||
@@ -1060,31 +1057,27 @@
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Internal method called by both remove and set. Does not trigger any
|
// Internal method called by both remove and set.
|
||||||
// additional events. Returns true if anything was actually removed.
|
// Returns removed models, or false if nothing is removed.
|
||||||
_removeModels: function(models, options) {
|
_removeModels: function(models, options) {
|
||||||
var i, l, index, model, removed = false;
|
var removed = [];
|
||||||
for (var i = 0, j = 0; i < models.length; i++) {
|
for (var i = 0; i < models.length; i++) {
|
||||||
var model = models[i] = this.get(models[i]);
|
var model = this.get(models[i]);
|
||||||
if (!model) continue;
|
if (!model) continue;
|
||||||
var id = this.modelId(model.attributes);
|
|
||||||
if (id != null) delete this._byId[id];
|
|
||||||
delete this._byId[model.cid];
|
|
||||||
var index = this.indexOf(model);
|
var index = this.indexOf(model);
|
||||||
this.models.splice(index, 1);
|
this.models.splice(index, 1);
|
||||||
this.length--;
|
this.length--;
|
||||||
|
|
||||||
if (!options.silent) {
|
if (!options.silent) {
|
||||||
options.index = index;
|
options.index = index;
|
||||||
model.trigger('remove', model, this, options);
|
model.trigger('remove', model, this, options);
|
||||||
}
|
}
|
||||||
models[j++] = model;
|
|
||||||
|
removed.push(model);
|
||||||
this._removeReference(model, options);
|
this._removeReference(model, options);
|
||||||
removed = true;
|
|
||||||
}
|
}
|
||||||
// We only need to slice if models array should be smaller, which is
|
return removed.length ? removed : false;
|
||||||
// caused by some models not actually getting removed.
|
|
||||||
if (models.length !== j) models = models.slice(0, j);
|
|
||||||
return removed;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Method for checking whether an object should be considered a model for
|
// Method for checking whether an object should be considered a model for
|
||||||
@@ -1103,6 +1096,9 @@
|
|||||||
|
|
||||||
// Internal method to sever a model's ties to a collection.
|
// Internal method to sever a model's ties to a collection.
|
||||||
_removeReference: function(model, options) {
|
_removeReference: function(model, options) {
|
||||||
|
delete this._byId[model.cid];
|
||||||
|
var id = this.modelId(model.attributes);
|
||||||
|
if (id != null) delete this._byId[id];
|
||||||
if (this === model.collection) delete model.collection;
|
if (this === model.collection) delete model.collection;
|
||||||
model.off('all', this._onModelEvent, this);
|
model.off('all', this._onModelEvent, this);
|
||||||
},
|
},
|
||||||
@@ -1133,7 +1129,7 @@
|
|||||||
var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4,
|
var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4,
|
||||||
foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3,
|
foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3,
|
||||||
select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 2,
|
select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 2,
|
||||||
contains: 2, invoke: 2, max: 3, min: 3, toArray: 1, size: 1, first: 3,
|
contains: 2, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
|
||||||
head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
|
head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
|
||||||
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
|
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
|
||||||
isEmpty: 1, chain: 1, sample: 3, partition: 3 };
|
isEmpty: 1, chain: 1, sample: 3, partition: 3 };
|
||||||
@@ -1170,7 +1166,6 @@
|
|||||||
// if an existing element is not provided...
|
// if an existing element is not provided...
|
||||||
var View = Backbone.View = function(options) {
|
var View = Backbone.View = function(options) {
|
||||||
this.cid = _.uniqueId('view');
|
this.cid = _.uniqueId('view');
|
||||||
options || (options = {});
|
|
||||||
_.extend(this, _.pick(options, viewOptions));
|
_.extend(this, _.pick(options, viewOptions));
|
||||||
this._ensureElement();
|
this._ensureElement();
|
||||||
this.initialize.apply(this, arguments);
|
this.initialize.apply(this, arguments);
|
||||||
@@ -1253,11 +1248,12 @@
|
|||||||
// Uses event delegation for efficiency.
|
// Uses event delegation for efficiency.
|
||||||
// Omitting the selector binds the event to `this.el`.
|
// Omitting the selector binds the event to `this.el`.
|
||||||
delegateEvents: function(events) {
|
delegateEvents: function(events) {
|
||||||
if (!(events || (events = _.result(this, 'events')))) return this;
|
events || (events = _.result(this, 'events'));
|
||||||
|
if (!events) return this;
|
||||||
this.undelegateEvents();
|
this.undelegateEvents();
|
||||||
for (var key in events) {
|
for (var key in events) {
|
||||||
var method = events[key];
|
var method = events[key];
|
||||||
if (!_.isFunction(method)) method = this[events[key]];
|
if (!_.isFunction(method)) method = this[method];
|
||||||
if (!method) continue;
|
if (!method) continue;
|
||||||
var match = key.match(delegateEventSplitter);
|
var match = key.match(delegateEventSplitter);
|
||||||
this.delegate(match[1], match[2], _.bind(method, this));
|
this.delegate(match[1], match[2], _.bind(method, this));
|
||||||
@@ -1270,6 +1266,7 @@
|
|||||||
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
|
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
|
||||||
delegate: function(eventName, selector, listener) {
|
delegate: function(eventName, selector, listener) {
|
||||||
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
|
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Clears all callbacks previously bound to the view by `delegateEvents`.
|
// Clears all callbacks previously bound to the view by `delegateEvents`.
|
||||||
@@ -1284,6 +1281,7 @@
|
|||||||
// `selector` and `listener` are both optional.
|
// `selector` and `listener` are both optional.
|
||||||
undelegate: function(eventName, selector, listener) {
|
undelegate: function(eventName, selector, listener) {
|
||||||
this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
|
this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Produces a DOM element to be assigned to your view. Exposed for
|
// Produces a DOM element to be assigned to your view. Exposed for
|
||||||
@@ -1647,15 +1645,16 @@
|
|||||||
// support the `hashchange` event, HTML5 history, or the user wants
|
// support the `hashchange` event, HTML5 history, or the user wants
|
||||||
// `hashChange` but not `pushState`.
|
// `hashChange` but not `pushState`.
|
||||||
if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
|
if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
|
||||||
var iframe = document.createElement('iframe');
|
this.iframe = document.createElement('iframe');
|
||||||
iframe.src = 'javascript:0';
|
this.iframe.src = 'javascript:0';
|
||||||
iframe.style.display = 'none';
|
this.iframe.style.display = 'none';
|
||||||
iframe.tabIndex = -1;
|
this.iframe.tabIndex = -1;
|
||||||
var body = document.body;
|
var body = document.body;
|
||||||
// Using `appendChild` will throw on IE < 9 if the document is not ready.
|
// Using `appendChild` will throw on IE < 9 if the document is not ready.
|
||||||
this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow;
|
var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow;
|
||||||
this.iframe.document.open().close();
|
iWindow.document.open();
|
||||||
this.iframe.location.hash = '#' + this.fragment;
|
iWindow.document.close();
|
||||||
|
iWindow.location.hash = '#' + this.fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a cross-platform `addEventListener` shim for older browsers.
|
// Add a cross-platform `addEventListener` shim for older browsers.
|
||||||
@@ -1693,7 +1692,7 @@
|
|||||||
|
|
||||||
// Clean up the iframe if necessary.
|
// Clean up the iframe if necessary.
|
||||||
if (this.iframe) {
|
if (this.iframe) {
|
||||||
document.body.removeChild(this.iframe.frameElement);
|
document.body.removeChild(this.iframe);
|
||||||
this.iframe = null;
|
this.iframe = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1716,7 +1715,7 @@
|
|||||||
// If the user pressed the back button, the iframe's hash will have
|
// If the user pressed the back button, the iframe's hash will have
|
||||||
// changed and we should use that for comparison.
|
// changed and we should use that for comparison.
|
||||||
if (current === this.fragment && this.iframe) {
|
if (current === this.fragment && this.iframe) {
|
||||||
current = this.getHash(this.iframe);
|
current = this.getHash(this.iframe.contentWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current === this.fragment) return false;
|
if (current === this.fragment) return false;
|
||||||
@@ -1774,12 +1773,18 @@
|
|||||||
// fragment to store history.
|
// fragment to store history.
|
||||||
} else if (this._wantsHashChange) {
|
} else if (this._wantsHashChange) {
|
||||||
this._updateHash(this.location, fragment, options.replace);
|
this._updateHash(this.location, fragment, options.replace);
|
||||||
if (this.iframe && (fragment !== this.getHash(this.iframe))) {
|
if (this.iframe && (fragment !== this.getHash(this.iframe.contentWindow))) {
|
||||||
|
var iWindow = this.iframe.contentWindow;
|
||||||
|
|
||||||
// Opening and closing the iframe tricks IE7 and earlier to push a
|
// Opening and closing the iframe tricks IE7 and earlier to push a
|
||||||
// history entry on hash-tag change. When replace is true, we don't
|
// history entry on hash-tag change. When replace is true, we don't
|
||||||
// want this.
|
// want this.
|
||||||
if (!options.replace) this.iframe.document.open().close();
|
if (!options.replace) {
|
||||||
this._updateHash(this.iframe.location, fragment, options.replace);
|
iWindow.document.open();
|
||||||
|
iWindow.document.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateHash(iWindow.location, fragment, options.replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you've told us that you explicitly don't want fallback hashchange-
|
// If you've told us that you explicitly don't want fallback hashchange-
|
||||||
|
|||||||
43
vendor/backbone/test/collection.js
vendored
43
vendor/backbone/test/collection.js
vendored
@@ -298,17 +298,13 @@
|
|||||||
deepEqual(col.pluck('id'), [1, 2, 3]);
|
deepEqual(col.pluck('id'), [1, 2, 3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("remove", 7, function() {
|
test("remove", 10, function() {
|
||||||
var removed = null;
|
var removed = null;
|
||||||
var otherRemoved = null;
|
|
||||||
var result = null;
|
var result = null;
|
||||||
col.on('remove', function(model, col, options) {
|
col.on('remove', function(model, col, options) {
|
||||||
removed = model.get('label');
|
removed = model.get('label');
|
||||||
equal(options.index, 3);
|
equal(options.index, 3);
|
||||||
});
|
});
|
||||||
otherCol.on('remove', function(model, col, options) {
|
|
||||||
otherRemoved = true;
|
|
||||||
});
|
|
||||||
result = col.remove(d);
|
result = col.remove(d);
|
||||||
equal(removed, 'd');
|
equal(removed, 'd');
|
||||||
strictEqual(result, d);
|
strictEqual(result, d);
|
||||||
@@ -317,7 +313,13 @@
|
|||||||
strictEqual(result, undefined);
|
strictEqual(result, undefined);
|
||||||
equal(col.length, 3);
|
equal(col.length, 3);
|
||||||
equal(col.first(), a);
|
equal(col.first(), a);
|
||||||
equal(otherRemoved, null);
|
col.off();
|
||||||
|
result = col.remove([c, d]);
|
||||||
|
equal(result.length, 1, 'only returns removed models');
|
||||||
|
equal(result[0], c, 'only returns removed models');
|
||||||
|
result = col.remove([c, b]);
|
||||||
|
equal(result.length, 1, 'only returns removed models');
|
||||||
|
equal(result[0], b, 'only returns removed models');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("add and remove return values", 13, function() {
|
test("add and remove return values", 13, function() {
|
||||||
@@ -559,6 +561,20 @@
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("create with wait:true should not call collection.parse", 0, function() {
|
||||||
|
var Collection = Backbone.Collection.extend({
|
||||||
|
url: '/test',
|
||||||
|
parse: function () {
|
||||||
|
ok(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var collection = new Collection;
|
||||||
|
|
||||||
|
collection.create({}, {wait: true});
|
||||||
|
this.ajaxSettings.success();
|
||||||
|
});
|
||||||
|
|
||||||
test("a failing create returns model with errors", function() {
|
test("a failing create returns model with errors", function() {
|
||||||
var ValidatingModel = Backbone.Model.extend({
|
var ValidatingModel = Backbone.Model.extend({
|
||||||
validate: function(attrs) {
|
validate: function(attrs) {
|
||||||
@@ -1605,4 +1621,19 @@
|
|||||||
collection.set([{id: 1}, {id: 2}]);
|
collection.set([{id: 1}, {id: 2}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("#3610 - invoke collects arguments", 3, function() {
|
||||||
|
var Model = Backbone.Model.extend({
|
||||||
|
method: function(a, b, c) {
|
||||||
|
equal(a, 1);
|
||||||
|
equal(b, 2);
|
||||||
|
equal(c, 3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var Collection = Backbone.Collection.extend({
|
||||||
|
model: Model
|
||||||
|
});
|
||||||
|
var collection = new Collection([{id: 1}]);
|
||||||
|
collection.invoke('method', 1, 2, 3);
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
18
vendor/backbone/test/events.js
vendored
18
vendor/backbone/test/events.js
vendored
@@ -66,6 +66,24 @@
|
|||||||
equal(obj.counter, 5);
|
equal(obj.counter, 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("binding and trigger with event maps context", 2, function() {
|
||||||
|
var obj = { counter: 0 };
|
||||||
|
var context = {};
|
||||||
|
_.extend(obj, Backbone.Events);
|
||||||
|
|
||||||
|
obj.on({
|
||||||
|
a: function() {
|
||||||
|
strictEqual(this, context, 'defaults `context` to `callback` param');
|
||||||
|
}
|
||||||
|
}, context).trigger('a');
|
||||||
|
|
||||||
|
obj.off().on({
|
||||||
|
a: function() {
|
||||||
|
strictEqual(this, context, 'will not override explicit `context` param');
|
||||||
|
}
|
||||||
|
}, this, context).trigger('a');
|
||||||
|
});
|
||||||
|
|
||||||
test("listenTo and stopListening", 1, function() {
|
test("listenTo and stopListening", 1, function() {
|
||||||
var a = _.extend({}, Backbone.Events);
|
var a = _.extend({}, Backbone.Events);
|
||||||
var b = _.extend({}, Backbone.Events);
|
var b = _.extend({}, Backbone.Events);
|
||||||
|
|||||||
15
vendor/backbone/test/model.js
vendored
15
vendor/backbone/test/model.js
vendored
@@ -550,6 +550,21 @@
|
|||||||
model.destroy(options);
|
model.destroy(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("#3470 - save and fetch with parse false", 2, function() {
|
||||||
|
var i = 0;
|
||||||
|
var model = new Backbone.Model();
|
||||||
|
model.parse = function() {
|
||||||
|
ok(false);
|
||||||
|
};
|
||||||
|
model.sync = function(method, model, options) {
|
||||||
|
options.success({i: ++i});
|
||||||
|
};
|
||||||
|
model.fetch({parse: false});
|
||||||
|
equal(model.get('i'), i);
|
||||||
|
model.save(null, {parse: false});
|
||||||
|
equal(model.get('i'), i);
|
||||||
|
});
|
||||||
|
|
||||||
test("save with PATCH", function() {
|
test("save with PATCH", function() {
|
||||||
doc.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4});
|
doc.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4});
|
||||||
doc.save();
|
doc.save();
|
||||||
|
|||||||
2
vendor/backbone/test/router.js
vendored
2
vendor/backbone/test/router.js
vendored
@@ -918,7 +918,7 @@
|
|||||||
|
|
||||||
test('#3358 - pushState to hashChange transition with search params', 1, function() {
|
test('#3358 - pushState to hashChange transition with search params', 1, function() {
|
||||||
Backbone.history.stop();
|
Backbone.history.stop();
|
||||||
location.replace('/root?foo=bar');
|
location.replace('http://example.com/root?foo=bar');
|
||||||
location.replace = function(url) {
|
location.replace = function(url) {
|
||||||
strictEqual(url, '/root#?foo=bar');
|
strictEqual(url, '/root#?foo=bar');
|
||||||
};
|
};
|
||||||
|
|||||||
42
vendor/backbone/test/view.js
vendored
42
vendor/backbone/test/view.js
vendored
@@ -48,6 +48,11 @@
|
|||||||
strictEqual(new View().one, 1);
|
strictEqual(new View().one, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("render", 1, function() {
|
||||||
|
var view = new Backbone.View;
|
||||||
|
equal(view.render(), view, '#render returns the view instance');
|
||||||
|
});
|
||||||
|
|
||||||
test("delegateEvents", 6, function() {
|
test("delegateEvents", 6, function() {
|
||||||
var counter1 = 0, counter2 = 0;
|
var counter1 = 0, counter2 = 0;
|
||||||
|
|
||||||
@@ -72,7 +77,7 @@
|
|||||||
equal(counter2, 3);
|
equal(counter2, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("delegate", 2, function() {
|
test("delegate", 3, function() {
|
||||||
var view = new Backbone.View({el: '#testElement'});
|
var view = new Backbone.View({el: '#testElement'});
|
||||||
view.delegate('click', 'h1', function() {
|
view.delegate('click', 'h1', function() {
|
||||||
ok(true);
|
ok(true);
|
||||||
@@ -81,6 +86,8 @@
|
|||||||
ok(true);
|
ok(true);
|
||||||
});
|
});
|
||||||
view.$('h1').trigger('click');
|
view.$('h1').trigger('click');
|
||||||
|
|
||||||
|
equal(view.delegate(), view, '#delegate returns the view instance');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("delegateEvents allows functions for callbacks", 3, function() {
|
test("delegateEvents allows functions for callbacks", 3, function() {
|
||||||
@@ -112,7 +119,7 @@
|
|||||||
view.$el.trigger('click');
|
view.$el.trigger('click');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("undelegateEvents", 6, function() {
|
test("undelegateEvents", 7, function() {
|
||||||
var counter1 = 0, counter2 = 0;
|
var counter1 = 0, counter2 = 0;
|
||||||
|
|
||||||
var view = new Backbone.View({el: '#testElement'});
|
var view = new Backbone.View({el: '#testElement'});
|
||||||
@@ -135,9 +142,11 @@
|
|||||||
view.$('h1').trigger('click');
|
view.$('h1').trigger('click');
|
||||||
equal(counter1, 2);
|
equal(counter1, 2);
|
||||||
equal(counter2, 3);
|
equal(counter2, 3);
|
||||||
|
|
||||||
|
equal(view.undelegateEvents(), view, '#undelegateEvents returns the view instance');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("undelegate", 0, function() {
|
test("undelegate", 1, function() {
|
||||||
view = new Backbone.View({el: '#testElement'});
|
view = new Backbone.View({el: '#testElement'});
|
||||||
view.delegate('click', function() { ok(false); });
|
view.delegate('click', function() { ok(false); });
|
||||||
view.delegate('click', 'h1', function() { ok(false); });
|
view.delegate('click', 'h1', function() { ok(false); });
|
||||||
@@ -146,6 +155,8 @@
|
|||||||
|
|
||||||
view.$('h1').trigger('click');
|
view.$('h1').trigger('click');
|
||||||
view.$el.trigger('click');
|
view.$el.trigger('click');
|
||||||
|
|
||||||
|
equal(view.undelegate(), view, '#undelegate returns the view instance');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("undelegate with passed handler", 1, function() {
|
test("undelegate with passed handler", 1, function() {
|
||||||
@@ -387,14 +398,14 @@
|
|||||||
equal(counter, 2);
|
equal(counter, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("remove", 1, function() {
|
test("remove", 2, function() {
|
||||||
var view = new Backbone.View;
|
var view = new Backbone.View;
|
||||||
document.body.appendChild(view.el);
|
document.body.appendChild(view.el);
|
||||||
|
|
||||||
view.delegate('click', function() { ok(false); });
|
view.delegate('click', function() { ok(false); });
|
||||||
view.listenTo(view, 'all x', function() { ok(false); });
|
view.listenTo(view, 'all x', function() { ok(false); });
|
||||||
|
|
||||||
view.remove();
|
equal(view.remove(), view, '#remove returns the view instance');
|
||||||
view.$el.trigger('click');
|
view.$el.trigger('click');
|
||||||
view.trigger('x');
|
view.trigger('x');
|
||||||
|
|
||||||
@@ -402,4 +413,25 @@
|
|||||||
notEqual(view.el.parentNode, document.body);
|
notEqual(view.el.parentNode, document.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("setElement", 3, function() {
|
||||||
|
var view = new Backbone.View({
|
||||||
|
events: {
|
||||||
|
click: function() { ok(false); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
view.events = {
|
||||||
|
click: function() { ok(true); }
|
||||||
|
};
|
||||||
|
var oldEl = view.el;
|
||||||
|
var $oldEl = view.$el;
|
||||||
|
|
||||||
|
view.setElement(document.createElement('div'));
|
||||||
|
|
||||||
|
$oldEl.click();
|
||||||
|
view.$el.click();
|
||||||
|
|
||||||
|
notEqual(oldEl, view.el);
|
||||||
|
notEqual($oldEl, view.$el);
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user