mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Update deps.
This commit is contained in:
306
vendor/backbone/backbone.js
vendored
306
vendor/backbone/backbone.js
vendored
@@ -36,7 +36,9 @@
|
||||
|
||||
// Create local references to array methods we'll want to use later.
|
||||
var array = [];
|
||||
var push = array.push;
|
||||
var slice = array.slice;
|
||||
var splice = array.splice;
|
||||
|
||||
// Current version of the library. Keep in sync with `package.json`.
|
||||
Backbone.VERSION = '1.1.2';
|
||||
@@ -106,46 +108,27 @@
|
||||
// callbacks for the event. If `name` is null, removes all bound
|
||||
// callbacks for all events.
|
||||
off: function(name, callback, context) {
|
||||
var retain, ev, events, names, i, l, j, k;
|
||||
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
|
||||
|
||||
// Remove all callbacks for all events.
|
||||
if (!name && !callback && !context) {
|
||||
this._events = void 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
var names = name ? [name] : _.keys(this._events);
|
||||
for (var i = 0, length = names.length; i < length; i++) {
|
||||
names = name ? [name] : _.keys(this._events);
|
||||
for (i = 0, l = names.length; i < l; i++) {
|
||||
name = names[i];
|
||||
|
||||
// Bail out if there are no events stored.
|
||||
var events = this._events[name];
|
||||
if (!events) continue;
|
||||
|
||||
// Remove all callbacks for this event.
|
||||
if (!callback && !context) {
|
||||
delete this._events[name];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find any remaining events.
|
||||
var remaining = [];
|
||||
for (var j = 0, k = events.length; j < k; j++) {
|
||||
var event = events[j];
|
||||
if (
|
||||
callback && callback !== event.callback &&
|
||||
callback !== event.callback._callback ||
|
||||
context && context !== event.context
|
||||
) {
|
||||
remaining.push(event);
|
||||
if (events = this._events[name]) {
|
||||
this._events[name] = retain = [];
|
||||
if (callback || context) {
|
||||
for (j = 0, k = events.length; j < k; j++) {
|
||||
ev = events[j];
|
||||
if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
|
||||
(context && context !== ev.context)) {
|
||||
retain.push(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace events if there are any remaining. Otherwise, clean up.
|
||||
if (remaining.length) {
|
||||
this._events[name] = remaining;
|
||||
} else {
|
||||
delete this._events[name];
|
||||
if (!retain.length) delete this._events[name];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +188,7 @@
|
||||
// Handle space separated event names.
|
||||
if (eventSplitter.test(name)) {
|
||||
var names = name.split(eventSplitter);
|
||||
for (var i = 0, length = names.length; i < length; i++) {
|
||||
for (var i = 0, l = names.length; i < l; i++) {
|
||||
obj[action].apply(obj, [names[i]].concat(rest));
|
||||
}
|
||||
return false;
|
||||
@@ -370,7 +353,7 @@
|
||||
// Trigger all relevant attribute changes.
|
||||
if (!silent) {
|
||||
if (changes.length) this._pending = options;
|
||||
for (var i = 0, length = changes.length; i < length; i++) {
|
||||
for (var i = 0, l = changes.length; i < l; i++) {
|
||||
this.trigger('change:' + changes[i], this, current[changes[i]], options);
|
||||
}
|
||||
}
|
||||
@@ -595,7 +578,6 @@
|
||||
|
||||
// Mix in each Underscore method as a proxy to `Model#attributes`.
|
||||
_.each(modelMethods, function(method) {
|
||||
if (!_[method]) return;
|
||||
Model.prototype[method] = function() {
|
||||
var args = slice.call(arguments);
|
||||
args.unshift(this.attributes);
|
||||
@@ -607,7 +589,7 @@
|
||||
// -------------------
|
||||
|
||||
// If models tend to represent a single row of data, a Backbone Collection is
|
||||
// more analogous to a table full of data ... or a small slice or page of that
|
||||
// more analagous to a table full of data ... or a small slice or page of that
|
||||
// table, or a collection of rows that belong together for a particular reason
|
||||
// -- all of the messages in this particular folder, all of the documents
|
||||
// belonging to this particular author, and so on. Collections maintain
|
||||
@@ -661,12 +643,13 @@
|
||||
var singular = !_.isArray(models);
|
||||
models = singular ? [models] : _.clone(models);
|
||||
options || (options = {});
|
||||
for (var i = 0, length = models.length; i < length; i++) {
|
||||
var model = models[i] = this.get(models[i]);
|
||||
var i, l, index, model;
|
||||
for (i = 0, l = models.length; i < l; i++) {
|
||||
model = models[i] = this.get(models[i]);
|
||||
if (!model) continue;
|
||||
delete this._byId[model.id];
|
||||
delete this._byId[model.cid];
|
||||
var index = this.indexOf(model);
|
||||
index = this.indexOf(model);
|
||||
this.models.splice(index, 1);
|
||||
this.length--;
|
||||
if (!options.silent) {
|
||||
@@ -686,9 +669,10 @@
|
||||
options = _.defaults({}, options, setOptions);
|
||||
if (options.parse) models = this.parse(models, options);
|
||||
var singular = !_.isArray(models);
|
||||
models = singular ? (models ? [models] : []) : models.slice();
|
||||
var id, model, attrs, existing, sort;
|
||||
models = singular ? (models ? [models] : []) : _.clone(models);
|
||||
var i, l, id, model, attrs, existing, sort;
|
||||
var at = options.at;
|
||||
var targetModel = this.model;
|
||||
var sortable = this.comparator && (at == null) && options.sort !== false;
|
||||
var sortAttr = _.isString(this.comparator) ? this.comparator : null;
|
||||
var toAdd = [], toRemove = [], modelMap = {};
|
||||
@@ -697,12 +681,12 @@
|
||||
|
||||
// Turn bare objects into model references, and prevent invalid models
|
||||
// from being added.
|
||||
for (var i = 0, length = models.length; i < length; i++) {
|
||||
for (i = 0, l = models.length; i < l; i++) {
|
||||
attrs = models[i] || {};
|
||||
if (this._isModel(attrs)) {
|
||||
if (attrs instanceof Model) {
|
||||
id = model = attrs;
|
||||
} else {
|
||||
id = attrs[this.model.prototype.idAttribute || 'id'];
|
||||
id = attrs[targetModel.prototype.idAttribute || 'id'];
|
||||
}
|
||||
|
||||
// If a duplicate is found, prevent it from being added and
|
||||
@@ -727,14 +711,13 @@
|
||||
|
||||
// Do not add multiple models with the same `id`.
|
||||
model = existing || model;
|
||||
if (!model) continue;
|
||||
if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
|
||||
modelMap[model.id] = true;
|
||||
}
|
||||
|
||||
// Remove nonexistent models if appropriate.
|
||||
if (remove) {
|
||||
for (var i = 0, length = this.length; i < length; i++) {
|
||||
for (i = 0, l = this.length; i < l; ++i) {
|
||||
if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
|
||||
}
|
||||
if (toRemove.length) this.remove(toRemove, options);
|
||||
@@ -745,13 +728,13 @@
|
||||
if (sortable) sort = true;
|
||||
this.length += toAdd.length;
|
||||
if (at != null) {
|
||||
for (var i = 0, length = toAdd.length; i < length; i++) {
|
||||
for (i = 0, l = toAdd.length; i < l; i++) {
|
||||
this.models.splice(at + i, 0, toAdd[i]);
|
||||
}
|
||||
} else {
|
||||
if (order) this.models.length = 0;
|
||||
var orderedModels = order || toAdd;
|
||||
for (var i = 0, length = orderedModels.length; i < length; i++) {
|
||||
for (i = 0, l = orderedModels.length; i < l; i++) {
|
||||
this.models.push(orderedModels[i]);
|
||||
}
|
||||
}
|
||||
@@ -762,7 +745,7 @@
|
||||
|
||||
// Unless silenced, it's time to fire all appropriate add/sort events.
|
||||
if (!options.silent) {
|
||||
for (var i = 0, length = toAdd.length; i < length; i++) {
|
||||
for (i = 0, l = toAdd.length; i < l; i++) {
|
||||
(model = toAdd[i]).trigger('add', model, this, options);
|
||||
}
|
||||
if (sort || (order && order.length)) this.trigger('sort', this, options);
|
||||
@@ -778,7 +761,7 @@
|
||||
// Useful for bulk operations and optimizations.
|
||||
reset: function(models, options) {
|
||||
options || (options = {});
|
||||
for (var i = 0, length = this.models.length; i < length; i++) {
|
||||
for (var i = 0, l = this.models.length; i < l; i++) {
|
||||
this._removeReference(this.models[i], options);
|
||||
}
|
||||
options.previousModels = this.models;
|
||||
@@ -912,10 +895,7 @@
|
||||
|
||||
// Create a new collection with an identical list of models as this one.
|
||||
clone: function() {
|
||||
return new this.constructor(this.models, {
|
||||
model: this.model,
|
||||
comparator: this.comparator
|
||||
});
|
||||
return new this.constructor(this.models);
|
||||
},
|
||||
|
||||
// Private method to reset all internal state. Called when the collection
|
||||
@@ -929,10 +909,7 @@
|
||||
// Prepare a hash of attributes (or other model) to be added to this
|
||||
// collection.
|
||||
_prepareModel: function(attrs, options) {
|
||||
if (this._isModel(attrs)) {
|
||||
if (!attrs.collection) attrs.collection = this;
|
||||
return attrs;
|
||||
}
|
||||
if (attrs instanceof Model) return attrs;
|
||||
options = options ? _.clone(options) : {};
|
||||
options.collection = this;
|
||||
var model = new this.model(attrs, options);
|
||||
@@ -941,16 +918,11 @@
|
||||
return false;
|
||||
},
|
||||
|
||||
// Method for checking whether an object should be considered a model for
|
||||
// the purposes of adding to the collection.
|
||||
_isModel: function (model) {
|
||||
return model instanceof Model;
|
||||
},
|
||||
|
||||
// Internal method to create a model's ties to a collection.
|
||||
_addReference: function(model, options) {
|
||||
this._byId[model.cid] = model;
|
||||
if (model.id != null) this._byId[model.id] = model;
|
||||
if (!model.collection) model.collection = this;
|
||||
model.on('all', this._onModelEvent, this);
|
||||
},
|
||||
|
||||
@@ -984,11 +956,10 @@
|
||||
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
|
||||
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
|
||||
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
|
||||
'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition'];
|
||||
'lastIndexOf', 'isEmpty', 'chain', 'sample'];
|
||||
|
||||
// Mix in each Underscore method as a proxy to `Collection#models`.
|
||||
_.each(methods, function(method) {
|
||||
if (!_[method]) return;
|
||||
Collection.prototype[method] = function() {
|
||||
var args = slice.call(arguments);
|
||||
args.unshift(this.models);
|
||||
@@ -1001,7 +972,6 @@
|
||||
|
||||
// Use attributes instead of properties.
|
||||
_.each(attributeMethods, function(method) {
|
||||
if (!_[method]) return;
|
||||
Collection.prototype[method] = function(value, context) {
|
||||
var iterator = _.isFunction(value) ? value : function(model) {
|
||||
return model.get(value);
|
||||
@@ -1029,6 +999,7 @@
|
||||
_.extend(this, _.pick(options, viewOptions));
|
||||
this._ensureElement();
|
||||
this.initialize.apply(this, arguments);
|
||||
this.delegateEvents();
|
||||
};
|
||||
|
||||
// Cached regex to split keys for `delegate`.
|
||||
@@ -1063,35 +1034,19 @@
|
||||
// Remove this view by taking the element out of the DOM, and removing any
|
||||
// applicable Backbone.Events listeners.
|
||||
remove: function() {
|
||||
this._removeElement();
|
||||
this.$el.remove();
|
||||
this.stopListening();
|
||||
return this;
|
||||
},
|
||||
|
||||
// Remove this view's element from the document and all event listeners
|
||||
// attached to it. Exposed for subclasses using an alternative DOM
|
||||
// manipulation API.
|
||||
_removeElement: function() {
|
||||
this.$el.remove();
|
||||
},
|
||||
|
||||
// Change the view's element (`this.el` property) and re-delegate the
|
||||
// view's events on the new element.
|
||||
setElement: function(element) {
|
||||
this.undelegateEvents();
|
||||
this._setElement(element);
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
// Creates the `this.el` and `this.$el` references for this view using the
|
||||
// given `el` and a hash of `attributes`. `el` can be a CSS selector or an
|
||||
// HTML string, a jQuery context or an element. Subclasses can override
|
||||
// this to utilize an alternative DOM manipulation API and are only required
|
||||
// to set the `this.el` property.
|
||||
_setElement: function(el) {
|
||||
this.$el = el instanceof Backbone.$ ? el : Backbone.$(el);
|
||||
// Change the view's element (`this.el` property), including event
|
||||
// re-delegation.
|
||||
setElement: function(element, delegate) {
|
||||
if (this.$el) this.undelegateEvents();
|
||||
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
|
||||
this.el = this.$el[0];
|
||||
if (delegate !== false) this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
// Set callbacks, where `this.events` is a hash of
|
||||
@@ -1107,6 +1062,8 @@
|
||||
// pairs. Callbacks will be bound to the view, with `this` set properly.
|
||||
// Uses event delegation for efficiency.
|
||||
// Omitting the selector binds the event to `this.el`.
|
||||
// This only works for delegate-able events: not `focus`, `blur`, and
|
||||
// not `change`, `submit`, and `reset` in Internet Explorer.
|
||||
delegateEvents: function(events) {
|
||||
if (!(events || (events = _.result(this, 'events')))) return this;
|
||||
this.undelegateEvents();
|
||||
@@ -1114,39 +1071,28 @@
|
||||
var method = events[key];
|
||||
if (!_.isFunction(method)) method = this[events[key]];
|
||||
if (!method) continue;
|
||||
|
||||
var match = key.match(delegateEventSplitter);
|
||||
this.delegate(match[1], match[2], _.bind(method, this));
|
||||
var eventName = match[1], selector = match[2];
|
||||
method = _.bind(method, this);
|
||||
eventName += '.delegateEvents' + this.cid;
|
||||
if (selector === '') {
|
||||
this.$el.on(eventName, method);
|
||||
} else {
|
||||
this.$el.on(eventName, selector, method);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// Add a single event listener to the view's element (or a child element
|
||||
// using `selector`). This only works for delegate-able events: not `focus`,
|
||||
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
|
||||
delegate: function(eventName, selector, listener) {
|
||||
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
|
||||
},
|
||||
|
||||
// Clears all callbacks previously bound to the view by `delegateEvents`.
|
||||
// Clears all callbacks previously bound to the view with `delegateEvents`.
|
||||
// You usually don't need to use this, but may wish to if you have multiple
|
||||
// Backbone views attached to the same DOM element.
|
||||
undelegateEvents: function() {
|
||||
if (this.$el) this.$el.off('.delegateEvents' + this.cid);
|
||||
this.$el.off('.delegateEvents' + this.cid);
|
||||
return this;
|
||||
},
|
||||
|
||||
// A finer-grained `undelegateEvents` for removing a single delegated event.
|
||||
// `selector` and `listener` are both optional.
|
||||
undelegate: function(eventName, selector, listener) {
|
||||
this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
|
||||
},
|
||||
|
||||
// Produces a DOM element to be assigned to your view. Exposed for
|
||||
// subclasses using an alternative DOM manipulation API.
|
||||
_createElement: function(tagName) {
|
||||
return document.createElement(tagName);
|
||||
},
|
||||
|
||||
// Ensure that the View has a DOM element to render into.
|
||||
// If `this.el` is a string, pass it through `$()`, take the first
|
||||
// matching element, and re-assign it to `el`. Otherwise, create
|
||||
@@ -1156,17 +1102,11 @@
|
||||
var attrs = _.extend({}, _.result(this, 'attributes'));
|
||||
if (this.id) attrs.id = _.result(this, 'id');
|
||||
if (this.className) attrs['class'] = _.result(this, 'className');
|
||||
this.setElement(this._createElement(_.result(this, 'tagName')));
|
||||
this._setAttributes(attrs);
|
||||
var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
|
||||
this.setElement($el, false);
|
||||
} else {
|
||||
this.setElement(_.result(this, 'el'));
|
||||
this.setElement(_.result(this, 'el'), false);
|
||||
}
|
||||
},
|
||||
|
||||
// Set attributes from a hash on this view's element. Exposed for
|
||||
// subclasses using an alternative DOM manipulation API.
|
||||
_setAttributes: function(attributes) {
|
||||
this.$el.attr(attributes);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1244,14 +1184,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Pass along `textStatus` and `errorThrown` from jQuery.
|
||||
var error = options.error;
|
||||
options.error = function(xhr, textStatus, errorThrown) {
|
||||
options.textStatus = textStatus;
|
||||
options.errorThrown = errorThrown;
|
||||
if (error) error.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Make the request, allowing the user to override any Ajax options.
|
||||
var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
|
||||
model.trigger('request', model, xhr, options);
|
||||
@@ -1319,18 +1251,17 @@
|
||||
var router = this;
|
||||
Backbone.history.route(route, function(fragment) {
|
||||
var args = router._extractParameters(route, fragment);
|
||||
if (router.execute(callback, args, name) !== false) {
|
||||
router.trigger.apply(router, ['route:' + name].concat(args));
|
||||
router.trigger('route', name, args);
|
||||
Backbone.history.trigger('route', router, name, args);
|
||||
}
|
||||
router.execute(callback, args);
|
||||
router.trigger.apply(router, ['route:' + name].concat(args));
|
||||
router.trigger('route', name, args);
|
||||
Backbone.history.trigger('route', router, name, args);
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
// Execute a route handler with the provided parameters. This is an
|
||||
// excellent place to do pre-route setup or post-route cleanup.
|
||||
execute: function(callback, args, name) {
|
||||
execute: function(callback, args) {
|
||||
if (callback) callback.apply(this, args);
|
||||
},
|
||||
|
||||
@@ -1403,6 +1334,12 @@
|
||||
// Cached regex for stripping leading and trailing slashes.
|
||||
var rootStripper = /^\/+|\/+$/g;
|
||||
|
||||
// Cached regex for detecting MSIE.
|
||||
var isExplorer = /msie [\w.]+/;
|
||||
|
||||
// Cached regex for removing a trailing slash.
|
||||
var trailingSlash = /\/$/;
|
||||
|
||||
// Cached regex for stripping urls of hash.
|
||||
var pathStripper = /#.*$/;
|
||||
|
||||
@@ -1418,8 +1355,7 @@
|
||||
|
||||
// Are we at the app root?
|
||||
atRoot: function() {
|
||||
var path = this.location.pathname.replace(/[^\/]$/, '$&/');
|
||||
return path === this.root && !this.location.search;
|
||||
return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
|
||||
},
|
||||
|
||||
// Gets the true hash value. Cannot use location.hash directly due to bug
|
||||
@@ -1429,19 +1365,14 @@
|
||||
return match ? match[1] : '';
|
||||
},
|
||||
|
||||
// Get the pathname and search params, without the root.
|
||||
getPath: function() {
|
||||
var path = decodeURI(this.location.pathname + this.location.search);
|
||||
var root = this.root.slice(0, -1);
|
||||
if (!path.indexOf(root)) path = path.slice(root.length);
|
||||
return path.slice(1);
|
||||
},
|
||||
|
||||
// Get the cross-browser normalized URL fragment from the path or hash.
|
||||
getFragment: function(fragment) {
|
||||
// Get the cross-browser normalized URL fragment, either from the URL,
|
||||
// the hash, or the override.
|
||||
getFragment: function(fragment, forcePushState) {
|
||||
if (fragment == null) {
|
||||
if (this._hasPushState || !this._wantsHashChange) {
|
||||
fragment = this.getPath();
|
||||
if (this._hasPushState || !this._wantsHashChange || forcePushState) {
|
||||
fragment = decodeURI(this.location.pathname + this.location.search);
|
||||
var root = this.root.replace(trailingSlash, '');
|
||||
if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
|
||||
} else {
|
||||
fragment = this.getHash();
|
||||
}
|
||||
@@ -1460,43 +1391,36 @@
|
||||
this.options = _.extend({root: '/'}, this.options, options);
|
||||
this.root = this.options.root;
|
||||
this._wantsHashChange = this.options.hashChange !== false;
|
||||
this._hasHashChange = 'onhashchange' in window;
|
||||
this._wantsPushState = !!this.options.pushState;
|
||||
this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
|
||||
this.fragment = this.getFragment();
|
||||
|
||||
// Add a cross-platform `addEventListener` shim for older browsers.
|
||||
var addEventListener = window.addEventListener || function (eventName, listener) {
|
||||
return attachEvent('on' + eventName, listener);
|
||||
};
|
||||
var fragment = this.getFragment();
|
||||
var docMode = document.documentMode;
|
||||
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
|
||||
|
||||
// Normalize root to always include a leading and trailing slash.
|
||||
this.root = ('/' + this.root + '/').replace(rootStripper, '/');
|
||||
|
||||
// Proxy an iframe to handle location events if the browser doesn't
|
||||
// support the `hashchange` event, HTML5 history, or the user wants
|
||||
// `hashChange` but not `pushState`.
|
||||
if (!this._hasHashChange && this._wantsHashChange && (!this._wantsPushState || !this._hasPushState)) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = 'javascript:0';
|
||||
iframe.style.display = 'none';
|
||||
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.navigate(this.fragment);
|
||||
if (oldIE && this._wantsHashChange) {
|
||||
var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
|
||||
this.iframe = frame.hide().appendTo('body')[0].contentWindow;
|
||||
this.navigate(fragment);
|
||||
}
|
||||
|
||||
// Depending on whether we're using pushState or hashes, and whether
|
||||
// 'onhashchange' is supported, determine how we check the URL state.
|
||||
if (this._hasPushState) {
|
||||
addEventListener('popstate', this.checkUrl, false);
|
||||
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
|
||||
addEventListener('hashchange', this.checkUrl, false);
|
||||
Backbone.$(window).on('popstate', this.checkUrl);
|
||||
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
|
||||
Backbone.$(window).on('hashchange', this.checkUrl);
|
||||
} else if (this._wantsHashChange) {
|
||||
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
|
||||
}
|
||||
|
||||
// Determine if we need to change the base url, for a pushState link
|
||||
// opened by a non-pushState browser.
|
||||
this.fragment = fragment;
|
||||
var loc = this.location;
|
||||
|
||||
// Transition from hashChange to pushState or vice versa if both are
|
||||
// requested.
|
||||
if (this._wantsHashChange && this._wantsPushState) {
|
||||
@@ -1504,14 +1428,16 @@
|
||||
// If we've started off with a route from a `pushState`-enabled
|
||||
// browser, but we're currently in a browser that doesn't support it...
|
||||
if (!this._hasPushState && !this.atRoot()) {
|
||||
this.location.replace(this.root + '#' + this.getPath());
|
||||
this.fragment = this.getFragment(null, true);
|
||||
this.location.replace(this.root + '#' + this.fragment);
|
||||
// Return immediately as browser will do redirect to new url
|
||||
return true;
|
||||
|
||||
// Or if we've started out with a hash-based route, but we're currently
|
||||
// in a browser where it could be `pushState`-based instead...
|
||||
} else if (this._hasPushState && this.atRoot()) {
|
||||
this.navigate(this.getHash(), {replace: true});
|
||||
} else if (this._hasPushState && this.atRoot() && loc.hash) {
|
||||
this.fragment = this.getHash().replace(routeStripper, '');
|
||||
this.history.replaceState({}, document.title, this.root + this.fragment);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1522,25 +1448,7 @@
|
||||
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
|
||||
// but possibly useful for unit testing Routers.
|
||||
stop: function() {
|
||||
// Add a cross-platform `removeEventListener` shim for older browsers.
|
||||
var removeEventListener = window.removeEventListener || function (eventName, listener) {
|
||||
return detachEvent('on' + eventName, listener);
|
||||
};
|
||||
|
||||
// Remove window listeners.
|
||||
if (this._hasPushState) {
|
||||
removeEventListener('popstate', this.checkUrl, false);
|
||||
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
|
||||
removeEventListener('hashchange', this.checkUrl, false);
|
||||
}
|
||||
|
||||
// Clean up the iframe if necessary.
|
||||
if (this.iframe) {
|
||||
document.body.removeChild(this.iframe.frameElement);
|
||||
this.iframe = null;
|
||||
}
|
||||
|
||||
// Some environments will throw when clearing an undefined interval.
|
||||
Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
|
||||
if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
|
||||
History.started = false;
|
||||
},
|
||||
@@ -1556,7 +1464,7 @@
|
||||
checkUrl: function(e) {
|
||||
var current = this.getFragment();
|
||||
if (current === this.fragment && this.iframe) {
|
||||
current = this.getHash(this.iframe);
|
||||
current = this.getFragment(this.getHash(this.iframe));
|
||||
}
|
||||
if (current === this.fragment) return false;
|
||||
if (this.iframe) this.navigate(current);
|
||||
@@ -1589,8 +1497,8 @@
|
||||
|
||||
var url = this.root + (fragment = this.getFragment(fragment || ''));
|
||||
|
||||
// Strip the hash and decode for matching.
|
||||
fragment = decodeURI(fragment.replace(pathStripper, ''));
|
||||
// Strip the hash for matching.
|
||||
fragment = fragment.replace(pathStripper, '');
|
||||
|
||||
if (this.fragment === fragment) return;
|
||||
this.fragment = fragment;
|
||||
@@ -1606,7 +1514,7 @@
|
||||
// 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.getFragment(this.getHash(this.iframe)))) {
|
||||
// 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.
|
||||
|
||||
30
vendor/backbone/test/collection.js
vendored
30
vendor/backbone/test/collection.js
vendored
@@ -60,20 +60,6 @@
|
||||
strictEqual(collection.last().get('a'), 4);
|
||||
});
|
||||
|
||||
test("clone preserves model and comparator", 3, function() {
|
||||
var Model = Backbone.Model.extend();
|
||||
var comparator = function(model){ return model.id; };
|
||||
|
||||
var collection = new Backbone.Collection([{id: 1}], {
|
||||
model: Model,
|
||||
comparator: comparator
|
||||
}).clone();
|
||||
collection.add({id: 2});
|
||||
ok(collection.at(0) instanceof Model);
|
||||
ok(collection.at(1) instanceof Model);
|
||||
strictEqual(collection.comparator, comparator);
|
||||
});
|
||||
|
||||
test("get", 6, function() {
|
||||
equal(col.get(0), d);
|
||||
equal(col.get(d.clone()), d);
|
||||
@@ -1349,20 +1335,4 @@
|
||||
equal(c.models.length, 1);
|
||||
});
|
||||
|
||||
test('#3020: #set with {add: false} should not throw.', 2, function() {
|
||||
var collection = new Backbone.Collection;
|
||||
collection.set([{id: 1}], {add: false});
|
||||
strictEqual(collection.length, 0);
|
||||
strictEqual(collection.models.length, 0);
|
||||
});
|
||||
|
||||
test("create with wait, model instance, #3028", 1, function() {
|
||||
var collection = new Backbone.Collection();
|
||||
var model = new Backbone.Model({id: 1});
|
||||
model.sync = function(){
|
||||
equal(this.collection, collection);
|
||||
};
|
||||
collection.create(model, {wait: true});
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
79
vendor/backbone/test/router.js
vendored
79
vendor/backbone/test/router.js
vendored
@@ -331,36 +331,6 @@
|
||||
Backbone.history.checkUrl();
|
||||
});
|
||||
|
||||
test("No events are triggered if #execute returns false.", 1, function() {
|
||||
var Router = Backbone.Router.extend({
|
||||
|
||||
routes: {
|
||||
foo: function() {
|
||||
ok(true);
|
||||
}
|
||||
},
|
||||
|
||||
execute: function(callback, args) {
|
||||
callback.apply(this, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var router = new Router;
|
||||
|
||||
router.on('route route:foo', function() {
|
||||
ok(false);
|
||||
});
|
||||
|
||||
Backbone.history.on('route', function() {
|
||||
ok(false);
|
||||
});
|
||||
|
||||
location.replace('http://example.com#foo');
|
||||
Backbone.history.checkUrl();
|
||||
});
|
||||
|
||||
test("#933, #908 - leading slash", 2, function() {
|
||||
location.replace('http://example.com/root/foo');
|
||||
|
||||
@@ -405,7 +375,7 @@
|
||||
Backbone.history.navigate('charñ', {trigger: true});
|
||||
equal(router.charType, 'UTF');
|
||||
Backbone.history.navigate('char%C3%B1', {trigger: true});
|
||||
equal(router.charType, 'UTF');
|
||||
equal(router.charType, 'escaped');
|
||||
});
|
||||
|
||||
test("#1185 - Use pathname when hashChange is not wanted.", 1, function() {
|
||||
@@ -768,7 +738,7 @@
|
||||
var Router = Backbone.Router.extend({
|
||||
routes: {
|
||||
path: function(params){
|
||||
strictEqual(params, 'x=y z');
|
||||
strictEqual(params, 'x=y%20z');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -837,49 +807,4 @@
|
||||
Backbone.history.start({pushState: true});
|
||||
});
|
||||
|
||||
test('Router#execute receives callback, args, name.', 3, function() {
|
||||
location.replace('http://example.com#foo/123/bar?x=y');
|
||||
Backbone.history.stop();
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
var Router = Backbone.Router.extend({
|
||||
routes: {'foo/:id/bar': 'foo'},
|
||||
foo: function(){},
|
||||
execute: function(callback, args, name) {
|
||||
strictEqual(callback, this.foo);
|
||||
deepEqual(args, ['123', 'x=y']);
|
||||
strictEqual(name, 'foo');
|
||||
}
|
||||
});
|
||||
var router = new Router;
|
||||
Backbone.history.start();
|
||||
});
|
||||
|
||||
test("pushState to hashChange with only search params.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com?a=b');
|
||||
location.replace = function(url) {
|
||||
strictEqual(url, '/#?a=b');
|
||||
};
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: null
|
||||
});
|
||||
Backbone.history.start({pushState: true});
|
||||
});
|
||||
|
||||
test("#3123 - History#navigate decodes before comparison.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/shop/search?keyword=short%20dress');
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(){ ok(false); },
|
||||
replaceState: function(){ ok(false); }
|
||||
}
|
||||
});
|
||||
Backbone.history.start({pushState: true});
|
||||
Backbone.history.navigate('shop/search?keyword=short%20dress', true);
|
||||
strictEqual(Backbone.history.fragment, 'shop/search?keyword=short dress');
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
11
vendor/backbone/test/sync.js
vendored
11
vendor/backbone/test/sync.js
vendored
@@ -207,15 +207,4 @@
|
||||
strictEqual(this.ajaxSettings.beforeSend(xhr), false);
|
||||
});
|
||||
|
||||
test('#2928 - Pass along `textStatus` and `errorThrown`.', 2, function() {
|
||||
var model = new Backbone.Model;
|
||||
model.url = '/test';
|
||||
model.on('error', function(model, xhr, options) {
|
||||
strictEqual(options.textStatus, 'textStatus');
|
||||
strictEqual(options.errorThrown, 'errorThrown');
|
||||
});
|
||||
model.fetch();
|
||||
this.ajaxSettings.error({}, 'textStatus', 'errorThrown');
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
128
vendor/backbone/test/view.js
vendored
128
vendor/backbone/test/view.js
vendored
@@ -20,22 +20,10 @@
|
||||
equal(view.el.other, void 0);
|
||||
});
|
||||
|
||||
test("$", 2, function() {
|
||||
test("jQuery", 1, function() {
|
||||
var view = new Backbone.View;
|
||||
view.setElement('<p><a><b>test</b></a></p>');
|
||||
var result = view.$('a b');
|
||||
|
||||
strictEqual(result[0].innerHTML, 'test');
|
||||
ok(result.length === +result.length);
|
||||
});
|
||||
|
||||
test("$el", 3, function() {
|
||||
var view = new Backbone.View;
|
||||
view.setElement('<p><a><b>test</b></a></p>');
|
||||
strictEqual(view.el.nodeType, 1);
|
||||
|
||||
ok(view.$el instanceof Backbone.$);
|
||||
strictEqual(view.$el[0], view.el);
|
||||
strictEqual(view.$('a b').html(), 'test');
|
||||
});
|
||||
|
||||
test("initialize", 1, function() {
|
||||
@@ -72,17 +60,6 @@
|
||||
equal(counter2, 3);
|
||||
});
|
||||
|
||||
test("delegate", 2, function() {
|
||||
var view = new Backbone.View({el: '#testElement'});
|
||||
view.delegate('click', 'h1', function() {
|
||||
ok(true);
|
||||
});
|
||||
view.delegate('click', function() {
|
||||
ok(true);
|
||||
});
|
||||
view.$('h1').trigger('click');
|
||||
});
|
||||
|
||||
test("delegateEvents allows functions for callbacks", 3, function() {
|
||||
var view = new Backbone.View({el: '<p></p>'});
|
||||
view.counter = 0;
|
||||
@@ -137,63 +114,6 @@
|
||||
equal(counter2, 3);
|
||||
});
|
||||
|
||||
test("undelegate", 0, function() {
|
||||
view = new Backbone.View({el: '#testElement'});
|
||||
view.delegate('click', function() { ok(false); });
|
||||
view.delegate('click', 'h1', function() { ok(false); });
|
||||
|
||||
view.undelegate('click');
|
||||
|
||||
view.$('h1').trigger('click');
|
||||
view.$el.trigger('click');
|
||||
});
|
||||
|
||||
test("undelegate with passed handler", 1, function() {
|
||||
view = new Backbone.View({el: '#testElement'});
|
||||
var listener = function() { ok(false); };
|
||||
view.delegate('click', listener);
|
||||
view.delegate('click', function() { ok(true); });
|
||||
view.undelegate('click', listener);
|
||||
view.$el.trigger('click');
|
||||
});
|
||||
|
||||
test("undelegate with selector", 2, function() {
|
||||
view = new Backbone.View({el: '#testElement'});
|
||||
view.delegate('click', function() { ok(true); });
|
||||
view.delegate('click', 'h1', function() { ok(false); });
|
||||
view.undelegate('click', 'h1');
|
||||
view.$('h1').trigger('click');
|
||||
view.$el.trigger('click');
|
||||
});
|
||||
|
||||
test("undelegate with handler and selector", 2, function() {
|
||||
view = new Backbone.View({el: '#testElement'});
|
||||
view.delegate('click', function() { ok(true); });
|
||||
var handler = function(){ ok(false); };
|
||||
view.delegate('click', 'h1', handler);
|
||||
view.undelegate('click', 'h1', handler);
|
||||
view.$('h1').trigger('click');
|
||||
view.$el.trigger('click');
|
||||
});
|
||||
|
||||
test("tagName can be provided as a string", 1, function() {
|
||||
var View = Backbone.View.extend({
|
||||
tagName: 'span'
|
||||
});
|
||||
|
||||
equal(new View().el.tagName, 'SPAN');
|
||||
});
|
||||
|
||||
test("tagName can be provided as a function", 1, function() {
|
||||
var View = Backbone.View.extend({
|
||||
tagName: function() {
|
||||
return 'p';
|
||||
}
|
||||
});
|
||||
|
||||
ok(new View().$el.is('p'));
|
||||
});
|
||||
|
||||
test("_ensureElement with DOM node el", 1, function() {
|
||||
var View = Backbone.View.extend({
|
||||
el: document.body
|
||||
@@ -281,19 +201,26 @@
|
||||
equal(5, count);
|
||||
});
|
||||
|
||||
test("custom events", 2, function() {
|
||||
test("custom events, with namespaces", 2, function() {
|
||||
var count = 0;
|
||||
|
||||
var View = Backbone.View.extend({
|
||||
el: $('body'),
|
||||
events: {
|
||||
"fake$event": function() { ok(true); }
|
||||
events: function() {
|
||||
return {"fake$event.namespaced": "run"};
|
||||
},
|
||||
run: function() {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
var view = new View;
|
||||
$('body').trigger('fake$event').trigger('fake$event');
|
||||
equal(count, 2);
|
||||
|
||||
$('body').off('fake$event');
|
||||
$('body').off('.namespaced');
|
||||
$('body').trigger('fake$event');
|
||||
equal(count, 2);
|
||||
});
|
||||
|
||||
test("#1048 - setElement uses provided object.", 2, function() {
|
||||
@@ -337,11 +264,21 @@
|
||||
ok(!view2.el.id);
|
||||
});
|
||||
|
||||
test("#1228 - tagName can be provided as a function", 1, function() {
|
||||
var View = Backbone.View.extend({
|
||||
tagName: function() {
|
||||
return 'p';
|
||||
}
|
||||
});
|
||||
|
||||
ok(new View().$el.is('p'));
|
||||
});
|
||||
|
||||
test("views stopListening", 0, function() {
|
||||
var View = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.listenTo(this.model, 'all x', function(){ ok(false); });
|
||||
this.listenTo(this.collection, 'all x', function(){ ok(false); });
|
||||
this.listenTo(this.model, 'all x', function(){ ok(false); }, this);
|
||||
this.listenTo(this.collection, 'all x', function(){ ok(false); }, this);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -387,19 +324,4 @@
|
||||
equal(counter, 2);
|
||||
});
|
||||
|
||||
test("remove", 1, 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();
|
||||
view.$el.trigger('click');
|
||||
view.trigger('x');
|
||||
|
||||
// In IE8 and below, parentNode still exists but is not document.body.
|
||||
notEqual(view.el.parentNode, document.body);
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user