sproutcore 1.9.1 → 1.9.2
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 +212 -11
- data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +17 -17
- data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +103 -86
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/bootstrap/tests/system/browser.js +33 -21
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +7 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +5 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +36 -30
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/many_array/core_methods.js +84 -42
- data/lib/frameworks/sproutcore/frameworks/desktop/{resources/debug → debug/resources}/a_sample_image.jpg +0 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/{resources/debug → debug/resources}/iframe.html +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/protocols/responder.js +68 -68
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/list_item.css +1 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/menu_item_view.css +1 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/slider.css +6 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/web/ui.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +45 -36
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/{gestureable.js → gesturable.js} +0 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/label.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/foundation/resources/benchmark.css +1 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/label/ui.js +13 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/views/inline_text_field.js +4 -33
- data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +31 -17
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +59 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/themes/ace/resources/master-detail/master-detail.css +4 -0
- data/lib/gen/app/templates/apps/@target_name@/Buildfile +3 -1
- data/lib/gen/app/templates/apps/@target_name@/core.js +3 -3
- data/lib/gen/app/templates/apps/@target_name@/main.js +7 -5
- data/lib/gen/app/templates/apps/@target_name@/resources/main_page.css +20 -0
- data/lib/gen/app/templates/apps/@target_name@/resources/main_page.js +7 -7
- data/lib/gen/controller/templates/controllers/@filename@_controller.js +2 -2
- data/lib/gen/data-source/templates/data_sources/@filename@_data_source.js +21 -21
- data/lib/gen/design/templates/resources/@filename@.css +12 -0
- data/lib/gen/framework/templates/frameworks/@target_name@/core.js +3 -3
- data/lib/gen/framework/templates/frameworks/@target_name@/english.lproj/strings.js +1 -1
- data/lib/gen/language/templates/@filename@/strings.js +1 -1
- data/lib/gen/model/templates/models/@filename@_model.js +1 -1
- data/lib/gen/page/templates/pages/@target_name@/core.js +3 -3
- data/lib/gen/project/templates/@filename@/Buildfile +29 -5
- data/lib/gen/{responder → state}/Buildfile +3 -2
- data/lib/gen/state/README +1 -0
- data/lib/gen/state/USAGE +15 -0
- data/lib/gen/state/templates/states/@filename@_state.js +24 -0
- data/lib/gen/state/templates/tests/states/@filename@_test.js +12 -0
- data/lib/gen/statechart_app/templates/apps/@target_name@/Buildfile +3 -1
- data/lib/gen/statechart_app/templates/apps/@target_name@/core.js +3 -3
- data/lib/gen/statechart_app/templates/apps/@target_name@/main.js +3 -10
- data/lib/gen/statechart_app/templates/apps/@target_name@/resources/main_page.css +20 -0
- data/lib/gen/statechart_app/templates/apps/@target_name@/resources/main_page.js +7 -7
- data/lib/gen/statechart_app/templates/apps/@target_name@/statechart.js +3 -3
- data/lib/sproutcore/models/generator.rb +1 -1
- data/spec/lib/models/generator/snake_case_spec.rb +26 -0
- data/sproutcore.gemspec +16 -16
- data/vendor/chance/lib/chance/instance/spriting.rb +32 -30
- metadata +30 -26
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/debug/apple-logo1.jpeg +0 -0
- data/lib/gen/responder/README +0 -1
- data/lib/gen/responder/USAGE +0 -15
- data/lib/gen/responder/templates/states/@filename@_state.js +0 -36
@@ -193,7 +193,7 @@ SC.detectBrowser = function(userAgent, language) {
|
|
193
193
|
// Normalize the os name.
|
194
194
|
if (isIOSDevice) { osAndVersion[1] = SC.OS.ios; }
|
195
195
|
else if (osAndVersion[1] === 'mac os x' || osAndVersion[1] === 'mac os') { osAndVersion[1] = SC.OS.mac; }
|
196
|
-
else if (osAndVersion[1] === 'windows nt') { osAndVersion[1] = SC.OS.
|
196
|
+
else if (osAndVersion[1] === 'windows nt') { osAndVersion[1] = SC.OS.win; }
|
197
197
|
|
198
198
|
// Normalize the os version.
|
199
199
|
osAndVersion[2] = osAndVersion[2] ? osAndVersion[2].replace(/_/g, '.') : '0';
|
@@ -41,7 +41,7 @@ var userAgents = {
|
|
41
41
|
device: SC.DEVICE.desktop,
|
42
42
|
name: SC.BROWSER.chrome,
|
43
43
|
version: '16.0.912.36',
|
44
|
-
os: SC.OS.
|
44
|
+
os: SC.OS.win,
|
45
45
|
osVersion: '6.1',
|
46
46
|
engine: SC.ENGINE.webkit,
|
47
47
|
engineVersion: '535.7'
|
@@ -62,7 +62,7 @@ var userAgents = {
|
|
62
62
|
device: SC.DEVICE.desktop,
|
63
63
|
name: SC.BROWSER.opera,
|
64
64
|
version: '8.65',
|
65
|
-
os: SC.OS.
|
65
|
+
os: SC.OS.win,
|
66
66
|
osVersion: '5.1',
|
67
67
|
engine: SC.ENGINE.opera,
|
68
68
|
engineVersion: '8.65'
|
@@ -71,7 +71,7 @@ var userAgents = {
|
|
71
71
|
device: SC.DEVICE.desktop,
|
72
72
|
name: SC.BROWSER.opera,
|
73
73
|
version: '10.62',
|
74
|
-
os: SC.OS.
|
74
|
+
os: SC.OS.win,
|
75
75
|
osVersion: '6.1',
|
76
76
|
engine: SC.ENGINE.presto,
|
77
77
|
engineVersion: '2.6.30'
|
@@ -80,7 +80,7 @@ var userAgents = {
|
|
80
80
|
device: SC.DEVICE.desktop,
|
81
81
|
name: SC.BROWSER.opera,
|
82
82
|
version: '11.51',
|
83
|
-
os: SC.OS.
|
83
|
+
os: SC.OS.win,
|
84
84
|
osVersion: '5.1',
|
85
85
|
engine: SC.ENGINE.presto,
|
86
86
|
engineVersion: '2.9.168'
|
@@ -89,7 +89,7 @@ var userAgents = {
|
|
89
89
|
device: SC.DEVICE.desktop,
|
90
90
|
name: SC.BROWSER.opera,
|
91
91
|
version: '12.00',
|
92
|
-
os: SC.OS.
|
92
|
+
os: SC.OS.win,
|
93
93
|
osVersion: '6.1',
|
94
94
|
engine: SC.ENGINE.presto,
|
95
95
|
engineVersion: '2.9.181'
|
@@ -119,7 +119,7 @@ var userAgents = {
|
|
119
119
|
device: SC.DEVICE.desktop,
|
120
120
|
name: SC.BROWSER.ie,
|
121
121
|
version: '7.0',
|
122
|
-
os: SC.OS.
|
122
|
+
os: SC.OS.win,
|
123
123
|
osVersion: '6.0',
|
124
124
|
engine: SC.ENGINE.trident,
|
125
125
|
engineVersion: '7.0'
|
@@ -128,7 +128,7 @@ var userAgents = {
|
|
128
128
|
device: SC.DEVICE.desktop,
|
129
129
|
name: SC.BROWSER.ie,
|
130
130
|
version: '8.0',
|
131
|
-
os: SC.OS.
|
131
|
+
os: SC.OS.win,
|
132
132
|
osVersion: '6.0',
|
133
133
|
engine: SC.ENGINE.trident,
|
134
134
|
engineVersion: '4.0'
|
@@ -137,7 +137,7 @@ var userAgents = {
|
|
137
137
|
device: SC.DEVICE.desktop,
|
138
138
|
name: SC.BROWSER.ie,
|
139
139
|
version: '9.0',
|
140
|
-
os: SC.OS.
|
140
|
+
os: SC.OS.win,
|
141
141
|
osVersion: '9.0',
|
142
142
|
engine: SC.ENGINE.trident,
|
143
143
|
engineVersion: '9.0'
|
@@ -146,7 +146,7 @@ var userAgents = {
|
|
146
146
|
device: SC.DEVICE.desktop,
|
147
147
|
name: SC.BROWSER.ie,
|
148
148
|
version: '10.0',
|
149
|
-
os: SC.OS.
|
149
|
+
os: SC.OS.win,
|
150
150
|
osVersion: '6.1',
|
151
151
|
engine: SC.ENGINE.trident,
|
152
152
|
engineVersion: '6.0'
|
@@ -155,7 +155,7 @@ var userAgents = {
|
|
155
155
|
device: SC.DEVICE.desktop,
|
156
156
|
name: SC.BROWSER.ie,
|
157
157
|
version: '10.6',
|
158
|
-
os: SC.OS.
|
158
|
+
os: SC.OS.win,
|
159
159
|
osVersion: '6.1',
|
160
160
|
engine: SC.ENGINE.trident,
|
161
161
|
engineVersion: '5.0'
|
@@ -164,11 +164,20 @@ var userAgents = {
|
|
164
164
|
device: SC.DEVICE.desktop,
|
165
165
|
name: SC.BROWSER.ie,
|
166
166
|
version: '10.0',
|
167
|
-
os: SC.OS.
|
167
|
+
os: SC.OS.win,
|
168
168
|
osVersion: '6.2',
|
169
169
|
engine: SC.ENGINE.trident,
|
170
170
|
engineVersion: '6.0'
|
171
171
|
},
|
172
|
+
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)": {
|
173
|
+
device: SC.DEVICE.desktop,
|
174
|
+
name: SC.BROWSER.ie,
|
175
|
+
version: '9.0',
|
176
|
+
os: SC.OS.win,
|
177
|
+
osVersion: '6.1',
|
178
|
+
engine: SC.ENGINE.trident,
|
179
|
+
engineVersion: '5.0'
|
180
|
+
},
|
172
181
|
|
173
182
|
// MOZILLA
|
174
183
|
|
@@ -176,7 +185,7 @@ var userAgents = {
|
|
176
185
|
device: SC.DEVICE.desktop,
|
177
186
|
name: SC.ENGINE.gecko,
|
178
187
|
version: '0',
|
179
|
-
os: SC.OS.
|
188
|
+
os: SC.OS.win,
|
180
189
|
osVersion: '6.1',
|
181
190
|
engine: SC.ENGINE.gecko,
|
182
191
|
engineVersion: '2.0b4'
|
@@ -215,7 +224,7 @@ var userAgents = {
|
|
215
224
|
device: SC.DEVICE.desktop,
|
216
225
|
name: SC.BROWSER.firefox,
|
217
226
|
version: '3.5.13',
|
218
|
-
os: SC.OS.
|
227
|
+
os: SC.OS.win,
|
219
228
|
osVersion: '6.1',
|
220
229
|
engine: SC.ENGINE.gecko,
|
221
230
|
engineVersion: '1.9.1.13'
|
@@ -224,7 +233,7 @@ var userAgents = {
|
|
224
233
|
device: SC.DEVICE.desktop,
|
225
234
|
name: SC.BROWSER.firefox,
|
226
235
|
version: '3.6.10',
|
227
|
-
os: SC.OS.
|
236
|
+
os: SC.OS.win,
|
228
237
|
osVersion: '6.1',
|
229
238
|
engine: SC.ENGINE.gecko,
|
230
239
|
engineVersion: '1.9.2.10'
|
@@ -233,7 +242,7 @@ var userAgents = {
|
|
233
242
|
device: SC.DEVICE.desktop,
|
234
243
|
name: SC.BROWSER.firefox,
|
235
244
|
version: '4.0b7pre',
|
236
|
-
os: SC.OS.
|
245
|
+
os: SC.OS.win,
|
237
246
|
osVersion: '6.1',
|
238
247
|
engine: SC.ENGINE.gecko,
|
239
248
|
engineVersion: '2.0b7pre'
|
@@ -242,7 +251,7 @@ var userAgents = {
|
|
242
251
|
device: SC.DEVICE.desktop,
|
243
252
|
name: SC.BROWSER.firefox,
|
244
253
|
version: '6.0',
|
245
|
-
os: SC.OS.
|
254
|
+
os: SC.OS.win,
|
246
255
|
osVersion: '6.1',
|
247
256
|
engine: SC.ENGINE.gecko,
|
248
257
|
engineVersion: '6.0'
|
@@ -299,7 +308,7 @@ var userAgents = {
|
|
299
308
|
device: SC.DEVICE.desktop,
|
300
309
|
name: SC.BROWSER.safari,
|
301
310
|
version: '4.1',
|
302
|
-
os: SC.OS.
|
311
|
+
os: SC.OS.win,
|
303
312
|
osVersion: '5.0',
|
304
313
|
engine: SC.ENGINE.webkit,
|
305
314
|
engineVersion: '533.16'
|
@@ -308,7 +317,7 @@ var userAgents = {
|
|
308
317
|
device: SC.DEVICE.desktop,
|
309
318
|
name: SC.BROWSER.safari,
|
310
319
|
version: '5.0.1',
|
311
|
-
os: SC.OS.
|
320
|
+
os: SC.OS.win,
|
312
321
|
osVersion: '5.2',
|
313
322
|
engine: SC.ENGINE.webkit,
|
314
323
|
engineVersion: '533.17.8'
|
@@ -317,7 +326,7 @@ var userAgents = {
|
|
317
326
|
device: SC.DEVICE.desktop,
|
318
327
|
name: SC.BROWSER.safari,
|
319
328
|
version: '5.0.2',
|
320
|
-
os: SC.OS.
|
329
|
+
os: SC.OS.win,
|
321
330
|
osVersion: '6.1',
|
322
331
|
engine: SC.ENGINE.webkit,
|
323
332
|
engineVersion: '533.18.1'
|
@@ -326,7 +335,7 @@ var userAgents = {
|
|
326
335
|
device: SC.DEVICE.desktop,
|
327
336
|
name: SC.BROWSER.safari,
|
328
337
|
version: '5.0.3',
|
329
|
-
os: SC.OS.
|
338
|
+
os: SC.OS.win,
|
330
339
|
osVersion: '6.0',
|
331
340
|
engine: SC.ENGINE.webkit,
|
332
341
|
engineVersion: '533.19.4'
|
@@ -335,7 +344,7 @@ var userAgents = {
|
|
335
344
|
device: SC.DEVICE.desktop,
|
336
345
|
name: SC.BROWSER.safari,
|
337
346
|
version: '5.0.4',
|
338
|
-
os: SC.OS.
|
347
|
+
os: SC.OS.win,
|
339
348
|
osVersion: '6.1',
|
340
349
|
engine: SC.ENGINE.webkit,
|
341
350
|
engineVersion: '533.20.25'
|
@@ -485,6 +494,9 @@ for (var userAgent in userAgents) {
|
|
485
494
|
browser = SC.detectBrowser(userAgent);
|
486
495
|
expected = userAgents[userAgent];
|
487
496
|
for (var key in expected) {
|
497
|
+
if ( !browser.hasOwnProperty(key) || browser[key] == null) {
|
498
|
+
ok(false,"Property %@ not set, expected %@".fmt(key, expected[key]));
|
499
|
+
}
|
488
500
|
if (browser[key] && typeof browser[key] !== "function") {
|
489
501
|
equals(browser[key], expected[key], "'" + key + "' should be '" + expected[key] + "'");
|
490
502
|
}
|
@@ -44,6 +44,8 @@ SC.platform = SC.Object.create({
|
|
44
44
|
- Android is assumed to support touch, but incorrectly reports that it does not.
|
45
45
|
- See: https://github.com/Modernizr/Modernizr/issues/84 for a discussion on detecting
|
46
46
|
touch capability.
|
47
|
+
- See: https://github.com/highslide-software/highcharts.com/issues/1331 for a discussion
|
48
|
+
about why we need to check if ontouchstart is null in addition to check if it's defined
|
47
49
|
*/
|
48
50
|
/**
|
49
51
|
YES if the current device supports touch events, NO otherwise.
|
@@ -53,7 +55,7 @@ SC.platform = SC.Object.create({
|
|
53
55
|
|
54
56
|
@property {Boolean}
|
55
57
|
*/
|
56
|
-
touch:
|
58
|
+
touch: !SC.none(window.ontouchstart) || SC.browser.name === SC.BROWSER.android,
|
57
59
|
|
58
60
|
/**
|
59
61
|
YES if the current browser supports bounce on scroll.
|
@@ -2017,8 +2017,13 @@ SC.RootResponder = SC.Object.extend(
|
|
2017
2017
|
drag: function() { return false; },
|
2018
2018
|
|
2019
2019
|
contextmenu: function(evt) {
|
2020
|
-
var view = this.targetViewForEvent(evt)
|
2021
|
-
|
2020
|
+
var view = this.targetViewForEvent(evt);
|
2021
|
+
|
2022
|
+
// Determine if any views took responsibility for the event.
|
2023
|
+
view = this.sendEvent('contextMenu', evt, view);
|
2024
|
+
ret = view ? evt.hasCustomEventHandling : YES;
|
2025
|
+
|
2026
|
+
return ret;
|
2022
2027
|
},
|
2023
2028
|
|
2024
2029
|
// ..........................................................
|
@@ -1466,10 +1466,13 @@ SC.CoreView.reopen(
|
|
1466
1466
|
Used to block the contextMenu per view.
|
1467
1467
|
|
1468
1468
|
@param evt {SC.Event} the contextmenu event
|
1469
|
-
@returns YES if the contextmenu
|
1469
|
+
@returns YES if the contextmenu will be allowed to show up
|
1470
1470
|
*/
|
1471
1471
|
contextMenu: function(evt) {
|
1472
|
-
if (this.get('isContextMenuEnabled')) {
|
1472
|
+
if (this.get('isContextMenuEnabled')) {
|
1473
|
+
evt.allowDefault();
|
1474
|
+
return YES;
|
1475
|
+
}
|
1473
1476
|
}
|
1474
1477
|
|
1475
1478
|
});
|
@@ -66,6 +66,13 @@ SC.View.reopen(
|
|
66
66
|
}
|
67
67
|
|
68
68
|
if (callback) { options.callback = callback; }
|
69
|
+
else if (options.callback) {
|
70
|
+
//@if(debug)
|
71
|
+
// Provide a little developer support if they are doing something that should be considered wrong.
|
72
|
+
SC.warn("Developer Warning: The callback method should be given as an argument not as part of the options object. Future versions of SproutCore will no longer support having the callback in the options hash. See discussion at: https://github.com/sproutcore/sproutcore/issues/861.");
|
73
|
+
//@endif
|
74
|
+
callback = options.callback;
|
75
|
+
}
|
69
76
|
|
70
77
|
// In the case of zero duration, just adjust and call the callback.
|
71
78
|
if (options.duration === 0) {
|
@@ -194,7 +194,7 @@ SC.MIXED_STATE = '__MIXED__';
|
|
194
194
|
|
195
195
|
* `dataSourceDidFetchQuery(query)` — the data source must call this when
|
196
196
|
it has completed fetching any related data for the query. This returns the
|
197
|
-
query results (record array) status into a `READY` state.
|
197
|
+
query results (i.e. the record array) status into a `READY` state.
|
198
198
|
* `dataSourceDidErrorQuery(query, error)` — the data source should call
|
199
199
|
this if it encounters an error in executing the query. This puts the query
|
200
200
|
results into an `ERROR` state.
|
@@ -8,13 +8,13 @@
|
|
8
8
|
/**
|
9
9
|
@class
|
10
10
|
|
11
|
-
A `ManyArray` is used to map an array of record ids back to their
|
11
|
+
A `ManyArray` is used to map an array of record ids back to their
|
12
12
|
record objects which will be materialized from the owner store on demand.
|
13
|
-
|
14
|
-
Whenever you create a `toMany()` relationship, the value returned from the
|
13
|
+
|
14
|
+
Whenever you create a `toMany()` relationship, the value returned from the
|
15
15
|
property will be an instance of `ManyArray`. You can generally customize the
|
16
16
|
behavior of ManyArray by passing settings to the `toMany()` helper.
|
17
|
-
|
17
|
+
|
18
18
|
@extends SC.Enumerable
|
19
19
|
@extends SC.Array
|
20
20
|
@since SproutCore 1.0
|
@@ -53,7 +53,7 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
53
53
|
|
54
54
|
/**
|
55
55
|
The `ManyAttribute` that created this array.
|
56
|
-
|
56
|
+
|
57
57
|
@default null
|
58
58
|
@type SC.ManyAttribute
|
59
59
|
*/
|
@@ -71,7 +71,7 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
71
71
|
}.property('record').cacheable(),
|
72
72
|
|
73
73
|
/**
|
74
|
-
The `storeKey` for the parent record of this many array. Editing this
|
74
|
+
The `storeKey` for the parent record of this many array. Editing this
|
75
75
|
array will place the parent record into a `READY_DIRTY` state.
|
76
76
|
|
77
77
|
@type Number
|
@@ -83,7 +83,7 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
83
83
|
|
84
84
|
|
85
85
|
/**
|
86
|
-
Returns the `storeId`s in read-only mode. Avoids modifying the record
|
86
|
+
Returns the `storeId`s in read-only mode. Avoids modifying the record
|
87
87
|
unnecessarily.
|
88
88
|
|
89
89
|
@type SC.Array
|
@@ -95,9 +95,9 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
95
95
|
|
96
96
|
|
97
97
|
/**
|
98
|
-
Returns an editable array of `storeId`s. Marks the owner records as
|
99
|
-
modified.
|
100
|
-
|
98
|
+
Returns an editable array of `storeId`s. Marks the owner records as
|
99
|
+
modified.
|
100
|
+
|
101
101
|
@type {SC.Array}
|
102
102
|
@property
|
103
103
|
*/
|
@@ -176,7 +176,7 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
176
176
|
|
177
177
|
/** @private
|
178
178
|
Returned length is a pass-through to the `storeIds` array.
|
179
|
-
|
179
|
+
|
180
180
|
@type Number
|
181
181
|
@property
|
182
182
|
*/
|
@@ -231,7 +231,7 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
231
231
|
len = recs ? (recs.get ? recs.get('length') : recs.length) : 0,
|
232
232
|
record = this.get('record'),
|
233
233
|
pname = this.get('propertyName'),
|
234
|
-
i,
|
234
|
+
i, ids, toRemove, inverse, attr, inverseRecord;
|
235
235
|
|
236
236
|
// map to store keys
|
237
237
|
ids = [] ;
|
@@ -326,11 +326,11 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
326
326
|
@param {SC.Record} inverseRecord the record this array is a part of
|
327
327
|
@returns {SC.ManyArray} receiver
|
328
328
|
*/
|
329
|
-
addInverseRecord: function(inverseRecord) {
|
330
|
-
|
329
|
+
addInverseRecord: function (inverseRecord) {
|
330
|
+
// Fast path!
|
331
331
|
if (!inverseRecord) return this;
|
332
|
-
|
333
|
-
|
332
|
+
|
333
|
+
var storeIds = this.get('editableStoreIds'),
|
334
334
|
orderBy = this.get('orderBy'),
|
335
335
|
len = storeIds.get('length'),
|
336
336
|
idx, record;
|
@@ -348,26 +348,32 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
|
|
348
348
|
return this;
|
349
349
|
},
|
350
350
|
|
351
|
-
/** @private
|
352
|
-
|
353
|
-
|
354
|
-
_findInsertionLocation: function(rec, min, max, orderBy) {
|
355
|
-
var idx = min+Math.floor((max-min)/2),
|
351
|
+
/** @private binary search to find insertion location */
|
352
|
+
_findInsertionLocation: function (rec, min, max, orderBy) {
|
353
|
+
var idx = min + Math.floor((max - min) / 2),
|
356
354
|
cur = this.objectAt(idx),
|
357
355
|
order = this._compare(rec, cur, orderBy);
|
356
|
+
|
358
357
|
if (order < 0) {
|
359
|
-
|
360
|
-
|
358
|
+
// The location is before the first index.
|
359
|
+
if (idx === 0) return idx;
|
360
|
+
|
361
|
+
// The location is in the lower subset.
|
362
|
+
else return this._findInsertionLocation(rec, 0, idx - 1, orderBy);
|
361
363
|
} else if (order > 0) {
|
362
|
-
|
363
|
-
|
364
|
-
|
364
|
+
// The location is after the current index.
|
365
|
+
if (idx >= max) return idx + 1;
|
366
|
+
|
367
|
+
// The location is in the upper subset.
|
368
|
+
else return this._findInsertionLocation(rec, idx + 1, max, orderBy);
|
369
|
+
} else {
|
370
|
+
// The location is the current index.
|
371
|
+
return idx;
|
372
|
+
}
|
365
373
|
},
|
366
374
|
|
367
|
-
/** @private
|
368
|
-
|
369
|
-
*/
|
370
|
-
_compare: function(a, b, orderBy) {
|
375
|
+
/** @private function to compare two objects*/
|
376
|
+
_compare: function (a, b, orderBy) {
|
371
377
|
var t = SC.typeOf(orderBy),
|
372
378
|
ret, idx, len;
|
373
379
|
|
@@ -9,17 +9,17 @@
|
|
9
9
|
var store, storeKey, storeId, rec, storeIds, recs, arrayRec;
|
10
10
|
module("SC.ManyArray core methods", {
|
11
11
|
setup: function() {
|
12
|
-
|
12
|
+
|
13
13
|
// setup dummy app and store
|
14
14
|
MyApp = SC.Object.create({
|
15
15
|
store: SC.Store.create()
|
16
16
|
});
|
17
|
-
|
17
|
+
|
18
18
|
// setup a dummy model
|
19
19
|
MyApp.Foo = SC.Record.extend({});
|
20
|
-
|
20
|
+
|
21
21
|
SC.RunLoop.begin();
|
22
|
-
|
22
|
+
|
23
23
|
// load some data
|
24
24
|
storeIds = [1,2,3,4];
|
25
25
|
MyApp.store.loadRecords(MyApp.Foo, [
|
@@ -29,25 +29,25 @@ module("SC.ManyArray core methods", {
|
|
29
29
|
{ guid: 4, firstName: "Johnny", lastName: "Cash", age: 17 },
|
30
30
|
{ guid: 50, firstName: "Holder", fooMany: storeIds }
|
31
31
|
]);
|
32
|
-
|
32
|
+
|
33
33
|
storeKey = MyApp.store.storeKeyFor(MyApp.Foo, 1);
|
34
|
-
|
34
|
+
|
35
35
|
// get record
|
36
36
|
rec = MyApp.store.materializeRecord(storeKey);
|
37
37
|
storeId = rec.get('id');
|
38
|
-
|
38
|
+
|
39
39
|
// get many array.
|
40
40
|
arrayRec = MyApp.store.materializeRecord(MyApp.store.storeKeyFor(MyApp.Foo, 50));
|
41
|
-
|
42
|
-
recs = SC.ManyArray.create({
|
41
|
+
|
42
|
+
recs = SC.ManyArray.create({
|
43
43
|
record: arrayRec,
|
44
|
-
propertyName: "fooMany",
|
44
|
+
propertyName: "fooMany",
|
45
45
|
recordType: MyApp.Foo,
|
46
46
|
isEditable: YES
|
47
47
|
});
|
48
|
-
arrayRec.relationships = [recs];
|
48
|
+
arrayRec.relationships = [recs];
|
49
49
|
},
|
50
|
-
|
50
|
+
|
51
51
|
teardown: function() {
|
52
52
|
SC.RunLoop.end();
|
53
53
|
}
|
@@ -55,25 +55,25 @@ module("SC.ManyArray core methods", {
|
|
55
55
|
|
56
56
|
// ..........................................................
|
57
57
|
// LENGTH
|
58
|
-
//
|
58
|
+
//
|
59
59
|
|
60
60
|
test("should pass through length", function() {
|
61
|
-
equals(recs.get('length'), storeIds.length, 'rec should pass through length');
|
61
|
+
equals(recs.get('length'), storeIds.length, 'rec should pass through length');
|
62
62
|
});
|
63
63
|
|
64
64
|
test("changing storeIds length should change length of rec array also", function() {
|
65
65
|
|
66
66
|
var oldlen = recs.get('length');
|
67
|
-
|
67
|
+
|
68
68
|
storeIds.pushObject(SC.Store.generateStoreKey()); // change length
|
69
|
-
|
69
|
+
|
70
70
|
ok(storeIds.length > oldlen, 'precond - storeKeys.length should have changed');
|
71
|
-
equals(recs.get('length'), storeIds.length, 'rec should pass through length');
|
71
|
+
equals(recs.get('length'), storeIds.length, 'rec should pass through length');
|
72
72
|
});
|
73
73
|
|
74
74
|
// ..........................................................
|
75
75
|
// objectAt
|
76
|
-
//
|
76
|
+
//
|
77
77
|
|
78
78
|
test("should materialize record for object", function() {
|
79
79
|
equals(storeIds[0], storeId, 'precond - storeIds[0] should be storeId');
|
@@ -86,12 +86,12 @@ test("reading past end of array length should return undefined", function() {
|
|
86
86
|
|
87
87
|
test("modifying the underlying storeId should change the returned materialized record", function() {
|
88
88
|
// read record once to make it materialized
|
89
|
-
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
90
|
-
|
89
|
+
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
90
|
+
|
91
91
|
// create a new record.
|
92
92
|
var rec2 = MyApp.store.createRecord(MyApp.Foo, { guid: 5, firstName: "Fred" });
|
93
93
|
var storeId2 = rec2.get('id');
|
94
|
-
|
94
|
+
|
95
95
|
// add to beginning of storeKey array
|
96
96
|
storeIds.unshiftObject(storeId2);
|
97
97
|
equals(recs.get('length'), 5, 'should now have length of 5');
|
@@ -102,39 +102,39 @@ test("modifying the underlying storeId should change the returned materialized r
|
|
102
102
|
test("reading a record not loaded in store should trigger retrieveRecord", function() {
|
103
103
|
var callCount = 0;
|
104
104
|
|
105
|
-
// patch up store to record a call and to make it look like data is not
|
105
|
+
// patch up store to record a call and to make it look like data is not
|
106
106
|
// loaded.
|
107
|
-
|
107
|
+
|
108
108
|
MyApp.store.removeDataHash(storeKey, SC.Record.EMPTY);
|
109
109
|
MyApp.store.retrieveRecord = function() { callCount++; };
|
110
|
-
|
110
|
+
|
111
111
|
var rec = recs.objectAt(0);
|
112
112
|
equals(MyApp.store.readStatus(rec), SC.Record.EMPTY, 'precond - storeKey must not be loaded');
|
113
|
-
|
113
|
+
|
114
114
|
equals(callCount, 1, 'store.retrieveRecord() should have been called');
|
115
115
|
});
|
116
116
|
|
117
117
|
// ..........................................................
|
118
118
|
// replace()
|
119
|
-
//
|
119
|
+
//
|
120
120
|
|
121
121
|
test("adding a record to the ManyArray should pass through storeIds", function() {
|
122
122
|
|
123
123
|
// read record once to make it materialized
|
124
|
-
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
125
|
-
|
124
|
+
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
125
|
+
|
126
126
|
// create a new record.
|
127
127
|
var rec2 = MyApp.store.createRecord(MyApp.Foo, { guid: 5, firstName: "rec2" });
|
128
128
|
var storeId2 = rec2.get('id');
|
129
|
-
|
129
|
+
|
130
130
|
// add record to beginning of record array
|
131
131
|
recs.unshiftObject(rec2);
|
132
|
-
|
132
|
+
|
133
133
|
// verify record array
|
134
134
|
equals(recs.get('length'), 5, 'should now have length of 2');
|
135
135
|
equals(recs.objectAt(0), rec2, 'recs.objectAt(0) should return new record');
|
136
136
|
equals(recs.objectAt(1), rec, 'recs.objectAt(1) should return old record');
|
137
|
-
|
137
|
+
|
138
138
|
// verify storeKeys
|
139
139
|
storeIds = arrayRec.readAttribute('fooMany'); // array might have changed
|
140
140
|
equals(storeIds.objectAt(0), storeId2, 'storeKeys[0] should return new storeKey');
|
@@ -143,7 +143,7 @@ test("adding a record to the ManyArray should pass through storeIds", function()
|
|
143
143
|
|
144
144
|
// ..........................................................
|
145
145
|
// Property Observing
|
146
|
-
//
|
146
|
+
//
|
147
147
|
|
148
148
|
test("changing the underlying storeIds should notify observers of records", function() {
|
149
149
|
|
@@ -152,8 +152,8 @@ test("changing the underlying storeIds should notify observers of records", func
|
|
152
152
|
cnt: 0,
|
153
153
|
observer: function() { this.cnt++; }
|
154
154
|
});
|
155
|
-
recs.addObserver('[]', obj, obj.observer);
|
156
|
-
|
155
|
+
recs.addObserver('[]', obj, obj.observer);
|
156
|
+
|
157
157
|
// now modify storeKeys
|
158
158
|
storeIds.pushObject(5);
|
159
159
|
equals(obj.cnt, 1, 'observer should have fired after changing storeKeys');
|
@@ -165,34 +165,34 @@ test("swapping storeIds array should change ManyArray and observers", function()
|
|
165
165
|
var rec2 = MyApp.store.createRecord(MyApp.Foo, { guid: 5, firstName: "rec2" });
|
166
166
|
var storeId2 = rec2.get('id');
|
167
167
|
var storeIds2 = [storeId2];
|
168
|
-
|
168
|
+
|
169
169
|
// setup observer
|
170
170
|
var obj = SC.Object.create({
|
171
171
|
cnt: 0,
|
172
172
|
observer: function() { this.cnt++; }
|
173
173
|
});
|
174
|
-
recs.addObserver('[]', obj, obj.observer);
|
175
|
-
|
174
|
+
recs.addObserver('[]', obj, obj.observer);
|
175
|
+
|
176
176
|
// read record once to make it materialized
|
177
|
-
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
178
|
-
|
177
|
+
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
|
178
|
+
|
179
179
|
// now swap storeKeys
|
180
180
|
obj.cnt = 0 ;
|
181
181
|
arrayRec.writeAttribute('fooMany', storeIds2);
|
182
182
|
|
183
183
|
SC.RunLoop.end();
|
184
184
|
SC.RunLoop.begin();
|
185
|
-
|
185
|
+
|
186
186
|
// verify observer fired and record changed
|
187
187
|
equals(obj.cnt, 1, 'observer should have fired after swap');
|
188
188
|
equals(recs.objectAt(0), rec2, 'recs.objectAt(0) should return new rec');
|
189
|
-
|
189
|
+
|
190
190
|
// modify storeKey2, make sure observer fires and content changes
|
191
191
|
obj.cnt = 0;
|
192
192
|
storeIds2.unshiftObject(storeId);
|
193
193
|
equals(obj.cnt, 1, 'observer should have fired after edit');
|
194
194
|
equals(recs.get('length'), 2, 'should reflect new length');
|
195
|
-
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should return pushed rec');
|
195
|
+
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should return pushed rec');
|
196
196
|
|
197
197
|
});
|
198
198
|
|
@@ -202,3 +202,45 @@ test("reduced properties", function() {
|
|
202
202
|
equals(recs.get('@min(age)'), 7, 'min reducer should return the correct value');
|
203
203
|
equals(recs.get('@average(age)'), (32+30+7+17)/4.0, 'average reducer should return the correct value');
|
204
204
|
});
|
205
|
+
|
206
|
+
test("Test that _findInsertionLocation returns the correct location.", function () {
|
207
|
+
var location,
|
208
|
+
newRec,
|
209
|
+
sortByFirstName = function (a, b) {
|
210
|
+
if (a.get('firstName') == b.get('firstName')) return 0;
|
211
|
+
else if (a.get('firstName') < b.get('firstName')) return -1;
|
212
|
+
else return 1;
|
213
|
+
};
|
214
|
+
|
215
|
+
// Order the many array manually by firstName.
|
216
|
+
arrayRec.set('fooMany', [3,2,1,4]);
|
217
|
+
recs._storeIdsContentDidChange(0, 4, 4);
|
218
|
+
|
219
|
+
// Check the insertion location of a record that should appear first.
|
220
|
+
newRec = SC.Object.create({ guid: 5, firstName: "Adam", lastName: "Doe", age: 15 });
|
221
|
+
location = recs._findInsertionLocation(newRec, 0, recs.get('length') - 1, sortByFirstName);
|
222
|
+
|
223
|
+
equals(location, 0, "The insertion location should be");
|
224
|
+
|
225
|
+
// Check the insertion location of a record that should appear in the middle.
|
226
|
+
newRec = SC.Object.create({ guid: 5, firstName: "Farmer", lastName: "Doe", age: 95 });
|
227
|
+
location = recs._findInsertionLocation(newRec, 0, recs.get('length') - 1, sortByFirstName);
|
228
|
+
|
229
|
+
equals(location, 1, "The insertion location should be");
|
230
|
+
|
231
|
+
newRec = SC.Object.create({ guid: 5, firstName: "Jen", lastName: "Doe", age: 95 });
|
232
|
+
location = recs._findInsertionLocation(newRec, 0, recs.get('length') - 1, sortByFirstName);
|
233
|
+
|
234
|
+
equals(location, 2, "The insertion location should be");
|
235
|
+
|
236
|
+
newRec = SC.Object.create({ guid: 5, firstName: "Johnny", lastName: "Doe", age: 95 });
|
237
|
+
location = recs._findInsertionLocation(newRec, 0, recs.get('length') - 1, sortByFirstName);
|
238
|
+
|
239
|
+
equals(location, 3, "The insertion location should be");
|
240
|
+
|
241
|
+
// Check the insertion location of a record that should appear last.
|
242
|
+
newRec = SC.Object.create({ guid: 5, firstName: "Zues", lastName: "Doe", age: 95 });
|
243
|
+
location = recs._findInsertionLocation(newRec, 0, recs.get('length') - 1, sortByFirstName);
|
244
|
+
|
245
|
+
equals(location, 4, "The insertion location should be");
|
246
|
+
});
|