sproutcore 1.5.0.rc.1 → 1.5.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/CHANGELOG +4 -0
  2. data/VERSION.yml +1 -1
  3. data/lib/frameworks/sproutcore/Buildfile +9 -4
  4. data/lib/frameworks/sproutcore/README.md +1 -0
  5. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/QuickLook/Preview.pdf +0 -0
  6. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/QuickLook/Thumbnail.tiff +0 -0
  7. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/data.plist +0 -0
  8. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image10.png +0 -0
  9. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image11.png +0 -0
  10. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image13.png +0 -0
  11. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image15.png +0 -0
  12. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image16.png +0 -0
  13. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image17.png +0 -0
  14. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image18.png +0 -0
  15. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image19.png +0 -0
  16. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image22.tiff +0 -0
  17. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image23.png +0 -0
  18. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image24.png +0 -0
  19. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image25.png +0 -0
  20. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image30.png +0 -0
  21. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image31.png +0 -0
  22. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image8.png +0 -0
  23. data/lib/frameworks/sproutcore/design/{TestRunner_Design.gaffle → TestRunner_Design.graffle}/image9.png +0 -0
  24. data/lib/frameworks/sproutcore/frameworks/animation/core.js +23 -25
  25. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +160 -0
  26. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +73 -82
  27. data/lib/frameworks/sproutcore/frameworks/core_foundation/core.js +1 -3
  28. data/lib/frameworks/sproutcore/frameworks/{handlebars/extensions → core_foundation/ext/handlebars}/bind.js +110 -7
  29. data/lib/frameworks/sproutcore/frameworks/{handlebars/extensions → core_foundation/ext/handlebars}/collection.js +10 -7
  30. data/lib/frameworks/sproutcore/frameworks/{handlebars/extensions → core_foundation/ext/handlebars}/localization.js +1 -1
  31. data/lib/frameworks/sproutcore/frameworks/{handlebars/extensions → core_foundation/ext/handlebars}/view.js +4 -2
  32. data/lib/frameworks/sproutcore/frameworks/{handlebars/extensions.js → core_foundation/ext/handlebars.js} +0 -57
  33. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/object.js +1 -3
  34. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +11 -0
  35. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/main.js +1 -3
  36. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +2 -4
  37. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/application.js +14 -16
  38. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/builder.js +29 -37
  39. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/datetime.js +0 -0
  40. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +71 -19
  41. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +3 -7
  42. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/page.js +5 -7
  43. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +1 -3
  44. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +4 -0
  45. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/timer.js +21 -27
  46. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/utils.js +3 -5
  47. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/array/array_case.js +3 -3
  48. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/object/single_enumerable_case.js +1 -1
  49. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/sparse_array.js +1 -1
  50. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/handlebars.js +93 -1
  51. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/clippingFrame.js +1 -1
  52. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/convertLayouts.js +13 -11
  53. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layer.js +2 -6
  54. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +4 -4
  55. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/theme.js +2 -0
  56. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view.js +4 -4
  57. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template.js +6 -2
  58. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template_collection.js +87 -32
  59. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +21 -25
  60. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/cascade.js +15 -19
  61. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +114 -167
  62. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +4 -4
  63. data/lib/frameworks/sproutcore/frameworks/datastore/models/child_attribute.js +4 -6
  64. data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +2 -4
  65. data/lib/frameworks/sproutcore/frameworks/datastore/models/fetched_attribute.js +7 -7
  66. data/lib/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +18 -20
  67. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +74 -72
  68. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +36 -29
  69. data/lib/frameworks/sproutcore/frameworks/datastore/models/single_attribute.js +2 -2
  70. data/lib/frameworks/sproutcore/frameworks/datastore/system/child_array.js +97 -78
  71. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +117 -97
  72. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +13 -13
  73. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +111 -108
  74. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +231 -198
  75. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +146 -145
  76. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/builders.js +21 -21
  77. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/flush.js +49 -50
  78. data/lib/frameworks/sproutcore/frameworks/datetime/{system → frameworks/core/system}/datetime.js +122 -171
  79. data/lib/frameworks/sproutcore/frameworks/datetime/{tests → frameworks/core/tests}/system/datetime.js +0 -0
  80. data/lib/frameworks/sproutcore/frameworks/datetime/{resources → frameworks/localized/resources}/strings.js +0 -0
  81. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/system/datetime.js +91 -0
  82. data/lib/frameworks/sproutcore/frameworks/desktop/core.js +18 -2
  83. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/border.js +23 -16
  84. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_fast_path.js +56 -45
  85. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_group.js +5 -2
  86. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +21 -19
  87. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +82 -77
  88. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/navigation_builder.js +18 -12
  89. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/scrollable.js +29 -17
  90. data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +148 -107
  91. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +31 -16
  92. data/lib/frameworks/sproutcore/frameworks/desktop/panes/modal.js +16 -13
  93. data/lib/frameworks/sproutcore/frameworks/desktop/panes/palette.js +38 -17
  94. data/lib/frameworks/sproutcore/frameworks/desktop/panes/panel.js +37 -25
  95. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +247 -144
  96. data/lib/frameworks/sproutcore/frameworks/desktop/panes/select_button.js +155 -100
  97. data/lib/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +39 -17
  98. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_data_source.js +9 -6
  99. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_source.js +18 -22
  100. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +27 -17
  101. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +77 -44
  102. data/lib/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +68 -33
  103. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +168 -110
  104. data/lib/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +37 -5
  105. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +187 -123
  106. data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +73 -49
  107. data/lib/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +34 -9
  108. data/lib/frameworks/sproutcore/frameworks/desktop/views/file.js +51 -14
  109. data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +38 -8
  110. data/lib/frameworks/sproutcore/frameworks/desktop/views/image_button.js +15 -9
  111. data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +54 -34
  112. data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +113 -42
  113. data/lib/frameworks/sproutcore/frameworks/desktop/views/master_detail.js +84 -28
  114. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +67 -51
  115. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +122 -35
  116. data/lib/frameworks/sproutcore/frameworks/desktop/views/navigation.js +40 -16
  117. data/lib/frameworks/sproutcore/frameworks/desktop/views/navigation_bar.js +28 -18
  118. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +27 -31
  119. data/lib/frameworks/sproutcore/frameworks/desktop/views/progress.js +118 -68
  120. data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +117 -61
  121. data/lib/frameworks/sproutcore/frameworks/desktop/views/scene.js +23 -16
  122. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +241 -77
  123. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +134 -69
  124. data/lib/frameworks/sproutcore/frameworks/desktop/views/segment.js +107 -25
  125. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +125 -48
  126. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +165 -69
  127. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +73 -24
  128. data/lib/frameworks/sproutcore/frameworks/desktop/views/separator.js +19 -5
  129. data/lib/frameworks/sproutcore/frameworks/desktop/views/source_list.js +16 -4
  130. data/lib/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +14 -7
  131. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +43 -37
  132. data/lib/frameworks/sproutcore/frameworks/desktop/views/split_divider.js +8 -1
  133. data/lib/frameworks/sproutcore/frameworks/desktop/views/stacked.js +14 -3
  134. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +16 -2
  135. data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +99 -0
  136. data/lib/frameworks/sproutcore/frameworks/desktop/views/thumb.js +13 -1
  137. data/lib/frameworks/sproutcore/frameworks/desktop/views/toolbar.js +58 -8
  138. data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +34 -18
  139. data/lib/frameworks/sproutcore/frameworks/desktop/views/well.js +25 -9
  140. data/lib/frameworks/sproutcore/frameworks/desktop/views/workspace.js +70 -36
  141. data/lib/frameworks/sproutcore/frameworks/foundation/controllers/tree.js +10 -5
  142. data/lib/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +28 -17
  143. data/lib/frameworks/sproutcore/frameworks/foundation/delegates/inline_text_field.js +41 -43
  144. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/pinch.js +42 -4
  145. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/swipe.js +94 -4
  146. data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap.js +41 -1
  147. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_mixin.js +2 -0
  148. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +18 -9
  149. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/collection_content.js +7 -5
  150. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_display.js +7 -8
  151. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +34 -24
  152. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/control.js +48 -18
  153. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +1 -0
  154. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/misc.js +1 -2
  155. data/lib/frameworks/sproutcore/frameworks/foundation/tasks/preload_bundle.js +1 -1
  156. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/beginEditing.js +0 -11
  157. data/lib/frameworks/sproutcore/frameworks/foundation/validators/date_time.js +1 -1
  158. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +8 -0
  159. data/lib/frameworks/sproutcore/frameworks/qunit/README.md +24 -0
  160. data/lib/frameworks/sproutcore/frameworks/qunit/package.json +21 -0
  161. data/lib/frameworks/sproutcore/frameworks/qunit/qunit/qunit.css +215 -0
  162. data/lib/frameworks/sproutcore/frameworks/qunit/qunit/qunit.js +1442 -0
  163. data/lib/frameworks/sproutcore/frameworks/qunit/test/headless.html +24 -0
  164. data/lib/frameworks/sproutcore/frameworks/qunit/test/index.html +18 -0
  165. data/lib/frameworks/sproutcore/frameworks/qunit/test/logs.html +17 -0
  166. data/lib/frameworks/sproutcore/frameworks/qunit/test/logs.js +150 -0
  167. data/lib/frameworks/sproutcore/frameworks/qunit/test/same.js +1421 -0
  168. data/lib/frameworks/sproutcore/frameworks/qunit/test/test.js +314 -0
  169. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +1 -1
  170. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +369 -60
  171. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +2 -405
  172. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +3 -9
  173. data/lib/frameworks/sproutcore/frameworks/runtime/private/property_chain.js +50 -45
  174. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +20 -1
  175. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +0 -9
  176. data/lib/frameworks/sproutcore/frameworks/runtime/tests/core/guidFor.js +1 -1
  177. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +36 -14
  178. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable/enumerable.js +0 -34
  179. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable/enumerable_observers.js +50 -61
  180. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +2 -2
  181. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/propertyChanges.js +1 -1
  182. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/registerDependentKeys.js +45 -1
  183. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/propertyChanges.js +1 -1
  184. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/object/bindings.js +5 -0
  185. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/object/enhance.js +1 -1
  186. data/lib/frameworks/sproutcore/frameworks/testing/core.js +3 -0
  187. data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +0 -1
  188. data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +0 -1
  189. data/lib/gen/html_app/templates/apps/@target_name@/@target_name@.js +1 -1
  190. data/vendor/chance/lib/chance/instance.rb +8 -6
  191. metadata +41 -31
  192. data/lib/frameworks/sproutcore/frameworks/testing/jquery.js +0 -3559
  193. data/lib/frameworks/sproutcore/frameworks/testing/qunit.js +0 -827
@@ -64,10 +64,14 @@ SC.Array = /** @scope SC.Array.prototype */{
64
64
  /**
65
65
  This is one of the primitves you must implement to support SC.Array. You
66
66
  should replace amt objects started at idx with the objects in the passed
67
- array. You should also call this.enumerableContentDidChange() ;
67
+ array.
68
68
 
69
- NOTE: JavaScript arrays already implement SC.Array and
70
- calls this.enumerableContentDidChange.
69
+ Before mutating the underlying data structure, you must call
70
+ this.arrayContentWillChange(). After the mutation is complete, you must
71
+ call arrayContentDidChange() and enumerableContentDidChange().
72
+
73
+ NOTE: JavaScript arrays already implement SC.Array and automatically call
74
+ the correct callbacks.
71
75
 
72
76
  @param {Number} idx
73
77
  Starting index in the array to replace. If idx >= length, then append to
@@ -203,9 +207,9 @@ SC.Array = /** @scope SC.Array.prototype */{
203
207
  /**
204
208
  Push the object onto the end of the array. Works just like push() but it
205
209
  is KVO-compliant.
206
-
210
+
207
211
  @param {Object} object the objects to push
208
-
212
+
209
213
  @return {Object} The passed object
210
214
  */
211
215
  pushObject: function(obj) {
@@ -231,7 +235,7 @@ SC.Array = /** @scope SC.Array.prototype */{
231
235
  /**
232
236
  Pop object from array or nil if none are left. Works just like pop() but
233
237
  it is KVO-compliant.
234
-
238
+
235
239
  @return {Object} The popped object
236
240
  */
237
241
  popObject: function() {
@@ -246,7 +250,7 @@ SC.Array = /** @scope SC.Array.prototype */{
246
250
  /**
247
251
  Shift an object from start of array or nil if none are left. Works just
248
252
  like shift() but it is KVO-compliant.
249
-
253
+
250
254
  @return {Object} The shifted object
251
255
  */
252
256
  shiftObject: function() {
@@ -259,7 +263,7 @@ SC.Array = /** @scope SC.Array.prototype */{
259
263
  /**
260
264
  Unshift an object to start of array. Works just like unshift() but it is
261
265
  KVO-compliant.
262
-
266
+
263
267
  @param {Object} obj the object to add
264
268
  @return {Object} The passed object
265
269
  */
@@ -268,7 +272,6 @@ SC.Array = /** @scope SC.Array.prototype */{
268
272
  return obj ;
269
273
  },
270
274
 
271
-
272
275
  /**
273
276
  Adds the named objects to the beginning of the array. Defers notifying
274
277
  observers until all objects have been added.
@@ -284,8 +287,8 @@ SC.Array = /** @scope SC.Array.prototype */{
284
287
  },
285
288
 
286
289
  /**
287
- Compares each item in the passed array to this one.
288
-
290
+ Compares each item in the passed array to this one.
291
+
289
292
  @param {Array} ary The array you want to compare to
290
293
  @returns {Boolean} true if they are equal.
291
294
  */
@@ -437,7 +440,7 @@ SC.Array = /** @scope SC.Array.prototype */{
437
440
  updateRangeObserver: function(rangeObserver, indexes) {
438
441
  return rangeObserver.update(this, indexes);
439
442
  },
440
-
443
+
441
444
  /**
442
445
  Removes a range observer from the receiver. The range observer must
443
446
  already be active on the array.
@@ -455,22 +458,58 @@ SC.Array = /** @scope SC.Array.prototype */{
455
458
  return ret ;
456
459
  },
457
460
 
458
- /**
459
- Updates observers with content change. To support range observers,
460
- you must pass three change parameters to this method. Otherwise this
461
- method will assume the entire range has changed.
461
+ addArrayObservers: function(options) {
462
+ this._modifyObserverSet('add', options);
463
+ },
462
464
 
463
- This also assumes you have already updated the length property.
464
- @param {Number} start the starting index of the change
465
- @param {Number} amt the final range of objects changed
466
- @param {Number} delta if you added or removed objects, the delta change
467
- @param {Array} addedObjects the objects that were added
468
- @param {Array} removedObjects the objects that were removed
469
- @returns {SC.Array} receiver
470
- */
471
- enumerableContentDidChange: function(start, amt, delta, addedObjects, removedObjects) {
465
+ removeArrayObservers: function(options) {
466
+ this._modifyObserverSet('remove', options);
467
+ },
468
+
469
+ _modifyObserverSet: function(method, options) {
470
+ var willChangeObservers, didChangeObservers;
471
+
472
+ var target = options.target || this;
473
+ var willChange = options.willChange || 'arrayWillChange';
474
+ var didChange = options.didChange || 'arrayDidChange';
475
+ var context = options.context;
476
+
477
+ if (typeof willChange === "string") {
478
+ willChange = target[willChange];
479
+ }
480
+
481
+ if (typeof didChange === "string") {
482
+ didChange = target[didChange];
483
+ }
484
+
485
+ willChangeObservers = this._kvo_for('_kvo_array_will_change', SC.ObserverSet);
486
+ didChangeObservers = this._kvo_for('_kvo_array_did_change', SC.ObserverSet);
487
+
488
+ willChangeObservers[method](target, willChange, context);
489
+ didChangeObservers[method](target, didChange, context);
490
+ },
491
+
492
+ arrayContentWillChange: function(start, removedCount, addedCount) {
493
+ this._teardownContentObservers(start, removedCount);
494
+
495
+ var member, members, membersLen, idx;
496
+ var target, action;
497
+ var willChangeObservers = this._kvo_array_will_change;
498
+ if (willChangeObservers) {
499
+ members = willChangeObservers.members;
500
+ membersLen = members.length;
501
+
502
+ for (idx = 0; idx < membersLen; idx++) {
503
+ member = members[idx];
504
+ target = member[0];
505
+ action = member[1];
506
+ action.call(target, start, removedCount, addedCount, this);
507
+ }
508
+ }
509
+ },
510
+
511
+ arrayContentDidChange: function(start, removedCount, addedCount) {
472
512
  var rangeob = this._array_rangeObservers,
473
- oldlen = this._array_oldLength,
474
513
  newlen, length, changes ;
475
514
 
476
515
  this.beginPropertyChanges();
@@ -478,40 +517,309 @@ SC.Array = /** @scope SC.Array.prototype */{
478
517
 
479
518
  // schedule info for range observers
480
519
  if (rangeob && rangeob.length>0) {
481
-
482
- // if no oldLength has been cached, just assume 0
483
- if (oldlen === undefined) oldlen = 0;
484
- this._array_oldLength = newlen = this.get('length');
485
-
486
- // normalize input parameters
487
- // if delta was not passed, assume it is the different between the
488
- // new and old length.
489
- if (start === undefined) start = 0;
490
- if (delta === undefined) delta = newlen - oldlen ;
491
- if (delta !== 0 || amt === undefined) {
492
- length = newlen - start ;
493
- if (delta<0) length -= delta; // cover removed range as well
520
+ changes = this._array_rangeChanges;
521
+ if (!changes) { changes = this._array_rangeChanges = SC.IndexSet.create(); }
522
+ if (removedCount === addedCount) {
523
+ length = removedCount;
494
524
  } else {
495
- length = amt ;
496
- }
525
+ length = this.get('length') - start;
497
526
 
498
- changes = this._array_rangeChanges;
499
- if (!changes) changes = this._array_rangeChanges = SC.IndexSet.create();
527
+ if (removedCount > addedCount) {
528
+ length += (removedCount - addedCount);
529
+ }
530
+ }
500
531
  changes.add(start, length);
501
532
  }
502
533
 
503
- this._setupContentObservers(addedObjects, removedObjects);
534
+ this._setupContentObservers(start, addedCount);
535
+
536
+ var member, members, membersLen, idx;
537
+ var target, action;
538
+ var didChangeObservers = this._kvo_array_did_change;
539
+ if (didChangeObservers) {
540
+ members = didChangeObservers.members;
541
+ membersLen = members.length;
542
+
543
+ for (idx = 0; idx < membersLen; idx++) {
544
+ member = members[idx];
545
+ target = member[0];
546
+ action = member[1];
547
+ action.call(target, start, removedCount, addedCount, this);
548
+ }
549
+ }
550
+
504
551
  this.notifyPropertyChange('[]') ;
505
552
  this.endPropertyChanges();
506
553
 
507
- // Only notify enumerable observers if we have enough information to do so.
508
- if (addedObjects && removedObjects) {
509
- this._notifyEnumerableObservers(addedObjects, removedObjects, start);
554
+ return this ;
555
+ },
556
+
557
+ /**
558
+ @private
559
+
560
+ When enumerable content has changed, remove enumerable observers from
561
+ items that are no longer in the enumerable, and add observers to newly
562
+ added items.
563
+
564
+ @param {Array} addedObjects the array of objects that have been added
565
+ @param {Array} removedObjects the array of objects that have been removed
566
+ */
567
+ _setupContentObservers: function(start, addedCount) {
568
+ var observedKeys = this._kvo_for('_kvo_content_observed_keys', SC.CoreSet);
569
+ var addedObjects;
570
+ var kvoKey;
571
+
572
+ // Only setup and teardown enumerable observers if we have keys to observe
573
+ if (observedKeys.get('length') > 0) {
574
+ addedObjects = this.slice(start, start+addedCount);
575
+
576
+ var self = this;
577
+ // added and resume the chain observer.
578
+ observedKeys.forEach(function(key) {
579
+ kvoKey = SC.keyFor('_kvo_content_observers', key);
580
+
581
+ // Get all original ChainObservers associated with the key
582
+ self._kvo_for(kvoKey).forEach(function(observer) {
583
+ addedObjects.forEach(function(item) {
584
+ self._resumeChainObservingForItemWithChainObserver(item, observer);
585
+ });
586
+ });
587
+ });
588
+ }
589
+ },
590
+
591
+ _teardownContentObservers: function(start, removedCount) {
592
+ var observedKeys = this._kvo_for('_kvo_content_observed_keys', SC.CoreSet);
593
+ var removedObjects;
594
+ var kvoKey;
595
+
596
+ // Only setup and teardown enumerable observers if we have keys to observe
597
+ if (observedKeys.get('length') > 0) {
598
+ removedObjects = this.slice(start, start+removedCount);
599
+
600
+ // added and resume the chain observer.
601
+ observedKeys.forEach(function(key) {
602
+ kvoKey = SC.keyFor('_kvo_content_observers', key);
603
+
604
+ // Loop through removed objects and remove any enumerable observers that
605
+ // belong to them.
606
+ removedObjects.forEach(function(item) {
607
+ item._kvo_for(kvoKey).forEach(function(observer) {
608
+ observer.destroyChain();
609
+ });
610
+ });
611
+ });
510
612
  }
613
+ },
614
+
615
+ teardownEnumerablePropertyChains: function(removedObjects) {
616
+ var chains = this._kvo_enumerable_property_chains;
617
+
618
+ if (chains) {
619
+ chains.forEach(function(chain) {
620
+ var idx, len = removedObjects.get('length'),
621
+ chainGuid = SC.guidFor(chain),
622
+ clonedChain, item, kvoChainList = '_kvo_enumerable_property_clones';
623
+
624
+ chain.notifyPropertyDidChange();
625
+
626
+ for (idx = 0; idx < len; idx++) {
627
+ item = removedObjects[idx];
628
+ clonedChain = item[kvoChainList][chainGuid];
629
+ clonedChain.deactivate();
630
+ delete item[kvoChainList][chainGuid];
631
+ }
632
+ }, this);
633
+ }
634
+ return this ;
635
+ },
511
636
 
637
+ /**
638
+ For all registered property chains on this object, removed them from objects
639
+ being removed from the enumerable, and clone them onto newly added objects.
640
+
641
+ @param {Object[]} addedObjects the objects being added to the enumerable
642
+ @param {Object[]} removedObjects the objected being removed from the enumerable
643
+ @returns {Object} receiver
644
+ */
645
+ setupEnumerablePropertyChains: function(addedObjects) {
646
+ var chains = this._kvo_enumerable_property_chains;
647
+
648
+ if (chains) {
649
+ chains.forEach(function(chain) {
650
+ var idx, len = addedObjects.get('length');
651
+
652
+ chain.notifyPropertyDidChange();
653
+
654
+ len = addedObjects.get('length');
655
+ for (idx = 0; idx < len; idx++) {
656
+ this._clonePropertyChainToItem(chain, addedObjects[idx]);
657
+ }
658
+ }, this);
659
+ }
512
660
  return this ;
513
661
  },
514
662
 
663
+ /**
664
+ Register a property chain to propagate to enumerable content.
665
+
666
+ This will clone the property chain to each item in the enumerable,
667
+ then save it so that it is automatically set up and torn down when
668
+ the enumerable content changes.
669
+
670
+ @param {String} property the property being listened for on this object
671
+ @param {SC._PropertyChain} chain the chain to clone to items
672
+ */
673
+ registerDependentKeyWithChain: function(property, chain) {
674
+ // Get the set of all existing property chains that should
675
+ // be propagated to enumerable contents. If that set doesn't
676
+ // exist yet, _kvo_for() will create it.
677
+ var kvoChainList = '_kvo_enumerable_property_chains',
678
+ chains, item, clone, cloneList;
679
+
680
+ chains = this._kvo_for(kvoChainList, SC.CoreSet);
681
+
682
+ // Save a reference to the chain on this object. If new objects
683
+ // are added to the enumerable, we will clone this chain and add
684
+ // it to the new object.
685
+ chains.add(chain);
686
+
687
+ this.forEach(function(item) {
688
+ this._clonePropertyChainToItem(chain, item);
689
+ }, this);
690
+ },
691
+
692
+ /**
693
+ Clones an SC._PropertyChain to a content item.
694
+
695
+ @param {SC._PropertyChain} chain
696
+ @param {Object} item
697
+ */
698
+ _clonePropertyChainToItem: function(chain, item) {
699
+ var clone = SC.clone(chain),
700
+ kvoCloneList = '_kvo_enumerable_property_clones',
701
+ cloneList;
702
+
703
+ clone.object = item;
704
+
705
+ cloneList = item[kvoCloneList] = item[kvoCloneList] || {};
706
+ cloneList[SC.guidFor(chain)] = clone;
707
+
708
+ clone.activate(item);
709
+ },
710
+
711
+ /**
712
+ Removes a dependent key from the enumerable, and tears it down on
713
+ all content objects.
714
+
715
+ @param {String} property
716
+ @param {SC._PropertyChain} chain
717
+ */
718
+ removeDependentKeyWithChain: function(property, chain) {
719
+ var kvoChainList = '_kvo_enumerable_property_chains',
720
+ kvoCloneList = '_kvo_enumerable_property_clones',
721
+ chains, item, clone, cloneList;
722
+
723
+ this.forEach(function(item) {
724
+ item.removeDependentKeyWithChain(property, chain);
725
+
726
+ cloneList = item[kvoCloneList];
727
+ clone = cloneList[SC.guidFor(chain)];
728
+
729
+ clone.deactivate(item);
730
+ }, this);
731
+ },
732
+
733
+ /**
734
+ @private
735
+
736
+ Clones a segment of an observer chain and applies it
737
+ to an element of this Enumerable.
738
+
739
+ @param {Object} item The element
740
+ @param {SC._ChainObserver} chainObserver the chain segment to begin from
741
+ */
742
+ _resumeChainObservingForItemWithChainObserver: function(item, chainObserver) {
743
+ var observer = SC.clone(chainObserver.next);
744
+ var key = observer.property;
745
+
746
+ // The chain observer should create new observers on the child object
747
+ observer.object = item;
748
+ item.addObserver(key, observer, observer.propertyDidChange);
749
+
750
+ // if we're in the initial chained observer setup phase, add the tail
751
+ // of the current observer segment to the list of tracked tails.
752
+ if(chainObserver.root.tails) {
753
+ chainObserver.root.tails.pushObject(observer.tail());
754
+ }
755
+
756
+ observer.propertyDidChange();
757
+
758
+ // Maintain a list of observers on the item so we can remove them
759
+ // if it is removed from the enumerable.
760
+ item._kvo_for(SC.keyFor('_kvo_content_observers', key)).push(observer);
761
+ },
762
+
763
+ /**
764
+ @private
765
+
766
+ Adds a content observer. Content observers are able to
767
+ propagate chain observers to each member item in the enumerable,
768
+ so that the observer is fired whenever a single item changes.
769
+
770
+ You should never call this method directly. Instead, you should
771
+ call addObserver() with the special '@each' property in the path.
772
+
773
+ For example, if you wanted to observe changes to each item's isDone
774
+ property, you could call:
775
+
776
+ arrayController.addObserver('@each.isDone');
777
+
778
+ @param {SC._ChainObserver} chainObserver the chain observer to propagate
779
+ */
780
+ _addContentObserver: function(chainObserver) {
781
+ var key = chainObserver.next.property;
782
+
783
+ // Add the key to a set so we know what we are observing
784
+ this._kvo_for('_kvo_content_observed_keys', SC.CoreSet).push(key);
785
+
786
+ // Add the passed ChainObserver to an ObserverSet for that key
787
+ var kvoKey = SC.keyFor('_kvo_content_observers', key);
788
+ this._kvo_for(kvoKey).push(chainObserver);
789
+
790
+ // set up chained observers on the initial content
791
+ this._setupContentObservers(0, chainObserver.object.get('length'));
792
+ },
793
+
794
+ /**
795
+ @private
796
+
797
+ Removes a content observer. Pass the same chain observer
798
+ that was used to add the content observer.
799
+
800
+ @param {SC._ChainObserver} chainObserver the chain observer to propagate
801
+ */
802
+
803
+ _removeContentObserver: function(chainObserver) {
804
+ var observers, kvoKey;
805
+ var observedKeys = this._kvo_content_observed_keys;
806
+ var key = chainObserver.next.property;
807
+
808
+ if (observedKeys.contains(key)) {
809
+
810
+ kvoKey = SC.keyFor('_kvo_content_observers', key);
811
+ observers = this._kvo_for(kvoKey);
812
+
813
+ observers.removeObject(chainObserver);
814
+
815
+ this._teardownContentObservers(0, chainObserver.object.get('length'));
816
+
817
+ if (observers.length === 0) {
818
+ this._kvo_for('_kvo_content_observed_keys').remove(key);
819
+ }
820
+ }
821
+ },
822
+
515
823
  /** @private
516
824
  Observer fires whenever the '[]' property changes. If there are
517
825
  range observers, will notify observers of change.
@@ -540,7 +848,7 @@ SC.Array = SC.mixin({}, SC.Enumerable, SC.Array) ;
540
848
  Returns a new array that is a slice of the receiver. This implementation
541
849
  uses the observable array methods to retrieve the objects for the new
542
850
  slice.
543
-
851
+
544
852
  If you don't pass in beginIndex and endIndex, it will act as a copy of the
545
853
  array.
546
854
 
@@ -615,22 +923,23 @@ if (!Array.prototype.lastIndexOf) {
615
923
 
616
924
  // primitive for array support.
617
925
  replace: function(idx, amt, objects) {
618
- var removedObjects;
926
+ if (this.isFrozen) { throw SC.FROZEN_ERROR ; }
619
927
 
620
- if (this.isFrozen) throw SC.FROZEN_ERROR ;
621
- if (!objects || objects.length === 0) {
622
- removedObjects = this.splice(idx, amt) ;
928
+ var args;
929
+ var len = objects ? (objects.get ? objects.get('length') : objects.length) : 0;
930
+
931
+ // Notify that array content is about to mutate.
932
+ this.arrayContentWillChange(idx, amt, len);
933
+
934
+ if (len === 0) {
935
+ this.splice(idx, amt) ;
623
936
  } else {
624
- var args = [idx, amt].concat(objects) ;
625
- removedObjects = this.splice.apply(this,args) ;
937
+ args = [idx, amt].concat(objects) ;
938
+ this.splice.apply(this,args) ;
626
939
  }
627
940
 
628
- // if we replaced exactly the same number of items, then pass only the
629
- // replaced range. Otherwise, pass the full remaining array length
630
- // since everything has shifted
631
- var len = objects ? (objects.get ? objects.get('length') : objects.length) : 0;
632
- objects = SC.isArray(objects) ? objects : [objects];
633
- this.enumerableContentDidChange(idx, amt, len - amt, objects, removedObjects) ;
941
+ this.arrayContentDidChange(idx, amt, len);
942
+ this.enumerableContentDidChange(idx, amt, len - amt) ;
634
943
  return this ;
635
944
  },
636
945