Skip to content
1,609 changes: 1,571 additions & 38 deletions public/javascripts/backbone.js

Large diffs are not rendered by default.

1,289 changes: 1,257 additions & 32 deletions public/javascripts/underscore.js

Large diffs are not rendered by default.

201 changes: 163 additions & 38 deletions readme.md

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions spec/javascripts/helpers/SpecHelper.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
beforeEach(function() {
this.addMatchers({
toBePlaying: function(expectedSong) {
var player = this.actual;
return player.currentlyPlayingSong === expectedSong &&
player.isPlaying;
}
});
});
var Logger = function () {
this.reset();
};

_.extend(Logger.prototype, {
log: function (content) {
this.entries.push(content);
},
reset: function () {
this.entries = [];
}
});
140 changes: 137 additions & 3 deletions spec/javascripts/multiSelect.deselect.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
describe("multi-select collection deselecting", function(){
var Model = Backbone.Model.extend({
initialize: function(){
var selectable = new Backbone.Picky.Selectable();
var selectable = new Backbone.Picky.Selectable(this);
_.extend(this, selectable);
}
});
Expand All @@ -10,7 +10,7 @@ describe("multi-select collection deselecting", function(){
model: Model,

initialize: function(){
var multiSelect = new Backbone.Picky.MultiSelect();
var multiSelect = new Backbone.Picky.MultiSelect(this);
_.extend(this, multiSelect);
}
});
Expand Down Expand Up @@ -42,6 +42,33 @@ describe("multi-select collection deselecting", function(){
});
});

describe("when no models are selected, and deselecting all, with options.silent enabled", function(){
var m1, m2, collection;

beforeEach(function(){
m1 = new Model();
m2 = new Model();

collection = new Collection([m1, m2]);
spyOn(collection, "trigger").andCallThrough();

collection.selectNone({silent: true});
});

it("should not trigger 'none' selected event", function(){
expect(collection.trigger).not.toHaveBeenCalledWith("select:none", collection);
});

it("should have a selected count of 0", function(){
expect(collection.selectedLength).toBe(0);
});

it("should not have any models in the selected list", function(){
var size = _.size(collection.selected);
expect(size).toBe(0);
});
});

describe("when 1 model is selected, and deselecting all", function(){
var m1, m2, collection;

Expand Down Expand Up @@ -70,18 +97,63 @@ describe("multi-select collection deselecting", function(){
});
});

describe("when all models are selected, and deselecting all", function(){
describe("when 1 model is selected, and deselecting all, with options.silent enabled", function(){
var m1, m2, collection;

beforeEach(function(){
m1 = new Model();
m2 = new Model();

collection = new Collection([m1, m2]);
m1.select();

spyOn(collection, "trigger").andCallThrough();
collection.selectNone({silent: true});
});

it("should not trigger 'none' selected event", function(){
expect(collection.trigger).not.toHaveBeenCalledWith("select:none", collection);
});

it("should have a selected count of 0", function(){
expect(collection.selectedLength).toBe(0);
});

it("should not have any models in the selected list", function(){
var size = _.size(collection.selected);
expect(size).toBe(0);
});
});

describe("when all models are selected, and deselecting all", function(){
var m1, m2, collection, selectedEventState, selectNoneEventState;

beforeEach(function(){
selectedEventState = { model: {}, collection: {} };
selectNoneEventState = { m1: {}, m2: {}, collection: {} };

m1 = new Model();
m2 = new Model();

collection = new Collection([m1, m2]);
m1.select();
m2.select();

spyOn(collection, "trigger").andCallThrough();

m1.on('deselected', function (model) {
selectedEventState.model.selected = model && model.selected;
selectedEventState.collection.selected = _.clone(collection.selected);
selectedEventState.collection.selectedLength = collection.selectedLength;
});

collection.on('select:none', function () {
selectNoneEventState.m1.selected = m1.selected;
selectNoneEventState.m2.selected = m2.selected;
selectNoneEventState.collection.selected = _.clone(collection.selected);
selectNoneEventState.collection.selectedLength = collection.selectedLength;
});

collection.selectNone();
});

Expand All @@ -97,6 +169,68 @@ describe("multi-select collection deselecting", function(){
var size = _.size(collection.selected);
expect(size).toBe(0);
});

it('should trigger a model\'s deselected event after the model status has been updated', function () {
expect(selectedEventState.model.selected).toEqual(false);
});

it('should trigger a model\'s selected event after the collection\'s selected models have been updated with that model', function () {
// m2 doesn't necessarily have to be removed from collection.selected at
// this time. The point is that events are fired when model and collection
// states are consistent. When m1 fires the 'deselected' event, only m1
// must have been removed from the collection.
expect(selectedEventState.collection.selected[m1.cid]).toBeUndefined();
});

it('should trigger a model\'s selected event after the collection\'s selected length has been updated', function () {
// collection.selectedLength could be 0 or 1 at this time. Again, all we
// are asking for is consistency - see comment above.
expect(selectedEventState.collection.selectedLength).toBeLessThan(2);
expect(selectedEventState.collection.selectedLength).toEqual(_.size(selectedEventState.collection.selected));
});

it('should trigger the collection\'s select:none event after the model status has been updated', function () {
expect(selectNoneEventState.m1.selected).toEqual(false);
expect(selectNoneEventState.m2.selected).toEqual(false);
});

it('should trigger the collection\'s select:none event after the collection\'s selected models have been updated', function () {
expect(selectNoneEventState.collection.selected).toEqual({});
});

it('should trigger the collection\'s select:none event after the collection\'s selected length has been updated', function () {
expect(selectNoneEventState.collection.selectedLength).toBe(0);
});

});

describe("when all models are selected, and deselecting all, with options.silent enabled", function(){
var m1, m2, collection;

beforeEach(function(){
m1 = new Model();
m2 = new Model();

collection = new Collection([m1, m2]);
m1.select();
m2.select();

spyOn(collection, "trigger").andCallThrough();
collection.selectNone({silent: true});
});

it("should not trigger 'none' selected event", function(){
expect(collection.trigger).not.toHaveBeenCalledWith("select:none", collection);
});

it("should have a selected count of 0", function(){
expect(collection.selectedLength).toBe(0);
});

it("should not have any models in the selected list", function(){
var size = _.size(collection.selected);
expect(size).toBe(0);
});
});

});
Loading