spine-rails 0.0.9 → 0.1.0
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/Gemfile +3 -3
- data/README.md +21 -21
- data/app/assets/javascripts/spine.js +279 -222
- data/app/assets/javascripts/spine/ajax.js +152 -94
- data/app/assets/javascripts/spine/list.js +29 -21
- data/app/assets/javascripts/spine/local.js +5 -3
- data/app/assets/javascripts/spine/manager.js +62 -38
- data/app/assets/javascripts/spine/relation.js +102 -85
- data/app/assets/javascripts/spine/route.js +73 -60
- data/app/assets/javascripts/spine/tabs.js +31 -23
- data/app/assets/javascripts/spine/tmpl.js +6 -1
- data/lib/generators/spine/scaffold/templates/controller.coffee.erb +2 -2
- data/lib/generators/spine/scaffold/templates/new.jst.erb +1 -1
- data/lib/spine/rails/version.rb +2 -2
- metadata +34 -65
data/Gemfile
CHANGED
@@ -4,6 +4,6 @@ source 'http://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
# Rails is already being pulled in through gemspec
|
6
6
|
# gem "rails", :git => "git://github.com/rails/rails.git"
|
7
|
-
gem "rack"
|
8
|
-
gem "sprockets"
|
9
|
-
gem "i18n"
|
7
|
+
gem "rack"
|
8
|
+
gem "sprockets"
|
9
|
+
gem "i18n"
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ This gem requires the use of [Rails 3.1](http://rubyonrails.org), [CoffeeScript]
|
|
9
9
|
This gem does two things:
|
10
10
|
|
11
11
|
* Adds Spine to the asset pipeline, so you can easily require it in your applications: `//= require spine`
|
12
|
-
|
12
|
+
|
13
13
|
* Adds some Spine generators, so you can easily create Spine Models, Views and Controllers.
|
14
14
|
|
15
15
|
### Installation
|
@@ -17,26 +17,26 @@ This gem does two things:
|
|
17
17
|
In your Gemfile, add this line:
|
18
18
|
|
19
19
|
gem "spine-rails"
|
20
|
-
|
20
|
+
|
21
21
|
Then run the following commands:
|
22
22
|
|
23
23
|
bundle install
|
24
|
-
|
24
|
+
|
25
25
|
rails generate spine:new
|
26
26
|
|
27
27
|
### Layout and namespacing
|
28
28
|
|
29
29
|
Running `rails g spine:new` will create the following directory structure:
|
30
|
-
|
30
|
+
|
31
31
|
app/assets/javascripts/app/models/
|
32
32
|
app/assets/javascripts/app/views/
|
33
33
|
app/assets/javascripts/app/controllers/
|
34
34
|
app/assets/javascripts/app/index.js.coffee
|
35
|
-
|
35
|
+
|
36
36
|
By default your application will be namespaced by the `app` directory. You can specify a different namespace with the `--app` option:
|
37
37
|
|
38
38
|
rails g spine:new --app foo_bar
|
39
|
-
|
39
|
+
|
40
40
|
**NOTE:** If you use the `--app` option here, then you will also have to specify it with other generators.
|
41
41
|
|
42
42
|
Use the top-level level `index.js.coffee` file to setup namespacing and initial controller instantiation.
|
@@ -48,19 +48,19 @@ spine-rails provides three simple generators to help you get started:
|
|
48
48
|
### Model
|
49
49
|
|
50
50
|
rails g spine:model User email username full_name
|
51
|
-
|
51
|
+
|
52
52
|
This generator creates a very minimal model inside `app/assets/javascript/app/models`. You have to provide a list of attributes for the model.
|
53
53
|
|
54
54
|
### Controller
|
55
|
-
|
55
|
+
|
56
56
|
rails g spine:controller Users
|
57
|
-
|
58
|
-
This generator creates a minimal `Users` controller in `app/assets/javascripts/app/controllers` to get you started.
|
57
|
+
|
58
|
+
This generator creates a minimal `Users` controller in `app/assets/javascripts/app/controllers` to get you started.
|
59
59
|
|
60
60
|
### View
|
61
61
|
|
62
62
|
rails g spine:view users/index
|
63
|
-
|
63
|
+
|
64
64
|
This generator creates a blank Spine view `app/assets/javascripts/app/views/users/index.jst.ejs`.
|
65
65
|
|
66
66
|
The generator will create views in `hamljs`, `eco` or `ejs` format, depending on the gems availale:
|
@@ -82,13 +82,13 @@ Edit your Gemfile and add
|
|
82
82
|
Install the gem and generate resource.
|
83
83
|
|
84
84
|
bundle install
|
85
|
-
|
85
|
+
|
86
86
|
rails g scaffold Post title:string content:string
|
87
87
|
rake db:migrate
|
88
|
-
|
88
|
+
|
89
89
|
rails g spine:new
|
90
90
|
rails g spine:model Post title content
|
91
|
-
rails g spine:
|
91
|
+
rails g spine:controller Posts
|
92
92
|
|
93
93
|
You now have the default Spine data structures available to work with.
|
94
94
|
|
@@ -98,22 +98,22 @@ Now you can use Spine:
|
|
98
98
|
|
99
99
|
// Sends an AJAX POST to the server
|
100
100
|
var post = App.Post.create({
|
101
|
-
title: 'Hello World!',
|
101
|
+
title: 'Hello World!',
|
102
102
|
content: 'Spine & Rails, sitting in a tree!'
|
103
|
-
});
|
103
|
+
});
|
104
104
|
|
105
105
|
// => ID returned from Rails
|
106
|
-
post.id;
|
107
|
-
|
106
|
+
post.id;
|
107
|
+
|
108
108
|
// Sends AJAX PUT to the server
|
109
109
|
post.updateAttributes({title: 'Goodbye'});
|
110
|
-
|
110
|
+
|
111
111
|
Reload the page, then:
|
112
112
|
|
113
113
|
App.Post.fetch(); // Fetch all posts
|
114
|
-
|
114
|
+
|
115
115
|
App.Post.first().content;
|
116
|
-
|
116
|
+
|
117
117
|
For more information on how to integrate Spine with Rails, please see the [Rails guide](http://spinejs.com/docs/rails).
|
118
118
|
|
119
119
|
Also if you want to have some useful helpers to bridge the gap between Spine and Rails, then [spine-extensions](https://github.com/dnagir/spine-extensions) is for you.
|
@@ -1,18 +1,11 @@
|
|
1
1
|
(function() {
|
2
|
-
var $, Controller, Events, Log, Model, Module, Spine,
|
3
|
-
|
4
|
-
for (var i = 0, l = this.length; i < l; i++) {
|
5
|
-
|
6
|
-
}
|
7
|
-
return
|
8
|
-
|
9
|
-
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
10
|
-
function ctor() { this.constructor = child; }
|
11
|
-
ctor.prototype = parent.prototype;
|
12
|
-
child.prototype = new ctor;
|
13
|
-
child.__super__ = parent.prototype;
|
14
|
-
return child;
|
15
|
-
};
|
2
|
+
var $, Controller, Events, Log, Model, Module, Spine, isArray, isBlank, makeArray, moduleKeywords,
|
3
|
+
__slice = Array.prototype.slice,
|
4
|
+
__indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
5
|
+
__hasProp = Object.prototype.hasOwnProperty,
|
6
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; },
|
7
|
+
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
8
|
+
|
16
9
|
Events = {
|
17
10
|
bind: function(ev, callback) {
|
18
11
|
var calls, evs, name, _i, _len;
|
@@ -36,14 +29,10 @@
|
|
36
29
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
37
30
|
ev = args.shift();
|
38
31
|
list = this.hasOwnProperty('_callbacks') && ((_ref = this._callbacks) != null ? _ref[ev] : void 0);
|
39
|
-
if (!list)
|
40
|
-
return false;
|
41
|
-
}
|
32
|
+
if (!list) return;
|
42
33
|
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
43
34
|
callback = list[_i];
|
44
|
-
if (callback.apply(this, args) === false)
|
45
|
-
break;
|
46
|
-
}
|
35
|
+
if (callback.apply(this, args) === false) break;
|
47
36
|
}
|
48
37
|
return true;
|
49
38
|
},
|
@@ -54,126 +43,130 @@
|
|
54
43
|
return this;
|
55
44
|
}
|
56
45
|
list = (_ref = this._callbacks) != null ? _ref[ev] : void 0;
|
57
|
-
if (!list)
|
58
|
-
return this;
|
59
|
-
}
|
46
|
+
if (!list) return this;
|
60
47
|
if (!callback) {
|
61
48
|
delete this._callbacks[ev];
|
62
49
|
return this;
|
63
50
|
}
|
64
51
|
for (i = 0, _len = list.length; i < _len; i++) {
|
65
52
|
cb = list[i];
|
66
|
-
if (cb === callback)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
}
|
53
|
+
if (!(cb === callback)) continue;
|
54
|
+
list = list.slice();
|
55
|
+
list.splice(i, 1);
|
56
|
+
this._callbacks[ev] = list;
|
57
|
+
break;
|
72
58
|
}
|
73
59
|
return this;
|
74
60
|
}
|
75
61
|
};
|
62
|
+
|
76
63
|
Log = {
|
77
64
|
trace: true,
|
78
65
|
logPrefix: '(App)',
|
79
66
|
log: function() {
|
80
67
|
var args;
|
81
68
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
82
|
-
if (!this.trace)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
return;
|
69
|
+
if (!this.trace) return;
|
70
|
+
if (this.logPrefix) args.unshift(this.logPrefix);
|
71
|
+
if (typeof console !== "undefined" && console !== null) {
|
72
|
+
if (typeof console.log === "function") console.log.apply(console, args);
|
87
73
|
}
|
88
|
-
if (this.logPrefix) {
|
89
|
-
args.unshift(this.logPrefix);
|
90
|
-
}
|
91
|
-
console.log.apply(console, args);
|
92
74
|
return this;
|
93
75
|
}
|
94
76
|
};
|
77
|
+
|
95
78
|
moduleKeywords = ['included', 'extended'];
|
79
|
+
|
96
80
|
Module = (function() {
|
81
|
+
|
97
82
|
Module.include = function(obj) {
|
98
|
-
var
|
99
|
-
if (!obj)
|
100
|
-
throw 'include(obj) requires obj';
|
101
|
-
}
|
83
|
+
var key, value, _ref;
|
84
|
+
if (!obj) throw 'include(obj) requires obj';
|
102
85
|
for (key in obj) {
|
103
86
|
value = obj[key];
|
104
|
-
if (__indexOf.call(moduleKeywords, key) < 0)
|
105
|
-
this.prototype[key] = value;
|
106
|
-
}
|
107
|
-
}
|
108
|
-
included = obj.included;
|
109
|
-
if (included) {
|
110
|
-
included.apply(this);
|
87
|
+
if (__indexOf.call(moduleKeywords, key) < 0) this.prototype[key] = value;
|
111
88
|
}
|
89
|
+
if ((_ref = obj.included) != null) _ref.apply(this);
|
112
90
|
return this;
|
113
91
|
};
|
92
|
+
|
114
93
|
Module.extend = function(obj) {
|
115
|
-
var
|
116
|
-
if (!obj)
|
117
|
-
throw 'extend(obj) requires obj';
|
118
|
-
}
|
94
|
+
var key, value, _ref;
|
95
|
+
if (!obj) throw 'extend(obj) requires obj';
|
119
96
|
for (key in obj) {
|
120
97
|
value = obj[key];
|
121
|
-
if (__indexOf.call(moduleKeywords, key) < 0)
|
122
|
-
this[key] = value;
|
123
|
-
}
|
124
|
-
}
|
125
|
-
extended = obj.extended;
|
126
|
-
if (extended) {
|
127
|
-
extended.apply(this);
|
98
|
+
if (__indexOf.call(moduleKeywords, key) < 0) this[key] = value;
|
128
99
|
}
|
100
|
+
if ((_ref = obj.extended) != null) _ref.apply(this);
|
129
101
|
return this;
|
130
102
|
};
|
103
|
+
|
131
104
|
Module.proxy = function(func) {
|
132
|
-
|
133
|
-
|
134
|
-
|
105
|
+
var _this = this;
|
106
|
+
return function() {
|
107
|
+
return func.apply(_this, arguments);
|
108
|
+
};
|
135
109
|
};
|
110
|
+
|
136
111
|
Module.prototype.proxy = function(func) {
|
137
|
-
|
138
|
-
|
139
|
-
|
112
|
+
var _this = this;
|
113
|
+
return function() {
|
114
|
+
return func.apply(_this, arguments);
|
115
|
+
};
|
140
116
|
};
|
117
|
+
|
141
118
|
function Module() {
|
142
|
-
if (typeof this.init === "function")
|
143
|
-
this.init.apply(this, arguments);
|
144
|
-
}
|
119
|
+
if (typeof this.init === "function") this.init.apply(this, arguments);
|
145
120
|
}
|
121
|
+
|
146
122
|
return Module;
|
123
|
+
|
147
124
|
})();
|
148
|
-
|
149
|
-
|
125
|
+
|
126
|
+
Model = (function(_super) {
|
127
|
+
|
128
|
+
__extends(Model, _super);
|
129
|
+
|
150
130
|
Model.extend(Events);
|
131
|
+
|
151
132
|
Model.records = {};
|
133
|
+
|
134
|
+
Model.crecords = {};
|
135
|
+
|
152
136
|
Model.attributes = [];
|
137
|
+
|
153
138
|
Model.configure = function() {
|
154
139
|
var attributes, name;
|
155
140
|
name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
156
141
|
this.className = name;
|
157
142
|
this.records = {};
|
158
|
-
|
159
|
-
|
160
|
-
}
|
143
|
+
this.crecords = {};
|
144
|
+
if (attributes.length) this.attributes = attributes;
|
161
145
|
this.attributes && (this.attributes = makeArray(this.attributes));
|
162
146
|
this.attributes || (this.attributes = []);
|
163
147
|
this.unbind();
|
164
148
|
return this;
|
165
149
|
};
|
150
|
+
|
166
151
|
Model.toString = function() {
|
167
152
|
return "" + this.className + "(" + (this.attributes.join(", ")) + ")";
|
168
153
|
};
|
154
|
+
|
169
155
|
Model.find = function(id) {
|
170
156
|
var record;
|
171
157
|
record = this.records[id];
|
172
|
-
if (!record)
|
173
|
-
|
174
|
-
}
|
158
|
+
if (!record && ("" + id).match(/c-\d+/)) return this.findCID(id);
|
159
|
+
if (!record) throw 'Unknown record';
|
175
160
|
return record.clone();
|
176
161
|
};
|
162
|
+
|
163
|
+
Model.findCID = function(cid) {
|
164
|
+
var record;
|
165
|
+
record = this.crecords[cid];
|
166
|
+
if (!record) throw 'Unknown record';
|
167
|
+
return record.clone();
|
168
|
+
};
|
169
|
+
|
177
170
|
Model.exists = function(id) {
|
178
171
|
try {
|
179
172
|
return this.find(id);
|
@@ -181,27 +174,26 @@
|
|
181
174
|
return false;
|
182
175
|
}
|
183
176
|
};
|
177
|
+
|
184
178
|
Model.refresh = function(values, options) {
|
185
179
|
var record, records, _i, _len;
|
186
|
-
if (options == null) {
|
187
|
-
options = {};
|
188
|
-
}
|
180
|
+
if (options == null) options = {};
|
189
181
|
if (options.clear) {
|
190
182
|
this.records = {};
|
183
|
+
this.crecords = {};
|
191
184
|
}
|
192
185
|
records = this.fromJSON(values);
|
193
|
-
if (!isArray(records))
|
194
|
-
records = [records];
|
195
|
-
}
|
186
|
+
if (!isArray(records)) records = [records];
|
196
187
|
for (_i = 0, _len = records.length; _i < _len; _i++) {
|
197
188
|
record = records[_i];
|
198
|
-
record.
|
199
|
-
record.id || (record.id = guid());
|
189
|
+
record.id || (record.id = record.cid);
|
200
190
|
this.records[record.id] = record;
|
191
|
+
this.crecords[record.cid] = record;
|
201
192
|
}
|
202
|
-
this.trigger('refresh', !options.clear && records);
|
193
|
+
this.trigger('refresh', !options.clear && this.cloneArray(records));
|
203
194
|
return this;
|
204
195
|
};
|
196
|
+
|
205
197
|
Model.select = function(callback) {
|
206
198
|
var id, record, result;
|
207
199
|
result = (function() {
|
@@ -210,30 +202,29 @@
|
|
210
202
|
_results = [];
|
211
203
|
for (id in _ref) {
|
212
204
|
record = _ref[id];
|
213
|
-
if (callback(record))
|
214
|
-
_results.push(record);
|
215
|
-
}
|
205
|
+
if (callback(record)) _results.push(record);
|
216
206
|
}
|
217
207
|
return _results;
|
218
208
|
}).call(this);
|
219
209
|
return this.cloneArray(result);
|
220
210
|
};
|
211
|
+
|
221
212
|
Model.findByAttribute = function(name, value) {
|
222
213
|
var id, record, _ref;
|
223
214
|
_ref = this.records;
|
224
215
|
for (id in _ref) {
|
225
216
|
record = _ref[id];
|
226
|
-
if (record[name] === value)
|
227
|
-
return record.clone();
|
228
|
-
}
|
217
|
+
if (record[name] === value) return record.clone();
|
229
218
|
}
|
230
219
|
return null;
|
231
220
|
};
|
221
|
+
|
232
222
|
Model.findAllByAttribute = function(name, value) {
|
233
223
|
return this.select(function(item) {
|
234
224
|
return item[name] === value;
|
235
225
|
});
|
236
226
|
};
|
227
|
+
|
237
228
|
Model.each = function(callback) {
|
238
229
|
var key, value, _ref, _results;
|
239
230
|
_ref = this.records;
|
@@ -244,23 +235,28 @@
|
|
244
235
|
}
|
245
236
|
return _results;
|
246
237
|
};
|
238
|
+
|
247
239
|
Model.all = function() {
|
248
240
|
return this.cloneArray(this.recordsValues());
|
249
241
|
};
|
242
|
+
|
250
243
|
Model.first = function() {
|
251
244
|
var record;
|
252
245
|
record = this.recordsValues()[0];
|
253
246
|
return record != null ? record.clone() : void 0;
|
254
247
|
};
|
248
|
+
|
255
249
|
Model.last = function() {
|
256
250
|
var record, values;
|
257
251
|
values = this.recordsValues();
|
258
252
|
record = values[values.length - 1];
|
259
253
|
return record != null ? record.clone() : void 0;
|
260
254
|
};
|
255
|
+
|
261
256
|
Model.count = function() {
|
262
257
|
return this.recordsValues().length;
|
263
258
|
};
|
259
|
+
|
264
260
|
Model.deleteAll = function() {
|
265
261
|
var key, value, _ref, _results;
|
266
262
|
_ref = this.records;
|
@@ -271,6 +267,7 @@
|
|
271
267
|
}
|
272
268
|
return _results;
|
273
269
|
};
|
270
|
+
|
274
271
|
Model.destroyAll = function() {
|
275
272
|
var key, value, _ref, _results;
|
276
273
|
_ref = this.records;
|
@@ -281,17 +278,21 @@
|
|
281
278
|
}
|
282
279
|
return _results;
|
283
280
|
};
|
284
|
-
|
285
|
-
|
281
|
+
|
282
|
+
Model.update = function(id, atts, options) {
|
283
|
+
return this.find(id).updateAttributes(atts, options);
|
286
284
|
};
|
287
|
-
|
285
|
+
|
286
|
+
Model.create = function(atts, options) {
|
288
287
|
var record;
|
289
288
|
record = new this(atts);
|
290
|
-
return record.save();
|
289
|
+
return record.save(options);
|
291
290
|
};
|
292
|
-
|
293
|
-
|
291
|
+
|
292
|
+
Model.destroy = function(id, options) {
|
293
|
+
return this.find(id).destroy(options);
|
294
294
|
};
|
295
|
+
|
295
296
|
Model.change = function(callbackOrParams) {
|
296
297
|
if (typeof callbackOrParams === 'function') {
|
297
298
|
return this.bind('change', callbackOrParams);
|
@@ -299,6 +300,7 @@
|
|
299
300
|
return this.trigger('change', callbackOrParams);
|
300
301
|
}
|
301
302
|
};
|
303
|
+
|
302
304
|
Model.fetch = function(callbackOrParams) {
|
303
305
|
if (typeof callbackOrParams === 'function') {
|
304
306
|
return this.bind('fetch', callbackOrParams);
|
@@ -306,17 +308,15 @@
|
|
306
308
|
return this.trigger('fetch', callbackOrParams);
|
307
309
|
}
|
308
310
|
};
|
311
|
+
|
309
312
|
Model.toJSON = function() {
|
310
313
|
return this.recordsValues();
|
311
314
|
};
|
315
|
+
|
312
316
|
Model.fromJSON = function(objects) {
|
313
317
|
var value, _i, _len, _results;
|
314
|
-
if (!objects)
|
315
|
-
|
316
|
-
}
|
317
|
-
if (typeof objects === 'string') {
|
318
|
-
objects = JSON.parse(objects);
|
319
|
-
}
|
318
|
+
if (!objects) return;
|
319
|
+
if (typeof objects === 'string') objects = JSON.parse(objects);
|
320
320
|
if (isArray(objects)) {
|
321
321
|
_results = [];
|
322
322
|
for (_i = 0, _len = objects.length; _i < _len; _i++) {
|
@@ -328,10 +328,12 @@
|
|
328
328
|
return new this(objects);
|
329
329
|
}
|
330
330
|
};
|
331
|
+
|
331
332
|
Model.fromForm = function() {
|
332
333
|
var _ref;
|
333
334
|
return (_ref = new this).fromForm.apply(_ref, arguments);
|
334
335
|
};
|
336
|
+
|
335
337
|
Model.recordsValues = function() {
|
336
338
|
var key, result, value, _ref;
|
337
339
|
result = [];
|
@@ -342,6 +344,7 @@
|
|
342
344
|
}
|
343
345
|
return result;
|
344
346
|
};
|
347
|
+
|
345
348
|
Model.cloneArray = function(array) {
|
346
349
|
var value, _i, _len, _results;
|
347
350
|
_results = [];
|
@@ -351,21 +354,29 @@
|
|
351
354
|
}
|
352
355
|
return _results;
|
353
356
|
};
|
354
|
-
|
357
|
+
|
358
|
+
Model.idCounter = 0;
|
359
|
+
|
360
|
+
Model.uid = function() {
|
361
|
+
return this.idCounter++;
|
362
|
+
};
|
363
|
+
|
355
364
|
function Model(atts) {
|
356
365
|
Model.__super__.constructor.apply(this, arguments);
|
357
|
-
this.
|
358
|
-
|
359
|
-
this.load(atts);
|
360
|
-
}
|
366
|
+
if (atts) this.load(atts);
|
367
|
+
this.cid || (this.cid = 'c-' + this.constructor.uid());
|
361
368
|
}
|
369
|
+
|
362
370
|
Model.prototype.isNew = function() {
|
363
|
-
return this.
|
371
|
+
return !this.exists();
|
364
372
|
};
|
373
|
+
|
365
374
|
Model.prototype.isValid = function() {
|
366
375
|
return !this.validate();
|
367
376
|
};
|
377
|
+
|
368
378
|
Model.prototype.validate = function() {};
|
379
|
+
|
369
380
|
Model.prototype.load = function(atts) {
|
370
381
|
var key, value;
|
371
382
|
for (key in atts) {
|
@@ -378,6 +389,7 @@
|
|
378
389
|
}
|
379
390
|
return this;
|
380
391
|
};
|
392
|
+
|
381
393
|
Model.prototype.attributes = function() {
|
382
394
|
var key, result, _i, _len, _ref;
|
383
395
|
result = {};
|
@@ -392,81 +404,92 @@
|
|
392
404
|
}
|
393
405
|
}
|
394
406
|
}
|
395
|
-
if (this.id)
|
396
|
-
result.id = this.id;
|
397
|
-
}
|
407
|
+
if (this.id) result.id = this.id;
|
398
408
|
return result;
|
399
409
|
};
|
410
|
+
|
400
411
|
Model.prototype.eql = function(rec) {
|
401
|
-
|
402
|
-
return rec && rec.constructor === this.constructor && (rec.id === this.id || (_ref = this.id, __indexOf.call(rec.ids, _ref) >= 0) || (_ref2 = rec.id, __indexOf.call(this.ids, _ref2) >= 0));
|
412
|
+
return !!(rec && rec.constructor === this.constructor && (rec.id === this.id || rec.cid === this.cid));
|
403
413
|
};
|
404
|
-
|
414
|
+
|
415
|
+
Model.prototype.save = function(options) {
|
405
416
|
var error, record;
|
406
|
-
|
407
|
-
if (
|
408
|
-
this.
|
409
|
-
|
417
|
+
if (options == null) options = {};
|
418
|
+
if (options.validate !== false) {
|
419
|
+
error = this.validate();
|
420
|
+
if (error) {
|
421
|
+
this.trigger('error', error);
|
422
|
+
return false;
|
423
|
+
}
|
410
424
|
}
|
411
|
-
this.trigger('beforeSave');
|
412
|
-
record = this.
|
413
|
-
this.trigger('save');
|
425
|
+
this.trigger('beforeSave', options);
|
426
|
+
record = this.isNew() ? this.create(options) : this.update(options);
|
427
|
+
this.trigger('save', options);
|
414
428
|
return record;
|
415
429
|
};
|
430
|
+
|
416
431
|
Model.prototype.updateAttribute = function(name, value) {
|
417
432
|
this[name] = value;
|
418
433
|
return this.save();
|
419
434
|
};
|
420
|
-
|
435
|
+
|
436
|
+
Model.prototype.updateAttributes = function(atts, options) {
|
421
437
|
this.load(atts);
|
422
|
-
return this.save();
|
438
|
+
return this.save(options);
|
423
439
|
};
|
440
|
+
|
424
441
|
Model.prototype.changeID = function(id) {
|
425
442
|
var records;
|
426
|
-
this.ids.push(this.id);
|
427
443
|
records = this.constructor.records;
|
428
444
|
records[id] = records[this.id];
|
429
445
|
delete records[this.id];
|
430
446
|
this.id = id;
|
431
447
|
return this.save();
|
432
448
|
};
|
433
|
-
|
434
|
-
|
449
|
+
|
450
|
+
Model.prototype.destroy = function(options) {
|
451
|
+
if (options == null) options = {};
|
452
|
+
this.trigger('beforeDestroy', options);
|
435
453
|
delete this.constructor.records[this.id];
|
454
|
+
delete this.constructor.crecords[this.cid];
|
436
455
|
this.destroyed = true;
|
437
|
-
this.trigger('destroy');
|
438
|
-
this.trigger('change', 'destroy');
|
456
|
+
this.trigger('destroy', options);
|
457
|
+
this.trigger('change', 'destroy', options);
|
439
458
|
this.unbind();
|
440
459
|
return this;
|
441
460
|
};
|
461
|
+
|
442
462
|
Model.prototype.dup = function(newRecord) {
|
443
463
|
var result;
|
444
464
|
result = new this.constructor(this.attributes());
|
445
465
|
if (newRecord === false) {
|
446
|
-
result.
|
466
|
+
result.cid = this.cid;
|
447
467
|
} else {
|
448
468
|
delete result.id;
|
449
469
|
}
|
450
470
|
return result;
|
451
471
|
};
|
472
|
+
|
452
473
|
Model.prototype.clone = function() {
|
453
474
|
return Object.create(this);
|
454
475
|
};
|
476
|
+
|
455
477
|
Model.prototype.reload = function() {
|
456
478
|
var original;
|
457
|
-
if (this.
|
458
|
-
return this;
|
459
|
-
}
|
479
|
+
if (this.isNew()) return this;
|
460
480
|
original = this.constructor.find(this.id);
|
461
481
|
this.load(original.attributes());
|
462
482
|
return original;
|
463
483
|
};
|
484
|
+
|
464
485
|
Model.prototype.toJSON = function() {
|
465
486
|
return this.attributes();
|
466
487
|
};
|
488
|
+
|
467
489
|
Model.prototype.toString = function() {
|
468
490
|
return "<" + this.constructor.className + " (" + (JSON.stringify(this)) + ")>";
|
469
491
|
};
|
492
|
+
|
470
493
|
Model.prototype.fromForm = function(form) {
|
471
494
|
var key, result, _i, _len, _ref;
|
472
495
|
result = {};
|
@@ -477,65 +500,86 @@
|
|
477
500
|
}
|
478
501
|
return this.load(result);
|
479
502
|
};
|
503
|
+
|
480
504
|
Model.prototype.exists = function() {
|
481
505
|
return this.id && this.id in this.constructor.records;
|
482
506
|
};
|
483
|
-
|
507
|
+
|
508
|
+
Model.prototype.update = function(options) {
|
484
509
|
var clone, records;
|
485
|
-
this.trigger('beforeUpdate');
|
510
|
+
this.trigger('beforeUpdate', options);
|
486
511
|
records = this.constructor.records;
|
487
512
|
records[this.id].load(this.attributes());
|
488
513
|
clone = records[this.id].clone();
|
489
|
-
clone.trigger('update');
|
490
|
-
clone.trigger('change', 'update');
|
514
|
+
clone.trigger('update', options);
|
515
|
+
clone.trigger('change', 'update', options);
|
491
516
|
return clone;
|
492
517
|
};
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
this.
|
500
|
-
|
501
|
-
|
502
|
-
clone
|
503
|
-
clone.trigger('create');
|
504
|
-
clone.trigger('change', 'create');
|
518
|
+
|
519
|
+
Model.prototype.create = function(options) {
|
520
|
+
var clone, record;
|
521
|
+
this.trigger('beforeCreate', options);
|
522
|
+
if (!this.id) this.id = this.cid;
|
523
|
+
record = this.dup(false);
|
524
|
+
this.constructor.records[this.id] = record;
|
525
|
+
this.constructor.crecords[this.cid] = record;
|
526
|
+
clone = record.clone();
|
527
|
+
clone.trigger('create', options);
|
528
|
+
clone.trigger('change', 'create', options);
|
505
529
|
return clone;
|
506
530
|
};
|
531
|
+
|
507
532
|
Model.prototype.bind = function(events, callback) {
|
508
|
-
var binder, unbinder
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
return this.constructor.unbind('unbind', unbinder);
|
533
|
+
var binder, unbinder,
|
534
|
+
_this = this;
|
535
|
+
this.constructor.bind(events, binder = function(record) {
|
536
|
+
if (record && _this.eql(record)) return callback.apply(_this, arguments);
|
537
|
+
});
|
538
|
+
this.constructor.bind('unbind', unbinder = function(record) {
|
539
|
+
if (record && _this.eql(record)) {
|
540
|
+
_this.constructor.unbind(events, binder);
|
541
|
+
return _this.constructor.unbind('unbind', unbinder);
|
518
542
|
}
|
519
|
-
}
|
543
|
+
});
|
520
544
|
return binder;
|
521
545
|
};
|
546
|
+
|
547
|
+
Model.prototype.one = function(events, callback) {
|
548
|
+
var binder,
|
549
|
+
_this = this;
|
550
|
+
return binder = this.bind(events, function() {
|
551
|
+
_this.constructor.unbind(events, binder);
|
552
|
+
return callback.apply(_this);
|
553
|
+
});
|
554
|
+
};
|
555
|
+
|
522
556
|
Model.prototype.trigger = function() {
|
523
557
|
var args, _ref;
|
524
558
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
525
559
|
args.splice(1, 0, this);
|
526
560
|
return (_ref = this.constructor).trigger.apply(_ref, args);
|
527
561
|
};
|
562
|
+
|
528
563
|
Model.prototype.unbind = function() {
|
529
564
|
return this.trigger('unbind');
|
530
565
|
};
|
566
|
+
|
531
567
|
return Model;
|
532
|
-
|
533
|
-
|
534
|
-
|
568
|
+
|
569
|
+
})(Module);
|
570
|
+
|
571
|
+
Controller = (function(_super) {
|
572
|
+
|
573
|
+
__extends(Controller, _super);
|
574
|
+
|
535
575
|
Controller.include(Events);
|
576
|
+
|
536
577
|
Controller.include(Log);
|
578
|
+
|
537
579
|
Controller.prototype.eventSplitter = /^(\S+)\s*(.*)$/;
|
580
|
+
|
538
581
|
Controller.prototype.tag = 'div';
|
582
|
+
|
539
583
|
function Controller(options) {
|
540
584
|
this.release = __bind(this.release, this);
|
541
585
|
var key, value, _ref;
|
@@ -545,30 +589,20 @@
|
|
545
589
|
value = _ref[key];
|
546
590
|
this[key] = value;
|
547
591
|
}
|
548
|
-
if (!this.el)
|
549
|
-
this.el = document.createElement(this.tag);
|
550
|
-
}
|
592
|
+
if (!this.el) this.el = document.createElement(this.tag);
|
551
593
|
this.el = $(this.el);
|
552
|
-
if (this.className)
|
553
|
-
|
554
|
-
}
|
594
|
+
if (this.className) this.el.addClass(this.className);
|
595
|
+
if (this.attributes) this.el.attr(this.attributes);
|
555
596
|
this.release(function() {
|
556
597
|
return this.el.remove();
|
557
598
|
});
|
558
|
-
if (!this.events)
|
559
|
-
|
560
|
-
|
561
|
-
if (
|
562
|
-
this.elements = this.constructor.elements;
|
563
|
-
}
|
564
|
-
if (this.events) {
|
565
|
-
this.delegateEvents();
|
566
|
-
}
|
567
|
-
if (this.elements) {
|
568
|
-
this.refreshElements();
|
569
|
-
}
|
599
|
+
if (!this.events) this.events = this.constructor.events;
|
600
|
+
if (!this.elements) this.elements = this.constructor.elements;
|
601
|
+
if (this.events) this.delegateEvents();
|
602
|
+
if (this.elements) this.refreshElements();
|
570
603
|
Controller.__super__.constructor.apply(this, arguments);
|
571
604
|
}
|
605
|
+
|
572
606
|
Controller.prototype.release = function(callback) {
|
573
607
|
if (typeof callback === 'function') {
|
574
608
|
return this.bind('release', callback);
|
@@ -576,25 +610,30 @@
|
|
576
610
|
return this.trigger('release');
|
577
611
|
}
|
578
612
|
};
|
613
|
+
|
579
614
|
Controller.prototype.$ = function(selector) {
|
580
615
|
return $(selector, this.el);
|
581
616
|
};
|
617
|
+
|
582
618
|
Controller.prototype.delegateEvents = function() {
|
583
619
|
var eventName, key, match, method, selector, _ref, _results;
|
584
620
|
_ref = this.events;
|
585
621
|
_results = [];
|
586
622
|
for (key in _ref) {
|
587
623
|
method = _ref[key];
|
588
|
-
if (typeof method !== 'function')
|
589
|
-
method = this.proxy(this[method]);
|
590
|
-
}
|
624
|
+
if (typeof method !== 'function') method = this.proxy(this[method]);
|
591
625
|
match = key.match(this.eventSplitter);
|
592
626
|
eventName = match[1];
|
593
627
|
selector = match[2];
|
594
|
-
|
628
|
+
if (selector === '') {
|
629
|
+
_results.push(this.el.bind(eventName, method));
|
630
|
+
} else {
|
631
|
+
_results.push(this.el.delegate(selector, eventName, method));
|
632
|
+
}
|
595
633
|
}
|
596
634
|
return _results;
|
597
635
|
};
|
636
|
+
|
598
637
|
Controller.prototype.refreshElements = function() {
|
599
638
|
var key, value, _ref, _results;
|
600
639
|
_ref = this.elements;
|
@@ -605,14 +644,17 @@
|
|
605
644
|
}
|
606
645
|
return _results;
|
607
646
|
};
|
647
|
+
|
608
648
|
Controller.prototype.delay = function(func, timeout) {
|
609
649
|
return setTimeout(this.proxy(func), timeout || 0);
|
610
650
|
};
|
651
|
+
|
611
652
|
Controller.prototype.html = function(element) {
|
612
653
|
this.el.html(element.el || element);
|
613
654
|
this.refreshElements();
|
614
655
|
return this.el;
|
615
656
|
};
|
657
|
+
|
616
658
|
Controller.prototype.append = function() {
|
617
659
|
var e, elements, _ref;
|
618
660
|
elements = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
@@ -629,11 +671,13 @@
|
|
629
671
|
this.refreshElements();
|
630
672
|
return this.el;
|
631
673
|
};
|
674
|
+
|
632
675
|
Controller.prototype.appendTo = function(element) {
|
633
676
|
this.el.appendTo(element.el || element);
|
634
677
|
this.refreshElements();
|
635
678
|
return this.el;
|
636
679
|
};
|
680
|
+
|
637
681
|
Controller.prototype.prepend = function() {
|
638
682
|
var e, elements, _ref;
|
639
683
|
elements = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
@@ -650,19 +694,24 @@
|
|
650
694
|
this.refreshElements();
|
651
695
|
return this.el;
|
652
696
|
};
|
697
|
+
|
653
698
|
Controller.prototype.replace = function(element) {
|
654
699
|
var previous, _ref;
|
655
|
-
_ref = [this.el, element.el || element], previous = _ref[0], this.el = _ref[1];
|
700
|
+
_ref = [this.el, $(element.el || element)], previous = _ref[0], this.el = _ref[1];
|
656
701
|
previous.replaceWith(this.el);
|
657
702
|
this.delegateEvents();
|
658
703
|
this.refreshElements();
|
659
704
|
return this.el;
|
660
705
|
};
|
706
|
+
|
661
707
|
return Controller;
|
662
|
-
|
663
|
-
|
708
|
+
|
709
|
+
})(Module);
|
710
|
+
|
711
|
+
$ = (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) || (typeof window !== "undefined" && window !== null ? window.Zepto : void 0) || function(element) {
|
664
712
|
return element;
|
665
713
|
};
|
714
|
+
|
666
715
|
if (typeof Object.create !== 'function') {
|
667
716
|
Object.create = function(o) {
|
668
717
|
var Func;
|
@@ -671,81 +720,89 @@
|
|
671
720
|
return new Func();
|
672
721
|
};
|
673
722
|
}
|
723
|
+
|
674
724
|
isArray = function(value) {
|
675
725
|
return Object.prototype.toString.call(value) === '[object Array]';
|
676
726
|
};
|
727
|
+
|
677
728
|
isBlank = function(value) {
|
678
729
|
var key;
|
679
|
-
if (!value)
|
680
|
-
return true;
|
681
|
-
}
|
730
|
+
if (!value) return true;
|
682
731
|
for (key in value) {
|
683
732
|
return false;
|
684
733
|
}
|
685
734
|
return true;
|
686
735
|
};
|
736
|
+
|
687
737
|
makeArray = function(args) {
|
688
738
|
return Array.prototype.slice.call(args, 0);
|
689
739
|
};
|
690
|
-
|
691
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
692
|
-
var r, v;
|
693
|
-
r = Math.random() * 16 | 0;
|
694
|
-
v = c === 'x' ? r : r & 3 | 8;
|
695
|
-
return v.toString(16);
|
696
|
-
}).toUpperCase();
|
697
|
-
};
|
740
|
+
|
698
741
|
Spine = this.Spine = {};
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
Spine.version = '1.0.
|
742
|
+
|
743
|
+
if (typeof module !== "undefined" && module !== null) module.exports = Spine;
|
744
|
+
|
745
|
+
Spine.version = '1.0.5';
|
746
|
+
|
703
747
|
Spine.isArray = isArray;
|
748
|
+
|
704
749
|
Spine.isBlank = isBlank;
|
750
|
+
|
705
751
|
Spine.$ = $;
|
752
|
+
|
706
753
|
Spine.Events = Events;
|
754
|
+
|
707
755
|
Spine.Log = Log;
|
756
|
+
|
708
757
|
Spine.Module = Module;
|
758
|
+
|
709
759
|
Spine.Controller = Controller;
|
760
|
+
|
710
761
|
Spine.Model = Model;
|
762
|
+
|
711
763
|
Module.extend.call(Spine, Events);
|
764
|
+
|
712
765
|
Module.create = Module.sub = Controller.create = Controller.sub = Model.sub = function(instances, statics) {
|
713
766
|
var result;
|
714
|
-
result = (function() {
|
715
|
-
|
767
|
+
result = (function(_super) {
|
768
|
+
|
769
|
+
__extends(result, _super);
|
770
|
+
|
716
771
|
function result() {
|
717
772
|
result.__super__.constructor.apply(this, arguments);
|
718
773
|
}
|
774
|
+
|
719
775
|
return result;
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
if (
|
725
|
-
result.extend(statics);
|
726
|
-
}
|
727
|
-
if (typeof result.unbind === "function") {
|
728
|
-
result.unbind();
|
729
|
-
}
|
776
|
+
|
777
|
+
})(this);
|
778
|
+
if (instances) result.include(instances);
|
779
|
+
if (statics) result.extend(statics);
|
780
|
+
if (typeof result.unbind === "function") result.unbind();
|
730
781
|
return result;
|
731
782
|
};
|
783
|
+
|
732
784
|
Model.setup = function(name, attributes) {
|
733
785
|
var Instance;
|
734
|
-
if (attributes == null)
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
786
|
+
if (attributes == null) attributes = [];
|
787
|
+
Instance = (function(_super) {
|
788
|
+
|
789
|
+
__extends(Instance, _super);
|
790
|
+
|
739
791
|
function Instance() {
|
740
792
|
Instance.__super__.constructor.apply(this, arguments);
|
741
793
|
}
|
794
|
+
|
742
795
|
return Instance;
|
743
|
-
|
796
|
+
|
797
|
+
})(this);
|
744
798
|
Instance.configure.apply(Instance, [name].concat(__slice.call(attributes)));
|
745
799
|
return Instance;
|
746
800
|
};
|
801
|
+
|
747
802
|
Module.init = Controller.init = Model.init = function(a1, a2, a3, a4, a5) {
|
748
803
|
return new this(a1, a2, a3, a4, a5);
|
749
804
|
};
|
805
|
+
|
750
806
|
Spine.Class = Module;
|
807
|
+
|
751
808
|
}).call(this);
|