sproutcore 0.9.11 → 0.9.12
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/History.txt +98 -73
- data/Manifest.txt +2 -1
- data/README.txt +1 -1
- data/Rakefile +8 -8
- data/app_generators/sproutcore/USAGE +2 -3
- data/app_generators/sproutcore/sproutcore_generator.rb +12 -12
- data/app_generators/sproutcore/templates/README +26 -23
- data/app_generators/sproutcore/templates/{sc-config.rb → sc-config} +32 -17
- data/bin/sc-build +17 -17
- data/bin/sc-server +1 -1
- data/bin/sproutcore +3 -3
- data/clients/sc_test_runner/english.lproj/no_tests.rhtml +0 -1
- data/config/hoe.rb +9 -9
- data/config/requirements.rb +1 -1
- data/frameworks/sproutcore/HISTORY +14 -0
- data/frameworks/sproutcore/core.js +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +1 -0
- data/frameworks/sproutcore/foundation/binding.js +2 -2
- data/frameworks/sproutcore/foundation/timer.js +55 -22
- data/frameworks/sproutcore/lib/index.rhtml +2 -3
- data/frameworks/sproutcore/models/record.js +204 -63
- data/frameworks/sproutcore/tests/models/model.rhtml +360 -0
- data/frameworks/sproutcore/views/button/button.js +22 -1
- data/frameworks/sproutcore/views/collection/collection.js +6 -2
- data/frameworks/sproutcore/views/collection/list.js +1 -0
- data/frameworks/sproutcore/views/collection/source_list.js +1 -0
- data/frameworks/sproutcore/views/field/text_field.js +11 -2
- data/frameworks/sproutcore/views/inline_text_field.js +3 -2
- data/frameworks/sproutcore/views/menu_item.js +1 -0
- data/frameworks/sproutcore/views/pagination.js +1 -0
- data/frameworks/sproutcore/views/view.js +4 -1
- data/lib/sproutcore/build_tools/html_builder.rb +36 -36
- data/lib/sproutcore/build_tools/resource_builder.rb +55 -54
- data/lib/sproutcore/build_tools.rb +12 -12
- data/lib/sproutcore/bundle.rb +162 -164
- data/lib/sproutcore/bundle_manifest.rb +154 -107
- data/lib/sproutcore/generator_helper.rb +23 -23
- data/lib/sproutcore/helpers/capture_helper.rb +10 -10
- data/lib/sproutcore/helpers/static_helper.rb +39 -26
- data/lib/sproutcore/helpers/tag_helper.rb +10 -10
- data/lib/sproutcore/helpers/text_helper.rb +36 -36
- data/lib/sproutcore/helpers.rb +1 -1
- data/lib/sproutcore/jsdoc.rb +10 -10
- data/lib/sproutcore/jsmin.rb +14 -14
- data/lib/sproutcore/library.rb +135 -87
- data/lib/sproutcore/merb/bundle_controller.rb +77 -54
- data/lib/sproutcore/merb/router.rb +19 -12
- data/lib/sproutcore/merb.rb +1 -1
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +121 -121
- data/lib/sproutcore.rb +5 -7
- data/sc-config.rb +6 -0
- data/sc_generators/client/README +1 -1
- data/sc_generators/client/USAGE +1 -2
- data/sc_generators/client/client_generator.rb +6 -6
- data/sc_generators/client/templates/core.js +2 -2
- data/sc_generators/client/templates/english.lproj/body.css +79 -81
- data/sc_generators/client/templates/english.lproj/strings.js +1 -2
- data/sc_generators/client/templates/main.js +6 -8
- data/sc_generators/controller/USAGE +1 -2
- data/sc_generators/controller/controller_generator.rb +7 -7
- data/sc_generators/controller/templates/controller.js +3 -3
- data/sc_generators/controller/templates/test.rhtml +1 -1
- data/sc_generators/framework/README +1 -2
- data/sc_generators/framework/USAGE +2 -3
- data/sc_generators/framework/framework_generator.rb +5 -5
- data/sc_generators/framework/templates/core.js +3 -3
- data/sc_generators/framework/templates/english.lproj/strings.js +1 -2
- data/sc_generators/language/USAGE +1 -2
- data/sc_generators/language/language_generator.rb +6 -6
- data/sc_generators/language/templates/strings.js +1 -2
- data/sc_generators/model/USAGE +1 -2
- data/sc_generators/model/model_generator.rb +7 -7
- data/sc_generators/model/templates/fixture.js +26 -26
- data/sc_generators/model/templates/model.js +5 -5
- data/sc_generators/model/templates/test.rhtml +2 -2
- data/sc_generators/test/USAGE +1 -2
- data/sc_generators/test/templates/test.rhtml +2 -2
- data/sc_generators/test/test_generator.rb +6 -6
- data/sc_generators/view/USAGE +1 -2
- data/sc_generators/view/templates/test.rhtml +2 -2
- data/sc_generators/view/templates/view.js +3 -3
- data/sc_generators/view/view_generator.rb +7 -7
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/sproutcore_spec.rb +3 -3
- data/tasks/deployment.rake +4 -4
- metadata +4 -3
|
@@ -5,43 +5,110 @@
|
|
|
5
5
|
|
|
6
6
|
require('foundation/object') ;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
@class
|
|
10
|
+
|
|
11
|
+
A Record is the core model class in SproutCore. It is analogous to
|
|
12
|
+
NSManagedObject in Core Data and EOEnterpriseObject in the Enterprise
|
|
13
|
+
Objects Framework (aka WebObjects), or ActiveRecord::Base in Rails.
|
|
14
|
+
|
|
15
|
+
To create a new model class, in your SproutCore workspace, do:
|
|
16
|
+
|
|
17
|
+
{{{
|
|
18
|
+
$ sc-gen model my_app/my_model
|
|
19
|
+
}}}
|
|
20
|
+
|
|
21
|
+
This will create MyApp.MyModel in clients/my_app/models/my_model.js.
|
|
22
|
+
|
|
23
|
+
The core attributes hash is used to store the values of a record in a
|
|
24
|
+
format that can be easily passed to/from the server. The values should
|
|
25
|
+
generally be stored in their raw string form. References to external
|
|
26
|
+
records should be stored as primary keys.
|
|
27
|
+
|
|
28
|
+
Normally you do not need to work with the attributes hash directly.
|
|
29
|
+
Instead you should use get/set on normal record properties. If the
|
|
30
|
+
property is not defined on the object, then the record will check the
|
|
31
|
+
attributes hash instead.
|
|
32
|
+
|
|
33
|
+
You can bulk update attributes from the server using the
|
|
34
|
+
updateAttributes() method.
|
|
35
|
+
|
|
36
|
+
@extends SC.Object
|
|
37
|
+
@since SproutCore 1.0
|
|
38
|
+
*/
|
|
39
|
+
SC.Record = SC.Object.extend(
|
|
40
|
+
/** @scope SC.Record.prototype */ {
|
|
9
41
|
|
|
10
42
|
// ...............................
|
|
11
43
|
// PROPERTIES
|
|
12
44
|
//
|
|
13
45
|
|
|
14
|
-
|
|
46
|
+
/**
|
|
47
|
+
Override this with the properties you want the record to manage.
|
|
48
|
+
|
|
49
|
+
@field
|
|
50
|
+
@type {Array}
|
|
51
|
+
*/
|
|
15
52
|
properties: ['guid'],
|
|
16
53
|
|
|
17
|
-
|
|
18
|
-
|
|
54
|
+
/**
|
|
55
|
+
This is the primary key used to distinguish records. If the keys
|
|
56
|
+
match, the records are assumed to be identical.
|
|
57
|
+
|
|
58
|
+
@field
|
|
59
|
+
@type {String}
|
|
60
|
+
*/
|
|
19
61
|
primaryKey: 'guid',
|
|
20
62
|
|
|
21
|
-
|
|
22
|
-
|
|
63
|
+
/**
|
|
64
|
+
When a new empty record is created, this will be set to true. It will be
|
|
65
|
+
set to false again the first time the record is committed.
|
|
66
|
+
|
|
67
|
+
@field
|
|
68
|
+
@type {Boolean}
|
|
69
|
+
*/
|
|
23
70
|
newRecord: false,
|
|
24
71
|
|
|
25
|
-
|
|
72
|
+
/**
|
|
73
|
+
Set to non-zero whenever the record has uncommitted changes.
|
|
74
|
+
|
|
75
|
+
@field
|
|
76
|
+
@type {Number}
|
|
77
|
+
*/
|
|
26
78
|
changeCount: 0,
|
|
27
79
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
80
|
+
/**
|
|
81
|
+
Set to true when the record is deleted. Will cause it to be removed
|
|
82
|
+
from any member collections. Once no more objects hold references to it,
|
|
83
|
+
the property will be disabled.
|
|
84
|
+
|
|
85
|
+
@field
|
|
86
|
+
@type {Boolean}
|
|
87
|
+
*/
|
|
31
88
|
isDeleted: false,
|
|
32
89
|
|
|
33
90
|
// ...............................
|
|
34
91
|
// CRUD OPERATIONS
|
|
35
92
|
//
|
|
36
93
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
94
|
+
/**
|
|
95
|
+
Set this URL to point to the type of resource this record is. Put a
|
|
96
|
+
'%@' where you expect the primaryKey to be inserted to identify the
|
|
97
|
+
record.
|
|
98
|
+
|
|
99
|
+
@field
|
|
100
|
+
@type {String}
|
|
101
|
+
*/
|
|
40
102
|
resourceURL: null,
|
|
41
103
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
104
|
+
/**
|
|
105
|
+
The item providing the data for this. Set to either the store or a
|
|
106
|
+
Server. Setting it to the Store will make refresh and commit effectively
|
|
107
|
+
null-ops.
|
|
108
|
+
|
|
109
|
+
@field
|
|
110
|
+
@type {SC.Store or SC.Server}
|
|
111
|
+
*/
|
|
45
112
|
dataSource: SC.Store,
|
|
46
113
|
|
|
47
114
|
|
|
@@ -65,15 +132,20 @@ SC.Record = SC.Object.extend({
|
|
|
65
132
|
return "@" + SC.getGUID(this);
|
|
66
133
|
},
|
|
67
134
|
|
|
68
|
-
|
|
69
|
-
|
|
135
|
+
/**
|
|
136
|
+
Invoked by the UI to request the model object be updated from the server.
|
|
137
|
+
|
|
138
|
+
Override to actually support server changes.
|
|
139
|
+
*/
|
|
70
140
|
refresh: function() {
|
|
71
141
|
if (!this.get('newRecord')) this.dataSource.refreshRecords([this]);
|
|
72
142
|
},
|
|
73
143
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
144
|
+
/**
|
|
145
|
+
Invoked by the UI to tell the model this record should be saved. Override
|
|
146
|
+
to support server changes. Note that this is used to support both the
|
|
147
|
+
create and update components of CRUD.
|
|
148
|
+
*/
|
|
77
149
|
commit: function() {
|
|
78
150
|
// no longer a new record once changes have been committed.
|
|
79
151
|
if (this.get('newRecord')) {
|
|
@@ -83,7 +155,9 @@ SC.Record = SC.Object.extend({
|
|
|
83
155
|
}
|
|
84
156
|
},
|
|
85
157
|
|
|
86
|
-
|
|
158
|
+
/**
|
|
159
|
+
This can delete the record. The non-server version just sets isDeleted.
|
|
160
|
+
*/
|
|
87
161
|
destroy: function() { this.dataSource.destroyRecords([this]) ; },
|
|
88
162
|
|
|
89
163
|
// ...............................
|
|
@@ -102,7 +176,12 @@ SC.Record = SC.Object.extend({
|
|
|
102
176
|
// You can bulk update attributes from the server using the
|
|
103
177
|
// updateAttributes() method.
|
|
104
178
|
|
|
105
|
-
|
|
179
|
+
/**
|
|
180
|
+
Gets an attribute, converting it to the proper format.
|
|
181
|
+
|
|
182
|
+
@param {string} key the attribute you want to read
|
|
183
|
+
@returns {value} the value of the key, or null if it doesn't exist
|
|
184
|
+
**/
|
|
106
185
|
readAttribute: function(key) {
|
|
107
186
|
if (!this._cachedAttributes) this._cachedAttributes = {} ;
|
|
108
187
|
var ret = this._cachedAttributes[key] ;
|
|
@@ -118,7 +197,13 @@ SC.Record = SC.Object.extend({
|
|
|
118
197
|
return (ret === undefined) ? null : ret;
|
|
119
198
|
},
|
|
120
199
|
|
|
121
|
-
|
|
200
|
+
/**
|
|
201
|
+
Updates the attribute, converting it back to the property format.
|
|
202
|
+
|
|
203
|
+
@param {String} key the attribute you want to read
|
|
204
|
+
@param {Object} value the attribute you want to read
|
|
205
|
+
@returns {Object} the value of the key, or null if it doesn't exist
|
|
206
|
+
**/
|
|
122
207
|
writeAttribute: function(key, value) {
|
|
123
208
|
var recordType = this._getRecordType(key+'Type') ;
|
|
124
209
|
var ret = this._attributeFromProperty(value, recordType) ;
|
|
@@ -130,11 +215,18 @@ SC.Record = SC.Object.extend({
|
|
|
130
215
|
return value ;
|
|
131
216
|
},
|
|
132
217
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
218
|
+
/**
|
|
219
|
+
This will take the incoming set of attributes and update internal set.
|
|
220
|
+
|
|
221
|
+
Note that if the attributes have never been set, then the object you pass
|
|
222
|
+
in may become the new set of attribute. This assumes the attrs you pass
|
|
223
|
+
in will not be modified later. This method also assumes it is coming from
|
|
224
|
+
the server, so the change count will be reset.
|
|
225
|
+
|
|
226
|
+
@param {Object} newAttrs the new attributes for the object
|
|
227
|
+
@param {Boolean} replace should the overwrite the in-place attributes, or replace them entirely
|
|
228
|
+
@returns {Boolean} isLoaded is the object loaded?
|
|
229
|
+
**/
|
|
138
230
|
updateAttributes: function(newAttrs, replace, isLoaded) {
|
|
139
231
|
var changed = false ;
|
|
140
232
|
if (this._attributes && (replace !== true)) {
|
|
@@ -161,20 +253,31 @@ SC.Record = SC.Object.extend({
|
|
|
161
253
|
}
|
|
162
254
|
},
|
|
163
255
|
|
|
164
|
-
|
|
165
|
-
|
|
256
|
+
/**
|
|
257
|
+
This will return the current set of attributes as a hash you can send back to the server.
|
|
258
|
+
|
|
259
|
+
@returns {Object} the current attributes of the receiver
|
|
260
|
+
**/
|
|
166
261
|
attributes: function() {
|
|
167
262
|
return Object.clone(this._attributes) ;
|
|
168
263
|
}.property(),
|
|
169
264
|
|
|
170
|
-
|
|
171
|
-
|
|
265
|
+
/**
|
|
266
|
+
If you try to get/set a property not defined by the record, then this
|
|
267
|
+
method will be called. It will try to get the value from the set of
|
|
268
|
+
attributes.
|
|
269
|
+
|
|
270
|
+
@param {String} key the attribute being get/set
|
|
271
|
+
@param {Object} value the value to set the key to, if present
|
|
272
|
+
@returns {Object} the value
|
|
273
|
+
**/
|
|
172
274
|
unknownProperty: function( key, value )
|
|
173
275
|
{
|
|
174
276
|
if (value !== undefined) {
|
|
175
277
|
|
|
176
|
-
// if we're modifying the PKEY, then SC.Store needs to relocate where
|
|
177
|
-
// store the old key, update the value, then let
|
|
278
|
+
// if we're modifying the PKEY, then SC.Store needs to relocate where
|
|
279
|
+
// this record is cached. store the old key, update the value, then let
|
|
280
|
+
// the store do the housekeeping...
|
|
178
281
|
var primaryKeyName = this.get('primaryKey');
|
|
179
282
|
if (key == primaryKeyName)
|
|
180
283
|
{
|
|
@@ -238,9 +341,16 @@ SC.Record = SC.Object.extend({
|
|
|
238
341
|
//
|
|
239
342
|
|
|
240
343
|
valueForSortKey: function(key) { return this.get(key); },
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
Compares the receiver to the passed object, using the array of keys to
|
|
347
|
+
determine the order. You can use this method as part of a call to sort()
|
|
348
|
+
on an array.
|
|
349
|
+
|
|
350
|
+
@param object {SC.Record} the other record
|
|
351
|
+
@param orderBy {Array} array of one or more keys. Optional.
|
|
352
|
+
@returns {Number} -1, 0, 1
|
|
353
|
+
*/
|
|
244
354
|
compareTo: function(object, orderBy) {
|
|
245
355
|
if (!orderBy) orderBy = [this.get('primaryKey')] ;
|
|
246
356
|
var ret = SC.Record.SORT_SAME ; var loc ;
|
|
@@ -291,8 +401,13 @@ SC.Record = SC.Object.extend({
|
|
|
291
401
|
return value ;
|
|
292
402
|
},
|
|
293
403
|
|
|
294
|
-
|
|
295
|
-
|
|
404
|
+
/**
|
|
405
|
+
Used to match records to a set of conditions. By default, this will
|
|
406
|
+
call matchCondition on each condition.
|
|
407
|
+
|
|
408
|
+
@param conditions {Hash} hash of conditions
|
|
409
|
+
@returns {Boolean} true if the receiver matches the hash of conditions.
|
|
410
|
+
*/
|
|
296
411
|
matchConditions: function(conditions) {
|
|
297
412
|
for(var key in conditions) {
|
|
298
413
|
var value = conditions[key] ;
|
|
@@ -306,31 +421,51 @@ SC.Record = SC.Object.extend({
|
|
|
306
421
|
}
|
|
307
422
|
return true ;
|
|
308
423
|
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
Returns true if the value of key matches the passed value. This is used
|
|
427
|
+
by matchConditions().
|
|
428
|
+
|
|
429
|
+
@param key {String} the key name
|
|
430
|
+
@param value {Object} the value to match agains
|
|
431
|
+
@returns {Boolean} true if matched
|
|
432
|
+
*/
|
|
313
433
|
matchCondition: function(key, value) {
|
|
314
434
|
var recValue = this.get(key) ;
|
|
315
435
|
var isMatch ;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
436
|
+
var loc ;
|
|
437
|
+
|
|
438
|
+
// The passed in value appears to be another record instance.
|
|
439
|
+
// just check for equality with the record as an optimization.
|
|
440
|
+
if (value && value.primaryKey) {
|
|
441
|
+
if ($type(recValue) === T_ARRAY) {
|
|
442
|
+
loc = recValue.length ;
|
|
443
|
+
while(--loc >= 0) {
|
|
444
|
+
if (recValue === value) return true;
|
|
445
|
+
}
|
|
446
|
+
} else return recValue === value ;
|
|
447
|
+
|
|
448
|
+
// Otherwise, do a more in-depth compare
|
|
449
|
+
} else {
|
|
450
|
+
if ($type(recValue) === T_ARRAY) {
|
|
451
|
+
loc = recValue.length ;
|
|
452
|
+
while(--loc >= 0) {
|
|
453
|
+
if (this._matchValue(recValue[loc],value)) return true;
|
|
454
|
+
}
|
|
455
|
+
} else return this._matchValue(recValue,value) ;
|
|
456
|
+
}
|
|
326
457
|
return false ;
|
|
327
458
|
},
|
|
328
459
|
|
|
329
460
|
_matchValue: function(recValue,value) {
|
|
330
|
-
//
|
|
331
|
-
if (recValue && recValue.primaryKey
|
|
461
|
+
// if we get here with recValue as a record, we must compare by guid, so grab it
|
|
462
|
+
if (recValue && recValue.primaryKey) recValue = recValue.get(recValue.primaryKey) ;
|
|
332
463
|
var stringify = (value instanceof RegExp);
|
|
333
|
-
|
|
464
|
+
if (stringify) {
|
|
465
|
+
return recValue.toString().match(value)
|
|
466
|
+
} else {
|
|
467
|
+
return recValue==value ;
|
|
468
|
+
}
|
|
334
469
|
},
|
|
335
470
|
|
|
336
471
|
// ...............................
|
|
@@ -346,7 +481,7 @@ SC.Record = SC.Object.extend({
|
|
|
346
481
|
if (value === null) value = "(null)" ;
|
|
347
482
|
return [key,value].join('=') ;
|
|
348
483
|
}) ;
|
|
349
|
-
return '
|
|
484
|
+
return this._type.toString() + '({ ' + ret.join(', ') + ' })' ;
|
|
350
485
|
},
|
|
351
486
|
|
|
352
487
|
propertyObserver: function(observing,target,key,value) {
|
|
@@ -355,11 +490,17 @@ SC.Record = SC.Object.extend({
|
|
|
355
490
|
|
|
356
491
|
_cprops: ['properties'],
|
|
357
492
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
493
|
+
/**
|
|
494
|
+
This method should be used by the server to push updated data into a
|
|
495
|
+
record. The data should be a hash with strings and arrays. This will
|
|
496
|
+
use any types you define to convert the values into their correct type.
|
|
497
|
+
Note that references to external objects should be a string with the
|
|
498
|
+
primaryKey value of the record.
|
|
499
|
+
|
|
500
|
+
@param data {Hash} the data hash
|
|
501
|
+
@param isLoaded {Boolean} true if the hash contains a full set of data for the record vs just a summary.
|
|
502
|
+
@returns {void}
|
|
503
|
+
*/
|
|
363
504
|
updateProperties: function(data,isLoaded) {
|
|
364
505
|
var rec = this ;
|
|
365
506
|
|