sproutcore 0.9.14 → 0.9.15
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/History.txt +43 -0
- data/Manifest.txt +12 -3
- data/bin/sc-build +19 -3
- data/bin/sc-install +5 -0
- data/bin/sc-remove +5 -0
- data/bin/sc-update +5 -0
- data/frameworks/prototype/prototype.js +267 -230
- data/frameworks/sproutcore/HISTORY +281 -135
- data/frameworks/sproutcore/controllers/array.js +133 -22
- data/frameworks/sproutcore/controllers/collection.js +4 -5
- data/frameworks/sproutcore/controllers/object.js +8 -2
- data/frameworks/sproutcore/core.js +361 -159
- data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
- data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +2 -2
- data/frameworks/sproutcore/foundation/application.js +6 -1
- data/frameworks/sproutcore/foundation/benchmark.js +37 -11
- data/frameworks/sproutcore/foundation/date.js +1 -1
- data/frameworks/sproutcore/foundation/enumerator.js +105 -0
- data/frameworks/sproutcore/foundation/object.js +19 -20
- data/frameworks/sproutcore/foundation/responder.js +1 -1
- data/frameworks/sproutcore/foundation/set.js +164 -57
- data/frameworks/sproutcore/foundation/string.js +151 -47
- data/frameworks/sproutcore/foundation/utils.js +84 -3
- data/frameworks/sproutcore/lib/collection_view.rb +1 -0
- data/frameworks/sproutcore/license.js +28 -0
- data/frameworks/sproutcore/mixins/array.js +73 -209
- data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
- data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
- data/frameworks/sproutcore/mixins/observable.js +153 -84
- data/frameworks/sproutcore/mixins/selection_support.js +13 -1
- data/frameworks/sproutcore/models/record.js +74 -27
- data/frameworks/sproutcore/models/store.js +7 -3
- data/frameworks/sproutcore/server/rails_server.js +82 -0
- data/frameworks/sproutcore/server/rest_server.js +178 -0
- data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
- data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
- data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
- data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
- data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
- data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
- data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
- data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
- data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
- data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
- data/frameworks/sproutcore/validators/date.js +1 -7
- data/frameworks/sproutcore/views/collection/collection.js +7 -2
- data/frameworks/sproutcore/views/list_item.js +141 -3
- data/frameworks/sproutcore/views/split.js +14 -11
- data/frameworks/sproutcore/views/view.js +9 -6
- data/lib/sproutcore/build_tools/html_builder.rb +19 -3
- data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
- data/lib/sproutcore/bundle.rb +21 -0
- data/lib/sproutcore/bundle_manifest.rb +64 -20
- data/lib/sproutcore/helpers/capture_helper.rb +2 -2
- data/lib/sproutcore/library.rb +33 -9
- data/lib/sproutcore/merb/bundle_controller.rb +16 -5
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +1 -1
- data/{sc-config.rb → sc-config} +5 -2
- metadata +24 -5
@@ -81,7 +81,7 @@ SC.Benchmark = {
|
|
81
81
|
@param key {String} The benchmark key you used when you called start()
|
82
82
|
@param time {Integer} Only pass if you want to explicitly set the end time. Otherwise start time is now.
|
83
83
|
*/
|
84
|
-
end: function(key, time) {
|
84
|
+
end: function(key, time, runs) {
|
85
85
|
if (!this.enabled) return ;
|
86
86
|
var stat = this._statFor(key) ;
|
87
87
|
var start = stat._starts.pop() ;
|
@@ -94,7 +94,7 @@ SC.Benchmark = {
|
|
94
94
|
if (start == 'ignore') return ;
|
95
95
|
|
96
96
|
stat.amt += (time || Date.now()) - start ;
|
97
|
-
stat.runs
|
97
|
+
stat.runs += (runs || 1) ;
|
98
98
|
|
99
99
|
if (this.verbose) this.log(key) ;
|
100
100
|
},
|
@@ -104,16 +104,17 @@ SC.Benchmark = {
|
|
104
104
|
run with the name you provide the number of times you indicate. Only the
|
105
105
|
function is a required param.
|
106
106
|
*/
|
107
|
-
bench: function(func, key, reps) {
|
107
|
+
bench: function(func, key, reps, context) {
|
108
108
|
if (!key) key = "bench%@".fmt(this._benchCount++) ;
|
109
109
|
if (!reps) reps = 1 ;
|
110
110
|
var ret ;
|
111
111
|
|
112
|
+
var runs = reps;
|
113
|
+
SC.Benchmark.start(key) ;
|
112
114
|
while(--reps >= 0) {
|
113
|
-
|
114
|
-
ret = func();
|
115
|
-
SC.Benchmark.end(key) ;
|
115
|
+
ret = func(context);
|
116
116
|
}
|
117
|
+
SC.Benchmark.end(key, null, runs) ;
|
117
118
|
|
118
119
|
return ret ;
|
119
120
|
},
|
@@ -129,7 +130,7 @@ SC.Benchmark = {
|
|
129
130
|
|
130
131
|
// replace with this helper.
|
131
132
|
object[method] = function() {
|
132
|
-
var key = '%@(%@)'.fmt(method,
|
133
|
+
var key = '%@(%@)'.fmt(method, SC.$A(arguments).join(', ')) ;
|
133
134
|
SC.Benchmark.start(key, topLevelOnly) ;
|
134
135
|
var ret = __func.apply(this, arguments) ;
|
135
136
|
SC.Benchmark.end(key) ;
|
@@ -156,9 +157,24 @@ SC.Benchmark = {
|
|
156
157
|
report: function(key) {
|
157
158
|
if (key) return this._genReport(key) ;
|
158
159
|
var ret = [] ;
|
160
|
+
|
161
|
+
// find the longest stat name...
|
162
|
+
var maxLen = 0 ;
|
163
|
+
for(var key in this.stats) {
|
164
|
+
if (!this.stats.hasOwnProperty(key)) continue ;
|
165
|
+
if (key.length > maxLen) maxLen = key.length;
|
166
|
+
}
|
167
|
+
|
168
|
+
// now gen report...
|
169
|
+
var keys = [] ;
|
159
170
|
for(var key in this.stats) {
|
160
171
|
if (!this.stats.hasOwnProperty(key)) continue ;
|
161
|
-
|
172
|
+
keys.push(key) ;
|
173
|
+
}
|
174
|
+
keys = keys.sort() ;
|
175
|
+
var max = keys.length ;
|
176
|
+
for(var idx=0;idx<max;idx++) {
|
177
|
+
ret.push(this._genReport(keys[idx], maxLen)) ;
|
162
178
|
}
|
163
179
|
return ret.join("\n") ;
|
164
180
|
},
|
@@ -187,11 +203,21 @@ SC.Benchmark = {
|
|
187
203
|
|
188
204
|
// PRIVATE METHODS
|
189
205
|
|
190
|
-
_genReport: function(key) {
|
206
|
+
_genReport: function(key, nameLength) {
|
191
207
|
var stat = this._statFor(key) ;
|
192
|
-
var avg = (stat.runs > 0) ? (Math.floor(stat.amt *
|
208
|
+
var avg = (stat.runs > 0) ? (Math.floor(stat.amt * 100000 / stat.runs) / 100000) : 0 ;
|
193
209
|
|
194
|
-
|
210
|
+
// Generate the name, adding padding spaces if needed.
|
211
|
+
var name = (stat.name || key) ;
|
212
|
+
nameLength = (nameLength) ? nameLength : 0;
|
213
|
+
if (nameLength > name.length) {
|
214
|
+
var toJoin = [name] ;
|
215
|
+
nameLength -= name.length ;
|
216
|
+
while(--nameLength >= 0) toJoin.push(' ') ;
|
217
|
+
name = toJoin.join('') ;
|
218
|
+
}
|
219
|
+
|
220
|
+
return 'BENCH | %@1 | avg: %@4 msec | total: %@2 msec | reps: %@3x '.fmt(name, stat.amt, stat.runs, avg) ;
|
195
221
|
},
|
196
222
|
|
197
223
|
// @private
|
@@ -290,7 +290,7 @@ Object.extend(Date,{
|
|
290
290
|
Object.extend(Date.prototype, {
|
291
291
|
|
292
292
|
// ------------------------------------------------------------------
|
293
|
-
// formatDate (date_object, format
|
293
|
+
// formatDate (date_object, format)
|
294
294
|
// Returns a date in the output format specified.
|
295
295
|
// The format string uses the same abbreviations as in getDateFromFormat()
|
296
296
|
//
|
@@ -0,0 +1,105 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// SproutCore -- JavaScript Application Framework
|
3
|
+
// copyright 2006-2008, Sprout Systems, Inc. and contributors.
|
4
|
+
// ==========================================================================
|
5
|
+
|
6
|
+
/**
|
7
|
+
@class
|
8
|
+
|
9
|
+
An object that iterates over all of the values in an object.
|
10
|
+
|
11
|
+
An instance of this object is returned everytime you call the
|
12
|
+
enumerator() method on an object that implements the SC.Enumerable mixin.
|
13
|
+
|
14
|
+
Once you create an enumerator instance, you can call nextObject() on it
|
15
|
+
until you can iterated through the entire collection. Once you have
|
16
|
+
exhausted the enumerator, you can reuse it if you want by calling reset().
|
17
|
+
|
18
|
+
@extends Object
|
19
|
+
@since SproutCore 1.0
|
20
|
+
*/
|
21
|
+
SC.Enumerator = function(enumerableObject) {
|
22
|
+
this.enumerable = enumerableObject ;
|
23
|
+
this.reset() ;
|
24
|
+
return this ;
|
25
|
+
} ;
|
26
|
+
|
27
|
+
SC.Enumerator.prototype = {
|
28
|
+
|
29
|
+
/**
|
30
|
+
Returns the next object in the enumeration or undefined when complete.
|
31
|
+
|
32
|
+
@returns {Object} the next object or undefined
|
33
|
+
*/
|
34
|
+
nextObject: function() {
|
35
|
+
var index = this._index ;
|
36
|
+
var len = this._length;
|
37
|
+
if (index >= len) return undefined ; // nothing to do
|
38
|
+
|
39
|
+
// get the value
|
40
|
+
var ret = this.enumerable.nextObject(index, this._previousObject, this._context) ;
|
41
|
+
this._previousObject = ret ;
|
42
|
+
this._index = index + 1 ;
|
43
|
+
|
44
|
+
if (index >= len) {
|
45
|
+
this._context = SC.Enumerator._pushContext(this._context);
|
46
|
+
}
|
47
|
+
|
48
|
+
return ret ;
|
49
|
+
},
|
50
|
+
|
51
|
+
/**
|
52
|
+
Resets the enumerator to the beginning. This is a nice way to reuse
|
53
|
+
an existing enumerator.
|
54
|
+
|
55
|
+
@returns {Object} this
|
56
|
+
*/
|
57
|
+
reset: function() {
|
58
|
+
var e = this.enumerable ;
|
59
|
+
if (!e) throw $error("Enumerator has been destroyed");
|
60
|
+
|
61
|
+
var len = this._length = (e.get) ? e.get('length') : e.length ;
|
62
|
+
this._index = 0;
|
63
|
+
this._previousObject = null ;
|
64
|
+
this._context = (len > 0) ? SC.Enumerator._popContext() : null;
|
65
|
+
},
|
66
|
+
|
67
|
+
/**
|
68
|
+
Releases the enumerators enumerable object. You cannot use this object
|
69
|
+
anymore. This is not often needed but it is useful when you need to
|
70
|
+
make sure memory gets cleared.
|
71
|
+
|
72
|
+
@returns {Object} null
|
73
|
+
*/
|
74
|
+
destroy: function() {
|
75
|
+
this.enumerable = this._length = this._index = this._previousObject = this._context = null;
|
76
|
+
}
|
77
|
+
|
78
|
+
} ;
|
79
|
+
|
80
|
+
/**
|
81
|
+
Use this method to manually create a new Enumerator object. Usually you
|
82
|
+
will not access this method directly but instead call enumerator() on the
|
83
|
+
item you want to enumerate.
|
84
|
+
|
85
|
+
@param {SC.Enumerable} The enumerable object.
|
86
|
+
@returns {SC.Enumerator} the enumerator
|
87
|
+
*/
|
88
|
+
SC.Enumerator.create = function(enumerableObject) {
|
89
|
+
return new SC.Enumerator(enumerableObject) ;
|
90
|
+
};
|
91
|
+
|
92
|
+
// Private context caching methods. This avoids recreating lots of context
|
93
|
+
// objects.
|
94
|
+
|
95
|
+
SC.Enumerator._popContext = function() {
|
96
|
+
var ret = (this._contextCache) ? this._contextCache.pop() : null ;
|
97
|
+
return ret || {} ;
|
98
|
+
} ;
|
99
|
+
|
100
|
+
SC.Enumerator._pushContext = function(context) {
|
101
|
+
var cache = this._contextCache = this._contextCache || [] ;
|
102
|
+
cache.push(context);
|
103
|
+
return null ;
|
104
|
+
};
|
105
|
+
|
@@ -49,13 +49,12 @@ SC.BENCHMARK_OBJECTS = NO;
|
|
49
49
|
|
50
50
|
*/
|
51
51
|
SC.Object = function(noinit) {
|
52
|
-
if (noinit === SC.Object._noinit_) return ;
|
53
|
-
var ret = SC.Object._init.apply(this
|
52
|
+
if (noinit === SC.Object._noinit_) return this ;
|
53
|
+
var ret = SC.Object._init.apply(this,SC.$A(arguments)) ;
|
54
54
|
return ret ;
|
55
55
|
};
|
56
56
|
|
57
|
-
|
58
|
-
/** @scope SC.Object */ {
|
57
|
+
SC.mixin(SC.Object, /** @scope SC.Object */ {
|
59
58
|
|
60
59
|
_noinit_: '__noinit__',
|
61
60
|
|
@@ -66,7 +65,7 @@ Object.extend(SC.Object,
|
|
66
65
|
@returns {void}
|
67
66
|
*/
|
68
67
|
mixin: function(props) {
|
69
|
-
var ext =
|
68
|
+
var ext = SC.$A(arguments) ;
|
70
69
|
for(var loc=0;loc<ext.length;loc++) {
|
71
70
|
Object.extend(this,ext[loc]);
|
72
71
|
}
|
@@ -86,8 +85,8 @@ Object.extend(SC.Object,
|
|
86
85
|
|
87
86
|
// build function. copy class methods on to it.
|
88
87
|
var ret = function(noinit) {
|
89
|
-
if (noinit && (typeof(noinit) == 'string') && (noinit == SC.Object._noinit_)) return ;
|
90
|
-
var ret = SC.Object._init.apply(this
|
88
|
+
if (noinit && (typeof(noinit) == 'string') && (noinit == SC.Object._noinit_)) return this ;
|
89
|
+
var ret = SC.Object._init.apply(this,SC.$A(arguments));
|
91
90
|
return ret ;
|
92
91
|
};
|
93
92
|
for(var prop in this) { ret[prop] = this[prop]; }
|
@@ -96,16 +95,16 @@ Object.extend(SC.Object,
|
|
96
95
|
var base = new this(SC.Object._noinit_) ;
|
97
96
|
|
98
97
|
// var base = SC.Object._extend({},this.prototype) ;
|
99
|
-
var extensions =
|
98
|
+
var extensions = SC.$A(arguments) ;
|
100
99
|
for(var loc=0;loc<extensions.length;loc++) {
|
101
100
|
base = SC.Object._extend(base, extensions[loc]);
|
102
101
|
}
|
103
102
|
ret.prototype = base ;
|
104
103
|
|
105
104
|
// return new extension
|
106
|
-
ret._guid = SC.
|
105
|
+
ret._guid = SC.generateGuid() ; // each time we extend we get a new guid
|
107
106
|
ret._type = this ;
|
108
|
-
|
107
|
+
|
109
108
|
if (SC.BENCHMARK_OBJECTS) SC.Benchmark.end('SC.Object.extend') ;
|
110
109
|
|
111
110
|
return ret ;
|
@@ -129,7 +128,7 @@ Object.extend(SC.Object,
|
|
129
128
|
@returns {SC.Object} new instance of the receiver class.
|
130
129
|
*/
|
131
130
|
create: function(props) {
|
132
|
-
var ret = new this(
|
131
|
+
var ret = new this(SC.$A(arguments),this) ;
|
133
132
|
return ret ;
|
134
133
|
},
|
135
134
|
|
@@ -254,14 +253,14 @@ Object.extend(SC.Object,
|
|
254
253
|
},
|
255
254
|
|
256
255
|
objectForPropertyPath: function(path,root) {
|
257
|
-
var parts = (
|
256
|
+
var parts = ($type(path) === T_STRING) ? path.split('.') : path ;
|
258
257
|
if (!root) root = window ;
|
259
|
-
var
|
260
|
-
while(
|
261
|
-
|
262
|
-
key =
|
258
|
+
var loc = 0, max = parts.length, key = null;
|
259
|
+
while((loc < max) && (root)) {
|
260
|
+
key = parts[loc++];
|
261
|
+
if (key) root = (root.get) ? root.get(key) : root[key] ;
|
263
262
|
}
|
264
|
-
return (
|
263
|
+
return (loc < max) ? undefined : root ;
|
265
264
|
},
|
266
265
|
|
267
266
|
|
@@ -274,7 +273,7 @@ Object.extend(SC.Object,
|
|
274
273
|
for(var loc=0;loc<extensions.length;loc++) {
|
275
274
|
ret = SC.Object._extend(ret,extensions[loc]) ;
|
276
275
|
}
|
277
|
-
ret._guid = SC.
|
276
|
+
ret._guid = SC.generateGuid() ;
|
278
277
|
ret._type = type ;
|
279
278
|
ret.init() ;
|
280
279
|
|
@@ -422,7 +421,7 @@ SC.Object.prototype = {
|
|
422
421
|
{
|
423
422
|
if ( !methodName ) return false;
|
424
423
|
|
425
|
-
var args =
|
424
|
+
var args = SC.$A(arguments);
|
426
425
|
var name = args.shift();
|
427
426
|
if (this.respondsTo(name))
|
428
427
|
{
|
@@ -734,7 +733,7 @@ SC.Object.prototype = {
|
|
734
733
|
if (interval === undefined) interval = 1 ;
|
735
734
|
var f = methodName ;
|
736
735
|
if (arguments.length > 2) {
|
737
|
-
var args
|
736
|
+
var args =SC.$A(arguments).slice(2,arguments.length);
|
738
737
|
args.unshift(this);
|
739
738
|
if ($type(f) === T_STRING) f = this[methodName] ;
|
740
739
|
f = f.bind.apply(f, args) ;
|
@@ -168,7 +168,7 @@ SC.Responder = SC.Object.extend(
|
|
168
168
|
doCommand: function(method)
|
169
169
|
{
|
170
170
|
var responder = this;
|
171
|
-
var args =
|
171
|
+
var args = SC.$A(arguments);
|
172
172
|
var method = args.shift();
|
173
173
|
var aliases = this._commandAliases[method];
|
174
174
|
var handled = false;
|
@@ -3,41 +3,116 @@
|
|
3
3
|
// copyright 2006-2008, Sprout Systems, Inc. and contributors.
|
4
4
|
// ==========================================================================
|
5
5
|
|
6
|
-
require('mixins/
|
6
|
+
require('mixins/enumerable') ;
|
7
|
+
require('mixins/observable') ;
|
7
8
|
|
8
9
|
/**
|
9
|
-
@class
|
10
|
+
@class
|
11
|
+
|
12
|
+
An unordered collection of objects.
|
10
13
|
|
11
14
|
A Set works a bit like an array except that its items are not ordered.
|
12
|
-
You can create a set to efficiently test for membership for an object.
|
13
|
-
|
14
|
-
|
15
|
+
You can create a set to efficiently test for membership for an object. You
|
16
|
+
can also iterate through a set just like an array, even accessing objects
|
17
|
+
by index, however there is no gaurantee as to their order.
|
18
|
+
|
19
|
+
Note that SC.Set is a primitive object, like an array. It does implement
|
20
|
+
limited key-value observing support but it does not extend from SC.Object
|
21
|
+
so you should not subclass it.
|
22
|
+
|
23
|
+
h1. Creating a Set
|
24
|
+
|
25
|
+
You can create a set like you would most objects using SC.Set.create() or
|
26
|
+
new SC.Set(). Most new sets you create will be empty, but you can also
|
27
|
+
initialize the set with some content by passing an array or other enumerable
|
28
|
+
of objects to the constructor.
|
29
|
+
|
30
|
+
Finally, you can pass in an existing set and the set will be copied. You
|
31
|
+
can also create a copy of a set by calling SC.Set#clone().
|
32
|
+
|
33
|
+
{{{
|
34
|
+
// creates a new empty set
|
35
|
+
var foundNames = SC.Set.create();
|
36
|
+
|
37
|
+
// creates a set with four names in it.
|
38
|
+
var names = SC.Set.create(["Charles", "Peter", "Chris", "Erich"]) ;
|
15
39
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
40
|
+
// creates a copy of the names set.
|
41
|
+
var namesCopy = SC.Set.create(names);
|
42
|
+
|
43
|
+
// same as above.
|
44
|
+
var anotherNamesCopy = names.clone();
|
45
|
+
}}}
|
20
46
|
|
21
|
-
|
47
|
+
h1. Adding/Removing Objects
|
48
|
+
|
49
|
+
You generally add or removed objects from a set using add() or remove().
|
50
|
+
You can add any type of object including primitives such as numbers,
|
51
|
+
strings, and booleans.
|
52
|
+
|
53
|
+
Note that objects can only exist one time in a set. If you call add() on
|
54
|
+
a set with the same object multiple times, the object will only be added
|
55
|
+
once. Likewise, calling remove() with the same object multiple times will
|
56
|
+
remove the object the first time and have no effect on future calls until
|
57
|
+
you add the object to the set again.
|
58
|
+
|
59
|
+
Note that you cannot add/remove null or undefined to a set. Any attempt to
|
60
|
+
do so will be ignored.
|
61
|
+
|
62
|
+
In addition to add/remove you can also call push()/pop(). Push behaves just
|
63
|
+
like add() but pop(), unlike remove() will pick an arbitrary object, remove
|
64
|
+
it and return it. This is a good way to use a set as a job queue when you
|
65
|
+
don't care which order the jobs are executed in.
|
66
|
+
|
67
|
+
h1. Testing for an Object
|
68
|
+
|
69
|
+
To test for an object's presence in a set you simply call SC.Set#contains().
|
70
|
+
This method tests for the object's hash, which is generally the same as the
|
71
|
+
object's _guid but if you implement the hash() method on the object, it will
|
72
|
+
use the return value from that method instead.
|
73
|
+
|
74
|
+
@extends Object
|
75
|
+
@extends SC.Enumerable
|
76
|
+
@since SproutCore 0.9.15
|
77
|
+
*/
|
78
|
+
SC.Set = function(items) {
|
79
|
+
if (items && items.length > 0) {
|
80
|
+
var idx = (items.get) ? items.get('length') : items.length ;
|
81
|
+
if (items.objectAt) {
|
82
|
+
while(--idx >= 0) this.add(items.objectAt(idx)) ;
|
83
|
+
} else {
|
84
|
+
while(--idx >= 0) this.add(items[idx]) ;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return this ;
|
88
|
+
} ;
|
89
|
+
|
90
|
+
SC.Set.prototype = {
|
91
|
+
|
92
|
+
/**
|
22
93
|
This property will change as the number of objects in the set changes.
|
23
94
|
|
24
95
|
@type number
|
25
|
-
*/
|
96
|
+
*/
|
26
97
|
length: 0,
|
27
98
|
|
28
99
|
/**
|
29
|
-
|
30
|
-
|
31
|
-
@type number
|
100
|
+
Clears the set
|
32
101
|
*/
|
33
|
-
|
102
|
+
clear: function() { this.length = 0; },
|
34
103
|
|
35
104
|
/**
|
36
105
|
Call this method to test for membership.
|
37
106
|
*/
|
38
107
|
contains: function(obj) {
|
39
|
-
|
40
|
-
|
108
|
+
|
109
|
+
// because of the way a set is "reset", the guid for an object may
|
110
|
+
// still be stored as a key, but points to an index that is beyond the
|
111
|
+
// length. Therefore the found idx must both be defined and less than
|
112
|
+
// the current length.
|
113
|
+
if (obj === null) return NO ;
|
114
|
+
var idx = this[SC.hashFor(obj)] ;
|
115
|
+
return ((idx != null) && (idx < this.length)) ;
|
41
116
|
},
|
42
117
|
|
43
118
|
/**
|
@@ -46,70 +121,102 @@ SC.Set = SC.Object.extend(SC.Array,
|
|
46
121
|
If the object is already in the set it will not be added again.
|
47
122
|
|
48
123
|
@param obj {Object} the object to add
|
49
|
-
@returns {
|
124
|
+
@returns {Object} this
|
50
125
|
*/
|
51
126
|
add: function(obj) {
|
52
|
-
if (obj == null) return
|
127
|
+
if (obj == null) return this; // cannot add null to a set.
|
53
128
|
|
54
|
-
var guid =
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
this
|
59
|
-
|
60
|
-
|
129
|
+
var guid = SC.hashFor(obj) ;
|
130
|
+
var idx = this[guid] ;
|
131
|
+
var len = this.length ;
|
132
|
+
if ((idx == null) || (idx >= len)) {
|
133
|
+
this[len] = obj ;
|
134
|
+
this[guid] = len ;
|
135
|
+
this.length = len+1;
|
136
|
+
}
|
137
|
+
return this ;
|
61
138
|
},
|
62
139
|
|
140
|
+
/**
|
141
|
+
Add all the items in the passed array.
|
142
|
+
*/
|
143
|
+
addEach: function(objects) {
|
144
|
+
var idx = objects.length ;
|
145
|
+
while(--idx >= 0) this.add(objects[idx]) ;
|
146
|
+
},
|
147
|
+
|
63
148
|
/**
|
64
149
|
Removes the object from the set if it is found.
|
65
150
|
|
66
151
|
If the object is not in the set, nothing will be changed.
|
67
152
|
|
68
153
|
@param obj {Object} the object to remove
|
69
|
-
@returns {
|
154
|
+
@returns {this} this
|
70
155
|
*/
|
71
156
|
remove: function(obj) {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
157
|
+
|
158
|
+
if (obj == null) return this ;
|
159
|
+
var guid = SC.hashFor(obj);
|
160
|
+
var idx = this[guid] ;
|
161
|
+
var len = this.length;
|
162
|
+
|
163
|
+
if ((idx == null) || (idx >= len)) return this; // not in set.
|
164
|
+
|
165
|
+
// clear the guid key
|
166
|
+
delete this[guid] ;
|
167
|
+
|
168
|
+
// to clear the index, we will swap the object stored in the last index.
|
169
|
+
// if this is the last object, just reduce the length.
|
170
|
+
if (idx < (len-1)) {
|
171
|
+
var obj = this[idx] = this[len-1];
|
172
|
+
this[SC.hashFor(obj)] = idx ;
|
173
|
+
}
|
174
|
+
|
175
|
+
// reduce the length
|
176
|
+
this.length = len-1;
|
177
|
+
return this ;
|
178
|
+
},
|
179
|
+
|
180
|
+
/**
|
181
|
+
Removes an arbitrary object from the set and returns it.
|
182
|
+
|
183
|
+
@returns {Object} an object from the set or null
|
184
|
+
*/
|
185
|
+
pop: function() {
|
186
|
+
var obj = (this.length > 0) ? this[this.length-1] : null ;
|
187
|
+
if (obj) this.remove(obj) ;
|
188
|
+
return obj ;
|
80
189
|
},
|
81
190
|
|
191
|
+
/**
|
192
|
+
Removes all the items in the passed array.
|
193
|
+
*/
|
194
|
+
removeEach: function(objects) {
|
195
|
+
var idx = objects.length ;
|
196
|
+
while(--idx >= 0) this.remove(objects[idx]) ;
|
197
|
+
},
|
198
|
+
|
82
199
|
// .......................................
|
83
200
|
// PRIVATE
|
84
|
-
|
85
|
-
|
201
|
+
_each: function(iterator) {
|
202
|
+
var len = this.length ;
|
203
|
+
for(var idx=0;idx<len;idx++) iterator(this[idx]) ;
|
86
204
|
},
|
87
205
|
|
88
|
-
|
89
|
-
|
90
|
-
if (!this.hasOwnProperty(key)) continue ;
|
91
|
-
if (key.match(/^@/)) iterator(this[key]) ;
|
92
|
-
}
|
206
|
+
toString: function() {
|
207
|
+
return "SC.Set<%@>".fmt(SC.SC.$A(this)) ;
|
93
208
|
}
|
94
209
|
|
95
|
-
}
|
210
|
+
} ;
|
211
|
+
|
212
|
+
// Make this enumerable and observable
|
213
|
+
SC.mixin(SC.Set.prototype, SC.Enumerable, SC.Observable) ;
|
96
214
|
|
97
|
-
SC.Set.prototype.push = SC.Set.prototype.unshift = SC.Set.prototype.add;
|
98
|
-
SC.Set.prototype.
|
215
|
+
SC.Set.prototype.push = SC.Set.prototype.unshift = SC.Set.prototype.add ;
|
216
|
+
SC.Set.prototype.shift = SC.Set.prototype.pop ;
|
99
217
|
|
100
|
-
SC.Set._create = SC.Set.create ;
|
101
218
|
|
102
219
|
/**
|
103
220
|
To create a set, pass an array of items instead of a hash.
|
104
221
|
*/
|
105
|
-
SC.Set.create = function(items) {
|
106
|
-
if (!items) items = [] ;
|
107
|
-
var hash = {}, loc = items.length ;
|
108
|
-
while(--loc >= 0) {
|
109
|
-
var item = items[loc];
|
110
|
-
if (item == null) continue ;
|
111
|
-
hash[SC.Set.prototype._guidFor(item)] = item ;
|
112
|
-
}
|
113
|
-
hash.length = items.length ;
|
114
|
-
return SC.Set._create(hash) ;
|
115
|
-
} ;
|
222
|
+
SC.Set.create = function(items) { return new SC.Set(items); };
|