mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Update vendor/backbone to 1.2.1.
This commit is contained in:
235
vendor/backbone/backbone.js
vendored
235
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
|
||||
// Backbone may be freely distributed under the MIT license.
|
||||
@@ -40,12 +40,11 @@
|
||||
// restored later on, if `noConflict` is used.
|
||||
var previousBackbone = root.Backbone;
|
||||
|
||||
// Create local references to array methods we'll want to use later.
|
||||
var array = [];
|
||||
var slice = array.slice;
|
||||
// Create a local reference to a common array method we'll want to use later.
|
||||
var slice = [].slice;
|
||||
|
||||
// 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
|
||||
// the `$` variable.
|
||||
@@ -69,6 +68,35 @@
|
||||
// form param named `model`.
|
||||
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
|
||||
// ---------------
|
||||
|
||||
@@ -96,6 +124,7 @@
|
||||
var i = 0, names;
|
||||
if (name && typeof name === 'object') {
|
||||
// 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++) {
|
||||
memo = iteratee(memo, names[i], name[names[i]], opts);
|
||||
}
|
||||
@@ -205,7 +234,7 @@
|
||||
// No events to consider.
|
||||
if (!events) return;
|
||||
|
||||
var i = 0, length, listening;
|
||||
var i = 0, listening;
|
||||
var context = options.context, listeners = options.listeners;
|
||||
|
||||
// Delete all events listeners and "drop" events.
|
||||
@@ -274,7 +303,7 @@
|
||||
};
|
||||
|
||||
// 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) {
|
||||
if (callback) {
|
||||
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.
|
||||
Events.bind = Events.on;
|
||||
Events.unbind = Events.off;
|
||||
@@ -444,10 +444,10 @@
|
||||
// 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.
|
||||
set: function(key, val, options) {
|
||||
var attr, attrs, unset, changes, silent, changing, prev, current;
|
||||
if (key == null) return this;
|
||||
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
var attrs;
|
||||
if (typeof key === 'object') {
|
||||
attrs = key;
|
||||
options = val;
|
||||
@@ -461,29 +461,32 @@
|
||||
if (!this._validate(attrs, options)) return false;
|
||||
|
||||
// Extract attributes and options.
|
||||
unset = options.unset;
|
||||
silent = options.silent;
|
||||
changes = [];
|
||||
changing = this._changing;
|
||||
var unset = options.unset;
|
||||
var silent = options.silent;
|
||||
var changes = [];
|
||||
var changing = this._changing;
|
||||
this._changing = true;
|
||||
|
||||
if (!changing) {
|
||||
this._previousAttributes = _.clone(this.attributes);
|
||||
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`.
|
||||
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
||||
|
||||
// For each `set` attribute, update or delete the current value.
|
||||
for (attr in attrs) {
|
||||
for (var attr in attrs) {
|
||||
val = attrs[attr];
|
||||
if (!_.isEqual(current[attr], val)) changes.push(attr);
|
||||
if (!_.isEqual(prev[attr], val)) {
|
||||
this.changed[attr] = val;
|
||||
changed[attr] = val;
|
||||
} else {
|
||||
delete this.changed[attr];
|
||||
delete changed[attr];
|
||||
}
|
||||
unset ? delete current[attr] : current[attr] = val;
|
||||
}
|
||||
@@ -539,13 +542,14 @@
|
||||
// determining if there *would be* a change.
|
||||
changedAttributes: function(diff) {
|
||||
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
|
||||
var val, changed = false;
|
||||
var old = this._changing ? this._previousAttributes : this.attributes;
|
||||
var changed = {};
|
||||
for (var attr in diff) {
|
||||
if (_.isEqual(old[attr], (val = diff[attr]))) continue;
|
||||
(changed || (changed = {}))[attr] = val;
|
||||
var val = diff[attr];
|
||||
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
|
||||
@@ -564,12 +568,12 @@
|
||||
// Fetch the model from the server, merging the response with the model's
|
||||
// local attributes. Any changed attributes will trigger a "change" event.
|
||||
fetch: function(options) {
|
||||
options = options ? _.clone(options) : {};
|
||||
if (options.parse === void 0) options.parse = true;
|
||||
options = _.extend({parse: true}, options);
|
||||
var model = this;
|
||||
var success = options.success;
|
||||
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);
|
||||
model.trigger('sync', model, resp, options);
|
||||
};
|
||||
@@ -581,9 +585,8 @@
|
||||
// If the server returns an attributes hash that differs, the model's
|
||||
// state will be `set` again.
|
||||
save: function(key, val, options) {
|
||||
var attrs, method, xhr, attributes = this.attributes, wait;
|
||||
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
var attrs;
|
||||
if (key == null || typeof key === 'object') {
|
||||
attrs = key;
|
||||
options = val;
|
||||
@@ -591,8 +594,8 @@
|
||||
(attrs = {})[key] = val;
|
||||
}
|
||||
|
||||
options = _.extend({validate: true}, options);
|
||||
wait = options.wait;
|
||||
options = _.extend({validate: true, parse: true}, options);
|
||||
var wait = options.wait;
|
||||
|
||||
// If we're not waiting and attributes exist, save acts as
|
||||
// `set(attr).save(null, opts)` with validation. Otherwise, check if
|
||||
@@ -603,35 +606,31 @@
|
||||
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)
|
||||
// updated with the server-side state.
|
||||
if (options.parse === void 0) options.parse = true;
|
||||
var model = this;
|
||||
var success = options.success;
|
||||
var attributes = this.attributes;
|
||||
options.success = function(resp) {
|
||||
// Ensure attributes are restored during synchronous saves.
|
||||
model.attributes = attributes;
|
||||
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
|
||||
if (wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
|
||||
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
|
||||
return false;
|
||||
}
|
||||
if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
|
||||
if (serverAttrs && !model.set(serverAttrs, options)) return false;
|
||||
if (success) success.call(options.context, model, resp, options);
|
||||
model.trigger('sync', model, resp, 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;
|
||||
xhr = this.sync(method, this, options);
|
||||
var xhr = this.sync(method, this, options);
|
||||
|
||||
// Restore attributes.
|
||||
if (attrs && wait) this.attributes = attributes;
|
||||
this.attributes = attributes;
|
||||
|
||||
return xhr;
|
||||
},
|
||||
@@ -676,8 +675,8 @@
|
||||
_.result(this.collection, 'url') ||
|
||||
urlError();
|
||||
if (this.isNew()) return base;
|
||||
var id = this.id || this.attributes[this.idAttribute];
|
||||
return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(id);
|
||||
var id = this.get(this.idAttribute);
|
||||
return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
|
||||
},
|
||||
|
||||
// **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.
|
||||
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,
|
||||
@@ -761,7 +760,7 @@
|
||||
// The JSON representation of a Collection is an array of the
|
||||
// models' attributes.
|
||||
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.
|
||||
@@ -776,12 +775,12 @@
|
||||
|
||||
// Remove a model, or a list of models from the set.
|
||||
remove: function(models, options) {
|
||||
var singular = !_.isArray(models), removed;
|
||||
options = _.extend({}, options);
|
||||
var singular = !_.isArray(models);
|
||||
models = singular ? [models] : _.clone(models);
|
||||
options || (options = {});
|
||||
removed = this._removeModels(models, options);
|
||||
var removed = this._removeModels(models, 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,
|
||||
@@ -790,7 +789,7 @@
|
||||
// the core operation for updating the data contained by the collection.
|
||||
set: function(models, options) {
|
||||
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);
|
||||
models = singular ? (models ? [models] : []) : models.slice();
|
||||
var id, model, attrs, existing, sort;
|
||||
@@ -910,8 +909,7 @@
|
||||
// Remove a model from the end of the collection.
|
||||
pop: function(options) {
|
||||
var model = this.at(this.length - 1);
|
||||
this.remove(model, options);
|
||||
return model;
|
||||
return this.remove(model, options);
|
||||
},
|
||||
|
||||
// Add a model to the beginning of the collection.
|
||||
@@ -922,8 +920,7 @@
|
||||
// Remove a model from the beginning of the collection.
|
||||
shift: function(options) {
|
||||
var model = this.at(0);
|
||||
this.remove(model, options);
|
||||
return model;
|
||||
return this.remove(model, options);
|
||||
},
|
||||
|
||||
// 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
|
||||
// data will be passed through the `reset` method instead of `set`.
|
||||
fetch: function(options) {
|
||||
options = options ? _.clone(options) : {};
|
||||
if (options.parse === void 0) options.parse = true;
|
||||
options = _.extend({parse: true}, options);
|
||||
var success = options.success;
|
||||
var collection = this;
|
||||
options.success = function(resp) {
|
||||
@@ -1006,7 +1002,8 @@
|
||||
create: function(model, options) {
|
||||
options = options ? _.clone(options) : {};
|
||||
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);
|
||||
var collection = this;
|
||||
var success = options.success;
|
||||
@@ -1060,31 +1057,27 @@
|
||||
return false;
|
||||
},
|
||||
|
||||
// Internal method called by both remove and set. Does not trigger any
|
||||
// additional events. Returns true if anything was actually removed.
|
||||
// Internal method called by both remove and set.
|
||||
// Returns removed models, or false if nothing is removed.
|
||||
_removeModels: function(models, options) {
|
||||
var i, l, index, model, removed = false;
|
||||
for (var i = 0, j = 0; i < models.length; i++) {
|
||||
var model = models[i] = this.get(models[i]);
|
||||
var removed = [];
|
||||
for (var i = 0; i < models.length; i++) {
|
||||
var model = this.get(models[i]);
|
||||
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);
|
||||
this.models.splice(index, 1);
|
||||
this.length--;
|
||||
|
||||
if (!options.silent) {
|
||||
options.index = index;
|
||||
model.trigger('remove', model, this, options);
|
||||
}
|
||||
models[j++] = model;
|
||||
|
||||
removed.push(model);
|
||||
this._removeReference(model, options);
|
||||
removed = true;
|
||||
}
|
||||
// We only need to slice if models array should be smaller, which is
|
||||
// caused by some models not actually getting removed.
|
||||
if (models.length !== j) models = models.slice(0, j);
|
||||
return removed;
|
||||
return removed.length ? removed : false;
|
||||
},
|
||||
|
||||
// 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.
|
||||
_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;
|
||||
model.off('all', this._onModelEvent, this);
|
||||
},
|
||||
@@ -1133,7 +1129,7 @@
|
||||
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,
|
||||
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,
|
||||
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
|
||||
isEmpty: 1, chain: 1, sample: 3, partition: 3 };
|
||||
@@ -1170,7 +1166,6 @@
|
||||
// if an existing element is not provided...
|
||||
var View = Backbone.View = function(options) {
|
||||
this.cid = _.uniqueId('view');
|
||||
options || (options = {});
|
||||
_.extend(this, _.pick(options, viewOptions));
|
||||
this._ensureElement();
|
||||
this.initialize.apply(this, arguments);
|
||||
@@ -1253,11 +1248,12 @@
|
||||
// Uses event delegation for efficiency.
|
||||
// Omitting the selector binds the event to `this.el`.
|
||||
delegateEvents: function(events) {
|
||||
if (!(events || (events = _.result(this, 'events')))) return this;
|
||||
events || (events = _.result(this, 'events'));
|
||||
if (!events) return this;
|
||||
this.undelegateEvents();
|
||||
for (var key in events) {
|
||||
var method = events[key];
|
||||
if (!_.isFunction(method)) method = this[events[key]];
|
||||
if (!_.isFunction(method)) method = this[method];
|
||||
if (!method) continue;
|
||||
var match = key.match(delegateEventSplitter);
|
||||
this.delegate(match[1], match[2], _.bind(method, this));
|
||||
@@ -1270,6 +1266,7 @@
|
||||
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
|
||||
delegate: function(eventName, selector, listener) {
|
||||
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Clears all callbacks previously bound to the view by `delegateEvents`.
|
||||
@@ -1284,6 +1281,7 @@
|
||||
// `selector` and `listener` are both optional.
|
||||
undelegate: function(eventName, 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
|
||||
@@ -1647,15 +1645,16 @@
|
||||
// support the `hashchange` event, HTML5 history, or the user wants
|
||||
// `hashChange` but not `pushState`.
|
||||
if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = 'javascript:0';
|
||||
iframe.style.display = 'none';
|
||||
iframe.tabIndex = -1;
|
||||
this.iframe = document.createElement('iframe');
|
||||
this.iframe.src = 'javascript:0';
|
||||
this.iframe.style.display = 'none';
|
||||
this.iframe.tabIndex = -1;
|
||||
var body = document.body;
|
||||
// Using `appendChild` will throw on IE < 9 if the document is not ready.
|
||||
this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow;
|
||||
this.iframe.document.open().close();
|
||||
this.iframe.location.hash = '#' + this.fragment;
|
||||
var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow;
|
||||
iWindow.document.open();
|
||||
iWindow.document.close();
|
||||
iWindow.location.hash = '#' + this.fragment;
|
||||
}
|
||||
|
||||
// Add a cross-platform `addEventListener` shim for older browsers.
|
||||
@@ -1693,7 +1692,7 @@
|
||||
|
||||
// Clean up the iframe if necessary.
|
||||
if (this.iframe) {
|
||||
document.body.removeChild(this.iframe.frameElement);
|
||||
document.body.removeChild(this.iframe);
|
||||
this.iframe = null;
|
||||
}
|
||||
|
||||
@@ -1716,7 +1715,7 @@
|
||||
// If the user pressed the back button, the iframe's hash will have
|
||||
// changed and we should use that for comparison.
|
||||
if (current === this.fragment && this.iframe) {
|
||||
current = this.getHash(this.iframe);
|
||||
current = this.getHash(this.iframe.contentWindow);
|
||||
}
|
||||
|
||||
if (current === this.fragment) return false;
|
||||
@@ -1774,12 +1773,18 @@
|
||||
// fragment to store history.
|
||||
} else if (this._wantsHashChange) {
|
||||
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
|
||||
// history entry on hash-tag change. When replace is true, we don't
|
||||
// want this.
|
||||
if (!options.replace) this.iframe.document.open().close();
|
||||
this._updateHash(this.iframe.location, fragment, options.replace);
|
||||
if (!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-
|
||||
|
||||
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]);
|
||||
});
|
||||
|
||||
test("remove", 7, function() {
|
||||
test("remove", 10, function() {
|
||||
var removed = null;
|
||||
var otherRemoved = null;
|
||||
var result = null;
|
||||
col.on('remove', function(model, col, options) {
|
||||
removed = model.get('label');
|
||||
equal(options.index, 3);
|
||||
});
|
||||
otherCol.on('remove', function(model, col, options) {
|
||||
otherRemoved = true;
|
||||
});
|
||||
result = col.remove(d);
|
||||
equal(removed, 'd');
|
||||
strictEqual(result, d);
|
||||
@@ -317,7 +313,13 @@
|
||||
strictEqual(result, undefined);
|
||||
equal(col.length, 3);
|
||||
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() {
|
||||
@@ -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() {
|
||||
var ValidatingModel = Backbone.Model.extend({
|
||||
validate: function(attrs) {
|
||||
@@ -1605,4 +1621,19 @@
|
||||
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);
|
||||
});
|
||||
|
||||
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() {
|
||||
var a = _.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);
|
||||
});
|
||||
|
||||
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() {
|
||||
doc.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4});
|
||||
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() {
|
||||
Backbone.history.stop();
|
||||
location.replace('/root?foo=bar');
|
||||
location.replace('http://example.com/root?foo=bar');
|
||||
location.replace = function(url) {
|
||||
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);
|
||||
});
|
||||
|
||||
test("render", 1, function() {
|
||||
var view = new Backbone.View;
|
||||
equal(view.render(), view, '#render returns the view instance');
|
||||
});
|
||||
|
||||
test("delegateEvents", 6, function() {
|
||||
var counter1 = 0, counter2 = 0;
|
||||
|
||||
@@ -72,7 +77,7 @@
|
||||
equal(counter2, 3);
|
||||
});
|
||||
|
||||
test("delegate", 2, function() {
|
||||
test("delegate", 3, function() {
|
||||
var view = new Backbone.View({el: '#testElement'});
|
||||
view.delegate('click', 'h1', function() {
|
||||
ok(true);
|
||||
@@ -81,6 +86,8 @@
|
||||
ok(true);
|
||||
});
|
||||
view.$('h1').trigger('click');
|
||||
|
||||
equal(view.delegate(), view, '#delegate returns the view instance');
|
||||
});
|
||||
|
||||
test("delegateEvents allows functions for callbacks", 3, function() {
|
||||
@@ -112,7 +119,7 @@
|
||||
view.$el.trigger('click');
|
||||
});
|
||||
|
||||
test("undelegateEvents", 6, function() {
|
||||
test("undelegateEvents", 7, function() {
|
||||
var counter1 = 0, counter2 = 0;
|
||||
|
||||
var view = new Backbone.View({el: '#testElement'});
|
||||
@@ -135,9 +142,11 @@
|
||||
view.$('h1').trigger('click');
|
||||
equal(counter1, 2);
|
||||
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.delegate('click', function() { ok(false); });
|
||||
view.delegate('click', 'h1', function() { ok(false); });
|
||||
@@ -146,6 +155,8 @@
|
||||
|
||||
view.$('h1').trigger('click');
|
||||
view.$el.trigger('click');
|
||||
|
||||
equal(view.undelegate(), view, '#undelegate returns the view instance');
|
||||
});
|
||||
|
||||
test("undelegate with passed handler", 1, function() {
|
||||
@@ -387,14 +398,14 @@
|
||||
equal(counter, 2);
|
||||
});
|
||||
|
||||
test("remove", 1, function() {
|
||||
test("remove", 2, function() {
|
||||
var view = new Backbone.View;
|
||||
document.body.appendChild(view.el);
|
||||
|
||||
view.delegate('click', 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.trigger('x');
|
||||
|
||||
@@ -402,4 +413,25 @@
|
||||
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