diff --git a/vendor/backbone/backbone.js b/vendor/backbone/backbone.js index 21bf42bb3..cfa836155 100644 --- a/vendor/backbone/backbone.js +++ b/vendor/backbone/backbone.js @@ -183,7 +183,7 @@ attributes || (attributes = {}); if (options && options.collection) this.collection = options.collection; if (options && options.parse) attributes = this.parse(attributes); - if (defaults = getValue(this, 'defaults')) { + if (defaults = _.result(this, 'defaults')) { attributes = _.extend({}, defaults, attributes); } this.attributes = {}; @@ -336,9 +336,7 @@ options.success = function(resp, status, xhr) { if (!model.set(model.parse(resp, xhr), options)) return false; if (success) success(model, resp, options); - model.trigger('sync', model, resp, options); }; - options.error = Backbone.wrapError(options.error, model, options); return this.sync('read', this, options); }, @@ -383,11 +381,9 @@ if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); if (!model.set(serverAttrs, options)) return false; if (success) success(model, resp, options); - model.trigger('sync', model, resp, options); }; // Finish configuring and sending the Ajax request. - options.error = Backbone.wrapError(options.error, model, options); var xhr = this.sync(this.isNew() ? 'create' : 'update', this, options); // When using `wait`, reset attributes to original values unless @@ -415,7 +411,6 @@ options.success = function(resp) { if (options.wait || model.isNew()) destroy(); if (success) success(model, resp, options); - if (!model.isNew()) model.trigger('sync', model, resp, options); }; if (this.isNew()) { @@ -423,7 +418,6 @@ return false; } - options.error = Backbone.wrapError(options.error, model, options); var xhr = this.sync('delete', this, options); if (!options.wait) destroy(); return xhr; @@ -433,7 +427,7 @@ // using Backbone's restful methods, override this to change the endpoint // that will be called. url: function() { - var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError(); + var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError(); if (this.isNew()) return base; return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id); }, @@ -527,8 +521,8 @@ // Check if the model is currently in a valid state. It's only possible to // get into an *invalid* state if you're using silent changes. - isValid: function() { - return !this.validate || !this.validate(this.attributes); + isValid: function(options) { + return !this.validate || !this.validate(this.attributes, options); }, // Run validation against the next complete set of model attributes, @@ -539,11 +533,8 @@ attrs = _.extend({}, this.attributes, attrs); var error = this.validate(attrs, options); if (!error) return true; - if (options && options.error) { - options.error(this, error, options); - } else { - this.trigger('error', this, error, options); - } + if (options && options.error) options.error(this, error, options); + this.trigger('error', this, error, options); return false; } @@ -781,9 +772,7 @@ options.success = function(resp, status, xhr) { collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options); if (success) success(collection, resp, options); - collection.trigger('sync', collection, resp, options); }; - options.error = Backbone.wrapError(options.error, collection, options); return this.sync('read', this, options); }, @@ -913,7 +902,6 @@ // }); // route: function(route, name, callback) { - Backbone.history || (Backbone.history = new History); if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (!callback) callback = this[name]; Backbone.history.route(route, _.bind(function(fragment) { @@ -1163,6 +1151,9 @@ }); + // Create the default Backbone.history. + Backbone.history = new History; + // Backbone.View // ------------- @@ -1260,7 +1251,7 @@ // 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 = getValue(this, 'events')))) return; + if (!(events || (events = _.result(this, 'events')))) return; this.undelegateEvents(); for (var key in events) { var method = events[key]; @@ -1303,10 +1294,10 @@ // an element from the `id`, `className` and `tagName` properties. _ensureElement: function() { if (!this.el) { - var attrs = _.extend({}, getValue(this, 'attributes')); - if (this.id) attrs.id = getValue(this, 'id'); - if (this.className) attrs['class'] = getValue(this, 'className'); - this.setElement(this.make(getValue(this, 'tagName'), attrs), false); + 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.make(_.result(this, 'tagName'), attrs), false); } else { this.setElement(this.el, false); } @@ -1351,7 +1342,7 @@ // Ensure that we have a URL. if (!options.url) { - params.url = getValue(model, 'url') || urlError(); + params.url = _.result(model, 'url') || urlError(); } // Ensure that we have the appropriate request data. @@ -1383,6 +1374,18 @@ params.processData = false; } + var success = options.success; + options.success = function(resp, status, xhr) { + if (success) success(resp, status, xhr); + model.trigger('sync', model, resp, options); + }; + + var error = options.error; + options.error = function(xhr, status, thrown) { + if (error) error(model, xhr, options); + model.trigger('error', model, xhr, options); + }; + // Make the request, allowing the user to override any Ajax options. return Backbone.ajax(_.extend(params, options)); }; @@ -1392,24 +1395,9 @@ return Backbone.$.ajax.apply(Backbone.$, arguments); }; - // Wrap an optional error callback with a fallback error event. - Backbone.wrapError = function(onError, originalModel, options) { - return function(model, resp) { - resp = model === originalModel ? resp : model; - if (onError) { - onError(originalModel, resp, options); - } else { - originalModel.trigger('error', originalModel, resp, options); - } - }; - }; - // Helpers // ------- - // Shared empty constructor function to aid in prototype-chain creation. - var ctor = function(){}; - // Helper function to correctly set up the prototype chain, for subclasses. // Similar to `goog.inherits`, but uses a hash of prototype properties and // class properties to be extended. @@ -1420,31 +1408,27 @@ // The constructor function for the new subclass is either defined by you // (the "constructor" property in your `extend` definition), or defaulted // by us to simply call the parent's constructor. - if (protoProps && protoProps.hasOwnProperty('constructor')) { + if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { child = function(){ parent.apply(this, arguments); }; } - // Inherit class (static) properties from parent. - _.extend(child, parent); - // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function. - ctor.prototype = parent.prototype; - child.prototype = new ctor(); + function Surrogate(){ this.constructor = child; }; + Surrogate.prototype = parent.prototype; + child.prototype = new Surrogate; // Add prototype properties (instance properties) to the subclass, // if supplied. if (protoProps) _.extend(child.prototype, protoProps); // Add static properties to the constructor function, if supplied. - if (staticProps) _.extend(child, staticProps); + _.extend(child, parent, staticProps); - // Correctly set child's `prototype.constructor`. - child.prototype.constructor = child; - - // Set a convenience property in case the parent's prototype is needed later. + // Set a convenience property in case the parent's prototype is needed + // later. child.__super__ = parent.prototype; return child; @@ -1453,13 +1437,6 @@ // Set up inheritance for the model, collection, and view. Model.extend = Collection.extend = Router.extend = View.extend = extend; - // Helper function to get a value from a Backbone object as a property - // or as a function. - var getValue = function(object, prop) { - if (!(object && object[prop])) return null; - return _.isFunction(object[prop]) ? object[prop]() : object[prop]; - }; - // Throw an error when a URL is needed, and none is supplied. var urlError = function() { throw new Error('A "url" property or function must be specified'); diff --git a/vendor/backbone/test/collection.js b/vendor/backbone/test/collection.js index 4752d1dcb..d3d5aaf87 100644 --- a/vendor/backbone/test/collection.js +++ b/vendor/backbone/test/collection.js @@ -1,13 +1,12 @@ $(document).ready(function() { - var lastRequest = null; - var sync = Backbone.sync; - var a, b, c, d, e, col, otherCol; - module("Backbone.Collection", { + module("Backbone.Collection", _.extend(new Environment, { setup: function() { + Environment.prototype.setup.apply(this, arguments); + a = new Backbone.Model({id: 3, label: 'a'}); b = new Backbone.Model({id: 2, label: 'b'}); c = new Backbone.Model({id: 1, label: 'c'}); @@ -15,21 +14,9 @@ $(document).ready(function() { e = null; col = new Backbone.Collection([a,b,c,d]); otherCol = new Backbone.Collection(); - - Backbone.sync = function(method, model, options) { - lastRequest = { - method: method, - model: model, - options: options - }; - }; - }, - - teardown: function() { - Backbone.sync = sync; } - }); + })); test("Collection: new and sort", 7, function() { equal(col.first(), a, "a should be first"); @@ -48,26 +35,18 @@ $(document).ready(function() { }); test("Collection: new and parse", 3, function() { - var MyCol = Backbone.Collection.extend({ - // only save the models that have an even value. + var Collection = Backbone.Collection.extend({ parse : function(data) { - var onlyEven = []; - _.each(data, function(datum) { - if (datum.a % 2 === 0) { - onlyEven.push(datum); - } + return _.filter(data, function(datum) { + return datum.a % 2 === 0; }); - - return onlyEven; } }); - anotherCol = new MyCol([ - { a : 1 },{ a : 2 },{ a : 3 },{ a : 4 } - ], { parse : true }); - - equal(anotherCol.length, 2); - equal(anotherCol.first().get('a'), 2) - equal(anotherCol.last().get('a'), 4); + var models = [{a: 1}, {a: 2}, {a: 3}, {a: 4}]; + var collection = new Collection(models, {parse: true}); + strictEqual(collection.length, 2); + strictEqual(collection.first().get('a'), 2); + strictEqual(collection.last().get('a'), 4); }); test("Collection: get, getByCid", 3, function() { @@ -379,21 +358,25 @@ $(document).ready(function() { }); test("Collection: fetch", 4, function() { - col.fetch(); - equal(lastRequest.method, 'read'); - equal(lastRequest.model, col); - equal(lastRequest.options.parse, true); + var collection = new Backbone.Collection; + collection.url = '/test'; + collection.fetch(); + equal(this.syncArgs.method, 'read'); + equal(this.syncArgs.model, collection); + equal(this.syncArgs.options.parse, true); - col.fetch({parse: false}); - equal(lastRequest.options.parse, false); + collection.fetch({parse: false}); + equal(this.syncArgs.options.parse, false); }); test("Collection: create", 4, function() { - var model = col.create({label: 'f'}, {wait: true}); - equal(lastRequest.method, 'create'); - equal(lastRequest.model, model); + var collection = new Backbone.Collection; + collection.url = '/test'; + var model = collection.create({label: 'f'}, {wait: true}); + equal(this.syncArgs.method, 'create'); + equal(this.syncArgs.model, model); equal(model.get('label'), 'f'); - equal(model.collection, col); + equal(model.collection, collection); }); test("Collection: create enforces validation", 1, function() { @@ -524,16 +507,17 @@ $(document).ready(function() { }); test("#714: access `model.collection` in a brand new model.", 2, function() { - var col = new Backbone.Collection; + var collection = new Backbone.Collection; + collection.url = '/test'; var Model = Backbone.Model.extend({ set: function(attrs) { equal(attrs.prop, 'value'); - equal(this.collection, col); + equal(this.collection, collection); return this; } }); - col.model = Model; - col.create({prop: 'value'}); + collection.model = Model; + collection.create({prop: 'value'}); }); test("#574, remove its own reference to the .models array.", 2, function() { @@ -659,15 +643,10 @@ $(document).ready(function() { }); test("#1412 - Trigger 'sync' event.", 2, function() { - var collection = new Backbone.Collection([], { - model: Backbone.Model.extend({ - sync: function(method, model, options) { - options.success(); - } - }) - }); - collection.sync = function(method, model, options) { options.success(); }; + var collection = new Backbone.Collection; + collection.url = '/test'; collection.on('sync', function() { ok(true); }); + Backbone.ajax = function(settings){ settings.success(); }; collection.fetch(); collection.create({id: 1}); }); diff --git a/vendor/backbone/test/model.js b/vendor/backbone/test/model.js index 8689d9754..2da0ae0f9 100644 --- a/vendor/backbone/test/model.js +++ b/vendor/backbone/test/model.js @@ -1,22 +1,15 @@ $(document).ready(function() { - // Variable to catch the last request. - var lastRequest = null; - // Variable to catch ajax params. - var ajaxParams = null; - var sync = Backbone.sync; - var ajax = Backbone.ajax; - var urlRoot = null; - var proxy = Backbone.Model.extend(); var klass = Backbone.Collection.extend({ url : function() { return '/collection'; } }); var doc, collection; - module("Backbone.Model", { + module("Backbone.Model", _.extend(new Environment, { setup: function() { + Environment.prototype.setup.apply(this, arguments); doc = new proxy({ id : '1-the-tempest', title : "The Tempest", @@ -25,27 +18,9 @@ $(document).ready(function() { }); collection = new klass(); collection.add(doc); - - Backbone.sync = function(method, model, options) { - lastRequest = { - method: method, - model: model, - options: options - }; - sync.apply(this, arguments); - }; - Backbone.ajax = function(params) { ajaxParams = params; }; - urlRoot = Backbone.Model.prototype.urlRoot; - Backbone.Model.prototype.urlRoot = '/'; - }, - - teardown: function() { - Backbone.sync = sync; - Backbone.ajax = ajax; - Backbone.Model.prototype.urlRoot = urlRoot; } - }); + })); test("Model: initialize", 3, function() { var Model = Backbone.Model.extend({ @@ -334,10 +309,12 @@ $(document).ready(function() { }); test("Model: save within change event", 1, function () { + var env = this; var model = new Backbone.Model({firstName : "Taylor", lastName: "Swift"}); + model.url = '/test'; model.on('change', function () { model.save(); - ok(_.isEqual(lastRequest.model, model)); + ok(_.isEqual(env.syncArgs.model, model)); }); model.set({lastName: 'Hicks'}); }); @@ -371,8 +348,8 @@ $(document).ready(function() { test("Model: save", 2, function() { doc.save({title : "Henry V"}); - equal(lastRequest.method, 'update'); - ok(_.isEqual(lastRequest.model, doc)); + equal(this.syncArgs.method, 'update'); + ok(_.isEqual(this.syncArgs.model, doc)); }); test("Model: save in positional style", 1, function() { @@ -388,14 +365,14 @@ $(document).ready(function() { test("Model: fetch", 2, function() { doc.fetch(); - equal(lastRequest.method, 'read'); - ok(_.isEqual(lastRequest.model, doc)); + equal(this.syncArgs.method, 'read'); + ok(_.isEqual(this.syncArgs.model, doc)); }); test("Model: destroy", 3, function() { doc.destroy(); - equal(lastRequest.method, 'delete'); - ok(_.isEqual(lastRequest.model, doc)); + equal(this.syncArgs.method, 'delete'); + ok(_.isEqual(this.syncArgs.model, doc)); var newModel = new Backbone.Model; equal(newModel.destroy(), false); @@ -472,7 +449,7 @@ $(document).ready(function() { equal(result, false); equal(model.get('a'), 100); equal(lastError, "Can't change admin status."); - equal(boundError, undefined); + equal(boundError, true); }); test("Model: defaults always extend attrs (#459)", 2, function() { @@ -595,8 +572,9 @@ $(document).ready(function() { test("save with `wait` succeeds without `validate`", 1, function() { var model = new Backbone.Model(); + model.url = '/test'; model.save({x: 1}, {wait: true}); - ok(lastRequest.model === model); + ok(this.syncArgs.model === model); }); test("`hasChanged` for falsey keys", 2, function() { @@ -616,18 +594,20 @@ $(document).ready(function() { test("`save` with `wait` sends correct attributes", 5, function() { var changed = 0; var model = new Backbone.Model({x: 1, y: 2}); + model.url = '/test'; model.on('change:x', function() { changed++; }); model.save({x: 3}, {wait: true}); - deepEqual(JSON.parse(ajaxParams.data), {x: 3, y: 2}); + deepEqual(JSON.parse(this.ajaxSettings.data), {x: 3, y: 2}); equal(model.get('x'), 1); equal(changed, 0); - lastRequest.options.success({}); + this.syncArgs.options.success({}); equal(model.get('x'), 3); equal(changed, 1); }); test("a failed `save` with `wait` doesn't leave attributes behind", 1, function() { var model = new Backbone.Model; + model.url = '/test'; model.save({x: 1}, {wait: true}); equal(model.get('x'), void 0); }); @@ -644,6 +624,7 @@ $(document).ready(function() { test("save with wait validates attributes", 1, function() { var model = new Backbone.Model(); + model.url = '/test'; model.validate = function() { ok(true); }; model.save({x: 1}, {wait: true}); }); @@ -776,24 +757,6 @@ $(document).ready(function() { model.set({a: true}); }); - test("Backbone.wrapError triggers `'error'`", 12, function() { - var resp = {}; - var options = {}; - var model = new Backbone.Model(); - model.on('error', error); - var callback = Backbone.wrapError(null, model, options); - callback(model, resp); - callback(resp); - callback = Backbone.wrapError(error, model, options); - callback(model, resp); - callback(resp); - function error(_model, _resp, _options) { - ok(model === _model); - ok(resp === _resp); - ok(options === _options); - } - }); - test("#1179 - isValid returns true in the absence of validate.", 1, function() { var model = new Backbone.Model(); model.validate = null; @@ -831,8 +794,9 @@ $(document).ready(function() { test("#1412 - Trigger 'sync' event.", 3, function() { var model = new Backbone.Model({id: 1}); - model.sync = function(method, model, options) { options.success(); }; - model.on('sync', function() { ok(true); }); + model.url = '/test'; + model.on('sync', function(){ ok(true); }); + Backbone.ajax = function(settings){ settings.success(); }; model.fetch(); model.save(); model.destroy(); diff --git a/vendor/backbone/test/router.js b/vendor/backbone/test/router.js index 701a1f07a..56d8a10d4 100644 --- a/vendor/backbone/test/router.js +++ b/vendor/backbone/test/router.js @@ -244,14 +244,11 @@ $(document).ready(function() { }); test("#1003 - History is started before navigate is called", 1, function() { - var history = new Backbone.History(); - history.navigate = function(){ - ok(Backbone.History.started); - }; Backbone.history.stop(); - history.start(); + Backbone.history.navigate = function(){ ok(Backbone.History.started); }; + Backbone.history.start(); // If this is not an old IE navigate will not be called. - if (!history.iframe) ok(true); + if (!Backbone.history.iframe) ok(true); }); test("Router: route callback gets passed decoded values", 3, function() { diff --git a/vendor/backbone/test/sync.js b/vendor/backbone/test/sync.js index f4afb5c14..d25c76ff2 100644 --- a/vendor/backbone/test/sync.js +++ b/vendor/backbone/test/sync.js @@ -1,8 +1,5 @@ $(document).ready(function() { - var ajax = Backbone.ajax; - var lastRequest = null; - var Library = Backbone.Collection.extend({ url : function() { return '/library'; } }); @@ -14,42 +11,36 @@ $(document).ready(function() { length : 123 }; - module("Backbone.sync", { + module("Backbone.sync", _.extend(new Environment, { setup : function() { - library = new Library(); - Backbone.ajax = function(obj) { - lastRequest = obj; - }; + Environment.prototype.setup.apply(this, arguments); + library = new Library; library.create(attrs, {wait: false}); - }, - - teardown: function() { - Backbone.ajax = ajax; } - }); + })); test("sync: read", 4, function() { library.fetch(); - equal(lastRequest.url, '/library'); - equal(lastRequest.type, 'GET'); - equal(lastRequest.dataType, 'json'); - ok(_.isEmpty(lastRequest.data)); + equal(this.ajaxSettings.url, '/library'); + equal(this.ajaxSettings.type, 'GET'); + equal(this.ajaxSettings.dataType, 'json'); + ok(_.isEmpty(this.ajaxSettings.data)); }); test("sync: passing data", 3, function() { library.fetch({data: {a: 'a', one: 1}}); - equal(lastRequest.url, '/library'); - equal(lastRequest.data.a, 'a'); - equal(lastRequest.data.one, 1); + equal(this.ajaxSettings.url, '/library'); + equal(this.ajaxSettings.data.a, 'a'); + equal(this.ajaxSettings.data.one, 1); }); test("sync: create", 6, function() { - equal(lastRequest.url, '/library'); - equal(lastRequest.type, 'POST'); - equal(lastRequest.dataType, 'json'); - var data = JSON.parse(lastRequest.data); + equal(this.ajaxSettings.url, '/library'); + equal(this.ajaxSettings.type, 'POST'); + equal(this.ajaxSettings.dataType, 'json'); + var data = JSON.parse(this.ajaxSettings.data); equal(data.title, 'The Tempest'); equal(data.author, 'Bill Shakespeare'); equal(data.length, 123); @@ -57,10 +48,10 @@ $(document).ready(function() { test("sync: update", 7, function() { library.first().save({id: '1-the-tempest', author: 'William Shakespeare'}); - equal(lastRequest.url, '/library/1-the-tempest'); - equal(lastRequest.type, 'PUT'); - equal(lastRequest.dataType, 'json'); - var data = JSON.parse(lastRequest.data); + equal(this.ajaxSettings.url, '/library/1-the-tempest'); + equal(this.ajaxSettings.type, 'PUT'); + equal(this.ajaxSettings.dataType, 'json'); + var data = JSON.parse(this.ajaxSettings.data); equal(data.id, '1-the-tempest'); equal(data.title, 'The Tempest'); equal(data.author, 'William Shakespeare'); @@ -70,11 +61,11 @@ $(document).ready(function() { test("sync: update with emulateHTTP and emulateJSON", 7, function() { Backbone.emulateHTTP = Backbone.emulateJSON = true; library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'POST'); - equal(lastRequest.dataType, 'json'); - equal(lastRequest.data._method, 'PUT'); - var data = JSON.parse(lastRequest.data.model); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'POST'); + equal(this.ajaxSettings.dataType, 'json'); + equal(this.ajaxSettings.data._method, 'PUT'); + var data = JSON.parse(this.ajaxSettings.data.model); equal(data.id, '2-the-tempest'); equal(data.author, 'Tim Shakespeare'); equal(data.length, 123); @@ -84,10 +75,10 @@ $(document).ready(function() { test("sync: update with just emulateHTTP", 6, function() { Backbone.emulateHTTP = true; library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'POST'); - equal(lastRequest.contentType, 'application/json'); - var data = JSON.parse(lastRequest.data); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'POST'); + equal(this.ajaxSettings.contentType, 'application/json'); + var data = JSON.parse(this.ajaxSettings.data); equal(data.id, '2-the-tempest'); equal(data.author, 'Tim Shakespeare'); equal(data.length, 123); @@ -97,10 +88,10 @@ $(document).ready(function() { test("sync: update with just emulateJSON", 6, function() { Backbone.emulateJSON = true; library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'PUT'); - equal(lastRequest.contentType, 'application/x-www-form-urlencoded'); - var data = JSON.parse(lastRequest.data.model); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'PUT'); + equal(this.ajaxSettings.contentType, 'application/x-www-form-urlencoded'); + var data = JSON.parse(this.ajaxSettings.data.model); equal(data.id, '2-the-tempest'); equal(data.author, 'Tim Shakespeare'); equal(data.length, 123); @@ -110,26 +101,26 @@ $(document).ready(function() { test("sync: read model", 3, function() { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); library.first().fetch(); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'GET'); - ok(_.isEmpty(lastRequest.data)); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'GET'); + ok(_.isEmpty(this.ajaxSettings.data)); }); test("sync: destroy", 3, function() { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); library.first().destroy({wait: true}); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'DELETE'); - equal(lastRequest.data, null); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'DELETE'); + equal(this.ajaxSettings.data, null); }); test("sync: destroy with emulateHTTP", 3, function() { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); Backbone.emulateHTTP = Backbone.emulateJSON = true; library.first().destroy(); - equal(lastRequest.url, '/library/2-the-tempest'); - equal(lastRequest.type, 'POST'); - equal(JSON.stringify(lastRequest.data), '{"_method":"DELETE"}'); + equal(this.ajaxSettings.url, '/library/2-the-tempest'); + equal(this.ajaxSettings.type, 'POST'); + equal(JSON.stringify(this.ajaxSettings.data), '{"_method":"DELETE"}'); Backbone.emulateHTTP = Backbone.emulateJSON = false; }); @@ -139,7 +130,7 @@ $(document).ready(function() { model.fetch(); }); model.fetch({url: '/one/two'}); - equal(lastRequest.url, '/one/two'); + equal(this.ajaxSettings.url, '/one/two'); }); test("#1052 - `options` is optional.", 0, function() { @@ -157,4 +148,13 @@ $(document).ready(function() { Backbone.sync('create', model); }); + test("Call provided error callback on error.", 1, function() { + var model = new Backbone.Model; + model.url = '/test'; + Backbone.sync('read', model, { + error: function() { ok(true); } + }); + this.ajaxSettings.error(); + }); + }); diff --git a/vendor/backbone/test/vendor/qunit.css b/vendor/backbone/test/vendor/qunit.css index 5684a4485..55970e006 100755 --- a/vendor/backbone/test/vendor/qunit.css +++ b/vendor/backbone/test/vendor/qunit.css @@ -1,11 +1,11 @@ /** - * QUnit v1.8.0 - A JavaScript Unit Testing Framework + * QUnit v1.10.0 - A JavaScript Unit Testing Framework * - * http://docs.jquery.com/QUnit + * http://qunitjs.com * - * Copyright (c) 2012 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license */ /** Font Family and Sizes */ @@ -20,7 +20,7 @@ /** Resets */ -#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { +#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } @@ -38,10 +38,10 @@ line-height: 1em; font-weight: normal; - border-radius: 15px 15px 0 0; - -moz-border-radius: 15px 15px 0 0; - -webkit-border-top-right-radius: 15px; - -webkit-border-top-left-radius: 15px; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; } #qunit-header a { @@ -54,9 +54,9 @@ color: #fff; } -#qunit-header label { +#qunit-testrunner-toolbar label { display: inline-block; - padding-left: 0.5em; + padding: 0 .5em 0 .1em; } #qunit-banner { @@ -67,6 +67,7 @@ padding: 0.5em 0 0.5em 2em; color: #5E740B; background-color: #eee; + overflow: hidden; } #qunit-userAgent { @@ -76,6 +77,9 @@ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } +#qunit-modulefilter-container { + float: right; +} /** Tests: Pass/Fail */ @@ -113,13 +117,9 @@ background-color: #fff; - border-radius: 15px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - - box-shadow: inset 0px 2px 13px #999; - -moz-box-shadow: inset 0px 2px 13px #999; - -webkit-box-shadow: inset 0px 2px 13px #999; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; } #qunit-tests table { @@ -162,8 +162,7 @@ #qunit-tests b.failed { color: #710909; } #qunit-tests li li { - margin: 0.5em; - padding: 0.4em 0.5em 0.4em 0.5em; + padding: 5px; background-color: #fff; border-bottom: none; list-style-position: inside; @@ -172,9 +171,9 @@ /*** Passing Styles */ #qunit-tests li li.pass { - color: #5E740B; + color: #3c510c; background-color: #fff; - border-left: 26px solid #C6E746; + border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } @@ -190,15 +189,15 @@ #qunit-tests li li.fail { color: #710909; background-color: #fff; - border-left: 26px solid #EE5757; + border-left: 10px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { - border-radius: 0 0 15px 15px; - -moz-border-radius: 0 0 15px 15px; - -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } diff --git a/vendor/backbone/test/vendor/qunit.js b/vendor/backbone/test/vendor/qunit.js index c1570c252..d4f17b5ae 100755 --- a/vendor/backbone/test/vendor/qunit.js +++ b/vendor/backbone/test/vendor/qunit.js @@ -1,11 +1,11 @@ /** - * QUnit v1.8.0 - A JavaScript Unit Testing Framework + * QUnit v1.10.0 - A JavaScript Unit Testing Framework * - * http://docs.jquery.com/QUnit + * http://qunitjs.com * - * Copyright (c) 2012 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license */ (function( window ) { @@ -17,6 +17,8 @@ var QUnit, fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, defined = { setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { @@ -304,7 +306,8 @@ QUnit = { // call on start of module test to prepend name to all tests module: function( name, testEnvironment ) { config.currentModule = name; - config.currentModuleTestEnviroment = testEnvironment; + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; }, asyncTest: function( testName, expected, callback ) { @@ -336,7 +339,7 @@ QUnit = { async: async, callback: callback, module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnviroment, + moduleTestEnvironment: config.currentModuleTestEnvironment, stack: sourceFromStacktrace( 2 ) }); @@ -349,7 +352,11 @@ QUnit = { // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. expect: function( asserts ) { - config.current.expected = asserts; + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } }, start: function( count ) { @@ -403,6 +410,8 @@ QUnit = { QUnit.assert = { /** * Asserts rough true-ish result. + * @name ok + * @function * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); */ ok: function( result, msg ) { @@ -413,6 +422,8 @@ QUnit.assert = { var source, details = { + module: config.current.module, + name: config.current.testName, result: result, message: msg }; @@ -437,36 +448,59 @@ QUnit.assert = { /** * Assert that the first two arguments are equal, with an optional message. * Prints out both actual and expected values. + * @name equal + * @function * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); */ equal: function( actual, expected, message ) { QUnit.push( expected == actual, actual, expected, message ); }, + /** + * @name notEqual + * @function + */ notEqual: function( actual, expected, message ) { QUnit.push( expected != actual, actual, expected, message ); }, + /** + * @name deepEqual + * @function + */ deepEqual: function( actual, expected, message ) { QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); }, + /** + * @name notDeepEqual + * @function + */ notDeepEqual: function( actual, expected, message ) { QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); }, + /** + * @name strictEqual + * @function + */ strictEqual: function( actual, expected, message ) { QUnit.push( expected === actual, actual, expected, message ); }, + /** + * @name notStrictEqual + * @function + */ notStrictEqual: function( actual, expected, message ) { QUnit.push( expected !== actual, actual, expected, message ); }, - raises: function( block, expected, message ) { + throws: function( block, expected, message ) { var actual, ok = false; + // 'expected' is optional if ( typeof expected === "string" ) { message = expected; expected = null; @@ -494,18 +528,29 @@ QUnit.assert = { } else if ( expected.call( {}, actual ) === true ) { ok = true; } - } - QUnit.push( ok, actual, null, message ); + QUnit.push( ok, actual, null, message ); + } else { + QUnit.pushFailure( message, null, 'No exception was thrown.' ); + } } }; -// @deprecated: Kept assertion helpers in root for backwards compatibility +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility + */ extend( QUnit, QUnit.assert ); /** - * @deprecated: Kept for backwards compatibility - * next step: remove entirely + * @deprecated since 1.9.0 + * Kept global "raises()" for backwards compatibility + */ +QUnit.raises = QUnit.assert.throws; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. */ QUnit.equals = function() { QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); @@ -549,7 +594,23 @@ config = { // when enabled, all tests must call expect() requireExpects: false, - urlConfig: [ "noglobals", "notrycatch" ], + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, // logging callback queues begin: [], @@ -661,17 +722,10 @@ extend( QUnit, { }, // Resets the test setup. Useful for tests that modify the DOM. - // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. reset: function() { - var fixture; - - if ( window.jQuery ) { - jQuery( "#qunit-fixture" ).html( config.fixture ); - } else { - fixture = id( "qunit-fixture" ); - if ( fixture ) { - fixture.innerHTML = config.fixture; - } + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; } }, @@ -732,6 +786,8 @@ extend( QUnit, { var output, source, details = { + module: config.current.module, + name: config.current.testName, result: result, message: message, actual: actual, @@ -770,26 +826,36 @@ extend( QUnit, { }); }, - pushFailure: function( message, source ) { + pushFailure: function( message, source, actual ) { if ( !config.current ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); } var output, details = { + module: config.current.module, + name: config.current.testName, result: false, message: message }; - message = escapeInnerText(message ) || "error"; + message = escapeInnerText( message ) || "error"; message = ""; output = message; + output += "
| Result: | " + escapeInnerText( actual ) + " |
|---|
| Source: | " + escapeInnerText( source ) + " |
|---|
" + escapeInnerText( source ) + "
\u2028<%= "\\u2028\\u2029" %>\u2029
'); strictEqual(tmpl(), '\u2028\u2028\u2029\u2029
'); diff --git a/vendor/underscore/underscore-min.js b/vendor/underscore/underscore-min.js index 9158d59ce..15530c637 100644 --- a/vendor/underscore/underscore-min.js +++ b/vendor/underscore/underscore-min.js @@ -5,28 +5,29 @@ // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore -(function(){var s=this,L=s._,o={},k=Array.prototype,p=Object.prototype,M=k.push,h=k.slice,N=k.unshift,m=p.toString,O=p.hasOwnProperty,z=k.forEach,A=k.map,B=k.reduce,C=k.reduceRight,D=k.filter,E=k.every,F=k.some,q=k.indexOf,G=k.lastIndexOf,p=Array.isArray,P=Object.keys,t=Function.prototype.bind,b=function(a){return new l(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var i=b.each=b.forEach=function(a,c, -d){if(a!=null)if(z&&a.forEach===z)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e