sproutcore 1.9.0 → 1.9.1
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/VERSION.yml +1 -1
- data/lib/frameworks/sproutcore/CHANGELOG.md +123 -1
- data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +13 -9
- data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +68 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +59 -60
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +6 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/locale.js +48 -29
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/selection_set/remove.js +53 -17
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroy.js +34 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroyLayer.js +47 -11
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +31 -36
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +10 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +55 -23
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +5 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +105 -105
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChanges.js +131 -30
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +3 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +9 -5
- data/lib/sproutcore/helpers/minifier.rb +0 -2
- data/lib/sproutcore/rack/filesystem.rb +5 -5
- 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
|
-
|
86
|
-
|
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.
|
97
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
90
98
|
view.parentViewDidResize();
|
91
|
-
|
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.
|
104
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
96
105
|
view.parentViewDidResize();
|
97
|
-
|
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.
|
111
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
102
112
|
view.parentViewDidResize();
|
103
|
-
|
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.
|
118
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
108
119
|
view.parentViewDidResize();
|
109
|
-
|
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.
|
125
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
114
126
|
view.parentViewDidResize();
|
115
|
-
|
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.
|
132
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
120
133
|
view.parentViewDidResize();
|
121
|
-
|
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.
|
139
|
+
view.viewDidResize.reset(); view.frameCallCount = 0;
|
126
140
|
view.parentViewDidResize();
|
127
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
218
|
-
left & top position
|
219
|
-
|
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
|
-
//
|
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
|
246
|
+
// The position may appear fixed, but only if none of the values are percentages.
|
238
247
|
if (ret) {
|
239
|
-
ret = (
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
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
|
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
|
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
|
-
|
650
|
+
sizeMayHaveChanged = this.useStaticLayout || !this.get('isFixedSize');
|
651
|
+
positionMayHaveChanged = !this.get('isFixedPosition');
|
620
652
|
|
621
|
-
|
622
|
-
|
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
|
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
|
|