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.
Files changed (88) hide show
  1. data/History.txt +98 -73
  2. data/Manifest.txt +2 -1
  3. data/README.txt +1 -1
  4. data/Rakefile +8 -8
  5. data/app_generators/sproutcore/USAGE +2 -3
  6. data/app_generators/sproutcore/sproutcore_generator.rb +12 -12
  7. data/app_generators/sproutcore/templates/README +26 -23
  8. data/app_generators/sproutcore/templates/{sc-config.rb → sc-config} +32 -17
  9. data/bin/sc-build +17 -17
  10. data/bin/sc-server +1 -1
  11. data/bin/sproutcore +3 -3
  12. data/clients/sc_test_runner/english.lproj/no_tests.rhtml +0 -1
  13. data/config/hoe.rb +9 -9
  14. data/config/requirements.rb +1 -1
  15. data/frameworks/sproutcore/HISTORY +14 -0
  16. data/frameworks/sproutcore/core.js +1 -1
  17. data/frameworks/sproutcore/english.lproj/theme.css +1 -0
  18. data/frameworks/sproutcore/foundation/binding.js +2 -2
  19. data/frameworks/sproutcore/foundation/timer.js +55 -22
  20. data/frameworks/sproutcore/lib/index.rhtml +2 -3
  21. data/frameworks/sproutcore/models/record.js +204 -63
  22. data/frameworks/sproutcore/tests/models/model.rhtml +360 -0
  23. data/frameworks/sproutcore/views/button/button.js +22 -1
  24. data/frameworks/sproutcore/views/collection/collection.js +6 -2
  25. data/frameworks/sproutcore/views/collection/list.js +1 -0
  26. data/frameworks/sproutcore/views/collection/source_list.js +1 -0
  27. data/frameworks/sproutcore/views/field/text_field.js +11 -2
  28. data/frameworks/sproutcore/views/inline_text_field.js +3 -2
  29. data/frameworks/sproutcore/views/menu_item.js +1 -0
  30. data/frameworks/sproutcore/views/pagination.js +1 -0
  31. data/frameworks/sproutcore/views/view.js +4 -1
  32. data/lib/sproutcore/build_tools/html_builder.rb +36 -36
  33. data/lib/sproutcore/build_tools/resource_builder.rb +55 -54
  34. data/lib/sproutcore/build_tools.rb +12 -12
  35. data/lib/sproutcore/bundle.rb +162 -164
  36. data/lib/sproutcore/bundle_manifest.rb +154 -107
  37. data/lib/sproutcore/generator_helper.rb +23 -23
  38. data/lib/sproutcore/helpers/capture_helper.rb +10 -10
  39. data/lib/sproutcore/helpers/static_helper.rb +39 -26
  40. data/lib/sproutcore/helpers/tag_helper.rb +10 -10
  41. data/lib/sproutcore/helpers/text_helper.rb +36 -36
  42. data/lib/sproutcore/helpers.rb +1 -1
  43. data/lib/sproutcore/jsdoc.rb +10 -10
  44. data/lib/sproutcore/jsmin.rb +14 -14
  45. data/lib/sproutcore/library.rb +135 -87
  46. data/lib/sproutcore/merb/bundle_controller.rb +77 -54
  47. data/lib/sproutcore/merb/router.rb +19 -12
  48. data/lib/sproutcore/merb.rb +1 -1
  49. data/lib/sproutcore/version.rb +1 -1
  50. data/lib/sproutcore/view_helpers.rb +121 -121
  51. data/lib/sproutcore.rb +5 -7
  52. data/sc-config.rb +6 -0
  53. data/sc_generators/client/README +1 -1
  54. data/sc_generators/client/USAGE +1 -2
  55. data/sc_generators/client/client_generator.rb +6 -6
  56. data/sc_generators/client/templates/core.js +2 -2
  57. data/sc_generators/client/templates/english.lproj/body.css +79 -81
  58. data/sc_generators/client/templates/english.lproj/strings.js +1 -2
  59. data/sc_generators/client/templates/main.js +6 -8
  60. data/sc_generators/controller/USAGE +1 -2
  61. data/sc_generators/controller/controller_generator.rb +7 -7
  62. data/sc_generators/controller/templates/controller.js +3 -3
  63. data/sc_generators/controller/templates/test.rhtml +1 -1
  64. data/sc_generators/framework/README +1 -2
  65. data/sc_generators/framework/USAGE +2 -3
  66. data/sc_generators/framework/framework_generator.rb +5 -5
  67. data/sc_generators/framework/templates/core.js +3 -3
  68. data/sc_generators/framework/templates/english.lproj/strings.js +1 -2
  69. data/sc_generators/language/USAGE +1 -2
  70. data/sc_generators/language/language_generator.rb +6 -6
  71. data/sc_generators/language/templates/strings.js +1 -2
  72. data/sc_generators/model/USAGE +1 -2
  73. data/sc_generators/model/model_generator.rb +7 -7
  74. data/sc_generators/model/templates/fixture.js +26 -26
  75. data/sc_generators/model/templates/model.js +5 -5
  76. data/sc_generators/model/templates/test.rhtml +2 -2
  77. data/sc_generators/test/USAGE +1 -2
  78. data/sc_generators/test/templates/test.rhtml +2 -2
  79. data/sc_generators/test/test_generator.rb +6 -6
  80. data/sc_generators/view/USAGE +1 -2
  81. data/sc_generators/view/templates/test.rhtml +2 -2
  82. data/sc_generators/view/templates/view.js +3 -3
  83. data/sc_generators/view/view_generator.rb +7 -7
  84. data/spec/spec.opts +1 -1
  85. data/spec/spec_helper.rb +1 -1
  86. data/spec/sproutcore_spec.rb +3 -3
  87. data/tasks/deployment.rake +4 -4
  88. metadata +4 -3
@@ -5,43 +5,110 @@
5
5
 
6
6
  require('foundation/object') ;
7
7
 
8
- SC.Record = SC.Object.extend({
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
- // override this with the properties you want the record to manage.
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
- // this is the primary key used to distinguish records. If the keys
18
- // match, the records are assumed to be identical.
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
- // when a new empty record is created, this will be set to true. It will be
22
- // set to false again the first time the record is committed.
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
- // set to non-zero whenever the record has uncommitted changes.
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
- // set to true when the record is deleted. Will cause it to be removed
29
- // from any member collections. Once no more objects hold references to it,
30
- // the property will be disabled.
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
- // Set this URL to point to the type of resource this record is. Put a
38
- // '%@' where you expect the primaryKey to be inserted to identify the
39
- // record.
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
- // The item providing the data for this. Set to either the store or a
43
- // Server. Setting it to the Store will make refresh and commit effectively
44
- // null-ops.
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
- // invoked by the UI to request the model object be updated from the server.
69
- // Override to actually support server changes.
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
- // invoked by the UI to tell the model this record should be saved. Override
75
- // to support server changes. Note that this is used to support both the
76
- // create and update components of CRUD.
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
- // this can delete the record. The non-server version just sets isDeleted.
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
- // gets an attribute, converting it to the proper format.
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
- // updates the attribute, converting it back to the property format.
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
- // This will take the incoming set of attributes and update internal set. Note that
134
- // if the attributes have never been set, then the object you pass in may become
135
- // the new set of attribute. This assumes the attrs you pass in will not be
136
- // modified later. This method also assumes it is coming from the server, so the
137
- // change count will be reset.
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
- // This will return the current set of attributes as a hash you can send back
165
- // to the server.
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
- // If you try to get/set a property not defined by the record, then this method
171
- // will be called. It will try to get the value from the set of attributes.
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 this record is cached.
177
- // store the old key, update the value, then let the store do the housekeeping...
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
- // this will compare the target object with the receiver, using the
243
- // orderBy parameters.
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
- // used to match records to a set of conditions. By default, this will
295
- // call matchCondition on each condition.
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
- // by default this just gets the key value and compares it. Based on the
311
- // type of the receiver's value, try to massage the condition value into
312
- // that.
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
- // massage value.
318
- if (value && value.primaryKey) value = value.get(value.primaryKey) ;
319
-
320
- if (recValue instanceof Array) {
321
- var loc = recValue.length ;
322
- while(--loc >= 0) {
323
- if (this._matchValue(recValue[loc],value)) return true;
324
- }
325
- } else return this._matchValue(recValue,value) ;
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
- // massage recValue a tad
331
- if (recValue && recValue.primaryKey && typeof(value) == "string") recValue = recValue.get(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
- return (stringify) ? recValue.toString().match(value) : recValue==value ;
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 'Record({ ' + ret.join(', ') + ' })' ;
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
- // This method should be used by the server to push updated data into a
359
- // record. The data should be a hash with strings and arrays. This will
360
- // use any types you define to convert the values into their correct type.
361
- // Note that references to external objects should be a string with the
362
- // primaryKey value of the record.
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