alpha-simprini-engine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +38 -0
- data/app/assets/javascripts/alpha_simprini.coffee +15 -0
- data/app/assets/javascripts/alpha_simprini/application.coffee +22 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/binding.coffee +119 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/helpers.coffee +17 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/tags.coffee +7 -0
- data/app/assets/javascripts/alpha_simprini/collection.coffee +62 -0
- data/app/assets/javascripts/alpha_simprini/delegate.coffee +21 -0
- data/app/assets/javascripts/alpha_simprini/event.coffee +75 -0
- data/app/assets/javascripts/alpha_simprini/html.coffee +56 -0
- data/app/assets/javascripts/alpha_simprini/mixin.coffee +10 -0
- data/app/assets/javascripts/alpha_simprini/model.coffee +137 -0
- data/app/assets/javascripts/alpha_simprini/models/radio_selection_model.coffee +9 -0
- data/app/assets/javascripts/alpha_simprini/packer.coffee +93 -0
- data/app/assets/javascripts/alpha_simprini/template_helpers.coffee +8 -0
- data/app/assets/javascripts/alpha_simprini/view.coffee +182 -0
- data/app/assets/javascripts/alpha_simprini/views/canvas.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/horizontal_split.coffee +9 -0
- data/app/assets/javascripts/alpha_simprini/views/panel.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/splitter.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/stage.coffee +7 -0
- data/app/assets/javascripts/alpha_simprini/views/vertical_split.coffee +8 -0
- data/app/assets/javascripts/alpha_simprini/views/viewport.coffee +0 -0
- data/app/assets/javascripts/bundle.js +16416 -0
- data/app/assets/javascripts/lib/backbone.coffee +11 -0
- data/app/assets/javascripts/lib/koffeecup_backbone_databind.coffee +25 -0
- data/app/assets/javascripts/lib/module.coffee +15 -0
- data/app/assets/javascripts/lib/state_machine.coffee +33 -0
- data/app/assets/javascripts/lib/string.coffee +13 -0
- data/app/assets/javascripts/qunit.js +1513 -0
- data/app/assets/javascripts/test.coffee +4 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/binding.coffee +118 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/helpers.coffee +10 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/tags.coffee +18 -0
- data/app/assets/javascripts/test/alpha_simprini/collection.coffee +7 -0
- data/app/assets/javascripts/test/alpha_simprini/event.coffee +43 -0
- data/app/assets/javascripts/test/alpha_simprini/model.coffee +63 -0
- data/app/assets/javascripts/test/alpha_simprini/view.coffee +72 -0
- data/app/assets/javascripts/test/alpha_simprini/views/canvas.coffee +8 -0
- data/app/assets/javascripts/test/alpha_simprini/views/horizontal_split.coffee +13 -0
- data/app/assets/javascripts/test/alpha_simprini/views/vertical_split.coffee +13 -0
- data/app/assets/javascripts/test/backbone/collection.js +345 -0
- data/app/assets/javascripts/test/backbone/events.js +86 -0
- data/app/assets/javascripts/test/backbone/model.js +426 -0
- data/app/assets/javascripts/test/backbone/view.js +137 -0
- data/app/assets/stylesheets/bootstrap.sass +6 -0
- data/app/assets/stylesheets/paneling.sass +2 -0
- data/app/assets/stylesheets/qunit.scss +228 -0
- data/app/assets/stylesheets/table.sass +10 -0
- data/app/assets/stylesheets/typography.sass +19 -0
- data/app/controllers/alpha_simprini/test_controller.rb +3 -0
- data/app/controllers/resources_controller.rb +7 -0
- data/app/views/alpha_simprini/test/root.rb +13 -0
- data/app/views/resources/base.rb +2 -0
- data/app/views/resources/edit.rb +9 -0
- data/app/views/resources/form.rb +26 -0
- data/app/views/resources/index.rb +41 -0
- data/app/views/resources/new.rb +9 -0
- data/app/views/resources/show.rb +42 -0
- data/app/views/resources/show_has_many.rb +28 -0
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +3 -0
- data/lib/alpha-simprini-engine.rb +33 -0
- data/lib/alpha-simprini-engine/version.rb +3 -0
- data/lib/alpha_simprini/directive_processor.rb +77 -0
- data/lib/alpha_simprini/packer.rb +161 -0
- data/lib/alpha_simprini/page.rb +37 -0
- data/lib/tasks/alpha-simprini-engine_tasks.rake +4 -0
- data/test/alpha-simprini-engine_test.rb +7 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +9 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +51 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +4 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/log/development.log +800 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C24/D70/sprockets%2F388a550030239f3784f207fa32954f64 +0 -0
- data/test/dummy/tmp/cache/assets/C34/620/sprockets%2F097ee8532856d48d70420c006f475889 +0 -0
- data/test/dummy/tmp/cache/assets/C6F/710/sprockets%2F908d18b0f21c18dad508851126164a41 +0 -0
- data/test/dummy/tmp/cache/assets/CA7/120/sprockets%2F35278a6c0150c40394fe02629c8b0eb9 +0 -0
- data/test/dummy/tmp/cache/assets/CDB/A80/sprockets%2F443b1c6e71b482fdd83b1833b7e27712 +0 -0
- data/test/dummy/tmp/cache/assets/CE3/FB0/sprockets%2F6d3f87a4232e0368bb86760780c5f1bd +0 -0
- data/test/dummy/tmp/cache/assets/D1C/160/sprockets%2F87876f7e55ebc78ae11c6c08a27f0605 +0 -0
- data/test/dummy/tmp/cache/assets/D26/6C0/sprockets%2F65bce2254bb3140a50326ea1654ea5df +0 -0
- data/test/dummy/tmp/cache/assets/D26/FA0/sprockets%2F1f50f59148df5f3e2ab889df381d9744 +0 -0
- data/test/dummy/tmp/cache/assets/D36/220/sprockets%2F841654b01d89eada195d7d1fe10b57b0 +0 -0
- data/test/dummy/tmp/cache/assets/D47/410/sprockets%2Ff1fe319eb4064bd5b861ac28f7d76555 +18122 -0
- data/test/dummy/tmp/cache/assets/D57/1E0/sprockets%2Fe267e3e1059799c429e4f5cfb95ec53c +0 -0
- data/test/dummy/tmp/cache/assets/D64/3E0/sprockets%2Fb49b7f8034b81ec601bc32fb127fbe08 +0 -0
- data/test/dummy/tmp/cache/assets/D65/850/sprockets%2F7a9b6a0e2d51adb43a1d3f859213e6b8 +15469 -0
- data/test/dummy/tmp/cache/assets/D6C/E30/sprockets%2Fcc7322b05ac2bef75e9f4f145d38117f +0 -0
- data/test/dummy/tmp/cache/assets/D7D/E00/sprockets%2Fce33b82451c73df1cfec69928b4f77b6 +0 -0
- data/test/dummy/tmp/cache/assets/D85/5D0/sprockets%2Fcf743946c378c148b19ce78eeaa9cc75 +0 -0
- data/test/dummy/tmp/cache/assets/DBB/560/sprockets%2F5a1d70cf7dd81a5ab5ce7a40a3a38d06 +0 -0
- data/test/dummy/tmp/cache/assets/DC1/670/sprockets%2Fefdfad0542298a1db90d24dc27ecc250 +0 -0
- data/test/dummy/tmp/cache/assets/DC5/1E0/sprockets%2F7517f22ad0f9dc13b8f0f6e0cc0e5de2 +0 -0
- data/test/dummy/tmp/cache/assets/DCC/220/sprockets%2F28d953c6ab9cc9a7db15600aabc6d77d +208 -0
- data/test/dummy/tmp/cache/assets/DCF/DF0/sprockets%2Ff0d3068f05825e1dfd9f5aaba946d3dc +0 -0
- data/test/dummy/tmp/cache/assets/DD3/0E0/sprockets%2F3e9e08a334bae7deadb5335f5e4f195f +0 -0
- data/test/dummy/tmp/cache/assets/DDB/980/sprockets%2Fbd2abc80a17c901e2f497f88f9be58cf +0 -0
- data/test/dummy/tmp/cache/assets/E00/ED0/sprockets%2Ffecf3bffeb200a47e96bd04cbc878076 +1535 -0
- data/test/dummy/tmp/cache/assets/EFB/560/sprockets%2Fbca0daf751c020cdeddabbefa51cb6ea +0 -0
- data/test/dummy/tmp/restart.txt +0 -0
- data/test/test_helper.rb +10 -0
- metadata +326 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
$(document).ready(function() {
|
|
2
|
+
|
|
3
|
+
module("Backbone.Events");
|
|
4
|
+
|
|
5
|
+
test("Events: bind and trigger", function() {
|
|
6
|
+
var obj = { counter: 0 };
|
|
7
|
+
_.extend(obj,Backbone.Events);
|
|
8
|
+
obj.bind('event', function() { obj.counter += 1; });
|
|
9
|
+
obj.trigger('event');
|
|
10
|
+
equals(obj.counter,1,'counter should be incremented.');
|
|
11
|
+
obj.trigger('event');
|
|
12
|
+
obj.trigger('event');
|
|
13
|
+
obj.trigger('event');
|
|
14
|
+
obj.trigger('event');
|
|
15
|
+
equals(obj.counter, 5, 'counter should be incremented five times.');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("Events: bind, then unbind all functions", function() {
|
|
19
|
+
var obj = { counter: 0 };
|
|
20
|
+
_.extend(obj,Backbone.Events);
|
|
21
|
+
var callback = function() { obj.counter += 1; };
|
|
22
|
+
obj.bind('event', callback);
|
|
23
|
+
obj.trigger('event');
|
|
24
|
+
obj.unbind('event');
|
|
25
|
+
obj.trigger('event');
|
|
26
|
+
equals(obj.counter, 1, 'counter should have only been incremented once.');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("Events: bind two callbacks, unbind only one", function() {
|
|
30
|
+
var obj = { counterA: 0, counterB: 0 };
|
|
31
|
+
_.extend(obj,Backbone.Events);
|
|
32
|
+
var callback = function() { obj.counterA += 1; };
|
|
33
|
+
obj.bind('event', callback);
|
|
34
|
+
obj.bind('event', function() { obj.counterB += 1; });
|
|
35
|
+
obj.trigger('event');
|
|
36
|
+
obj.unbind('event', callback);
|
|
37
|
+
obj.trigger('event');
|
|
38
|
+
equals(obj.counterA, 1, 'counterA should have only been incremented once.');
|
|
39
|
+
equals(obj.counterB, 2, 'counterB should have been incremented twice.');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("Events: unbind a callback in the midst of it firing", function() {
|
|
43
|
+
var obj = {counter: 0};
|
|
44
|
+
_.extend(obj, Backbone.Events);
|
|
45
|
+
var callback = function() {
|
|
46
|
+
obj.counter += 1;
|
|
47
|
+
obj.unbind('event', callback);
|
|
48
|
+
};
|
|
49
|
+
obj.bind('event', callback);
|
|
50
|
+
obj.trigger('event');
|
|
51
|
+
obj.trigger('event');
|
|
52
|
+
obj.trigger('event');
|
|
53
|
+
equals(obj.counter, 1, 'the callback should have been unbound.');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("Events: two binds that unbind themeselves", function() {
|
|
57
|
+
var obj = { counterA: 0, counterB: 0 };
|
|
58
|
+
_.extend(obj,Backbone.Events);
|
|
59
|
+
var incrA = function(){ obj.counterA += 1; obj.unbind('event', incrA); };
|
|
60
|
+
var incrB = function(){ obj.counterB += 1; obj.unbind('event', incrB); };
|
|
61
|
+
obj.bind('event', incrA);
|
|
62
|
+
obj.bind('event', incrB);
|
|
63
|
+
obj.trigger('event');
|
|
64
|
+
obj.trigger('event');
|
|
65
|
+
obj.trigger('event');
|
|
66
|
+
equals(obj.counterA, 1, 'counterA should have only been incremented once.');
|
|
67
|
+
equals(obj.counterB, 1, 'counterB should have only been incremented once.');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("Events: bind a callback with a supplied context", function () {
|
|
71
|
+
expect(1);
|
|
72
|
+
|
|
73
|
+
var TestClass = function () { return this; }
|
|
74
|
+
TestClass.prototype.assertTrue = function () {
|
|
75
|
+
ok(true, '`this` was bound to the callback')
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
var obj = _.extend({},Backbone.Events);
|
|
79
|
+
|
|
80
|
+
obj.bind('event', function () { this.assertTrue(); }, (new TestClass));
|
|
81
|
+
|
|
82
|
+
obj.trigger('event');
|
|
83
|
+
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
});
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
$(document).ready(function() {
|
|
2
|
+
|
|
3
|
+
module("Backbone.Model");
|
|
4
|
+
|
|
5
|
+
// Variable to catch the last request.
|
|
6
|
+
window.lastRequest = null;
|
|
7
|
+
|
|
8
|
+
window.originalSync = Backbone.sync;
|
|
9
|
+
|
|
10
|
+
// Stub out Backbone.request...
|
|
11
|
+
Backbone.sync = function() {
|
|
12
|
+
lastRequest = _.toArray(arguments);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
var attrs = {
|
|
16
|
+
id : '1-the-tempest',
|
|
17
|
+
title : "The Tempest",
|
|
18
|
+
author : "Bill Shakespeare",
|
|
19
|
+
length : 123
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
var proxy = Backbone.Model.extend();
|
|
23
|
+
var doc = new proxy(attrs);
|
|
24
|
+
|
|
25
|
+
var klass = Backbone.Collection.extend({
|
|
26
|
+
url : function() { return '/collection'; }
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
var collection = new klass();
|
|
30
|
+
collection.add(doc);
|
|
31
|
+
|
|
32
|
+
test("Model: initialize", function() {
|
|
33
|
+
var Model = Backbone.Model.extend({
|
|
34
|
+
initialize: function() {
|
|
35
|
+
this.one = 1;
|
|
36
|
+
equals(this.collection, collection);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
var model = new Model({}, {collection: collection});
|
|
40
|
+
equals(model.one, 1);
|
|
41
|
+
equals(model.collection, collection);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("Model: initialize with attributes and options", function() {
|
|
45
|
+
var Model = Backbone.Model.extend({
|
|
46
|
+
initialize: function(attributes, options) {
|
|
47
|
+
this.one = options.one;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
var model = new Model({}, {one: 1});
|
|
51
|
+
equals(model.one, 1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("Model: url", function() {
|
|
55
|
+
equals(doc.url(), '/collection/1-the-tempest');
|
|
56
|
+
doc.collection.url = '/collection/';
|
|
57
|
+
equals(doc.url(), '/collection/1-the-tempest');
|
|
58
|
+
doc.collection = null;
|
|
59
|
+
var failed = false;
|
|
60
|
+
try {
|
|
61
|
+
doc.url();
|
|
62
|
+
} catch (e) {
|
|
63
|
+
failed = true;
|
|
64
|
+
}
|
|
65
|
+
equals(failed, true);
|
|
66
|
+
doc.collection = collection;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("Model: url when using urlRoot, and uri encoding", function() {
|
|
70
|
+
var Model = Backbone.Model.extend({
|
|
71
|
+
urlRoot: '/collection'
|
|
72
|
+
});
|
|
73
|
+
var model = new Model();
|
|
74
|
+
equals(model.url(), '/collection');
|
|
75
|
+
model.set({id: '+1+'});
|
|
76
|
+
equals(model.url(), '/collection/%2B1%2B');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("Model: clone", function() {
|
|
80
|
+
attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
|
|
81
|
+
a = new Backbone.Model(attrs);
|
|
82
|
+
b = a.clone();
|
|
83
|
+
equals(a.get('foo'), 1);
|
|
84
|
+
equals(a.get('bar'), 2);
|
|
85
|
+
equals(a.get('baz'), 3);
|
|
86
|
+
equals(b.get('foo'), a.get('foo'), "Foo should be the same on the clone.");
|
|
87
|
+
equals(b.get('bar'), a.get('bar'), "Bar should be the same on the clone.");
|
|
88
|
+
equals(b.get('baz'), a.get('baz'), "Baz should be the same on the clone.");
|
|
89
|
+
a.set({foo : 100});
|
|
90
|
+
equals(a.get('foo'), 100);
|
|
91
|
+
equals(b.get('foo'), 1, "Changing a parent attribute does not change the clone.");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("Model: isNew", function() {
|
|
95
|
+
attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
|
|
96
|
+
a = new Backbone.Model(attrs);
|
|
97
|
+
ok(a.isNew(), "it should be new");
|
|
98
|
+
attrs = { 'foo': 1, 'bar': 2, 'baz': 3, 'id': -5 };
|
|
99
|
+
a = new Backbone.Model(attrs);
|
|
100
|
+
ok(!a.isNew(), "any defined ID is legal, negative or positive");
|
|
101
|
+
attrs = { 'foo': 1, 'bar': 2, 'baz': 3, 'id': 0 };
|
|
102
|
+
a = new Backbone.Model(attrs);
|
|
103
|
+
ok(!a.isNew(), "any defined ID is legal, including zero");
|
|
104
|
+
ok( new Backbone.Model({ }).isNew(), "is true when there is no id");
|
|
105
|
+
ok(!new Backbone.Model({ 'id': 2 }).isNew(), "is false for a positive integer");
|
|
106
|
+
ok(!new Backbone.Model({ 'id': -5 }).isNew(), "is false for a negative integer");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("Model: get", function() {
|
|
110
|
+
equals(doc.get('title'), 'The Tempest');
|
|
111
|
+
equals(doc.get('author'), 'Bill Shakespeare');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("Model: escape", function() {
|
|
115
|
+
equals(doc.escape('title'), 'The Tempest');
|
|
116
|
+
doc.set({audience: 'Bill & Bob'});
|
|
117
|
+
equals(doc.escape('audience'), 'Bill & Bob');
|
|
118
|
+
doc.set({audience: 'Tim > Joan'});
|
|
119
|
+
equals(doc.escape('audience'), 'Tim > Joan');
|
|
120
|
+
doc.set({audience: 10101});
|
|
121
|
+
equals(doc.escape('audience'), '10101');
|
|
122
|
+
doc.unset('audience');
|
|
123
|
+
equals(doc.escape('audience'), '');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("Model: has", function() {
|
|
127
|
+
attrs = {};
|
|
128
|
+
a = new Backbone.Model(attrs);
|
|
129
|
+
equals(a.has("name"), false);
|
|
130
|
+
_([true, "Truth!", 1, false, '', 0]).each(function(value) {
|
|
131
|
+
a.set({'name': value});
|
|
132
|
+
equals(a.has("name"), true);
|
|
133
|
+
});
|
|
134
|
+
a.unset('name');
|
|
135
|
+
equals(a.has('name'), false);
|
|
136
|
+
_([null, undefined]).each(function(value) {
|
|
137
|
+
a.set({'name': value});
|
|
138
|
+
equals(a.has("name"), false);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("Model: set and unset", function() {
|
|
143
|
+
attrs = {id: 'id', foo: 1, bar: 2, baz: 3};
|
|
144
|
+
a = new Backbone.Model(attrs);
|
|
145
|
+
var changeCount = 0;
|
|
146
|
+
a.bind("change:foo", function() { changeCount += 1; });
|
|
147
|
+
a.set({'foo': 2});
|
|
148
|
+
ok(a.get('foo')== 2, "Foo should have changed.");
|
|
149
|
+
ok(changeCount == 1, "Change count should have incremented.");
|
|
150
|
+
a.set({'foo': 2}); // set with value that is not new shouldn't fire change event
|
|
151
|
+
ok(a.get('foo')== 2, "Foo should NOT have changed, still 2");
|
|
152
|
+
ok(changeCount == 1, "Change count should NOT have incremented.");
|
|
153
|
+
|
|
154
|
+
a.unset('foo');
|
|
155
|
+
ok(a.get('foo')== null, "Foo should have changed");
|
|
156
|
+
ok(changeCount == 2, "Change count should have incremented for unset.");
|
|
157
|
+
|
|
158
|
+
a.unset('id');
|
|
159
|
+
equals(a.id, undefined, "Unsetting the id should remove the id property.");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("Model: multiple unsets", function() {
|
|
163
|
+
var i = 0;
|
|
164
|
+
var counter = function(){ i++; };
|
|
165
|
+
var model = new Backbone.Model({a: 1});
|
|
166
|
+
model.bind("change:a", counter);
|
|
167
|
+
model.set({a: 2});
|
|
168
|
+
model.unset('a');
|
|
169
|
+
model.unset('a');
|
|
170
|
+
equals(i, 2, 'Unset does not fire an event for missing attributes.');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("Model: using a non-default id attribute.", function() {
|
|
174
|
+
var MongoModel = Backbone.Model.extend({idAttribute : '_id'});
|
|
175
|
+
var model = new MongoModel({id: 'eye-dee', _id: 25, title: 'Model'});
|
|
176
|
+
equals(model.get('id'), 'eye-dee');
|
|
177
|
+
equals(model.id, 25);
|
|
178
|
+
equals(model.isNew(), false);
|
|
179
|
+
model.unset('_id');
|
|
180
|
+
equals(model.id, undefined);
|
|
181
|
+
equals(model.isNew(), true);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("Model: set an empty string", function() {
|
|
185
|
+
var model = new Backbone.Model({name : "Model"});
|
|
186
|
+
model.set({name : ''});
|
|
187
|
+
equals(model.get('name'), '');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("Model: clear", function() {
|
|
191
|
+
var changed;
|
|
192
|
+
var model = new Backbone.Model({name : "Model"});
|
|
193
|
+
model.bind("change:name", function(){ changed = true; });
|
|
194
|
+
model.clear();
|
|
195
|
+
equals(changed, true);
|
|
196
|
+
equals(model.get('name'), undefined);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("Model: defaults", function() {
|
|
200
|
+
var Defaulted = Backbone.Model.extend({
|
|
201
|
+
defaults: {
|
|
202
|
+
"one": 1,
|
|
203
|
+
"two": 2
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
var model = new Defaulted({two: null});
|
|
207
|
+
equals(model.get('one'), 1);
|
|
208
|
+
equals(model.get('two'), null);
|
|
209
|
+
Defaulted = Backbone.Model.extend({
|
|
210
|
+
defaults: function() {
|
|
211
|
+
return {
|
|
212
|
+
"one": 3,
|
|
213
|
+
"two": 4
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
var model = new Defaulted({two: null});
|
|
218
|
+
equals(model.get('one'), 3);
|
|
219
|
+
equals(model.get('two'), null);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("Model: change, hasChanged, changedAttributes, previous, previousAttributes", function() {
|
|
223
|
+
var model = new Backbone.Model({name : "Tim", age : 10});
|
|
224
|
+
equals(model.changedAttributes(), false);
|
|
225
|
+
model.bind('change', function() {
|
|
226
|
+
ok(model.hasChanged('name'), 'name changed');
|
|
227
|
+
ok(!model.hasChanged('age'), 'age did not');
|
|
228
|
+
ok(_.isEqual(model.changedAttributes(), {name : 'Rob'}), 'changedAttributes returns the changed attrs');
|
|
229
|
+
equals(model.previous('name'), 'Tim');
|
|
230
|
+
ok(_.isEqual(model.previousAttributes(), {name : "Tim", age : 10}), 'previousAttributes is correct');
|
|
231
|
+
});
|
|
232
|
+
model.set({name : 'Rob'}, {silent : true});
|
|
233
|
+
equals(model.hasChanged(), true);
|
|
234
|
+
equals(model.hasChanged('name'), true);
|
|
235
|
+
model.change();
|
|
236
|
+
equals(model.get('name'), 'Rob');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("Model: change with options", function() {
|
|
240
|
+
var value;
|
|
241
|
+
var model = new Backbone.Model({name: 'Rob'});
|
|
242
|
+
model.bind('change', function(model, options) {
|
|
243
|
+
value = options.prefix + model.get('name');
|
|
244
|
+
});
|
|
245
|
+
model.set({name: 'Bob'}, {silent: true});
|
|
246
|
+
model.change({prefix: 'Mr. '});
|
|
247
|
+
equals(value, 'Mr. Bob');
|
|
248
|
+
model.set({name: 'Sue'}, {prefix: 'Ms. '});
|
|
249
|
+
equals(value, 'Ms. Sue');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("Model: change after initialize", function () {
|
|
253
|
+
var changed = 0;
|
|
254
|
+
var attrs = {id: 1, label: 'c'};
|
|
255
|
+
var obj = new Backbone.Model(attrs);
|
|
256
|
+
obj.bind('change', function() { changed += 1; });
|
|
257
|
+
obj.set(attrs);
|
|
258
|
+
equals(changed, 0);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("Model: save within change event", function () {
|
|
262
|
+
var model = new Backbone.Model({firstName : "Taylor", lastName: "Swift"});
|
|
263
|
+
model.bind('change', function () {
|
|
264
|
+
model.save();
|
|
265
|
+
ok(_.isEqual(lastRequest[1], model));
|
|
266
|
+
});
|
|
267
|
+
model.set({lastName: 'Hicks'});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("Model: save", function() {
|
|
271
|
+
doc.save({title : "Henry V"});
|
|
272
|
+
equals(lastRequest[0], 'update');
|
|
273
|
+
ok(_.isEqual(lastRequest[1], doc));
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test("Model: fetch", function() {
|
|
277
|
+
doc.fetch();
|
|
278
|
+
ok(lastRequest[0], 'read');
|
|
279
|
+
ok(_.isEqual(lastRequest[1], doc));
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test("Model: destroy", function() {
|
|
283
|
+
doc.destroy();
|
|
284
|
+
equals(lastRequest[0], 'delete');
|
|
285
|
+
ok(_.isEqual(lastRequest[1], doc));
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test("Model: non-persisted destroy", function() {
|
|
289
|
+
attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
|
|
290
|
+
a = new Backbone.Model(attrs);
|
|
291
|
+
a.sync = function() { throw "should not be called"; };
|
|
292
|
+
ok(a.destroy(), "non-persisted model should not call sync");
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("Model: validate", function() {
|
|
296
|
+
var lastError;
|
|
297
|
+
var model = new Backbone.Model();
|
|
298
|
+
model.validate = function(attrs) {
|
|
299
|
+
if (attrs.admin) return "Can't change admin status.";
|
|
300
|
+
};
|
|
301
|
+
model.bind('error', function(model, error) {
|
|
302
|
+
lastError = error;
|
|
303
|
+
});
|
|
304
|
+
var result = model.set({a: 100});
|
|
305
|
+
equals(result, model);
|
|
306
|
+
equals(model.get('a'), 100);
|
|
307
|
+
equals(lastError, undefined);
|
|
308
|
+
result = model.set({admin: true}, {silent: true});
|
|
309
|
+
equals(lastError, undefined);
|
|
310
|
+
equals(model.get('admin'), true);
|
|
311
|
+
result = model.set({a: 200, admin: true});
|
|
312
|
+
equals(result, false);
|
|
313
|
+
equals(model.get('a'), 100);
|
|
314
|
+
equals(lastError, "Can't change admin status.");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("Model: validate on unset and clear", function() {
|
|
318
|
+
var error;
|
|
319
|
+
var model = new Backbone.Model({name: "One"});
|
|
320
|
+
model.validate = function(attrs) {
|
|
321
|
+
if ("name" in attrs) {
|
|
322
|
+
if (!attrs.name) {
|
|
323
|
+
error = true;
|
|
324
|
+
return "No thanks.";
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
model.set({name: "Two"});
|
|
329
|
+
equals(model.get('name'), 'Two');
|
|
330
|
+
equals(error, undefined);
|
|
331
|
+
model.unset('name');
|
|
332
|
+
equals(error, true);
|
|
333
|
+
equals(model.get('name'), 'Two');
|
|
334
|
+
model.clear();
|
|
335
|
+
equals(model.get('name'), 'Two');
|
|
336
|
+
delete model.validate;
|
|
337
|
+
model.clear();
|
|
338
|
+
equals(model.get('name'), undefined);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("Model: validate with error callback", function() {
|
|
342
|
+
var lastError, boundError;
|
|
343
|
+
var model = new Backbone.Model();
|
|
344
|
+
model.validate = function(attrs) {
|
|
345
|
+
if (attrs.admin) return "Can't change admin status.";
|
|
346
|
+
};
|
|
347
|
+
var callback = function(model, error) {
|
|
348
|
+
lastError = error;
|
|
349
|
+
};
|
|
350
|
+
model.bind('error', function(model, error) {
|
|
351
|
+
boundError = true;
|
|
352
|
+
});
|
|
353
|
+
var result = model.set({a: 100}, {error: callback});
|
|
354
|
+
equals(result, model);
|
|
355
|
+
equals(model.get('a'), 100);
|
|
356
|
+
equals(lastError, undefined);
|
|
357
|
+
equals(boundError, undefined);
|
|
358
|
+
result = model.set({a: 200, admin: true}, {error: callback});
|
|
359
|
+
equals(result, false);
|
|
360
|
+
equals(model.get('a'), 100);
|
|
361
|
+
equals(lastError, "Can't change admin status.");
|
|
362
|
+
equals(boundError, undefined);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("Model: defaults always extend attrs (#459)", function() {
|
|
366
|
+
var Defaulted = Backbone.Model.extend({
|
|
367
|
+
defaults: {one: 1},
|
|
368
|
+
initialize : function(attrs, opts) {
|
|
369
|
+
equals(attrs.one, 1);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
var providedattrs = new Defaulted({});
|
|
373
|
+
var emptyattrs = new Defaulted();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test("Model: Inherit class properties", function() {
|
|
377
|
+
var Parent = Backbone.Model.extend({
|
|
378
|
+
instancePropSame: function() {},
|
|
379
|
+
instancePropDiff: function() {}
|
|
380
|
+
}, {
|
|
381
|
+
classProp: function() {}
|
|
382
|
+
});
|
|
383
|
+
var Child = Parent.extend({
|
|
384
|
+
instancePropDiff: function() {}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
var adult = new Parent;
|
|
388
|
+
var kid = new Child;
|
|
389
|
+
|
|
390
|
+
equals(Child.classProp, Parent.classProp);
|
|
391
|
+
notEqual(Child.classProp, undefined);
|
|
392
|
+
|
|
393
|
+
equals(kid.instancePropSame, adult.instancePropSame);
|
|
394
|
+
notEqual(kid.instancePropSame, undefined);
|
|
395
|
+
|
|
396
|
+
notEqual(Child.prototype.instancePropDiff, Parent.prototype.instancePropDiff);
|
|
397
|
+
notEqual(Child.prototype.instancePropDiff, undefined);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test("Model: Nested change events don't clobber previous attributes", function() {
|
|
401
|
+
var A = Backbone.Model.extend({
|
|
402
|
+
initialize: function() {
|
|
403
|
+
this.bind("change:state", function(a, newState) {
|
|
404
|
+
equals(a.previous('state'), undefined);
|
|
405
|
+
equals(newState, 'hello');
|
|
406
|
+
// Fire a nested change event.
|
|
407
|
+
this.set({ other: "whatever" });
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
var B = Backbone.Model.extend({
|
|
413
|
+
initialize: function() {
|
|
414
|
+
this.get("a").bind("change:state", function(a, newState) {
|
|
415
|
+
equals(a.previous('state'), undefined);
|
|
416
|
+
equals(newState, 'hello');
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
a = new A();
|
|
422
|
+
b = new B({a: a});
|
|
423
|
+
a.set({state: 'hello'});
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
});
|