sproutcore 1.9.0 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|