sproutcore 1.8.1 → 1.8.2.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 +17 -2
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/root_responder.js +23 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare.js +26 -24
- data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_fast_path.js +117 -118
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +9 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +48 -38
- data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +42 -40
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +55 -53
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_child.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/split_child.js +20 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/views/split.js +170 -170
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +22 -6
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +5 -9
- metadata +2 -2
data/VERSION.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
CHANGE LOG
|
2
|
-
|
1
|
+
CHANGE LOG
|
2
|
+
==========
|
3
3
|
|
4
4
|
Edge
|
5
5
|
----------
|
@@ -18,6 +18,21 @@ Edge
|
|
18
18
|
|
19
19
|
### BUG FIXES
|
20
20
|
|
21
|
+
|
22
|
+
1.8.2 - BUG FIXES
|
23
|
+
----------
|
24
|
+
|
25
|
+
* Fixed syntax error in Datastore unit test. [c62a0a9]
|
26
|
+
* SC.SplitView can now mixin SC.SplitChild. [6f1586c]
|
27
|
+
* Thinned picker pane border divs so that they don't overlap the content view. [0b06db2]
|
28
|
+
* Prevents target property conflict when configuring button targets with SC.AlertPane. [0364b5c]
|
29
|
+
* Changed the aria-orientation of horizontal SC.ScrollView to 'horizontal' from 'vertical'. [c3ee69b]
|
30
|
+
* Allows SC.CollectionFastPath to work with sparse content by always returning an item view even when content isn't yet available. [020653b]
|
31
|
+
* Prevents SC.GridView from iterating over its content array in order to work with sparse content. [020653b]
|
32
|
+
* The 'mobile-safari' body class name is no longer being added in all browsers. [b491224]
|
33
|
+
* Enables pasting in SC.TextFieldView to notify that the value changed. [a51318b]
|
34
|
+
* Prevents default touch behavior being intercepted on <textarea> and <select> elements. [8093963]
|
35
|
+
|
21
36
|
1.8.1 - BUG FIXES
|
22
37
|
----------
|
23
38
|
|
@@ -13,7 +13,7 @@ SC.setupBodyClassNames = function() {
|
|
13
13
|
if (!el) return ;
|
14
14
|
|
15
15
|
browser = SC.browser.current ;
|
16
|
-
platform = SC.browser.
|
16
|
+
platform = SC.browser.isWindows ? 'windows' : SC.browser.isMac ? 'mac' : 'other-platform' ;
|
17
17
|
style = document.documentElement.style;
|
18
18
|
shadows = (style.MozBoxShadow !== undefined) ||
|
19
19
|
(style.webkitBoxShadow !== undefined) ||
|
@@ -46,7 +46,7 @@ SC.setupBodyClassNames = function() {
|
|
46
46
|
}
|
47
47
|
|
48
48
|
if(browser==="safari" || browser==="chrome") classNames.push('webkit');
|
49
|
-
if (SC.browser.
|
49
|
+
if (SC.browser.isMobileSafari) classNames.push('mobile-safari') ;
|
50
50
|
if ('createTouch' in document) classNames.push('touch');
|
51
51
|
el.className = classNames.join(' ') ;
|
52
52
|
} ;
|
@@ -1488,7 +1488,7 @@ SC.RootResponder = SC.Object.extend(
|
|
1488
1488
|
ignoreTouchHandle: function(evt) {
|
1489
1489
|
if(SC.browser.isMobileSafari){
|
1490
1490
|
var tag = evt.target.tagName;
|
1491
|
-
if(tag==="INPUT" || tag==="A"){
|
1491
|
+
if(tag==="INPUT" || tag==="TEXTAREA" || tag==="A" || tag==="SELECT"){
|
1492
1492
|
evt.allowDefault();
|
1493
1493
|
return YES;
|
1494
1494
|
}
|
@@ -82,6 +82,29 @@ test("root_responder.makeKeyPane() : Should make the main pane as the key pane i
|
|
82
82
|
equals(responder.get('keyPane'),lightPane);
|
83
83
|
});
|
84
84
|
|
85
|
+
test("root_responder.ignoreTouchHandle() : Should ignore TEXTAREA, INPUT, A, and SELECT elements", function () {
|
86
|
+
var wasMobileSafari = SC.browser.isMobileSafari;
|
87
|
+
SC.browser.isMobileSafari = YES;
|
88
|
+
|
89
|
+
["A", "INPUT", "TEXTAREA", "SELECT"].forEach(function (tag) {
|
90
|
+
ok(responder.ignoreTouchHandle({
|
91
|
+
target: { tagName: tag },
|
92
|
+
allowDefault: SC.K
|
93
|
+
}), "should pass touch events through to <" + tag + ">s");
|
94
|
+
});
|
95
|
+
|
96
|
+
["AUDIO", "B", "Q", "BR", "BODY", "BUTTON", "CANVAS", "FORM",
|
97
|
+
"IFRAME", "IMG", "OPTION", "P", "PROGRESS", "STRONG",
|
98
|
+
"TABLE", "TBODY", "TR", "TH", "TD", "VIDEO"].forEach(function (tag) {
|
99
|
+
ok(!responder.ignoreTouchHandle({
|
100
|
+
target: { tagName: tag },
|
101
|
+
allowDefault: SC.K
|
102
|
+
}), "should NOT pass touch events through to <" + tag + ">s");
|
103
|
+
});
|
104
|
+
|
105
|
+
SC.browser.isMobileSafari = wasMobileSafari;
|
106
|
+
});
|
107
|
+
|
85
108
|
//// CLEANUP
|
86
109
|
/// Commenting out this two functions as the methods don't exist
|
87
110
|
//// confirm with Charles
|
@@ -4,22 +4,22 @@
|
|
4
4
|
// License: Licensed under MIT license (see license.js)
|
5
5
|
// ==========================================================================
|
6
6
|
/*globals module ok equals same test MyApp */
|
7
|
-
|
7
|
+
|
8
8
|
// test parsing of query string
|
9
9
|
var store, storeKey, rec1, rec2, rec3, rec4, rec5, MyApp, q;
|
10
10
|
module("SC.Query comparison of records", {
|
11
11
|
setup: function() {
|
12
|
-
|
12
|
+
|
13
13
|
SC.RunLoop.begin();
|
14
|
-
|
14
|
+
|
15
15
|
// setup dummy app and store
|
16
16
|
MyApp = SC.Object.create({
|
17
17
|
store: SC.Store.create()
|
18
18
|
});
|
19
|
-
|
19
|
+
|
20
20
|
// setup a dummy model
|
21
21
|
MyApp.Foo = SC.Record.extend({});
|
22
|
-
|
22
|
+
|
23
23
|
// load some data
|
24
24
|
MyApp.store.loadRecords(MyApp.Foo, [
|
25
25
|
{ guid: 1, firstName: "John", lastName: "Doe", year: 1974 },
|
@@ -28,9 +28,9 @@ module("SC.Query comparison of records", {
|
|
28
28
|
{ guid: 4, firstName: "Johnny", lastName: "Cash", active: false },
|
29
29
|
{ guid: 5, firstName: "Bert", lastName: "Berthold", active: true }
|
30
30
|
]);
|
31
|
-
|
31
|
+
|
32
32
|
SC.RunLoop.end();
|
33
|
-
|
33
|
+
|
34
34
|
rec1 = MyApp.store.find(MyApp.Foo,1);
|
35
35
|
rec2 = MyApp.store.find(MyApp.Foo,2);
|
36
36
|
rec3 = MyApp.store.find(MyApp.Foo,3);
|
@@ -51,42 +51,42 @@ module("SC.Query comparison of records", {
|
|
51
51
|
rec18 = MyApp.store.createRecord(MyApp.Foo, { firstName: "Amie", lastName: "Frontenac", active: true });
|
52
52
|
rec19 = MyApp.store.createRecord(MyApp.Foo, { firstName: "Amelie", lastName: "Auguste", active: true });
|
53
53
|
rec20 = MyApp.store.createRecord(MyApp.Foo, { firstName: "Percy", lastName: "Douglas", active: true });
|
54
|
-
|
54
|
+
|
55
55
|
q = SC.Query.create();
|
56
56
|
}
|
57
57
|
});
|
58
|
-
|
59
|
-
|
58
|
+
|
59
|
+
|
60
60
|
// ..........................................................
|
61
61
|
// TESTS
|
62
|
-
//
|
62
|
+
//
|
63
63
|
|
64
64
|
test("parse() should work with conditions = null", function(){
|
65
65
|
q.parse();
|
66
66
|
});
|
67
|
-
|
67
|
+
|
68
68
|
test("building the order", function() {
|
69
69
|
// undefined orderBy
|
70
70
|
q.orderBy = null;
|
71
71
|
q.parse();
|
72
72
|
equals(q._order.length, 0, 'order should be empty');
|
73
|
-
|
73
|
+
|
74
74
|
// empty orderBy
|
75
75
|
q.orderBy = "";
|
76
76
|
q.parse();
|
77
77
|
equals(q._order.length, 0, 'order should be empty');
|
78
|
-
|
78
|
+
|
79
79
|
// single property
|
80
80
|
q.orderBy = "firstName";
|
81
81
|
q.parse();
|
82
82
|
equals(q._order[0].propertyName,'firstName', 'propertyName should be firstName');
|
83
|
-
|
83
|
+
|
84
84
|
// more properties
|
85
85
|
q.orderBy = "lastName, firstName";
|
86
86
|
q.parse();
|
87
87
|
equals(q._order[0].propertyName,'lastName', 'propertyName should be lastName');
|
88
88
|
equals(q._order[1].propertyName,'firstName', 'propertyName should be firstName');
|
89
|
-
|
89
|
+
|
90
90
|
// more properties with direction
|
91
91
|
q.orderBy = "lastName, firstName, year DESC";
|
92
92
|
q.parse();
|
@@ -102,6 +102,8 @@ test("no order should result in comparison by guid", function() {
|
|
102
102
|
q.orderBy = null;
|
103
103
|
q.parse();
|
104
104
|
equals(q.compare(rec1,rec2), -1, 'guid 1 should be before guid 2');
|
105
|
+
});
|
106
|
+
|
105
107
|
/**
|
106
108
|
This test was added to prove new code that switched from ordering by guid
|
107
109
|
if there is no orderBy property on the query to ordering by storeKey if
|
@@ -147,34 +149,34 @@ test("comparing non existent properties", function() {
|
|
147
149
|
q.parse();
|
148
150
|
equals(q.compare(rec5,rec1), -1, 'null should be before 1974');
|
149
151
|
});
|
150
|
-
|
152
|
+
|
151
153
|
test("comparing null and boolean properties", function() {
|
152
154
|
q.orderBy = "active";
|
153
155
|
q.parse();
|
154
156
|
equals(q.compare(rec3,rec4), -1, 'null should be before false');
|
155
157
|
equals(q.compare(rec4,rec5), -1, 'false should be before true');
|
156
158
|
});
|
157
|
-
|
159
|
+
|
158
160
|
test("comparing number properties", function() {
|
159
161
|
q.orderBy = "year";
|
160
162
|
q.parse();
|
161
163
|
equals(q.compare(rec1,rec2), -1, '1974 should be before 1975');
|
162
|
-
|
164
|
+
|
163
165
|
q.orderBy = "year DESC";
|
164
166
|
q.parse();
|
165
167
|
equals(q.compare(rec1,rec2), 1, '1974 should be after 1975 with DESC');
|
166
|
-
});
|
167
|
-
|
168
|
-
|
168
|
+
});
|
169
|
+
|
170
|
+
|
169
171
|
test("comparing string properties", function() {
|
170
172
|
q.orderBy = "firstName";
|
171
173
|
q.parse();
|
172
174
|
equals(q.compare(rec1,rec2), 1, 'John should be after Jane');
|
173
|
-
|
175
|
+
|
174
176
|
q.orderBy = "firstName DESC";
|
175
177
|
q.parse();
|
176
178
|
equals(q.compare(rec1,rec2), -1, 'John should be before Jane with DESC');
|
177
|
-
});
|
179
|
+
});
|
178
180
|
|
179
181
|
test("comparing by equal properties should use guid for order", function() {
|
180
182
|
q.orderBy = "lastName";
|
@@ -5,9 +5,9 @@
|
|
5
5
|
// License: Licensed under MIT license (see license.js)
|
6
6
|
// ==========================================================================
|
7
7
|
|
8
|
-
/**
|
8
|
+
/**
|
9
9
|
@namespace
|
10
|
-
|
10
|
+
|
11
11
|
An experimental `CollectionView` mixin that makes it extremely fast under
|
12
12
|
certain circumstances, including for mobile devices.
|
13
13
|
*/
|
@@ -19,12 +19,12 @@ SC.CollectionFastPath = {
|
|
19
19
|
initMixin: function() {
|
20
20
|
this._indexMap = {};
|
21
21
|
},
|
22
|
-
|
22
|
+
|
23
23
|
/**
|
24
24
|
Returns the pool for a given example view.
|
25
|
-
|
25
|
+
|
26
26
|
The pool is calculated based on the guid for the example view class.
|
27
|
-
|
27
|
+
|
28
28
|
@param {SC.View} exampleView
|
29
29
|
*/
|
30
30
|
poolForExampleView: function(exampleView) {
|
@@ -32,31 +32,31 @@ SC.CollectionFastPath = {
|
|
32
32
|
if (!this[poolKey]) this[poolKey] = [];
|
33
33
|
return this[poolKey];
|
34
34
|
},
|
35
|
-
|
35
|
+
|
36
36
|
/**
|
37
37
|
Creates an item view from a given example view, configuring it with basic settings
|
38
38
|
and the supplied attributes.
|
39
|
-
|
39
|
+
|
40
40
|
@param {SC.View} exampleView
|
41
41
|
@param {Hash} attrs
|
42
42
|
*/
|
43
43
|
createItemViewFromExampleView: function(exampleView, attrs) {
|
44
44
|
// create the example view
|
45
45
|
var ret = this.createItemView(exampleView, null, attrs);
|
46
|
-
|
46
|
+
|
47
47
|
// for our pooling, if it is poolable, mark the view as poolable and
|
48
48
|
// give it a reference to its pool.
|
49
49
|
if (ret.isPoolable) {
|
50
50
|
ret.owningPool = this.poolForExampleView(exampleView);
|
51
51
|
}
|
52
|
-
|
52
|
+
|
53
53
|
// we will sometimes need to know what example view created the item view
|
54
54
|
ret.createdFromExampleView = exampleView;
|
55
55
|
|
56
56
|
// and now, return (duh)
|
57
57
|
return ret;
|
58
58
|
},
|
59
|
-
|
59
|
+
|
60
60
|
/**
|
61
61
|
@param {SC.View} itemView
|
62
62
|
@param {Hash} attrs
|
@@ -78,7 +78,7 @@ SC.CollectionFastPath = {
|
|
78
78
|
itemView.setIfChanged('page', this.page);
|
79
79
|
itemView.endPropertyChanges();
|
80
80
|
},
|
81
|
-
|
81
|
+
|
82
82
|
/**
|
83
83
|
Configures a pooled view, calling `.awakeFromPool` if it is defined.
|
84
84
|
|
@@ -88,15 +88,15 @@ SC.CollectionFastPath = {
|
|
88
88
|
wakePooledView: function(itemView, attrs) {
|
89
89
|
// configure
|
90
90
|
this.configureItemView(itemView, attrs);
|
91
|
-
|
91
|
+
|
92
92
|
// awake from the pool, etc.
|
93
93
|
if (itemView.awakeFromPool) itemView.awakeFromPool(itemView.owningPool, this);
|
94
94
|
},
|
95
|
-
|
95
|
+
|
96
96
|
/**
|
97
97
|
Gets an item view from an example view, from a pool if possible, and otherwise
|
98
98
|
by generating it.
|
99
|
-
|
99
|
+
|
100
100
|
@param {SC.View} exampleView
|
101
101
|
@param {Hash} attrs
|
102
102
|
*/
|
@@ -104,7 +104,7 @@ SC.CollectionFastPath = {
|
|
104
104
|
// we will try to get it from a pool. This will fill ret. If ret is not
|
105
105
|
// filled, then we'll know to generate one.
|
106
106
|
var ret;
|
107
|
-
|
107
|
+
|
108
108
|
// if it is poolable, we just grab from the pool.
|
109
109
|
if (exampleView.prototype.isPoolable) {
|
110
110
|
var pool = this.poolForExampleView(exampleView);
|
@@ -113,18 +113,18 @@ SC.CollectionFastPath = {
|
|
113
113
|
this.wakePooledView(ret, attrs);
|
114
114
|
}
|
115
115
|
}
|
116
|
-
|
116
|
+
|
117
117
|
if (!ret) {
|
118
118
|
ret = this.createItemViewFromExampleView(exampleView, attrs);
|
119
119
|
}
|
120
|
-
|
120
|
+
|
121
121
|
return ret;
|
122
122
|
},
|
123
|
-
|
123
|
+
|
124
124
|
/**
|
125
125
|
Releases an item view. If the item view is pooled, it puts it into the pool;
|
126
126
|
otherwise, this calls `.destroy()`.
|
127
|
-
|
127
|
+
|
128
128
|
This is called for one of two purposes: to release a view that is no longer displaying,
|
129
129
|
or to release an older cached version of a view that needed to be replaced because the
|
130
130
|
example view changed.
|
@@ -137,30 +137,30 @@ SC.CollectionFastPath = {
|
|
137
137
|
itemView.destroy();
|
138
138
|
return;
|
139
139
|
}
|
140
|
-
|
140
|
+
|
141
141
|
// otherwise, we need to return to view
|
142
142
|
var pool = itemView.owningPool;
|
143
143
|
pool.push(itemView);
|
144
144
|
if (itemView.hibernateInPool) itemView.hibernateInPool(pool, this);
|
145
145
|
},
|
146
|
-
|
146
|
+
|
147
147
|
/** @private
|
148
148
|
Returns YES if the item at the index is a group.
|
149
149
|
*/
|
150
150
|
contentIndexIsGroup: function(view, content, index) {
|
151
151
|
var contentDelegate = this.get("contentDelegate");
|
152
|
-
|
152
|
+
|
153
153
|
// setup our properties
|
154
154
|
var groupIndexes = this.get('_contentGroupIndexes'), isGroupView = NO;
|
155
|
-
|
155
|
+
|
156
156
|
// and do our checking
|
157
157
|
isGroupView = groupIndexes && groupIndexes.contains(index);
|
158
158
|
if (isGroupView) isGroupView = contentDelegate.contentIndexIsGroup(this, this.get("content"), index);
|
159
|
-
|
159
|
+
|
160
160
|
// and return
|
161
161
|
return isGroupView;
|
162
162
|
},
|
163
|
-
|
163
|
+
|
164
164
|
/** @private
|
165
165
|
Determines the example view for a content index. There are two optional parameters that will
|
166
166
|
speed things up: `contentObject` and `isGroupView`. If you don't supply them, they must be computed.
|
@@ -182,24 +182,24 @@ SC.CollectionFastPath = {
|
|
182
182
|
if (key && item) ExampleView = item.get(key);
|
183
183
|
if (!ExampleView) ExampleView = this.get('exampleView');
|
184
184
|
}
|
185
|
-
|
185
|
+
|
186
186
|
return ExampleView;
|
187
187
|
},
|
188
|
-
|
188
|
+
|
189
189
|
/** @private
|
190
190
|
This may seem somewhat awkward, but it is for memory performance: this fills in a hash
|
191
191
|
YOU provide with the properties for the given content index.
|
192
|
-
|
192
|
+
|
193
193
|
Properties include both the attributes given to the view and some `CollectionView` tracking
|
194
194
|
properties, most importantly the exampleView.
|
195
195
|
*/
|
196
196
|
setAttributesForItem: function(item, index, attrs) {
|
197
|
-
var del = this.get('contentDelegate'),
|
197
|
+
var del = this.get('contentDelegate'),
|
198
198
|
isGroupView = this.contentIndexIsGroup(this, this.get('content'), index),
|
199
199
|
ExampleView = this.exampleViewForItem(item, index),
|
200
200
|
content = this.get("content");
|
201
|
-
|
202
|
-
//
|
201
|
+
|
202
|
+
//
|
203
203
|
// FIGURE OUT "NORMAL" ATTRIBUTES
|
204
204
|
//
|
205
205
|
attrs.createdFromExampleView = ExampleView;
|
@@ -218,11 +218,11 @@ SC.CollectionFastPath = {
|
|
218
218
|
attrs.layout = this.layoutForContentIndex(index);
|
219
219
|
if (!attrs.layout) attrs.layout = ExampleView.prototype.layout;
|
220
220
|
},
|
221
|
-
|
221
|
+
|
222
222
|
//
|
223
223
|
// ITEM LOADING/DOM MANAGEMENT
|
224
224
|
//
|
225
|
-
|
225
|
+
|
226
226
|
/** @private
|
227
227
|
Returns mapped item views for the supplied item.
|
228
228
|
*/
|
@@ -230,9 +230,9 @@ SC.CollectionFastPath = {
|
|
230
230
|
if (!map) map = this._viewMap;
|
231
231
|
return map[SC.guidFor(item)];
|
232
232
|
},
|
233
|
-
|
233
|
+
|
234
234
|
/** @private
|
235
|
-
Returns the mapped view for an item at the specified index.
|
235
|
+
Returns the mapped view for an item at the specified index.
|
236
236
|
*/
|
237
237
|
mappedViewForItem: function(item, idx, map) {
|
238
238
|
if (!map) map = this._viewMap;
|
@@ -240,24 +240,24 @@ SC.CollectionFastPath = {
|
|
240
240
|
if (!m) return undefined;
|
241
241
|
return m[idx];
|
242
242
|
},
|
243
|
-
|
243
|
+
|
244
244
|
/** @private
|
245
245
|
Maps a view to an item/index combination.
|
246
246
|
*/
|
247
247
|
mapView: function(item, index, view, map) {
|
248
248
|
// get the default view map if a map was not supplied
|
249
249
|
if (!map) map = this._viewMap;
|
250
|
-
|
250
|
+
|
251
251
|
// get the item map
|
252
252
|
var g = SC.guidFor(item),
|
253
253
|
imap = map[g];
|
254
254
|
if (!imap) imap = map[g] = {_length: 0};
|
255
|
-
|
255
|
+
|
256
256
|
// fill in the index
|
257
257
|
imap[index] = view;
|
258
258
|
imap._length++;
|
259
259
|
},
|
260
|
-
|
260
|
+
|
261
261
|
/** @private
|
262
262
|
Unmaps a view from an item/index combination.
|
263
263
|
*/
|
@@ -265,20 +265,20 @@ SC.CollectionFastPath = {
|
|
265
265
|
if (!map) map = this._viewMap;
|
266
266
|
var g = SC.guidFor(item),
|
267
267
|
imap = map[g];
|
268
|
-
|
268
|
+
|
269
269
|
// return if there is nothing to do
|
270
270
|
if (!imap) return;
|
271
|
-
|
271
|
+
|
272
272
|
// remove
|
273
273
|
if (imap[index]) {
|
274
274
|
var v = imap[index];
|
275
275
|
delete imap[index];
|
276
|
-
|
276
|
+
|
277
277
|
imap._length--;
|
278
278
|
if (imap._length <= 0) delete map[g];
|
279
279
|
}
|
280
280
|
},
|
281
|
-
|
281
|
+
|
282
282
|
/**
|
283
283
|
Returns the item view for the given content index.
|
284
284
|
NOTE: THIS WILL ADD THE VIEW TO DOM TEMPORARILY (it will be cleaned if
|
@@ -289,53 +289,52 @@ SC.CollectionFastPath = {
|
|
289
289
|
itemViewForContentIndex: function(index) {
|
290
290
|
var content = this.get("content");
|
291
291
|
if (!content) return;
|
292
|
-
|
292
|
+
|
293
293
|
var item = content.objectAt(index);
|
294
|
-
|
295
|
-
|
294
|
+
|
296
295
|
var exampleView = this.exampleViewForItem(item, index),
|
297
296
|
view = this._indexMap[index];
|
298
|
-
|
297
|
+
|
299
298
|
if (view && view.createdFromExampleView !== exampleView) {
|
300
299
|
this.removeItemView(view);
|
301
300
|
this.unmapView(item, index);
|
302
301
|
view = null;
|
303
302
|
}
|
304
|
-
|
303
|
+
|
305
304
|
if (!view) {
|
306
305
|
view = this.addItemView(exampleView, item, index);
|
307
306
|
}
|
308
|
-
|
307
|
+
|
309
308
|
return view;
|
310
309
|
},
|
311
|
-
|
310
|
+
|
312
311
|
/** @private
|
313
312
|
Returns the nearest item view index to the supplied index mapped to the item.
|
314
313
|
*/
|
315
314
|
nearestMappedViewIndexForItem: function(item, index, map) {
|
316
315
|
var m = this.mappedViewsForItem(item, map);
|
317
316
|
if (!m) return null;
|
318
|
-
|
317
|
+
|
319
318
|
// keep track of nearest and the nearest distance
|
320
319
|
var nearest = null, ndist = -1, dist = 0;
|
321
|
-
|
320
|
+
|
322
321
|
// loop through
|
323
322
|
for (var idx in m) {
|
324
323
|
idx = parseInt(idx, 10);
|
325
324
|
if (isNaN(idx)) continue;
|
326
325
|
// get distance
|
327
326
|
dist = Math.abs(index - idx);
|
328
|
-
|
327
|
+
|
329
328
|
// compare to nearest distance
|
330
329
|
if (ndist < 0 || dist < ndist) {
|
331
330
|
ndist = dist;
|
332
331
|
nearest = idx;
|
333
332
|
}
|
334
333
|
}
|
335
|
-
|
334
|
+
|
336
335
|
return nearest;
|
337
336
|
},
|
338
|
-
|
337
|
+
|
339
338
|
/** @private
|
340
339
|
Remaps the now showing views to their new indexes (if they have moved).
|
341
340
|
*/
|
@@ -353,11 +352,11 @@ SC.CollectionFastPath = {
|
|
353
352
|
// first, find items which we can (that already exist, etc.)
|
354
353
|
nowShowing.forEach(function(idx) {
|
355
354
|
item = content.objectAt(idx);
|
356
|
-
|
355
|
+
|
357
356
|
// determine if we have view(s) in the old map for the item
|
358
357
|
var possibleExistingViews = this.mappedViewsForItem(item, oldMap);
|
359
358
|
if (possibleExistingViews) {
|
360
|
-
|
359
|
+
|
361
360
|
// if it is the same index, we just take it. End of story.
|
362
361
|
if (possibleExistingViews[idx]) {
|
363
362
|
var v = possibleExistingViews[idx];
|
@@ -373,14 +372,14 @@ SC.CollectionFastPath = {
|
|
373
372
|
itemsToAdd.push(idx);
|
374
373
|
}
|
375
374
|
}, this);
|
376
|
-
|
375
|
+
|
377
376
|
// now there are also some items which _could_ exist (but might not!)
|
378
377
|
for (var idx = 0, len = mayExist.length; idx < len; idx++) {
|
379
378
|
var newIdx = mayExist[idx];
|
380
379
|
item = content.objectAt(newIdx);
|
381
380
|
var nearestOldIndex = this.nearestMappedViewIndexForItem(item, newIdx, oldMap),
|
382
381
|
nearestView;
|
383
|
-
|
382
|
+
|
384
383
|
if (!SC.none(nearestOldIndex)) {
|
385
384
|
nearestView = this.mappedViewForItem(item, nearestOldIndex, oldMap);
|
386
385
|
var newExampleView = this.exampleViewForItem(item, newIdx);
|
@@ -397,10 +396,10 @@ SC.CollectionFastPath = {
|
|
397
396
|
itemsToAdd.push(newIdx);
|
398
397
|
}
|
399
398
|
}
|
400
|
-
|
399
|
+
|
401
400
|
return oldMap;
|
402
401
|
},
|
403
|
-
|
402
|
+
|
404
403
|
/**
|
405
404
|
Reloads.
|
406
405
|
|
@@ -409,57 +408,57 @@ SC.CollectionFastPath = {
|
|
409
408
|
*/
|
410
409
|
reloadIfNeeded: function(nowShowing, scrollOnly) {
|
411
410
|
var content = this.get("content"), invalid;
|
412
|
-
|
411
|
+
|
413
412
|
// we use the nowShowing to determine what should and should not be showing.
|
414
413
|
if (!nowShowing || !nowShowing.isIndexSet) nowShowing = this.get('nowShowing');
|
415
|
-
|
414
|
+
|
416
415
|
// we only update if this is a non-scrolling update.
|
417
416
|
// don't worry: we'll actually update after the fact, and the invalid indexes should
|
418
417
|
// be queued up nicely.
|
419
418
|
if (!scrollOnly) {
|
420
419
|
invalid = this._invalidIndexes;
|
421
420
|
if (!invalid || !this.get('isVisibleInWindow')) return this;
|
422
|
-
this._invalidIndexes = NO;
|
423
|
-
|
421
|
+
this._invalidIndexes = NO;
|
422
|
+
|
424
423
|
// tell others we will be reloading
|
425
424
|
if (invalid.isIndexSet && invalid.contains(nowShowing)) invalid = YES ;
|
426
425
|
if (this.willReload) this.willReload(invalid === YES ? null : invalid);
|
427
426
|
}
|
428
|
-
|
427
|
+
|
429
428
|
// get arrays of items to add/remove
|
430
429
|
var itemsToAdd = this._itemsToAdd || (this._itemsToAdd = []);
|
431
|
-
|
430
|
+
|
432
431
|
// remap
|
433
432
|
var oldMap = this.remapItemViews(nowShowing);
|
434
|
-
|
433
|
+
|
435
434
|
// The oldMap has the items to remove, so supply it to processRemovals
|
436
435
|
this.processRemovals(oldMap);
|
437
|
-
|
436
|
+
|
438
437
|
// handle the invalid set (if it is present)
|
439
438
|
if (invalid) {
|
440
439
|
this.processUpdates(invalid === YES ? nowShowing : invalid);
|
441
440
|
}
|
442
|
-
|
441
|
+
|
443
442
|
// process items to add
|
444
443
|
this.processAdds();
|
445
|
-
|
444
|
+
|
446
445
|
// only clear the DOM pools if this is not during scrolling. Adding/removing is a
|
447
446
|
// bad idea while scrolling :)
|
448
447
|
if (!scrollOnly) this.clearDOMPools();
|
449
|
-
|
448
|
+
|
450
449
|
// clear the lists
|
451
450
|
itemsToAdd.length = 0;
|
452
|
-
|
451
|
+
|
453
452
|
// and if this is a full reload, we need to adjust layout
|
454
453
|
if (!scrollOnly) {
|
455
454
|
var layout = this.computeLayout();
|
456
455
|
if (layout) this.adjust(layout);
|
457
456
|
if (this.didReload) this.didReload(invalid === YES ? null : invalid);
|
458
457
|
}
|
459
|
-
|
458
|
+
|
460
459
|
return this;
|
461
460
|
},
|
462
|
-
|
461
|
+
|
463
462
|
/**
|
464
463
|
Loops through remove queue and removes.
|
465
464
|
|
@@ -472,17 +471,17 @@ SC.CollectionFastPath = {
|
|
472
471
|
for (var itemIdx in imap) {
|
473
472
|
itemIdx = parseInt(itemIdx, 10);
|
474
473
|
if (isNaN(itemIdx)) continue;
|
475
|
-
|
474
|
+
|
476
475
|
var view = imap[itemIdx];
|
477
|
-
|
476
|
+
|
478
477
|
if (this._indexMap[itemIdx] === view) delete this._indexMap[itemIdx];
|
479
|
-
|
478
|
+
|
480
479
|
view._isInCollection = NO;
|
481
480
|
this.removeItemView(view);
|
482
481
|
}
|
483
482
|
}
|
484
483
|
},
|
485
|
-
|
484
|
+
|
486
485
|
/** @private
|
487
486
|
Loops through update queue and... updates.
|
488
487
|
*/
|
@@ -497,23 +496,23 @@ SC.CollectionFastPath = {
|
|
497
496
|
}
|
498
497
|
}, this);
|
499
498
|
},
|
500
|
-
|
499
|
+
|
501
500
|
/** @private
|
502
501
|
Loops through add queue and, well, adds.
|
503
502
|
*/
|
504
503
|
processAdds: function() {
|
505
504
|
var content = this.get("content");
|
506
|
-
|
505
|
+
|
507
506
|
var add = this._itemsToAdd, idx, len = add.length, itemIdx, item;
|
508
507
|
for (idx = 0; idx < len; idx++) {
|
509
508
|
itemIdx = add[idx]; item = content.objectAt(itemIdx);
|
510
|
-
|
509
|
+
|
511
510
|
// get example view and create item view
|
512
511
|
var exampleView = this.exampleViewForItem(item, itemIdx);
|
513
512
|
var view = this.addItemView(exampleView, item, itemIdx);
|
514
513
|
}
|
515
514
|
},
|
516
|
-
|
515
|
+
|
517
516
|
/** @private
|
518
517
|
Clear all DOM pools.
|
519
518
|
*/
|
@@ -523,34 +522,34 @@ SC.CollectionFastPath = {
|
|
523
522
|
this.clearDOMPool(pools[p]);
|
524
523
|
}
|
525
524
|
},
|
526
|
-
|
525
|
+
|
527
526
|
/**
|
528
527
|
@type Number
|
529
528
|
@default 10
|
530
529
|
*/
|
531
530
|
domPoolSize: 10,
|
532
|
-
|
531
|
+
|
533
532
|
/** @private
|
534
533
|
Clears a specific DOM pool.
|
535
534
|
*/
|
536
535
|
clearDOMPool: function(pool) {
|
537
536
|
var idx, len = pool.length, item;
|
538
|
-
|
537
|
+
|
539
538
|
// we skip one because there is a buffer area of one while scrolling
|
540
539
|
for (idx = this.domPoolSize; idx < len; idx++) {
|
541
540
|
item = pool[idx];
|
542
541
|
|
543
542
|
// remove from DOM
|
544
543
|
this.removeChild(item);
|
545
|
-
|
544
|
+
|
546
545
|
// release the item
|
547
546
|
this.releaseItemView(item);
|
548
547
|
}
|
549
|
-
|
548
|
+
|
550
549
|
// pool is cleared.
|
551
550
|
pool.length = Math.min(pool.length, this.domPoolSize);
|
552
551
|
},
|
553
|
-
|
552
|
+
|
554
553
|
/** @private
|
555
554
|
Returns the DOM pool for the given exampleView.
|
556
555
|
*/
|
@@ -560,7 +559,7 @@ SC.CollectionFastPath = {
|
|
560
559
|
if (!pool) pool = pools[guid] = [];
|
561
560
|
return pool;
|
562
561
|
},
|
563
|
-
|
562
|
+
|
564
563
|
/** @private
|
565
564
|
Tries to find an item for the given example view in a dom pool.
|
566
565
|
If one could not be found, returns `null`.
|
@@ -572,7 +571,7 @@ SC.CollectionFastPath = {
|
|
572
571
|
if (view.wakeFromDOMPool) view.wakeFromDOMPool();
|
573
572
|
return view;
|
574
573
|
},
|
575
|
-
|
574
|
+
|
576
575
|
/** @private
|
577
576
|
Sends a view to a DOM pool.
|
578
577
|
*/
|
@@ -584,48 +583,48 @@ SC.CollectionFastPath = {
|
|
584
583
|
view.set("layerId", SC.guidFor(view));
|
585
584
|
if (view.sleepInDOMPool) view.sleepInDOMPool();
|
586
585
|
},
|
587
|
-
|
586
|
+
|
588
587
|
/** @private
|
589
588
|
Adds an item view (grabbing the actual item from one of the pools if possible).
|
590
589
|
*/
|
591
590
|
addItemView: function(exampleView, object, index) {
|
592
591
|
var view, attrs = this._TMP_ATTRS || (this._TMP_ATTRS = {});
|
593
|
-
|
592
|
+
|
594
593
|
// in any case, we need attributes
|
595
594
|
this.setAttributesForItem(object, index, attrs);
|
596
|
-
|
595
|
+
|
597
596
|
// try to get from DOM pool first
|
598
597
|
if (view = this.itemFromDOMPool(exampleView)) {
|
599
598
|
// set attributes
|
600
599
|
this.configureItemView(view, attrs);
|
601
|
-
|
600
|
+
|
602
601
|
// set that it is in the collection
|
603
602
|
view._isInCollection = YES;
|
604
|
-
|
603
|
+
|
605
604
|
// add to view map (if not used, it will be removed)
|
606
605
|
this.mapView(object, index, view);
|
607
606
|
this._indexMap[index] = view;
|
608
|
-
|
607
|
+
|
609
608
|
// and that should have repositioned too
|
610
609
|
return view;
|
611
610
|
}
|
612
|
-
|
611
|
+
|
613
612
|
// otherwise, just allocate a view
|
614
613
|
view = this.allocateItemView(exampleView, attrs);
|
615
|
-
|
614
|
+
|
616
615
|
// and then, add it
|
617
616
|
this.appendChild(view);
|
618
|
-
|
617
|
+
|
619
618
|
// set that it is in the collection.
|
620
619
|
view._isInCollection = YES;
|
621
|
-
|
620
|
+
|
622
621
|
// add to view map (if not used, it will be removed)
|
623
622
|
this.mapView(object, index, view);
|
624
623
|
this._indexMap[index] = view;
|
625
|
-
|
624
|
+
|
626
625
|
return view;
|
627
626
|
},
|
628
|
-
|
627
|
+
|
629
628
|
/** @private
|
630
629
|
Removes an item view.
|
631
630
|
*/
|
@@ -637,11 +636,11 @@ SC.CollectionFastPath = {
|
|
637
636
|
}
|
638
637
|
current._isInCollection = NO;
|
639
638
|
},
|
640
|
-
|
639
|
+
|
641
640
|
/**
|
642
641
|
Updates the specified item view. If the view is not "layer cacheable" or the
|
643
642
|
example view has changed, it will be redrawn.
|
644
|
-
|
643
|
+
|
645
644
|
Otherwise, nothing will happen.
|
646
645
|
*/
|
647
646
|
updateItemView: function(current, exampleView, object, index) {
|
@@ -650,7 +649,7 @@ SC.CollectionFastPath = {
|
|
650
649
|
this.unmapView(current, index);
|
651
650
|
delete this._indexMap[index];
|
652
651
|
this.removeItemView(current, object, index);
|
653
|
-
|
652
|
+
|
654
653
|
// add new and map
|
655
654
|
var newView = this.addItemView(exampleView, object, index);
|
656
655
|
} else {
|
@@ -660,8 +659,8 @@ SC.CollectionFastPath = {
|
|
660
659
|
this.configureItemView(current, attrs);
|
661
660
|
}
|
662
661
|
},
|
663
|
-
|
664
|
-
|
662
|
+
|
663
|
+
|
665
664
|
/** @private
|
666
665
|
Tells `ScrollView` that this should receive live updates during touch scrolling.
|
667
666
|
We are so fast, aren't we?
|
@@ -673,39 +672,39 @@ SC.CollectionFastPath = {
|
|
673
672
|
|
674
673
|
/** @private */
|
675
674
|
_tolerance: 100,
|
676
|
-
|
675
|
+
|
677
676
|
/** @private */
|
678
677
|
touchScrollDidChange: function(left, top) {
|
679
678
|
// prevent getting too many in close succession.
|
680
679
|
if (Date.now() - this._lastTouchScrollTime < 25) return;
|
681
|
-
|
680
|
+
|
682
681
|
var clippingFrame = this.get('clippingFrame');
|
683
|
-
|
682
|
+
|
684
683
|
var cf = this._inScrollClippingFrame || (this._inScrollClippingFrame = {x: 0, y: 0, width: 0, height: 0});
|
685
684
|
cf.x = clippingFrame.x; cf.y = clippingFrame.y; cf.width = clippingFrame.width; cf.height = clippingFrame.height;
|
686
|
-
|
685
|
+
|
687
686
|
// update
|
688
687
|
cf.x = left;
|
689
688
|
cf.y = top;
|
690
|
-
|
689
|
+
|
691
690
|
var r = this.contentIndexesInRect(cf);
|
692
691
|
if (!r) return; // no rect, do nothing.
|
693
|
-
|
694
|
-
var len = this.get('length'),
|
692
|
+
|
693
|
+
var len = this.get('length'),
|
695
694
|
max = r.get('max'), min = r.get('min');
|
696
695
|
|
697
696
|
if (max > len || min < 0) {
|
698
697
|
r = r.copy();
|
699
698
|
r.remove(len, max-len).remove(min, 0-min).freeze();
|
700
699
|
}
|
701
|
-
|
700
|
+
|
702
701
|
if (this._lastNowShowing) {
|
703
702
|
if (r.contains(this._lastNowShowing) && this._lastNowShowing.contains(r)) return;
|
704
703
|
}
|
705
704
|
this._lastNowShowing = r;
|
706
705
|
this.reloadIfNeeded(r, YES);
|
707
|
-
|
706
|
+
|
708
707
|
this._lastTouchScrollTime = Date.now();
|
709
708
|
}
|
710
|
-
|
709
|
+
|
711
710
|
};
|