mirror of
https://github.com/jashkenas/backbone.git
synced 2026-01-23 05:48:10 -05:00
resolved merge
This commit is contained in:
36
backbone.js
36
backbone.js
@@ -220,7 +220,7 @@
|
||||
// Extract attributes and options.
|
||||
options || (options = {});
|
||||
if (!attrs) return this;
|
||||
if (attrs.attributes) attrs = attrs.attributes;
|
||||
if (attrs instanceof Backbone.Model) attrs = attrs.attributes;
|
||||
if (options.unset) for (var attr in attrs) attrs[attr] = void 0;
|
||||
var now = this.attributes, escaped = this._escapedAttributes;
|
||||
|
||||
@@ -239,11 +239,11 @@
|
||||
for (attr in attrs) {
|
||||
val = attrs[attr];
|
||||
if (!_.isEqual(now[attr], val) || (options.unset && (attr in now))) {
|
||||
options.unset ? delete now[attr] : now[attr] = val;
|
||||
delete escaped[attr];
|
||||
this._changed = true;
|
||||
changes[attr] = val;
|
||||
}
|
||||
options.unset ? delete now[attr] : now[attr] = val;
|
||||
}
|
||||
|
||||
// Fire `change:attribute` events.
|
||||
@@ -364,7 +364,7 @@
|
||||
|
||||
// Create a new model with identical attributes to this one.
|
||||
clone: function() {
|
||||
return new this.constructor(this);
|
||||
return new this.constructor(this.attributes);
|
||||
},
|
||||
|
||||
// A model is new if it has never been saved to the server, and lacks an id.
|
||||
@@ -468,43 +468,45 @@
|
||||
},
|
||||
|
||||
// Add a model, or list of models to the set. Pass **silent** to avoid
|
||||
// firing the `added` event for every new model.
|
||||
// firing the `add` event for every new model.
|
||||
add: function(models, options) {
|
||||
var i, index, length;
|
||||
var i, index, length, model, cids = {};
|
||||
options || (options = {});
|
||||
if (!_.isArray(models)) models = [models];
|
||||
models = slice.call(models);
|
||||
models = _.isArray(models) ? models.slice() : [models];
|
||||
for (i = 0, length = models.length; i < length; i++) {
|
||||
var model = models[i] = this._prepareModel(models[i], options);
|
||||
if (!model) {
|
||||
if (!(model = models[i] = this._prepareModel(models[i], options))) {
|
||||
throw new Error("Can't add an invalid model to a collection");
|
||||
}
|
||||
var hasId = model.id != null;
|
||||
if (this._byCid[model.cid] || (hasId && this._byId[model.id])) {
|
||||
throw new Error("Can't add the same model to a collection twice");
|
||||
}
|
||||
}
|
||||
for (i = 0; i < length; i++) {
|
||||
(model = models[i]).on('all', this._onModelEvent, this);
|
||||
this._byCid[model.cid] = model;
|
||||
if (hasId) this._byId[model.id] = model;
|
||||
model.on('all', this._onModelEvent, this);
|
||||
if (model.id != null) this._byId[model.id] = model;
|
||||
cids[model.cid] = true;
|
||||
}
|
||||
this.length += length;
|
||||
index = options.at != null ? options.at : this.models.length;
|
||||
splice.apply(this.models, [index, 0].concat(models));
|
||||
if (this.comparator) this.sort({silent: true});
|
||||
if (options.silent) return this;
|
||||
for (i = 0; i < length; i++) {
|
||||
options.index = index + i;
|
||||
models[i].trigger('add', models[i], this, options);
|
||||
for (i = 0, length = this.models.length; i < length; i++) {
|
||||
if (!cids[(model = this.models[i]).cid]) continue;
|
||||
options.index = i;
|
||||
model.trigger('add', model, this, options);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// Remove a model, or a list of models from the set. Pass silent to avoid
|
||||
// firing the `removed` event for every model removed.
|
||||
// firing the `remove` event for every model removed.
|
||||
remove: function(models, options) {
|
||||
var i, index, model;
|
||||
options || (options = {});
|
||||
models = _.isArray(models) ? slice.call(models) : [models];
|
||||
models = _.isArray(models) ? models.slice() : [models];
|
||||
for (i = 0, l = models.length; i < l; i++) {
|
||||
model = this.getByCid(models[i]) || this.get(models[i]);
|
||||
if (!model) continue;
|
||||
@@ -561,7 +563,7 @@
|
||||
|
||||
// When you have more items than you want to add or remove individually,
|
||||
// you can reset the entire set with a new list of models, without firing
|
||||
// any `added` or `removed` events. Fires `reset` when finished.
|
||||
// any `add` or `remove` events. Fires `reset` when finished.
|
||||
reset: function(models, options) {
|
||||
models || (models = []);
|
||||
options || (options = {});
|
||||
|
||||
@@ -17,25 +17,25 @@ $(document).ready(function() {
|
||||
var otherCol = new Backbone.Collection();
|
||||
|
||||
test("Collection: new and sort", function() {
|
||||
equals(col.first(), a, "a should be first");
|
||||
equals(col.last(), d, "d should be last");
|
||||
equal(col.first(), a, "a should be first");
|
||||
equal(col.last(), d, "d should be last");
|
||||
col.comparator = function(a, b) {
|
||||
return a.id > b.id ? -1 : 1;
|
||||
};
|
||||
col.sort();
|
||||
equals(col.first(), a, "a should be first");
|
||||
equals(col.last(), d, "d should be last");
|
||||
equal(col.first(), a, "a should be first");
|
||||
equal(col.last(), d, "d should be last");
|
||||
col.comparator = function(model) { return model.id; };
|
||||
col.sort();
|
||||
equals(col.first(), d, "d should be first");
|
||||
equals(col.last(), a, "a should be last");
|
||||
equals(col.length, 4);
|
||||
equal(col.first(), d, "d should be first");
|
||||
equal(col.last(), a, "a should be last");
|
||||
equal(col.length, 4);
|
||||
});
|
||||
|
||||
test("Collection: get, getByCid", function() {
|
||||
equals(col.get(0), d);
|
||||
equals(col.get(2), b);
|
||||
equals(col.getByCid(col.first().cid), col.first());
|
||||
equal(col.get(0), d);
|
||||
equal(col.get(2), b);
|
||||
equal(col.getByCid(col.first().cid), col.first());
|
||||
});
|
||||
|
||||
test("Collection: get with non-default ids", function() {
|
||||
@@ -45,9 +45,9 @@ $(document).ready(function() {
|
||||
});
|
||||
var model = new MongoModel({_id: 100});
|
||||
col.add(model);
|
||||
equals(col.get(100), model);
|
||||
equal(col.get(100), model);
|
||||
model.set({_id: 101});
|
||||
equals(col.get(101), model);
|
||||
equal(col.get(101), model);
|
||||
});
|
||||
|
||||
test("Collection: add model with attributes modified by set", function() {
|
||||
@@ -74,7 +74,7 @@ $(document).ready(function() {
|
||||
model: CustomSetModel
|
||||
});
|
||||
var col = new CustomSetCollection([{ num_as_string: 2 }]);
|
||||
equals(col.length, 1);
|
||||
equal(col.length, 1);
|
||||
});
|
||||
|
||||
test("Collection: update index when id changes", function() {
|
||||
@@ -84,18 +84,18 @@ $(document).ready(function() {
|
||||
{id : 1, name : 'two'}
|
||||
]);
|
||||
var one = col.get(0);
|
||||
equals(one.get('name'), 'one');
|
||||
equal(one.get('name'), 'one');
|
||||
one.set({id : 101});
|
||||
equals(col.get(0), null);
|
||||
equals(col.get(101).get('name'), 'one');
|
||||
equal(col.get(0), null);
|
||||
equal(col.get(101).get('name'), 'one');
|
||||
});
|
||||
|
||||
test("Collection: at", function() {
|
||||
equals(col.at(2), b);
|
||||
equal(col.at(2), b);
|
||||
});
|
||||
|
||||
test("Collection: pluck", function() {
|
||||
equals(col.pluck('label').join(' '), 'd c b a');
|
||||
equal(col.pluck('label').join(' '), 'd c b a');
|
||||
});
|
||||
|
||||
test("Collection: add", function() {
|
||||
@@ -107,33 +107,33 @@ $(document).ready(function() {
|
||||
});
|
||||
col.bind('add', function(model, collection, options){
|
||||
added = model.get('label');
|
||||
equals(options.index, 4);
|
||||
equal(options.index, 4);
|
||||
opts = options;
|
||||
});
|
||||
col.add(e, {amazing: true});
|
||||
equals(added, 'e');
|
||||
equals(col.length, 5);
|
||||
equals(col.last(), e);
|
||||
equals(otherCol.length, 1);
|
||||
equals(secondAdded, null);
|
||||
equal(added, 'e');
|
||||
equal(col.length, 5);
|
||||
equal(col.last(), e);
|
||||
equal(otherCol.length, 1);
|
||||
equal(secondAdded, null);
|
||||
ok(opts.amazing);
|
||||
|
||||
var f = new Backbone.Model({id: 20, label : 'f'});
|
||||
var g = new Backbone.Model({id: 21, label : 'g'});
|
||||
var h = new Backbone.Model({id: 22, label : 'h'});
|
||||
var atCol = new Backbone.Collection([f, g, h]);
|
||||
equals(atCol.length, 3);
|
||||
equal(atCol.length, 3);
|
||||
atCol.add(e, {at: 1});
|
||||
equals(atCol.length, 4);
|
||||
equals(atCol.at(1), e);
|
||||
equals(atCol.last(), h);
|
||||
equal(atCol.length, 4);
|
||||
equal(atCol.at(1), e);
|
||||
equal(atCol.last(), h);
|
||||
});
|
||||
|
||||
test("Collection: add multiple models", function() {
|
||||
var col = new Backbone.Collection([{at: 0}, {at: 1}, {at: 9}]);
|
||||
col.add([{at: 2}, {at: 3}, {at: 4}, {at: 5}, {at: 6}, {at: 7}, {at: 8}], {at: 2});
|
||||
for (var i = 0; i <= 5; i++) {
|
||||
equals(col.at(i).get('at'), i);
|
||||
equal(col.at(i).get('at'), i);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -161,27 +161,27 @@ $(document).ready(function() {
|
||||
var e = new Backbone.Model({id: 10, label : 'e'});
|
||||
e.bind('add', function(model, collection) {
|
||||
counter++;
|
||||
equals(e, model);
|
||||
equal(e, model);
|
||||
if (counter > 1) {
|
||||
equals(collection, colF);
|
||||
equal(collection, colF);
|
||||
} else {
|
||||
equals(collection, colE);
|
||||
equal(collection, colE);
|
||||
}
|
||||
});
|
||||
var colE = new Backbone.Collection([]);
|
||||
colE.bind('add', function(model, collection) {
|
||||
equals(e, model);
|
||||
equals(colE, collection);
|
||||
equal(e, model);
|
||||
equal(colE, collection);
|
||||
});
|
||||
var colF = new Backbone.Collection([]);
|
||||
colF.bind('add', function(model, collection) {
|
||||
equals(e, model);
|
||||
equals(colF, collection);
|
||||
equal(e, model);
|
||||
equal(colF, collection);
|
||||
});
|
||||
colE.add(e);
|
||||
equals(e.collection, colE);
|
||||
equal(e.collection, colE);
|
||||
colF.add(e);
|
||||
equals(e.collection, colE);
|
||||
equal(e.collection, colE);
|
||||
});
|
||||
|
||||
test("Collection: add model with parse", function() {
|
||||
@@ -195,7 +195,7 @@ $(document).ready(function() {
|
||||
var Col = Backbone.Collection.extend({model: Model});
|
||||
var col = new Col;
|
||||
col.add({value: 1}, {parse: true});
|
||||
equals(col.at(0).get('value'), 2);
|
||||
equal(col.at(0).get('value'), 2);
|
||||
});
|
||||
|
||||
test("Collection: add model to collection with sort()-style comparator", function() {
|
||||
@@ -209,9 +209,9 @@ $(document).ready(function() {
|
||||
col.add(tom);
|
||||
col.add(rob);
|
||||
col.add(tim);
|
||||
equals(col.indexOf(rob), 0);
|
||||
equals(col.indexOf(tim), 1);
|
||||
equals(col.indexOf(tom), 2);
|
||||
equal(col.indexOf(rob), 0);
|
||||
equal(col.indexOf(tim), 1);
|
||||
equal(col.indexOf(tom), 2);
|
||||
});
|
||||
|
||||
test("Collection: comparator that depends on `this`", function() {
|
||||
@@ -223,23 +223,23 @@ $(document).ready(function() {
|
||||
return this.negative(a.id);
|
||||
};
|
||||
col.add([{id: 1}, {id: 2}, {id: 3}]);
|
||||
equals(col.pluck('id').join(' '), '3 2 1');
|
||||
equal(col.pluck('id').join(' '), '3 2 1');
|
||||
});
|
||||
|
||||
test("Collection: remove", function() {
|
||||
var removed = otherRemoved = null;
|
||||
col.bind('remove', function(model, col, options) {
|
||||
removed = model.get('label');
|
||||
equals(options.index, 4);
|
||||
equal(options.index, 4);
|
||||
});
|
||||
otherCol.bind('remove', function(model, col, options) {
|
||||
otherRemoved = true;
|
||||
});
|
||||
col.remove(e);
|
||||
equals(removed, 'e');
|
||||
equals(col.length, 4);
|
||||
equals(col.first(), d);
|
||||
equals(otherRemoved, null);
|
||||
equal(removed, 'e');
|
||||
equal(col.length, 4);
|
||||
equal(col.first(), d);
|
||||
equal(otherRemoved, null);
|
||||
});
|
||||
|
||||
test("Collection: events are unbound on remove", function() {
|
||||
@@ -248,11 +248,11 @@ $(document).ready(function() {
|
||||
var emcees = new Backbone.Collection([dj]);
|
||||
emcees.bind('change', function(){ counter++; });
|
||||
dj.set({name : 'Kool'});
|
||||
equals(counter, 1);
|
||||
equal(counter, 1);
|
||||
emcees.reset([]);
|
||||
equals(dj.collection, undefined);
|
||||
equal(dj.collection, undefined);
|
||||
dj.set({name : 'Shadow'});
|
||||
equals(counter, 1);
|
||||
equal(counter, 1);
|
||||
});
|
||||
|
||||
test("Collection: remove in multiple collections", function() {
|
||||
@@ -272,11 +272,11 @@ $(document).ready(function() {
|
||||
ok(colE.length == 1);
|
||||
ok(colF.length == 1);
|
||||
colE.remove(e);
|
||||
equals(passed, false);
|
||||
equal(passed, false);
|
||||
ok(colE.length == 0);
|
||||
colF.remove(e);
|
||||
ok(colF.length == 0);
|
||||
equals(passed, true);
|
||||
equal(passed, true);
|
||||
});
|
||||
|
||||
test("Collection: remove same model in multiple collection", function() {
|
||||
@@ -284,33 +284,33 @@ $(document).ready(function() {
|
||||
var e = new Backbone.Model({id: 5, title: 'Othello'});
|
||||
e.bind('remove', function(model, collection) {
|
||||
counter++;
|
||||
equals(e, model);
|
||||
equal(e, model);
|
||||
if (counter > 1) {
|
||||
equals(collection, colE);
|
||||
equal(collection, colE);
|
||||
} else {
|
||||
equals(collection, colF);
|
||||
equal(collection, colF);
|
||||
}
|
||||
});
|
||||
var colE = new Backbone.Collection([e]);
|
||||
colE.bind('remove', function(model, collection) {
|
||||
equals(e, model);
|
||||
equals(colE, collection);
|
||||
equal(e, model);
|
||||
equal(colE, collection);
|
||||
});
|
||||
var colF = new Backbone.Collection([e]);
|
||||
colF.bind('remove', function(model, collection) {
|
||||
equals(e, model);
|
||||
equals(colF, collection);
|
||||
equal(e, model);
|
||||
equal(colF, collection);
|
||||
});
|
||||
equals(colE, e.collection);
|
||||
equal(colE, e.collection);
|
||||
colF.remove(e);
|
||||
ok(colF.length == 0);
|
||||
ok(colE.length == 1);
|
||||
equals(counter, 1);
|
||||
equals(colE, e.collection);
|
||||
equal(counter, 1);
|
||||
equal(colE, e.collection);
|
||||
colE.remove(e);
|
||||
equals(null, e.collection);
|
||||
equal(null, e.collection);
|
||||
ok(colE.length == 0);
|
||||
equals(counter, 2);
|
||||
equal(counter, 2);
|
||||
});
|
||||
|
||||
test("Collection: model destroy removes from all collections", function() {
|
||||
@@ -321,7 +321,7 @@ $(document).ready(function() {
|
||||
e.destroy();
|
||||
ok(colE.length == 0);
|
||||
ok(colF.length == 0);
|
||||
equals(undefined, e.collection);
|
||||
equal(undefined, e.collection);
|
||||
});
|
||||
|
||||
test("Colllection: non-persisted model destroy removes from all collections", function() {
|
||||
@@ -332,25 +332,25 @@ $(document).ready(function() {
|
||||
e.destroy();
|
||||
ok(colE.length == 0);
|
||||
ok(colF.length == 0);
|
||||
equals(undefined, e.collection);
|
||||
equal(undefined, e.collection);
|
||||
});
|
||||
|
||||
test("Collection: fetch", function() {
|
||||
col.fetch();
|
||||
equals(lastRequest[0], 'read');
|
||||
equals(lastRequest[1], col);
|
||||
equals(lastRequest[2].parse, true);
|
||||
equal(lastRequest[0], 'read');
|
||||
equal(lastRequest[1], col);
|
||||
equal(lastRequest[2].parse, true);
|
||||
|
||||
col.fetch({parse: false});
|
||||
equals(lastRequest[2].parse, false);
|
||||
equal(lastRequest[2].parse, false);
|
||||
});
|
||||
|
||||
test("Collection: create", function() {
|
||||
var model = col.create({label: 'f'}, {wait: true});
|
||||
equals(lastRequest[0], 'create');
|
||||
equals(lastRequest[1], model);
|
||||
equals(model.get('label'), 'f');
|
||||
equals(model.collection, col);
|
||||
equal(lastRequest[0], 'create');
|
||||
equal(lastRequest[1], model);
|
||||
equal(model.get('label'), 'f');
|
||||
equal(model.collection, col);
|
||||
});
|
||||
|
||||
test("Collection: create enforces validation", function() {
|
||||
@@ -363,7 +363,7 @@ $(document).ready(function() {
|
||||
model: ValidatingModel
|
||||
});
|
||||
var col = new ValidatingCollection();
|
||||
equals(col.create({"foo":"bar"}),false);
|
||||
equal(col.create({"foo":"bar"}),false);
|
||||
});
|
||||
|
||||
test("Collection: a failing create runs the error callback", function() {
|
||||
@@ -379,7 +379,7 @@ $(document).ready(function() {
|
||||
var callback = function(model, error) { flag = true; };
|
||||
var col = new ValidatingCollection();
|
||||
col.create({"foo":"bar"}, { error: callback });
|
||||
equals(flag, true);
|
||||
equal(flag, true);
|
||||
});
|
||||
|
||||
test("collection: initialize", function() {
|
||||
@@ -389,26 +389,26 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var coll = new Collection;
|
||||
equals(coll.one, 1);
|
||||
equal(coll.one, 1);
|
||||
});
|
||||
|
||||
test("Collection: toJSON", function() {
|
||||
equals(JSON.stringify(col), '[{"id":0,"label":"d"},{"id":1,"label":"c"},{"id":2,"label":"b"},{"id":3,"label":"a"}]');
|
||||
equal(JSON.stringify(col), '[{"id":0,"label":"d"},{"id":1,"label":"c"},{"id":2,"label":"b"},{"id":3,"label":"a"}]');
|
||||
});
|
||||
|
||||
test("Collection: Underscore methods", function() {
|
||||
equals(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
|
||||
equals(col.any(function(model){ return model.id === 100; }), false);
|
||||
equals(col.any(function(model){ return model.id === 0; }), true);
|
||||
equals(col.indexOf(b), 2);
|
||||
equals(col.size(), 4);
|
||||
equals(col.rest().length, 3);
|
||||
equal(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
|
||||
equal(col.any(function(model){ return model.id === 100; }), false);
|
||||
equal(col.any(function(model){ return model.id === 0; }), true);
|
||||
equal(col.indexOf(b), 2);
|
||||
equal(col.size(), 4);
|
||||
equal(col.rest().length, 3);
|
||||
ok(!_.include(col.rest()), a);
|
||||
ok(!_.include(col.rest()), d);
|
||||
ok(!col.isEmpty());
|
||||
ok(!_.include(col.without(d)), d);
|
||||
equals(col.max(function(model){ return model.id; }).id, 3);
|
||||
equals(col.min(function(model){ return model.id; }).id, 0);
|
||||
equal(col.max(function(model){ return model.id; }).id, 3);
|
||||
equal(col.min(function(model){ return model.id; }).id, 0);
|
||||
same(col.chain()
|
||||
.filter(function(o){ return o.id % 2 === 0; })
|
||||
.map(function(o){ return o.id * 2; })
|
||||
@@ -421,16 +421,16 @@ $(document).ready(function() {
|
||||
var models = col.models;
|
||||
col.bind('reset', function() { resetCount += 1; });
|
||||
col.reset([]);
|
||||
equals(resetCount, 1);
|
||||
equals(col.length, 0);
|
||||
equals(col.last(), null);
|
||||
equal(resetCount, 1);
|
||||
equal(col.length, 0);
|
||||
equal(col.last(), null);
|
||||
col.reset(models);
|
||||
equals(resetCount, 2);
|
||||
equals(col.length, 4);
|
||||
equals(col.last(), a);
|
||||
equal(resetCount, 2);
|
||||
equal(col.length, 4);
|
||||
equal(col.last(), a);
|
||||
col.reset(_.map(models, function(m){ return m.attributes; }));
|
||||
equals(resetCount, 3);
|
||||
equals(col.length, 4);
|
||||
equal(resetCount, 3);
|
||||
equal(col.length, 4);
|
||||
ok(col.last() !== a);
|
||||
ok(_.isEqual(col.last().attributes, a.attributes));
|
||||
});
|
||||
@@ -439,14 +439,14 @@ $(document).ready(function() {
|
||||
var fired = null;
|
||||
a.bind("custom", function() { fired = true; });
|
||||
a.trigger("custom");
|
||||
equals(fired, true);
|
||||
equal(fired, true);
|
||||
});
|
||||
|
||||
test("Collection: add does not alter arguments", function(){
|
||||
var attrs = {};
|
||||
var models = [attrs];
|
||||
new Backbone.Collection().add(models);
|
||||
equals(models.length, 1);
|
||||
equal(models.length, 1);
|
||||
ok(attrs === models[0]);
|
||||
});
|
||||
|
||||
@@ -454,8 +454,8 @@ $(document).ready(function() {
|
||||
var col = new Backbone.Collection;
|
||||
var Model = Backbone.Model.extend({
|
||||
set: function(attrs) {
|
||||
equals(attrs.prop, 'value');
|
||||
equals(this.collection, col);
|
||||
equal(attrs.prop, 'value');
|
||||
equal(this.collection, col);
|
||||
}
|
||||
});
|
||||
col.model = Model;
|
||||
@@ -466,9 +466,9 @@ $(document).ready(function() {
|
||||
var col = new Backbone.Collection([
|
||||
{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}
|
||||
]);
|
||||
equals(col.length, 6);
|
||||
equal(col.length, 6);
|
||||
col.remove(col.models);
|
||||
equals(col.length, 0);
|
||||
equal(col.length, 0);
|
||||
});
|
||||
|
||||
test("#861, adding models to a collection which do not pass validation", function() {
|
||||
@@ -489,4 +489,37 @@ $(document).ready(function() {
|
||||
}, "Can't add an invalid model to a collection");
|
||||
});
|
||||
|
||||
test("Collection: index with comparator", function() {
|
||||
expect(4);
|
||||
var counter = 0;
|
||||
var col = new Backbone.Collection([{id: 2}, {id: 4}], {
|
||||
comparator: function(model){ return model.id; }
|
||||
}).on('add', function(model, colleciton, options){
|
||||
if (model.id == 1) {
|
||||
equal(options.index, 0);
|
||||
equal(counter++, 0);
|
||||
}
|
||||
if (model.id == 3) {
|
||||
equal(options.index, 2);
|
||||
equal(counter++, 1);
|
||||
}
|
||||
});
|
||||
col.add([{id: 3}, {id: 1}]);
|
||||
});
|
||||
|
||||
test("Collection: throwing during add leaves consistent state", function() {
|
||||
expect(4);
|
||||
var col = new Backbone.Collection();
|
||||
col.bind('test', function() { ok(false); });
|
||||
col.model = Backbone.Model.extend({
|
||||
validate: function(attrs){ if (!attrs.valid) return 'invalid'; }
|
||||
});
|
||||
var model = new col.model({id: 1, valid: true});
|
||||
raises(function() { col.add([model, {id: 2}]); });
|
||||
model.trigger('test');
|
||||
ok(!col.getByCid(model.cid));
|
||||
ok(!col.get(1));
|
||||
equal(col.length, 0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -7,12 +7,12 @@ $(document).ready(function() {
|
||||
_.extend(obj,Backbone.Events);
|
||||
obj.on('event', function() { obj.counter += 1; });
|
||||
obj.trigger('event');
|
||||
equals(obj.counter,1,'counter should be incremented.');
|
||||
equal(obj.counter,1,'counter should be incremented.');
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
equals(obj.counter, 5, 'counter should be incremented five times.');
|
||||
equal(obj.counter, 5, 'counter should be incremented five times.');
|
||||
});
|
||||
|
||||
test("Events: binding and triggering multiple events", function() {
|
||||
@@ -22,17 +22,17 @@ $(document).ready(function() {
|
||||
obj.on('a b c', function() { obj.counter += 1; });
|
||||
|
||||
obj.trigger('a');
|
||||
equals(obj.counter, 1);
|
||||
equal(obj.counter, 1);
|
||||
|
||||
obj.trigger('a b');
|
||||
equals(obj.counter, 3);
|
||||
equal(obj.counter, 3);
|
||||
|
||||
obj.trigger('c');
|
||||
equals(obj.counter, 4);
|
||||
equal(obj.counter, 4);
|
||||
|
||||
obj.off('a c');
|
||||
obj.trigger('a b c');
|
||||
equals(obj.counter, 5);
|
||||
equal(obj.counter, 5);
|
||||
});
|
||||
|
||||
test("Events: trigger all for each event", function() {
|
||||
@@ -57,7 +57,7 @@ $(document).ready(function() {
|
||||
obj.trigger('event');
|
||||
obj.off('event');
|
||||
obj.trigger('event');
|
||||
equals(obj.counter, 1, 'counter should have only been incremented once.');
|
||||
equal(obj.counter, 1, 'counter should have only been incremented once.');
|
||||
});
|
||||
|
||||
test("Events: bind two callbacks, unbind only one", function() {
|
||||
@@ -69,8 +69,8 @@ $(document).ready(function() {
|
||||
obj.trigger('event');
|
||||
obj.off('event', callback);
|
||||
obj.trigger('event');
|
||||
equals(obj.counterA, 1, 'counterA should have only been incremented once.');
|
||||
equals(obj.counterB, 2, 'counterB should have been incremented twice.');
|
||||
equal(obj.counterA, 1, 'counterA should have only been incremented once.');
|
||||
equal(obj.counterB, 2, 'counterB should have been incremented twice.');
|
||||
});
|
||||
|
||||
test("Events: unbind a callback in the midst of it firing", function() {
|
||||
@@ -84,7 +84,7 @@ $(document).ready(function() {
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
equals(obj.counter, 1, 'the callback should have been unbound.');
|
||||
equal(obj.counter, 1, 'the callback should have been unbound.');
|
||||
});
|
||||
|
||||
test("Events: two binds that unbind themeselves", function() {
|
||||
@@ -97,8 +97,8 @@ $(document).ready(function() {
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
obj.trigger('event');
|
||||
equals(obj.counterA, 1, 'counterA should have only been incremented once.');
|
||||
equals(obj.counterB, 1, 'counterB should have only been incremented once.');
|
||||
equal(obj.counterA, 1, 'counterA should have only been incremented once.');
|
||||
equal(obj.counterB, 1, 'counterB should have only been incremented once.');
|
||||
});
|
||||
|
||||
test("Events: bind a callback with a supplied context", function () {
|
||||
@@ -128,7 +128,7 @@ $(document).ready(function() {
|
||||
obj.bind('event', incr1);
|
||||
obj.bind('event', incr2);
|
||||
obj.trigger('event');
|
||||
equals(obj.counter, 3, 'counter should have been incremented three times');
|
||||
equal(obj.counter, 3, 'counter should have been incremented three times');
|
||||
});
|
||||
|
||||
test("Events: callback list is not altered during trigger", function () {
|
||||
@@ -136,13 +136,13 @@ $(document).ready(function() {
|
||||
var incr = function(){ counter++; };
|
||||
obj.bind('event', function(){ obj.bind('event', incr).bind('all', incr); })
|
||||
.trigger('event');
|
||||
equals(counter, 0, 'bind does not alter callback list');
|
||||
equal(counter, 0, 'bind does not alter callback list');
|
||||
obj.unbind()
|
||||
.bind('event', function(){ obj.unbind('event', incr).unbind('all', incr); })
|
||||
.bind('event', incr)
|
||||
.bind('all', incr)
|
||||
.trigger('event');
|
||||
equals(counter, 2, 'unbind does not alter callback list');
|
||||
equal(counter, 2, 'unbind does not alter callback list');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
204
test/model.js
204
test/model.js
@@ -33,12 +33,12 @@ $(document).ready(function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
this.one = 1;
|
||||
equals(this.collection, collection);
|
||||
equal(this.collection, collection);
|
||||
}
|
||||
});
|
||||
var model = new Model({}, {collection: collection});
|
||||
equals(model.one, 1);
|
||||
equals(model.collection, collection);
|
||||
equal(model.one, 1);
|
||||
equal(model.collection, collection);
|
||||
});
|
||||
|
||||
test("Model: initialize with attributes and options", function() {
|
||||
@@ -48,7 +48,7 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var model = new Model({}, {one: 1});
|
||||
equals(model.one, 1);
|
||||
equal(model.one, 1);
|
||||
});
|
||||
|
||||
test("Model: initialize with parsed attributes", function() {
|
||||
@@ -59,13 +59,13 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var model = new Model({value: 1}, {parse: true});
|
||||
equals(model.get('value'), 2);
|
||||
equal(model.get('value'), 2);
|
||||
});
|
||||
|
||||
test("Model: url", function() {
|
||||
equals(doc.url(), '/collection/1-the-tempest');
|
||||
equal(doc.url(), '/collection/1-the-tempest');
|
||||
doc.collection.url = '/collection/';
|
||||
equals(doc.url(), '/collection/1-the-tempest');
|
||||
equal(doc.url(), '/collection/1-the-tempest');
|
||||
doc.collection = null;
|
||||
var failed = false;
|
||||
try {
|
||||
@@ -73,7 +73,7 @@ $(document).ready(function() {
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
equals(failed, true);
|
||||
equal(failed, true);
|
||||
doc.collection = collection;
|
||||
});
|
||||
|
||||
@@ -82,9 +82,9 @@ $(document).ready(function() {
|
||||
urlRoot: '/collection'
|
||||
});
|
||||
var model = new Model();
|
||||
equals(model.url(), '/collection');
|
||||
equal(model.url(), '/collection');
|
||||
model.set({id: '+1+'});
|
||||
equals(model.url(), '/collection/%2B1%2B');
|
||||
equal(model.url(), '/collection/%2B1%2B');
|
||||
});
|
||||
|
||||
test("Model: url when using urlRoot as a function to determine urlRoot at runtime", function() {
|
||||
@@ -95,24 +95,24 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
var model = new Model({parent_id: 1});
|
||||
equals(model.url(), '/nested/1/collection');
|
||||
equal(model.url(), '/nested/1/collection');
|
||||
model.set({id: 2});
|
||||
equals(model.url(), '/nested/1/collection/2');
|
||||
equal(model.url(), '/nested/1/collection/2');
|
||||
});
|
||||
|
||||
test("Model: clone", function() {
|
||||
attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
|
||||
a = new Backbone.Model(attrs);
|
||||
b = a.clone();
|
||||
equals(a.get('foo'), 1);
|
||||
equals(a.get('bar'), 2);
|
||||
equals(a.get('baz'), 3);
|
||||
equals(b.get('foo'), a.get('foo'), "Foo should be the same on the clone.");
|
||||
equals(b.get('bar'), a.get('bar'), "Bar should be the same on the clone.");
|
||||
equals(b.get('baz'), a.get('baz'), "Baz should be the same on the clone.");
|
||||
equal(a.get('foo'), 1);
|
||||
equal(a.get('bar'), 2);
|
||||
equal(a.get('baz'), 3);
|
||||
equal(b.get('foo'), a.get('foo'), "Foo should be the same on the clone.");
|
||||
equal(b.get('bar'), a.get('bar'), "Bar should be the same on the clone.");
|
||||
equal(b.get('baz'), a.get('baz'), "Baz should be the same on the clone.");
|
||||
a.set({foo : 100});
|
||||
equals(a.get('foo'), 100);
|
||||
equals(b.get('foo'), 1, "Changing a parent attribute does not change the clone.");
|
||||
equal(a.get('foo'), 100);
|
||||
equal(b.get('foo'), 1, "Changing a parent attribute does not change the clone.");
|
||||
});
|
||||
|
||||
test("Model: isNew", function() {
|
||||
@@ -131,35 +131,35 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
test("Model: get", function() {
|
||||
equals(doc.get('title'), 'The Tempest');
|
||||
equals(doc.get('author'), 'Bill Shakespeare');
|
||||
equal(doc.get('title'), 'The Tempest');
|
||||
equal(doc.get('author'), 'Bill Shakespeare');
|
||||
});
|
||||
|
||||
test("Model: escape", function() {
|
||||
equals(doc.escape('title'), 'The Tempest');
|
||||
equal(doc.escape('title'), 'The Tempest');
|
||||
doc.set({audience: 'Bill & Bob'});
|
||||
equals(doc.escape('audience'), 'Bill & Bob');
|
||||
equal(doc.escape('audience'), 'Bill & Bob');
|
||||
doc.set({audience: 'Tim > Joan'});
|
||||
equals(doc.escape('audience'), 'Tim > Joan');
|
||||
equal(doc.escape('audience'), 'Tim > Joan');
|
||||
doc.set({audience: 10101});
|
||||
equals(doc.escape('audience'), '10101');
|
||||
equal(doc.escape('audience'), '10101');
|
||||
doc.unset('audience');
|
||||
equals(doc.escape('audience'), '');
|
||||
equal(doc.escape('audience'), '');
|
||||
});
|
||||
|
||||
test("Model: has", function() {
|
||||
attrs = {};
|
||||
a = new Backbone.Model(attrs);
|
||||
equals(a.has("name"), false);
|
||||
equal(a.has("name"), false);
|
||||
_([true, "Truth!", 1, false, '', 0]).each(function(value) {
|
||||
a.set({'name': value});
|
||||
equals(a.has("name"), true);
|
||||
equal(a.has("name"), true);
|
||||
});
|
||||
a.unset('name');
|
||||
equals(a.has('name'), false);
|
||||
equal(a.has('name'), false);
|
||||
_([null, undefined]).each(function(value) {
|
||||
a.set({'name': value});
|
||||
equals(a.has("name"), false);
|
||||
equal(a.has("name"), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,7 +177,7 @@ $(document).ready(function() {
|
||||
ok(changeCount == 1, "Change count should NOT have incremented.");
|
||||
|
||||
a.validate = function(attrs) {
|
||||
equals(attrs.foo, void 0, 'ignore values when unsetting');
|
||||
equal(attrs.foo, void 0, 'ignore values when unsetting');
|
||||
};
|
||||
a.unset('foo');
|
||||
ok(a.get('foo') == null, "Foo should have changed");
|
||||
@@ -185,7 +185,7 @@ $(document).ready(function() {
|
||||
ok(changeCount == 2, "Change count should have incremented for unset.");
|
||||
|
||||
a.unset('id');
|
||||
equals(a.id, undefined, "Unsetting the id should remove the id property.");
|
||||
equal(a.id, undefined, "Unsetting the id should remove the id property.");
|
||||
});
|
||||
|
||||
test("Model: multiple unsets", function() {
|
||||
@@ -196,7 +196,7 @@ $(document).ready(function() {
|
||||
model.set({a: 2});
|
||||
model.unset('a');
|
||||
model.unset('a');
|
||||
equals(i, 2, 'Unset does not fire an event for missing attributes.');
|
||||
equal(i, 2, 'Unset does not fire an event for missing attributes.');
|
||||
});
|
||||
|
||||
test("Model: unset and changedAttributes", function() {
|
||||
@@ -212,18 +212,18 @@ $(document).ready(function() {
|
||||
test("Model: using a non-default id attribute.", function() {
|
||||
var MongoModel = Backbone.Model.extend({idAttribute : '_id'});
|
||||
var model = new MongoModel({id: 'eye-dee', _id: 25, title: 'Model'});
|
||||
equals(model.get('id'), 'eye-dee');
|
||||
equals(model.id, 25);
|
||||
equals(model.isNew(), false);
|
||||
equal(model.get('id'), 'eye-dee');
|
||||
equal(model.id, 25);
|
||||
equal(model.isNew(), false);
|
||||
model.unset('_id');
|
||||
equals(model.id, undefined);
|
||||
equals(model.isNew(), true);
|
||||
equal(model.id, undefined);
|
||||
equal(model.isNew(), true);
|
||||
});
|
||||
|
||||
test("Model: set an empty string", function() {
|
||||
var model = new Backbone.Model({name : "Model"});
|
||||
model.set({name : ''});
|
||||
equals(model.get('name'), '');
|
||||
equal(model.get('name'), '');
|
||||
});
|
||||
|
||||
test("Model: clear", function() {
|
||||
@@ -235,8 +235,8 @@ $(document).ready(function() {
|
||||
ok('name' in changedAttrs);
|
||||
});
|
||||
model.clear();
|
||||
equals(changed, true);
|
||||
equals(model.get('name'), undefined);
|
||||
equal(changed, true);
|
||||
equal(model.get('name'), undefined);
|
||||
});
|
||||
|
||||
test("Model: defaults", function() {
|
||||
@@ -247,8 +247,8 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var model = new Defaulted({two: null});
|
||||
equals(model.get('one'), 1);
|
||||
equals(model.get('two'), null);
|
||||
equal(model.get('one'), 1);
|
||||
equal(model.get('two'), null);
|
||||
Defaulted = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
@@ -258,25 +258,25 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var model = new Defaulted({two: null});
|
||||
equals(model.get('one'), 3);
|
||||
equals(model.get('two'), null);
|
||||
equal(model.get('one'), 3);
|
||||
equal(model.get('two'), null);
|
||||
});
|
||||
|
||||
test("Model: change, hasChanged, changedAttributes, previous, previousAttributes", function() {
|
||||
var model = new Backbone.Model({name : "Tim", age : 10});
|
||||
equals(model.changedAttributes(), false);
|
||||
equal(model.changedAttributes(), false);
|
||||
model.on('change', function() {
|
||||
ok(model.hasChanged('name'), 'name changed');
|
||||
ok(!model.hasChanged('age'), 'age did not');
|
||||
ok(_.isEqual(model.changedAttributes(), {name : 'Rob'}), 'changedAttributes returns the changed attrs');
|
||||
equals(model.previous('name'), 'Tim');
|
||||
equal(model.previous('name'), 'Tim');
|
||||
ok(_.isEqual(model.previousAttributes(), {name : "Tim", age : 10}), 'previousAttributes is correct');
|
||||
});
|
||||
model.set({name : 'Rob'}, {silent : true});
|
||||
equals(model.hasChanged(), true);
|
||||
equals(model.hasChanged('name'), true);
|
||||
equal(model.hasChanged(), true);
|
||||
equal(model.hasChanged('name'), true);
|
||||
model.change();
|
||||
equals(model.get('name'), 'Rob');
|
||||
equal(model.get('name'), 'Rob');
|
||||
});
|
||||
|
||||
test("Model: change with options", function() {
|
||||
@@ -287,9 +287,9 @@ $(document).ready(function() {
|
||||
});
|
||||
model.set({name: 'Bob'}, {silent: true});
|
||||
model.change({prefix: 'Mr. '});
|
||||
equals(value, 'Mr. Bob');
|
||||
equal(value, 'Mr. Bob');
|
||||
model.set({name: 'Sue'}, {prefix: 'Ms. '});
|
||||
equals(value, 'Ms. Sue');
|
||||
equal(value, 'Ms. Sue');
|
||||
});
|
||||
|
||||
test("Model: change after initialize", function () {
|
||||
@@ -298,7 +298,7 @@ $(document).ready(function() {
|
||||
var obj = new Backbone.Model(attrs);
|
||||
obj.on('change', function() { changed += 1; });
|
||||
obj.set(attrs);
|
||||
equals(changed, 0);
|
||||
equal(changed, 0);
|
||||
});
|
||||
|
||||
test("Model: save within change event", function () {
|
||||
@@ -322,12 +322,12 @@ $(document).ready(function() {
|
||||
lastError = error;
|
||||
}});
|
||||
|
||||
equals(lastError, "Can't change admin status.");
|
||||
equal(lastError, "Can't change admin status.");
|
||||
});
|
||||
|
||||
test("Model: save", function() {
|
||||
doc.save({title : "Henry V"});
|
||||
equals(lastRequest[0], 'update');
|
||||
equal(lastRequest[0], 'update');
|
||||
ok(_.isEqual(lastRequest[1], doc));
|
||||
});
|
||||
|
||||
@@ -337,7 +337,7 @@ $(document).ready(function() {
|
||||
options.success();
|
||||
};
|
||||
model.save('title', 'Twelfth Night');
|
||||
equals(model.get('title'), 'Twelfth Night');
|
||||
equal(model.get('title'), 'Twelfth Night');
|
||||
});
|
||||
|
||||
test("Model: fetch", function() {
|
||||
@@ -348,7 +348,7 @@ $(document).ready(function() {
|
||||
|
||||
test("Model: destroy", function() {
|
||||
doc.destroy();
|
||||
equals(lastRequest[0], 'delete');
|
||||
equal(lastRequest[0], 'delete');
|
||||
ok(_.isEqual(lastRequest[1], doc));
|
||||
});
|
||||
|
||||
@@ -370,16 +370,16 @@ $(document).ready(function() {
|
||||
lastError = error;
|
||||
});
|
||||
var result = model.set({a: 100});
|
||||
equals(result, model);
|
||||
equals(model.get('a'), 100);
|
||||
equals(lastError, undefined);
|
||||
equal(result, model);
|
||||
equal(model.get('a'), 100);
|
||||
equal(lastError, undefined);
|
||||
result = model.set({admin: true}, {silent: true});
|
||||
equals(lastError, undefined);
|
||||
equals(model.get('admin'), true);
|
||||
equal(lastError, undefined);
|
||||
equal(model.get('admin'), true);
|
||||
result = model.set({a: 200, admin: true});
|
||||
equals(result, false);
|
||||
equals(model.get('a'), 100);
|
||||
equals(lastError, "Can't change admin status.");
|
||||
equal(result, false);
|
||||
equal(model.get('a'), 100);
|
||||
equal(lastError, "Can't change admin status.");
|
||||
});
|
||||
|
||||
test("Model: validate on unset and clear", function() {
|
||||
@@ -394,16 +394,16 @@ $(document).ready(function() {
|
||||
}
|
||||
};
|
||||
model.set({name: "Two"});
|
||||
equals(model.get('name'), 'Two');
|
||||
equals(error, undefined);
|
||||
equal(model.get('name'), 'Two');
|
||||
equal(error, undefined);
|
||||
model.unset('name');
|
||||
equals(error, true);
|
||||
equals(model.get('name'), 'Two');
|
||||
equal(error, true);
|
||||
equal(model.get('name'), 'Two');
|
||||
model.clear();
|
||||
equals(model.get('name'), 'Two');
|
||||
equal(model.get('name'), 'Two');
|
||||
delete model.validate;
|
||||
model.clear();
|
||||
equals(model.get('name'), undefined);
|
||||
equal(model.get('name'), undefined);
|
||||
});
|
||||
|
||||
test("Model: validate with error callback", function() {
|
||||
@@ -419,22 +419,22 @@ $(document).ready(function() {
|
||||
boundError = true;
|
||||
});
|
||||
var result = model.set({a: 100}, {error: callback});
|
||||
equals(result, model);
|
||||
equals(model.get('a'), 100);
|
||||
equals(lastError, undefined);
|
||||
equals(boundError, undefined);
|
||||
equal(result, model);
|
||||
equal(model.get('a'), 100);
|
||||
equal(lastError, undefined);
|
||||
equal(boundError, undefined);
|
||||
result = model.set({a: 200, admin: true}, {error: callback});
|
||||
equals(result, false);
|
||||
equals(model.get('a'), 100);
|
||||
equals(lastError, "Can't change admin status.");
|
||||
equals(boundError, undefined);
|
||||
equal(result, false);
|
||||
equal(model.get('a'), 100);
|
||||
equal(lastError, "Can't change admin status.");
|
||||
equal(boundError, undefined);
|
||||
});
|
||||
|
||||
test("Model: defaults always extend attrs (#459)", function() {
|
||||
var Defaulted = Backbone.Model.extend({
|
||||
defaults: {one: 1},
|
||||
initialize : function(attrs, opts) {
|
||||
equals(this.attributes.one, 1);
|
||||
equal(this.attributes.one, 1);
|
||||
}
|
||||
});
|
||||
var providedattrs = new Defaulted({});
|
||||
@@ -455,10 +455,10 @@ $(document).ready(function() {
|
||||
var adult = new Parent;
|
||||
var kid = new Child;
|
||||
|
||||
equals(Child.classProp, Parent.classProp);
|
||||
equal(Child.classProp, Parent.classProp);
|
||||
notEqual(Child.classProp, undefined);
|
||||
|
||||
equals(kid.instancePropSame, adult.instancePropSame);
|
||||
equal(kid.instancePropSame, adult.instancePropSame);
|
||||
notEqual(kid.instancePropSame, undefined);
|
||||
|
||||
notEqual(Child.prototype.instancePropDiff, Parent.prototype.instancePropDiff);
|
||||
@@ -469,8 +469,8 @@ $(document).ready(function() {
|
||||
var A = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
this.on("change:state", function(a, newState) {
|
||||
equals(a.previous('state'), undefined);
|
||||
equals(newState, 'hello');
|
||||
equal(a.previous('state'), undefined);
|
||||
equal(newState, 'hello');
|
||||
// Fire a nested change event.
|
||||
this.set({ other: "whatever" });
|
||||
});
|
||||
@@ -480,8 +480,8 @@ $(document).ready(function() {
|
||||
var B = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
this.get("a").on("change:state", function(a, newState) {
|
||||
equals(a.previous('state'), undefined);
|
||||
equals(newState, 'hello');
|
||||
equal(a.previous('state'), undefined);
|
||||
equal(newState, 'hello');
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -519,9 +519,9 @@ $(document).ready(function() {
|
||||
var model = new Backbone.Model;
|
||||
|
||||
var assertion = function() {
|
||||
equals(model.get('a'), 'a');
|
||||
equals(model.get('b'), 'b');
|
||||
equals(model.get('c'), 'c');
|
||||
equal(model.get('a'), 'a');
|
||||
equal(model.get('b'), 'b');
|
||||
equal(model.get('c'), 'c');
|
||||
};
|
||||
|
||||
model.on('change:a', assertion);
|
||||
@@ -531,4 +531,28 @@ $(document).ready(function() {
|
||||
model.set({a: 'a', b: 'b', c: 'c'});
|
||||
});
|
||||
|
||||
test("#871, set with attributes property", function() {
|
||||
var model = new Backbone.Model();
|
||||
model.set({attributes: true});
|
||||
ok(model.has('attributes'));
|
||||
});
|
||||
|
||||
test("set value regardless of equality/change", function() {
|
||||
var model = new Backbone.Model({x: []});
|
||||
var a = [];
|
||||
model.set({x: a});
|
||||
ok(model.get('x') === a);
|
||||
});
|
||||
|
||||
test("unset fires change for undefined attributes", 1, function() {
|
||||
var model = new Backbone.Model({x: undefined});
|
||||
model.bind('change:x', function(){ ok(true); });
|
||||
model.unset('x');
|
||||
});
|
||||
|
||||
test("set: undefined values", function() {
|
||||
var model = new Backbone.Model({x: undefined});
|
||||
ok('x' in model.attributes);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Backbone.noConflict");
|
||||
|
||||
|
||||
test('Backbone.noConflict', function() {
|
||||
var noconflictBackbone = Backbone.noConflict();
|
||||
equals(window.Backbone, undefined, 'Returned window.Backbone');
|
||||
equal(window.Backbone, undefined, 'Returned window.Backbone');
|
||||
window.Backbone = noconflictBackbone;
|
||||
equals(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone');
|
||||
equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,16 +72,16 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
test("Router: initialize", function() {
|
||||
equals(router.testing, 101);
|
||||
equal(router.testing, 101);
|
||||
});
|
||||
|
||||
asyncTest("Router: routes (simple)", 4, function() {
|
||||
window.location.hash = 'search/news';
|
||||
setTimeout(function() {
|
||||
equals(router.query, 'news');
|
||||
equals(router.page, undefined);
|
||||
equals(lastRoute, 'search');
|
||||
equals(lastArgs[0], 'news');
|
||||
equal(router.query, 'news');
|
||||
equal(router.page, undefined);
|
||||
equal(lastRoute, 'search');
|
||||
equal(lastArgs[0], 'news');
|
||||
start();
|
||||
}, 10);
|
||||
});
|
||||
@@ -89,40 +89,40 @@ $(document).ready(function() {
|
||||
asyncTest("Router: routes (two part)", 2, function() {
|
||||
window.location.hash = 'search/nyc/p10';
|
||||
setTimeout(function() {
|
||||
equals(router.query, 'nyc');
|
||||
equals(router.page, '10');
|
||||
equal(router.query, 'nyc');
|
||||
equal(router.page, '10');
|
||||
start();
|
||||
}, 10);
|
||||
});
|
||||
|
||||
test("Router: routes via navigate", 2, function() {
|
||||
Backbone.history.navigate('search/manhattan/p20', {trigger: true});
|
||||
equals(router.query, 'manhattan');
|
||||
equals(router.page, '20');
|
||||
equal(router.query, 'manhattan');
|
||||
equal(router.page, '20');
|
||||
});
|
||||
|
||||
test("Router: routes via navigate for backwards-compatibility", 2, function() {
|
||||
Backbone.history.navigate('search/manhattan/p20', true);
|
||||
equals(router.query, 'manhattan');
|
||||
equals(router.page, '20');
|
||||
equal(router.query, 'manhattan');
|
||||
equal(router.page, '20');
|
||||
});
|
||||
|
||||
test("Router: doesn't fire routes to the same place twice", function() {
|
||||
equals(router.count, 0);
|
||||
equal(router.count, 0);
|
||||
router.navigate('counter', {trigger: true});
|
||||
equals(router.count, 1);
|
||||
equal(router.count, 1);
|
||||
router.navigate('/counter', {trigger: true});
|
||||
router.navigate('/counter', {trigger: true});
|
||||
equals(router.count, 1);
|
||||
equal(router.count, 1);
|
||||
router.navigate('search/counter', {trigger: true});
|
||||
router.navigate('counter', {trigger: true});
|
||||
equals(router.count, 2);
|
||||
equal(router.count, 2);
|
||||
});
|
||||
|
||||
test("Router: use implicit callback if none provided", function() {
|
||||
router.count = 0;
|
||||
router.navigate('implicit', {trigger: true})
|
||||
equals(router.count, 1);
|
||||
equal(router.count, 1);
|
||||
});
|
||||
|
||||
asyncTest("Router: routes via navigate with {replace: true}", function() {
|
||||
@@ -131,10 +131,10 @@ $(document).ready(function() {
|
||||
router.navigate('search/manhattan/then_here');
|
||||
router.navigate('search/manhattan/finally_here', {replace: true});
|
||||
|
||||
equals(window.location.hash, "#search/manhattan/finally_here");
|
||||
equal(window.location.hash, "#search/manhattan/finally_here");
|
||||
window.history.go(-1);
|
||||
setTimeout(function() {
|
||||
equals(window.location.hash, "#search/manhattan/start_here");
|
||||
equal(window.location.hash, "#search/manhattan/start_here");
|
||||
start();
|
||||
}, 500);
|
||||
});
|
||||
@@ -142,7 +142,7 @@ $(document).ready(function() {
|
||||
asyncTest("Router: routes (splats)", function() {
|
||||
window.location.hash = 'splat/long-list/of/splatted_99args/end';
|
||||
setTimeout(function() {
|
||||
equals(router.args, 'long-list/of/splatted_99args');
|
||||
equal(router.args, 'long-list/of/splatted_99args');
|
||||
start();
|
||||
}, 10);
|
||||
});
|
||||
@@ -150,9 +150,9 @@ $(document).ready(function() {
|
||||
asyncTest("Router: routes (complex)", 3, function() {
|
||||
window.location.hash = 'one/two/three/complex-part/four/five/six/seven';
|
||||
setTimeout(function() {
|
||||
equals(router.first, 'one/two/three');
|
||||
equals(router.part, 'part');
|
||||
equals(router.rest, 'four/five/six/seven');
|
||||
equal(router.first, 'one/two/three');
|
||||
equal(router.part, 'part');
|
||||
equal(router.rest, 'four/five/six/seven');
|
||||
start();
|
||||
}, 10);
|
||||
});
|
||||
@@ -160,11 +160,11 @@ $(document).ready(function() {
|
||||
asyncTest("Router: routes (query)", 5, function() {
|
||||
window.location.hash = 'mandel?a=b&c=d';
|
||||
setTimeout(function() {
|
||||
equals(router.entity, 'mandel');
|
||||
equals(router.queryArgs, 'a=b&c=d');
|
||||
equals(lastRoute, 'query');
|
||||
equals(lastArgs[0], 'mandel');
|
||||
equals(lastArgs[1], 'a=b&c=d');
|
||||
equal(router.entity, 'mandel');
|
||||
equal(router.queryArgs, 'a=b&c=d');
|
||||
equal(lastRoute, 'query');
|
||||
equal(lastArgs[0], 'mandel');
|
||||
equal(lastArgs[1], 'a=b&c=d');
|
||||
start();
|
||||
}, 10);
|
||||
});
|
||||
@@ -172,7 +172,7 @@ $(document).ready(function() {
|
||||
asyncTest("Router: routes (anything)", 1, function() {
|
||||
window.location.hash = 'doesnt-match-a-route';
|
||||
setTimeout(function() {
|
||||
equals(router.anything, 'doesnt-match-a-route');
|
||||
equal(router.anything, 'doesnt-match-a-route');
|
||||
start();
|
||||
window.location.hash = '';
|
||||
}, 10);
|
||||
@@ -185,7 +185,7 @@ $(document).ready(function() {
|
||||
router.bind("route:noCallback", myCallback);
|
||||
window.location.hash = "noCallback";
|
||||
setTimeout(function(){
|
||||
equals(callbackFired, true);
|
||||
equal(callbackFired, true);
|
||||
start();
|
||||
window.location.hash = '';
|
||||
}, 10);
|
||||
|
||||
94
test/sync.js
94
test/sync.js
@@ -22,102 +22,102 @@ $(document).ready(function() {
|
||||
test("sync: read", function() {
|
||||
Backbone.sync = originalSync;
|
||||
library.fetch();
|
||||
equals(lastRequest.url, '/library');
|
||||
equals(lastRequest.type, 'GET');
|
||||
equals(lastRequest.dataType, 'json');
|
||||
equal(lastRequest.url, '/library');
|
||||
equal(lastRequest.type, 'GET');
|
||||
equal(lastRequest.dataType, 'json');
|
||||
ok(_.isEmpty(lastRequest.data));
|
||||
});
|
||||
|
||||
test("sync: passing data", function() {
|
||||
library.fetch({data: {a: 'a', one: 1}});
|
||||
equals(lastRequest.url, '/library');
|
||||
equals(lastRequest.data.a, 'a');
|
||||
equals(lastRequest.data.one, 1);
|
||||
equal(lastRequest.url, '/library');
|
||||
equal(lastRequest.data.a, 'a');
|
||||
equal(lastRequest.data.one, 1);
|
||||
});
|
||||
|
||||
test("sync: create", function() {
|
||||
library.create(attrs, {wait: false});
|
||||
equals(lastRequest.url, '/library');
|
||||
equals(lastRequest.type, 'POST');
|
||||
equals(lastRequest.dataType, 'json');
|
||||
equal(lastRequest.url, '/library');
|
||||
equal(lastRequest.type, 'POST');
|
||||
equal(lastRequest.dataType, 'json');
|
||||
var data = JSON.parse(lastRequest.data);
|
||||
equals(data.title, 'The Tempest');
|
||||
equals(data.author, 'Bill Shakespeare');
|
||||
equals(data.length, 123);
|
||||
equal(data.title, 'The Tempest');
|
||||
equal(data.author, 'Bill Shakespeare');
|
||||
equal(data.length, 123);
|
||||
});
|
||||
|
||||
test("sync: update", function() {
|
||||
library.first().save({id: '1-the-tempest', author: 'William Shakespeare'});
|
||||
equals(lastRequest.url, '/library/1-the-tempest');
|
||||
equals(lastRequest.type, 'PUT');
|
||||
equals(lastRequest.dataType, 'json');
|
||||
equal(lastRequest.url, '/library/1-the-tempest');
|
||||
equal(lastRequest.type, 'PUT');
|
||||
equal(lastRequest.dataType, 'json');
|
||||
var data = JSON.parse(lastRequest.data);
|
||||
equals(data.id, '1-the-tempest');
|
||||
equals(data.title, 'The Tempest');
|
||||
equals(data.author, 'William Shakespeare');
|
||||
equals(data.length, 123);
|
||||
equal(data.id, '1-the-tempest');
|
||||
equal(data.title, 'The Tempest');
|
||||
equal(data.author, 'William Shakespeare');
|
||||
equal(data.length, 123);
|
||||
});
|
||||
|
||||
test("sync: update with emulateHTTP and emulateJSON", function() {
|
||||
Backbone.emulateHTTP = Backbone.emulateJSON = true;
|
||||
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'POST');
|
||||
equals(lastRequest.dataType, 'json');
|
||||
equals(lastRequest.data._method, 'PUT');
|
||||
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);
|
||||
equals(data.id, '2-the-tempest');
|
||||
equals(data.author, 'Tim Shakespeare');
|
||||
equals(data.length, 123);
|
||||
equal(data.id, '2-the-tempest');
|
||||
equal(data.author, 'Tim Shakespeare');
|
||||
equal(data.length, 123);
|
||||
Backbone.emulateHTTP = Backbone.emulateJSON = false;
|
||||
});
|
||||
|
||||
test("sync: update with just emulateHTTP", function() {
|
||||
Backbone.emulateHTTP = true;
|
||||
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'POST');
|
||||
equals(lastRequest.contentType, 'application/json');
|
||||
equal(lastRequest.url, '/library/2-the-tempest');
|
||||
equal(lastRequest.type, 'POST');
|
||||
equal(lastRequest.contentType, 'application/json');
|
||||
var data = JSON.parse(lastRequest.data);
|
||||
equals(data.id, '2-the-tempest');
|
||||
equals(data.author, 'Tim Shakespeare');
|
||||
equals(data.length, 123);
|
||||
equal(data.id, '2-the-tempest');
|
||||
equal(data.author, 'Tim Shakespeare');
|
||||
equal(data.length, 123);
|
||||
Backbone.emulateHTTP = false;
|
||||
});
|
||||
|
||||
test("sync: update with just emulateJSON", function() {
|
||||
Backbone.emulateJSON = true;
|
||||
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'PUT');
|
||||
equals(lastRequest.contentType, 'application/x-www-form-urlencoded');
|
||||
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);
|
||||
equals(data.id, '2-the-tempest');
|
||||
equals(data.author, 'Tim Shakespeare');
|
||||
equals(data.length, 123);
|
||||
equal(data.id, '2-the-tempest');
|
||||
equal(data.author, 'Tim Shakespeare');
|
||||
equal(data.length, 123);
|
||||
Backbone.emulateJSON = false;
|
||||
});
|
||||
|
||||
test("sync: read model", function() {
|
||||
library.first().fetch();
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'GET');
|
||||
equal(lastRequest.url, '/library/2-the-tempest');
|
||||
equal(lastRequest.type, 'GET');
|
||||
ok(_.isEmpty(lastRequest.data));
|
||||
});
|
||||
|
||||
test("sync: destroy", function() {
|
||||
library.first().destroy({wait: true});
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'DELETE');
|
||||
equals(lastRequest.data, null);
|
||||
equal(lastRequest.url, '/library/2-the-tempest');
|
||||
equal(lastRequest.type, 'DELETE');
|
||||
equal(lastRequest.data, null);
|
||||
});
|
||||
|
||||
test("sync: destroy with emulateHTTP", function() {
|
||||
Backbone.emulateHTTP = Backbone.emulateJSON = true;
|
||||
library.first().destroy();
|
||||
equals(lastRequest.url, '/library/2-the-tempest');
|
||||
equals(lastRequest.type, 'POST');
|
||||
equals(JSON.stringify(lastRequest.data), '{"_method":"DELETE"}');
|
||||
equal(lastRequest.url, '/library/2-the-tempest');
|
||||
equal(lastRequest.type, 'POST');
|
||||
equal(JSON.stringify(lastRequest.data), '{"_method":"DELETE"}');
|
||||
Backbone.emulateHTTP = Backbone.emulateJSON = false;
|
||||
});
|
||||
|
||||
@@ -127,7 +127,7 @@ $(document).ready(function() {
|
||||
model.fetch();
|
||||
});
|
||||
model.fetch({url: '/one/two'});
|
||||
equals(lastRequest.url, '/one/two');
|
||||
equal(lastRequest.url, '/one/two');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
68
test/view.js
68
test/view.js
@@ -8,10 +8,10 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
test("View: constructor", function() {
|
||||
equals(view.el.id, 'test-view');
|
||||
equals(view.el.className, 'test-view');
|
||||
equals(view.options.id, 'test-view');
|
||||
equals(view.options.className, 'test-view');
|
||||
equal(view.el.id, 'test-view');
|
||||
equal(view.el.className, 'test-view');
|
||||
equal(view.options.id, 'test-view');
|
||||
equal(view.options.className, 'test-view');
|
||||
});
|
||||
|
||||
test("View: jQuery", function() {
|
||||
@@ -22,9 +22,9 @@ $(document).ready(function() {
|
||||
|
||||
test("View: make", function() {
|
||||
var div = view.make('div', {id: 'test-div'}, "one two three");
|
||||
equals(div.tagName.toLowerCase(), 'div');
|
||||
equals(div.id, 'test-div');
|
||||
equals($(div).text(), 'one two three');
|
||||
equal(div.tagName.toLowerCase(), 'div');
|
||||
equal(div.id, 'test-div');
|
||||
equal($(div).text(), 'one two three');
|
||||
});
|
||||
|
||||
test("View: initialize", function() {
|
||||
@@ -34,7 +34,7 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
var view = new View;
|
||||
equals(view.one, 1);
|
||||
equal(view.one, 1);
|
||||
});
|
||||
|
||||
test("View: delegateEvents", function() {
|
||||
@@ -45,15 +45,15 @@ $(document).ready(function() {
|
||||
var events = {"click #qunit-banner": "increment"};
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(counter, 1);
|
||||
equals(counter2, 1);
|
||||
equal(counter, 1);
|
||||
equal(counter2, 1);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(counter, 2);
|
||||
equals(counter2, 2);
|
||||
equal(counter, 2);
|
||||
equal(counter2, 2);
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(counter, 3);
|
||||
equals(counter2, 3);
|
||||
equal(counter, 3);
|
||||
equal(counter2, 3);
|
||||
});
|
||||
|
||||
test("View: delegateEvents allows functions for callbacks", function() {
|
||||
@@ -62,12 +62,12 @@ $(document).ready(function() {
|
||||
var events = {"click": function() { this.counter++; }};
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(view.counter, 1);
|
||||
equal(view.counter, 1);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(view.counter, 2);
|
||||
equal(view.counter, 2);
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-banner').trigger('click');
|
||||
equals(view.counter, 3);
|
||||
equal(view.counter, 3);
|
||||
});
|
||||
|
||||
test("View: undelegateEvents", function() {
|
||||
@@ -79,16 +79,16 @@ $(document).ready(function() {
|
||||
var events = {"click #qunit-userAgent": "increment"};
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-userAgent').trigger('click');
|
||||
equals(counter, 1);
|
||||
equals(counter2, 1);
|
||||
equal(counter, 1);
|
||||
equal(counter2, 1);
|
||||
view.undelegateEvents();
|
||||
$('#qunit-userAgent').trigger('click');
|
||||
equals(counter, 1);
|
||||
equals(counter2, 2);
|
||||
equal(counter, 1);
|
||||
equal(counter2, 2);
|
||||
view.delegateEvents(events);
|
||||
$('#qunit-userAgent').trigger('click');
|
||||
equals(counter, 2);
|
||||
equals(counter2, 3);
|
||||
equal(counter, 2);
|
||||
equal(counter2, 3);
|
||||
});
|
||||
|
||||
test("View: _ensureElement with DOM node el", function() {
|
||||
@@ -96,7 +96,7 @@ $(document).ready(function() {
|
||||
el: document.body
|
||||
});
|
||||
var view = new ViewClass;
|
||||
equals(view.el, document.body);
|
||||
equal(view.el, document.body);
|
||||
});
|
||||
|
||||
test("View: _ensureElement with string el", function() {
|
||||
@@ -104,13 +104,13 @@ $(document).ready(function() {
|
||||
el: "body"
|
||||
});
|
||||
var view = new ViewClass;
|
||||
equals(view.el, document.body);
|
||||
equal(view.el, document.body);
|
||||
|
||||
ViewClass = Backbone.View.extend({
|
||||
el: "body > h2"
|
||||
});
|
||||
view = new ViewClass;
|
||||
equals(view.el, $("#qunit-banner").get(0));
|
||||
equal(view.el, $("#qunit-banner").get(0));
|
||||
|
||||
ViewClass = Backbone.View.extend({
|
||||
el: "#nonexistent"
|
||||
@@ -121,8 +121,8 @@ $(document).ready(function() {
|
||||
|
||||
test("View: with attributes", function() {
|
||||
var view = new Backbone.View({attributes : {'class': 'one', id: 'two'}});
|
||||
equals(view.el.className, 'one');
|
||||
equals(view.el.id, 'two');
|
||||
equal(view.el.className, 'one');
|
||||
equal(view.el.id, 'two');
|
||||
});
|
||||
|
||||
test("View: with attributes as a function", function() {
|
||||
@@ -131,7 +131,7 @@ $(document).ready(function() {
|
||||
return {'class': 'dynamic'};
|
||||
}
|
||||
});
|
||||
equals((new viewClass).el.className, 'dynamic');
|
||||
equal((new viewClass).el.className, 'dynamic');
|
||||
});
|
||||
|
||||
test("View: multiple views per element", function() {
|
||||
@@ -147,15 +147,15 @@ $(document).ready(function() {
|
||||
|
||||
var view1 = new ViewClass;
|
||||
$("body").trigger("click");
|
||||
equals(1, count);
|
||||
equal(1, count);
|
||||
|
||||
var view2 = new ViewClass;
|
||||
$("body").trigger("click");
|
||||
equals(3, count);
|
||||
equal(3, count);
|
||||
|
||||
view1.delegateEvents();
|
||||
$("body").trigger("click");
|
||||
equals(5, count);
|
||||
equal(5, count);
|
||||
});
|
||||
|
||||
test("View: custom events, with namespaces", function() {
|
||||
@@ -172,10 +172,10 @@ $(document).ready(function() {
|
||||
|
||||
var view = new ViewClass;
|
||||
$('body').trigger('fake$event').trigger('fake$event');
|
||||
equals(count, 2);
|
||||
equal(count, 2);
|
||||
$('body').unbind('.namespaced');
|
||||
$('body').trigger('fake$event');
|
||||
equals(count, 2);
|
||||
equal(count, 2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user