sproutcore 1.9.0 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (24) hide show
  1. data/VERSION.yml +1 -1
  2. data/lib/frameworks/sproutcore/CHANGELOG.md +123 -1
  3. data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +13 -9
  4. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +68 -0
  5. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +59 -60
  6. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +6 -4
  7. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/locale.js +48 -29
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/selection_set/remove.js +53 -17
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroy.js +34 -0
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroyLayer.js +47 -11
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +31 -36
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +10 -10
  13. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +55 -23
  14. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +1 -1
  15. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +5 -1
  16. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +105 -105
  17. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChanges.js +131 -30
  18. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +1 -0
  19. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +3 -2
  20. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  21. data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +9 -5
  22. data/lib/sproutcore/helpers/minifier.rb +0 -2
  23. data/lib/sproutcore/rack/filesystem.rb +5 -5
  24. metadata +3 -2
@@ -82,69 +82,64 @@ test("making sure that the frame value is correct inside viewDidResize()", funct
82
82
  //
83
83
  module("SC.View#parentViewDidResize");
84
84
 
85
- // view.callCount must increments whenever something interesting happens
86
- function testParentViewDidResizeWithAlignments(view) {
85
+ test("Optimized notify on frame and optimized cascade call to child views.", function() {
86
+ var view = SC.View.create({
87
+ // instrument...
88
+ frameCallCount: 0,
89
+ frameDidChange: function() {
90
+ this.frameCallCount++;
91
+ }.observes('frame'),
92
+ viewDidResize: CoreTest.stub('viewDidResize', SC.View.prototype.viewDidResize)
93
+ });
94
+
87
95
  // try with fixed layout
88
96
  view.set('layout', { top: 10, left: 10, height: 10, width: 10 });
89
- view.callCount = 0 ;
97
+ view.viewDidResize.reset(); view.frameCallCount = 0;
90
98
  view.parentViewDidResize();
91
- equals(view.callCount, 0, 'should not notify frame changed');
99
+ view.viewDidResize.expect(0);
100
+ equals(view.frameCallCount, 0, 'should not notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
92
101
 
93
102
  // try with flexible height
94
103
  view.set('layout', { top: 10, left: 10, bottom: 10, width: 10 });
95
- view.callCount = 0 ;
104
+ view.viewDidResize.reset(); view.frameCallCount = 0;
96
105
  view.parentViewDidResize();
97
- equals(view.callCount, 1, 'should notify frame changed');
106
+ view.viewDidResize.expect(1);
107
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
98
108
 
99
109
  // try with flexible width
100
110
  view.set('layout', { top: 10, left: 10, height: 10, right: 10 });
101
- view.callCount = 0 ;
111
+ view.viewDidResize.reset(); view.frameCallCount = 0;
102
112
  view.parentViewDidResize();
103
- equals(view.callCount, 1, 'should notify frame changed');
113
+ view.viewDidResize.expect(1);
114
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
104
115
 
105
116
  // try with right align
106
117
  view.set('layout', { top: 10, right: 10, height: 10, width: 10 });
107
- view.callCount = 0 ;
118
+ view.viewDidResize.reset(); view.frameCallCount = 0;
108
119
  view.parentViewDidResize();
109
- equals(view.callCount, 1, 'should notify frame changed');
120
+ view.viewDidResize.expect(0);
121
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
110
122
 
111
123
  // try with bottom align
112
124
  view.set('layout', { top: 10, bottom: 10, height: 10, width: 10 });
113
- view.callCount = 0 ;
125
+ view.viewDidResize.reset(); view.frameCallCount = 0;
114
126
  view.parentViewDidResize();
115
- equals(view.callCount, 1, 'should notify frame changed');
127
+ view.viewDidResize.expect(0);
128
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
116
129
 
117
130
  // try with center horizontal align
118
131
  view.set('layout', { centerX: 10, top: 10, height: 10, width: 10 });
119
- view.callCount = 0 ;
132
+ view.viewDidResize.reset(); view.frameCallCount = 0;
120
133
  view.parentViewDidResize();
121
- equals(view.callCount, 1, 'should notify frame changed');
134
+ view.viewDidResize.expect(0);
135
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
122
136
 
123
137
  // try with center vertical align
124
138
  view.set('layout', { left: 10, centerY: 10, height: 10, width: 10 });
125
- view.callCount = 0 ;
139
+ view.viewDidResize.reset(); view.frameCallCount = 0;
126
140
  view.parentViewDidResize();
127
- equals(view.callCount, 1, 'should notify frame changed');
128
- }
129
-
130
- test("notifies 'frame' property change unless layout is fixed", function() {
131
- var view = SC.View.create({
132
- // instrument...
133
- callCount: 0 ,
134
- frameDidChange: function() {
135
- this.callCount++;
136
- }.observes('frame')
137
- });
138
- testParentViewDidResizeWithAlignments(view);
139
- });
140
-
141
- test("calls viewDidResize on self unless layout is fixed", function() {
142
- var view = SC.View.create({
143
- // instrument...
144
- callCount: 0 ,
145
- viewDidResize: function() { this.callCount++; }
146
- });
147
- testParentViewDidResizeWithAlignments(view);
141
+ view.viewDidResize.expect(0);
142
+ equals(view.frameCallCount, 1, 'should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
148
143
  });
149
144
 
150
145
  // ..........................................................
@@ -156,7 +156,7 @@ SC.CoreView.reopen(
156
156
  if (!value) {
157
157
  var parent = this.get('parentView');
158
158
  if (parent) { parent = parent.get('layer'); }
159
- if (parent) { this._view_layer = value = this.findLayerInParentLayer(parent); }
159
+ this._view_layer = value = this.findLayerInParentLayer(parent);
160
160
  }
161
161
  }
162
162
  return value ;
@@ -215,7 +215,7 @@ SC.CoreView.reopen(
215
215
  */
216
216
  findLayerInParentLayer: function(parentLayer) {
217
217
  var id = "#" + this.get('layerId');
218
- return jQuery(id)[0] || jQuery(id, parentLayer)[0] ;
218
+ return jQuery(id, parentLayer)[0] || jQuery(id)[0];
219
219
  },
220
220
 
221
221
  /**
@@ -1314,17 +1314,11 @@ SC.CoreView.reopen(
1314
1314
 
1315
1315
  this._destroy(); // core destroy method
1316
1316
 
1317
- // remove from parent if found
1318
- if (this.get('parentView')) { this.removeFromParent(); }
1319
-
1320
1317
  //Do generic destroy. It takes care of mixins and sets isDestroyed to YES.
1321
- sc_super();
1322
- return this; // done with cleanup
1318
+ return sc_super();
1323
1319
  },
1324
1320
 
1325
1321
  _destroy: function() {
1326
- if (this.get('isDestroyed')) { return this ; } // nothing to do
1327
-
1328
1322
  // destroy the layer -- this will avoid each child view destroying
1329
1323
  // the layer over and over again...
1330
1324
  this.destroyLayer() ;
@@ -1341,7 +1335,13 @@ SC.CoreView.reopen(
1341
1335
  delete this._CQ ;
1342
1336
  delete this.page ;
1343
1337
 
1344
- return this ;
1338
+ // remove from parent if found.
1339
+ if (this.get('parentView')) { this.removeFromParent(); }
1340
+
1341
+ // clear owner.
1342
+ this.set('owner', null);
1343
+
1344
+ return this;
1345
1345
  },
1346
1346
 
1347
1347
  /**
@@ -214,34 +214,64 @@ SC.View.reopen(
214
214
  layout: { top: 0, left: 0, bottom: 0, right: 0 },
215
215
 
216
216
  /**
217
- Returns whether the layout is 'fixed' or not. A fixed layout has a fixed
218
- left & top position within its parent's frame as well as a fixed width and height.
219
- Fixed layouts are therefore unaffected by changes to their parent view's
220
- layout.
217
+ Returns whether the layout is 'fixed' or not. A fixed layout means a
218
+ fixed left & top position and fixed width & height. Fixed layouts are
219
+ therefore unaffected by changes to their parent view's layout.
221
220
 
222
221
  @returns {Boolean} YES if fixed, NO otherwise
223
222
  @test in layoutStyle
224
223
  */
225
224
  isFixedLayout: function() {
225
+ return this.get('isFixedPosition') && this.get('isFixedSize');
226
+ }.property('isFixedPosition', 'isFixedSize').cacheable(),
227
+
228
+ /**
229
+ Returns whether the position is 'fixed' or not. A fixed position means a
230
+ fixed left & top position within its parent's frame. Fixed positions are
231
+ therefore unaffected by changes to their parent view's size.
232
+
233
+ @returns {Boolean} YES if fixed, NO otherwise
234
+ @test in layoutStyle
235
+ */
236
+ isFixedPosition: function() {
226
237
  var layout = this.get('layout'),
227
238
  ret;
228
239
 
229
- // Layout is fixed if it has width + height !== SC.LAYOUT_AUTO and left + top
240
+ // Position is fixed if it has left + top !== SC.LAYOUT_AUTO
230
241
  ret = (
231
- ((layout.width !== undefined) && (layout.height !== undefined)) &&
232
- ((layout.width !== SC.LAYOUT_AUTO) && (layout.height !== SC.LAYOUT_AUTO)) &&
233
242
  ((layout.left !== undefined) && (layout.top !== undefined)) &&
234
243
  ((layout.left !== SC.LAYOUT_AUTO) && (layout.top !== SC.LAYOUT_AUTO))
235
244
  );
236
245
 
237
- // The layout may appear fixed, but only if none of the values are percentages
246
+ // The position may appear fixed, but only if none of the values are percentages.
238
247
  if (ret) {
239
- ret = (
240
- !SC.isPercentage(layout.top) &&
241
- !SC.isPercentage(layout.left) &&
242
- !SC.isPercentage(layout.width) &&
243
- !SC.isPercentage(layout.height)
244
- );
248
+ ret = ( !SC.isPercentage(layout.top) && !SC.isPercentage(layout.left) );
249
+ }
250
+
251
+ return ret;
252
+ }.property('layout').cacheable(),
253
+
254
+ /**
255
+ Returns whether the size is 'fixed' or not. A fixed size means a fixed
256
+ width and height. Fixed sizes are therefore unaffected by changes to their
257
+ parent view's size.
258
+
259
+ @returns {Boolean} YES if fixed, NO otherwise
260
+ @test in layoutStyle
261
+ */
262
+ isFixedSize: function () {
263
+ var layout = this.get('layout'),
264
+ ret;
265
+
266
+ // Size is fixed if it has width + height !== SC.LAYOUT_AUTO
267
+ ret = (
268
+ ((layout.width !== undefined) && (layout.height !== undefined)) &&
269
+ ((layout.width !== SC.LAYOUT_AUTO) && (layout.height !== SC.LAYOUT_AUTO))
270
+ );
271
+
272
+ // The size may appear fixed, but only if none of the values are percentages.
273
+ if (ret) {
274
+ ret = ( !SC.isPercentage(layout.width) && !SC.isPercentage(layout.height) );
245
275
  }
246
276
 
247
277
  return ret;
@@ -604,26 +634,28 @@ SC.View.reopen(
604
634
  This method may be called on your view whenever the parent view resizes.
605
635
 
606
636
  The default version of this method will reset the frame and then call
607
- viewDidResize(). You will not usually override this method, but you may
608
- override the viewDidResize() method.
637
+ viewDidResize() if its size may have changed. You will not usually override
638
+ this method, but you may override the viewDidResize() method.
609
639
 
610
640
  @returns {void}
611
641
  @test in viewDidResize
612
642
  */
613
643
  parentViewDidResize: function() {
614
- var frameMayHaveChanged;
644
+ var positionMayHaveChanged,
645
+ sizeMayHaveChanged;
615
646
 
616
647
  // If this view uses static layout, our "do we think the frame changed?"
617
648
  // result of isFixedLayout is not applicable and we simply have to assume
618
649
  // that the frame may have changed.
619
- frameMayHaveChanged = this.useStaticLayout || !this.get('isFixedLayout');
650
+ sizeMayHaveChanged = this.useStaticLayout || !this.get('isFixedSize');
651
+ positionMayHaveChanged = !this.get('isFixedPosition');
620
652
 
621
- // Do we think there's a chance our frame will have changed as a result?
622
- if (frameMayHaveChanged) {
623
- // There's a chance our frame changed. Invoke viewDidResize(), which
624
- // will notify about our change to 'frame' (if it actually changed) and
625
- // appropriately notify our child views.
653
+ if (sizeMayHaveChanged) {
654
+ // If our size isn't fixed, our frame may have changed and it will effect our child views.
626
655
  this.viewDidResize();
656
+ } else if (positionMayHaveChanged) {
657
+ // If our size is fixed but our position isn't, our frame may have changed, but it won't effect our child views.
658
+ this._viewFrameDidChange();
627
659
  }
628
660
  },
629
661
 
@@ -139,7 +139,7 @@ SC.View.reopen(
139
139
  }
140
140
  });
141
141
 
142
- // Even though its layer has not necessarily been created, the child views
142
+ // Even though its layer has not necessarily been created, the child views
143
143
  // are added immediately. Hence notify views immediately.
144
144
  if (this.didAddChild) { this.didAddChild(view, beforeView) ; }
145
145
  if (view.didAddToParent) { view.didAddToParent(this, beforeView) ; }
@@ -454,7 +454,11 @@ SC.Record = SC.Object.extend(
454
454
  this.propertyDidChange('id'); // Reset computed value
455
455
  }
456
456
 
457
- if(!ignoreDidChange) this.endEditing(key);
457
+ if(!ignoreDidChange) { this.endEditing(key); }
458
+ else {
459
+ // We must still inform the store of the change so that it can track the change across stores.
460
+ store.dataHashDidChange(storeKey, null, undefined, key);
461
+ }
458
462
  }
459
463
  return this ;
460
464
  },
@@ -14,11 +14,11 @@ sc_require('system/store');
14
14
  all at once. You usually will use a `NestedStore` as part of store chaining
15
15
  to stage changes to your object graph before sharing them with the rest of
16
16
  the application.
17
-
18
- Normally you will not create a nested store directly. Instead, you can
17
+
18
+ Normally you will not create a nested store directly. Instead, you can
19
19
  retrieve a nested store by using the `chain()` method. When you are finished
20
20
  working with the nested store, `destroy()` will dispose of it.
21
-
21
+
22
22
  @extends SC.Store
23
23
  @since SproutCore 1.0
24
24
  */
@@ -26,7 +26,7 @@ SC.NestedStore = SC.Store.extend(
26
26
  /** @scope SC.NestedStore.prototype */ {
27
27
 
28
28
  /**
29
- This is set to YES when there are changes that have not been committed
29
+ This is set to YES when there are changes that have not been committed
30
30
  yet.
31
31
 
32
32
  @type Boolean
@@ -36,31 +36,31 @@ SC.NestedStore = SC.Store.extend(
36
36
 
37
37
  /**
38
38
  The parent store this nested store is chained to. Nested stores must have
39
- a parent store in order to function properly. Normally, you create a
39
+ a parent store in order to function properly. Normally, you create a
40
40
  nested store using the `SC.Store#chain()` method and this property will be
41
41
  set for you.
42
-
42
+
43
43
  @type SC.Store
44
44
  @default null
45
45
  */
46
46
  parentStore: null,
47
47
 
48
48
  /**
49
- `YES` if the view is nested. Walk like a duck
50
-
49
+ `YES` if the store is nested. Walk like a duck
50
+
51
51
  @type Boolean
52
52
  @default YES
53
53
  */
54
54
  isNested: YES,
55
55
 
56
56
  /**
57
- If YES, then the attribute hash state will be locked when you first
57
+ If YES, then the attribute hash state will be locked when you first
58
58
  read the data hash or status. This means that if you retrieve a record
59
- then change the record in the parent store, the changes will not be
59
+ then change the record in the parent store, the changes will not be
60
60
  visible to your nested store until you commit or discard changes.
61
-
61
+
62
62
  If `NO`, then the attribute hash will lock only when you write data.
63
-
63
+
64
64
  Normally you want to lock your attribute hash the first time you read it.
65
65
  This will make your nested store behave most consistently. However, if
66
66
  you are using multiple sibling nested stores at one time, you may want
@@ -68,7 +68,7 @@ SC.NestedStore = SC.Store.extend(
68
68
  in the other one immediately. In this case you will be responsible for
69
69
  ensuring that the sibling stores do not edit the same part of the object
70
70
  graph at the same time.
71
-
71
+
72
72
  @type Boolean
73
73
  @default YES
74
74
  */
@@ -76,18 +76,18 @@ SC.NestedStore = SC.Store.extend(
76
76
 
77
77
  /** @private
78
78
  Array contains the base revision for an attribute hash when it was first
79
- cloned from the parent store. If the attribute hash is edited and
80
- committed, the commit will fail if the parent attributes hash has been
79
+ cloned from the parent store. If the attribute hash is edited and
80
+ committed, the commit will fail if the parent attributes hash has been
81
81
  edited since.
82
-
82
+
83
83
  This is a form of optimistic locking, hence the name.
84
-
84
+
85
85
  Each store gets its own array of locks, which are selectively populated
86
86
  as needed.
87
-
88
- Note that this is kept as an array because it will be stored as a dense
87
+
88
+ Note that this is kept as an array because it will be stored as a dense
89
89
  array on some browsers, making it faster.
90
-
90
+
91
91
  @type Array
92
92
  @default null
93
93
  */
@@ -98,21 +98,21 @@ SC.NestedStore = SC.Store.extend(
98
98
  was last committed. This array is used to sync data hash changes between
99
99
  chained stores. For a log changes that may actually be committed back to
100
100
  the server see the changelog property.
101
-
101
+
102
102
  @type SC.Set
103
103
  @default YES
104
104
  */
105
105
  chainedChanges: null,
106
-
106
+
107
107
  // ..........................................................
108
108
  // STORE CHAINING
109
- //
110
-
109
+ //
110
+
111
111
  /**
112
112
  `find()` cannot accept REMOTE queries in a nested store. This override will
113
113
  verify that condition for you. See `SC.Store#find()` for info on using this
114
114
  method.
115
-
115
+
116
116
  @param {SC.Query} query query object to use.
117
117
  @returns {SC.Record|SC.RecordArray}
118
118
  */
@@ -122,9 +122,9 @@ SC.NestedStore = SC.Store.extend(
122
122
  }
123
123
  return sc_super();
124
124
  },
125
-
125
+
126
126
  /**
127
- Propagate this store's changes to its parent. If the store does not
127
+ Propagate this store's changes to its parent. If the store does not
128
128
  have a parent, this has no effect other than to clear the change set.
129
129
 
130
130
  @param {Boolean} force if YES, does not check for conflicts first
@@ -143,7 +143,7 @@ SC.NestedStore = SC.Store.extend(
143
143
 
144
144
  /**
145
145
  Discard the changes made to this store and reset the store.
146
-
146
+
147
147
  @returns {SC.Store} receiver
148
148
  */
149
149
  discardChanges: function() {
@@ -162,26 +162,26 @@ SC.NestedStore = SC.Store.extend(
162
162
  this._notifyRecordPropertyChange(parseInt(storeKey, 10));
163
163
  }
164
164
  }
165
- }
166
-
165
+ }
166
+
167
167
  this.reset();
168
168
  this.flush();
169
169
  return this ;
170
170
  },
171
-
171
+
172
172
  /**
173
- When you are finished working with a chained store, call this method to
173
+ When you are finished working with a chained store, call this method to
174
174
  tear it down. This will also discard any pending changes.
175
-
175
+
176
176
  @returns {SC.Store} receiver
177
177
  */
178
178
  destroy: function() {
179
179
  this.discardChanges();
180
-
180
+
181
181
  var parentStore = this.get('parentStore');
182
182
  if (parentStore) parentStore.willDestroyNestedStore(this);
183
-
184
- sc_super();
183
+
184
+ sc_super();
185
185
  return this ;
186
186
  },
187
187
 
@@ -193,33 +193,33 @@ SC.NestedStore = SC.Store.extend(
193
193
  // requires a pstore to reset
194
194
  var parentStore = this.get('parentStore');
195
195
  if (!parentStore) throw SC.Store.NO_PARENT_STORE_ERROR;
196
-
196
+
197
197
  // inherit data store from parent store.
198
198
  this.dataHashes = SC.beget(parentStore.dataHashes);
199
199
  this.revisions = SC.beget(parentStore.revisions);
200
200
  this.statuses = SC.beget(parentStore.statuses);
201
-
201
+
202
202
  // beget nested records references
203
203
  this.childRecords = parentStore.childRecords ? SC.beget(parentStore.childRecords) : {};
204
204
  this.parentRecords = parentStore.parentRecords ? SC.beget(parentStore.parentRecords) : {};
205
-
205
+
206
206
  // also, reset private temporary objects
207
207
  this.chainedChanges = this.locks = this.editables = null;
208
208
  this.changelog = null ;
209
209
 
210
210
  // TODO: Notify record instances
211
-
211
+
212
212
  this.set('hasChanges', NO);
213
213
  },
214
-
214
+
215
215
  /** @private
216
-
216
+
217
217
  Chain to parentstore
218
218
  */
219
219
  refreshQuery: function(query) {
220
220
  var parentStore = this.get('parentStore');
221
221
  if (parentStore) parentStore.refreshQuery(query);
222
- return this ;
222
+ return this ;
223
223
  },
224
224
 
225
225
  /**
@@ -228,7 +228,7 @@ SC.NestedStore = SC.Store.extend(
228
228
  Delegates the call to the parent store.
229
229
 
230
230
  @param {Number} storeKey The store key of the record.
231
-
231
+
232
232
  @returns {SC.Error} SC.Error or null if no error associated with the record.
233
233
  */
234
234
  readError: function(storeKey) {
@@ -242,25 +242,25 @@ SC.NestedStore = SC.Store.extend(
242
242
  Delegates the call to the parent store.
243
243
 
244
244
  @param {SC.Query} query The SC.Query with which the error is associated.
245
-
245
+
246
246
  @returns {SC.Error} SC.Error or null if no error associated with the query.
247
247
  */
248
248
  readQueryError: function(query) {
249
249
  var parentStore = this.get('parentStore');
250
250
  return parentStore ? parentStore.readQueryError(query) : null;
251
251
  },
252
-
252
+
253
253
  // ..........................................................
254
254
  // CORE ATTRIBUTE API
255
- //
255
+ //
256
256
  // The methods in this layer work on data hashes in the store. They do not
257
- // perform any changes that can impact records. Usually you will not need
257
+ // perform any changes that can impact records. Usually you will not need
258
258
  // to use these methods.
259
-
259
+
260
260
  /**
261
261
  Returns the current edit status of a storekey. May be one of `INHERITED`,
262
262
  `EDITABLE`, and `LOCKED`. Used mostly for unit testing.
263
-
263
+
264
264
  @param {Number} storeKey the store key
265
265
  @returns {Number} edit status
266
266
  */
@@ -268,15 +268,15 @@ SC.NestedStore = SC.Store.extend(
268
268
  var editables = this.editables, locks = this.locks;
269
269
  return (editables && editables[storeKey]) ? SC.Store.EDITABLE : (locks && locks[storeKey]) ? SC.Store.LOCKED : SC.Store.INHERITED ;
270
270
  },
271
-
271
+
272
272
  /** @private
273
- Locks the data hash so that it iterates independently from the parent
273
+ Locks the data hash so that it iterates independently from the parent
274
274
  store.
275
275
  */
276
276
  _lock: function(storeKey) {
277
- var locks = this.locks, rev, editables,
277
+ var locks = this.locks, rev, editables,
278
278
  pk, pr, path, tup, obj, key;
279
-
279
+
280
280
  // already locked -- nothing to do
281
281
  if (locks && locks[storeKey]) return this;
282
282
 
@@ -286,8 +286,8 @@ SC.NestedStore = SC.Store.extend(
286
286
  // fixup editables
287
287
  editables = this.editables;
288
288
  if (editables) editables[storeKey] = 0;
289
-
290
-
289
+
290
+
291
291
  // if the data hash in the parent store is editable, then clone the hash
292
292
  // for our own use. Otherwise, just copy a reference to the data hash
293
293
  // in the parent store. -- find first non-inherited state
@@ -295,13 +295,13 @@ SC.NestedStore = SC.Store.extend(
295
295
  while(pstore && (editState=pstore.storeKeyEditState(storeKey)) === SC.Store.INHERITED) {
296
296
  pstore = pstore.get('parentStore');
297
297
  }
298
-
298
+
299
299
  if (pstore && editState === SC.Store.EDITABLE) {
300
-
300
+
301
301
  pk = this.childRecords[storeKey];
302
302
  if (pk){
303
303
  // Since this is a nested record we have to actually walk up the parent chain
304
- // to get to the root parent and clone that hash. And then reconstruct the
304
+ // to get to the root parent and clone that hash. And then reconstruct the
305
305
  // memory space linking.
306
306
  this._lock(pk);
307
307
  pr = this.parentRecords[pk];
@@ -317,37 +317,37 @@ SC.NestedStore = SC.Store.extend(
317
317
  }
318
318
  if (!editables) editables = this.editables = [];
319
319
  editables[storeKey] = 1 ; // mark as editable
320
-
320
+
321
321
  } else this.dataHashes[storeKey] = pstore.dataHashes[storeKey];
322
-
322
+
323
323
  // also copy the status + revision
324
324
  this.statuses[storeKey] = this.statuses[storeKey];
325
325
  rev = this.revisions[storeKey] = this.revisions[storeKey];
326
-
326
+
327
327
  // save a lock and make it not editable
328
- locks[storeKey] = rev || 1;
329
-
328
+ locks[storeKey] = rev || 1;
329
+
330
330
  return this ;
331
331
  },
332
-
332
+
333
333
  /** @private - adds chaining support */
334
334
  readDataHash: function(storeKey) {
335
335
  if (this.get('lockOnRead')) this._lock(storeKey);
336
336
  return this.dataHashes[storeKey];
337
337
  },
338
-
338
+
339
339
  /** @private - adds chaining support */
340
340
  readEditableDataHash: function(storeKey) {
341
341
 
342
342
  // lock the data hash if needed
343
343
  this._lock(storeKey);
344
-
344
+
345
345
  return sc_super();
346
346
  },
347
-
348
- /** @private - adds chaining support -
347
+
348
+ /** @private - adds chaining support -
349
349
  Does not call sc_super because the implementation of the method vary too
350
- much.
350
+ much.
351
351
  */
352
352
  writeDataHash: function(storeKey, hash, status) {
353
353
  var locks = this.locks, didLock = NO, rev ;
@@ -373,24 +373,24 @@ SC.NestedStore = SC.Store.extend(
373
373
 
374
374
  if (!didLock) {
375
375
  rev = this.revisions[storeKey] = this.revisions[storeKey]; // copy ref
376
-
376
+
377
377
  // make sure we lock if needed.
378
378
  if (!locks) locks = this.locks = [];
379
379
  if (!locks[storeKey]) locks[storeKey] = rev || 1;
380
380
  }
381
-
381
+
382
382
  // Also note that this hash is now editable. (Even if we locked it,
383
383
  // above, it may not have been marked as editable.)
384
384
  var editables = this.editables;
385
385
  if (!editables) editables = this.editables = [];
386
386
  editables[storeKey] = 1 ; // use number for dense array support
387
-
387
+
388
388
  return this ;
389
389
  },
390
390
 
391
391
  /** @private - adds chaining support */
392
392
  removeDataHash: function(storeKey, status) {
393
-
393
+
394
394
  // record optimistic lock revision
395
395
  var locks = this.locks;
396
396
  if (!locks) locks = this.locks = [];
@@ -398,15 +398,15 @@ SC.NestedStore = SC.Store.extend(
398
398
 
399
399
  return sc_super();
400
400
  },
401
-
401
+
402
402
  /** @private - bookkeeping for a single data hash. */
403
403
  dataHashDidChange: function(storeKeys, rev, statusOnly, key) {
404
404
  // update the revision for storeKey. Use generateStoreKey() because that
405
- // guarantees a universally (to this store hierarchy anyway) unique
405
+ // guarantees a universally (to this store hierarchy anyway) unique
406
406
  // key value.
407
407
  if (!rev) rev = SC.Store.generateStoreKey();
408
408
  var isArray, len, idx, storeKey;
409
-
409
+
410
410
  isArray = SC.typeOf(storeKeys) === SC.T_ARRAY;
411
411
  if (isArray) {
412
412
  len = storeKeys.length;
@@ -417,7 +417,7 @@ SC.NestedStore = SC.Store.extend(
417
417
 
418
418
  var changes = this.chainedChanges;
419
419
  if (!changes) changes = this.chainedChanges = SC.Set.create();
420
-
420
+
421
421
  for(idx=0;idx<len;idx++) {
422
422
  if (isArray) storeKey = storeKeys[idx];
423
423
  this._lock(storeKey);
@@ -432,13 +432,13 @@ SC.NestedStore = SC.Store.extend(
432
432
 
433
433
  // ..........................................................
434
434
  // SYNCING CHANGES
435
- //
436
-
435
+ //
436
+
437
437
  /** @private - adapt for nested store */
438
438
  commitChangesFromNestedStore: function(nestedStore, changes, force) {
439
439
 
440
440
  sc_super();
441
-
441
+
442
442
  // save a lock for each store key if it does not have one already
443
443
  // also add each storeKey to my own changes set.
444
444
  var pstore = this.get('parentStore'), psRevisions = pstore.revisions, i;
@@ -452,38 +452,38 @@ SC.NestedStore = SC.Store.extend(
452
452
  if (!myLocks[storeKey]) myLocks[storeKey] = psRevisions[storeKey]||1;
453
453
  myChanges.add(storeKey);
454
454
  }
455
-
455
+
456
456
  // Finally, mark store as dirty if we have changes
457
457
  this.setIfChanged('hasChanges', myChanges.get('length')>0);
458
458
  this.flush();
459
-
459
+
460
460
  return this ;
461
461
  },
462
462
 
463
463
  // ..........................................................
464
464
  // HIGH-LEVEL RECORD API
465
- //
466
-
467
-
465
+ //
466
+
467
+
468
468
  /** @private - adapt for nested store */
469
469
  queryFor: function(recordType, conditions, params) {
470
470
  return this.get('parentStore').queryFor(recordType, conditions, params);
471
471
  },
472
-
472
+
473
473
  /** @private - adapt for nested store */
474
- findAll: function(recordType, conditions, params, recordArray, _store) {
474
+ findAll: function(recordType, conditions, params, recordArray, _store) {
475
475
  if (!_store) _store = this;
476
476
  return this.get('parentStore').findAll(recordType, conditions, params, recordArray, _store);
477
477
  },
478
478
 
479
479
  // ..........................................................
480
480
  // CORE RECORDS API
481
- //
482
- // The methods in this section can be used to manipulate records without
481
+ //
482
+ // The methods in this section can be used to manipulate records without
483
483
  // actually creating record instances.
484
-
484
+
485
485
  /** @private - adapt for nested store
486
-
486
+
487
487
  Unlike for the main store, for nested stores if isRefresh=YES, we'll throw
488
488
  an error if the record is dirty. We'll otherwise avoid setting our status
489
489
  because that can disconnect us from upper and/or lower stores.
@@ -498,7 +498,7 @@ SC.NestedStore = SC.Store.extend(
498
498
  for(idx=0;idx<len;idx++) {
499
499
  storeKey = !storeKeys ? pstore.storeKeyFor(recordTypes, ids[idx]) : storeKeys[idx];
500
500
  status = this.peekStatus(storeKey);
501
-
501
+
502
502
  // We won't allow calling retrieve on a dirty record in a nested store
503
503
  // (although we do allow it in the main store). This is because doing
504
504
  // so would involve writing a unique status, and that would break the
@@ -519,7 +519,7 @@ SC.NestedStore = SC.Store.extend(
519
519
 
520
520
  var changed = NO;
521
521
  var statusOnly = NO;
522
-
522
+
523
523
  if (dataHashes && dataHashes.hasOwnProperty(storeKey)) {
524
524
  delete dataHashes[storeKey];
525
525
  changed = YES;
@@ -536,12 +536,12 @@ SC.NestedStore = SC.Store.extend(
536
536
  if (!changed) statusOnly = YES;
537
537
  changed = YES;
538
538
  }
539
-
539
+
540
540
  if (changed) this._notifyRecordPropertyChange(storeKey, statusOnly);
541
541
  }
542
542
  }
543
543
  }
544
-
544
+
545
545
  return pstore.retrieveRecords(recordTypes, ids, storeKeys, isRefresh);
546
546
  },
547
547
 
@@ -554,7 +554,7 @@ SC.NestedStore = SC.Store.extend(
554
554
  commitRecord: function(recordType, id, storeKey) {
555
555
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
556
556
  },
557
-
557
+
558
558
  /** @private - adapt for nested store */
559
559
  cancelRecords: function(recordTypes, ids, storeKeys) {
560
560
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
@@ -564,22 +564,22 @@ SC.NestedStore = SC.Store.extend(
564
564
  cancelRecord: function(recordType, id, storeKey) {
565
565
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
566
566
  },
567
-
567
+
568
568
  // ..........................................................
569
569
  // DATA SOURCE CALLBACKS
570
- //
570
+ //
571
571
  // Mathods called by the data source on the store
572
572
 
573
573
  /** @private - adapt for nested store */
574
574
  dataSourceDidCancel: function(storeKey) {
575
575
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
576
576
  },
577
-
577
+
578
578
  /** @private - adapt for nested store */
579
579
  dataSourceDidComplete: function(storeKey, dataHash, newId) {
580
580
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
581
581
  },
582
-
582
+
583
583
  /** @private - adapt for nested store */
584
584
  dataSourceDidDestroy: function(storeKey) {
585
585
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
@@ -592,13 +592,13 @@ SC.NestedStore = SC.Store.extend(
592
592
 
593
593
  // ..........................................................
594
594
  // PUSH CHANGES FROM DATA SOURCE
595
- //
596
-
595
+ //
596
+
597
597
  /** @private - adapt for nested store */
598
598
  pushRetrieve: function(recordType, id, dataHash, storeKey) {
599
599
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
600
600
  },
601
-
601
+
602
602
  /** @private - adapt for nested store */
603
603
  pushDestroy: function(recordType, id, storeKey) {
604
604
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
@@ -608,6 +608,6 @@ SC.NestedStore = SC.Store.extend(
608
608
  pushError: function(recordType, id, error, storeKey) {
609
609
  throw SC.Store.NESTED_STORE_UNSUPPORTED_ERROR;
610
610
  }
611
-
611
+
612
612
  }) ;
613
613