sproutcore 0.9.14 → 0.9.15
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,129 +1,218 @@
|
|
1
|
-
//@license
|
2
1
|
// ==========================================================================
|
3
|
-
// SproutCore
|
4
|
-
// copyright 2006-2008, Sprout Systems, Inc. and contributors.
|
5
|
-
//
|
6
|
-
// Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
-
// copy of this software and associated documentation files (the "Software"),
|
8
|
-
// to deal in the Software without restriction, including without limitation
|
9
|
-
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
-
// and/or sell copies of the Software, and to permit persons to whom the
|
11
|
-
// Software is furnished to do so, subject to the following conditions:
|
12
|
-
//
|
13
|
-
// The above copyright notice and this permission notice shall be included in
|
14
|
-
// all copies or substantial portions of the Software.
|
15
|
-
//
|
16
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
-
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
-
// DEALINGS IN THE SOFTWARE.
|
23
|
-
//
|
24
|
-
// For more information about SproutCore, visit http://www.sproutcore.com
|
25
|
-
//
|
26
|
-
//
|
27
|
-
// ==========================================================================
|
28
|
-
//@license
|
29
|
-
|
30
|
-
// ==========================================================================
|
31
|
-
// Utility Classes
|
2
|
+
// SproutCore
|
32
3
|
// Author: Charles Jolley
|
33
|
-
// copyright 2006, Sprout Systems, Inc.
|
34
|
-
//
|
35
|
-
// This file contains a number of utility methods and classes used throughout
|
36
|
-
// SproutCore. This should be loaded after your load Prototype but before you
|
37
|
-
// load any other SproutCore objects. In general, this is the only
|
38
|
-
// dependency most SproutCore objects will have.
|
39
|
-
//
|
4
|
+
// copyright 2006-2008, Sprout Systems, Inc.
|
40
5
|
// ==========================================================================
|
41
6
|
|
42
|
-
if (!window.SC) {
|
43
|
-
/**
|
44
|
-
@namespace
|
45
|
-
|
46
|
-
All objects live in the SproutCore namespace, which is also availabe in the
|
47
|
-
abbreviation SC.
|
48
|
-
*/
|
49
|
-
SC = {};
|
50
|
-
SproutCore = SC ;
|
51
|
-
}
|
52
|
-
|
53
|
-
// this makes for some nicer to read code
|
54
|
-
var YES = true ; var NO = false ;
|
55
|
-
|
56
7
|
// this is used by the JavascriptCompile class on the server side. You can
|
57
8
|
// use this to automatically determine the order javascript files need to be
|
58
9
|
// included in. On the client side, this is a NOP.
|
59
|
-
function require(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
} ;
|
10
|
+
var require = require || function require() { } ;
|
11
|
+
require('license') ;
|
12
|
+
|
13
|
+
// ........................................
|
14
|
+
// GLOBAL CONSTANTS
|
15
|
+
//
|
16
|
+
// Most global constants should be defined inside of the SC namespace.
|
17
|
+
// However the following two are useful enough and generally benign enough
|
18
|
+
// to put into the global object.
|
19
|
+
var YES = true ;
|
20
|
+
var NO = false ;
|
21
|
+
|
22
|
+
// prevent a console.log from blowing things up if we are on a browser that
|
23
|
+
// does not support it
|
24
|
+
if (typeof console === 'undefined') {
|
25
|
+
var console = console || window.console || {} ;
|
26
|
+
console.log = console.info = console.warn = console.error = function(){};
|
77
27
|
}
|
78
|
-
window.logCount = 0 ;
|
79
28
|
|
80
29
|
// ........................................
|
81
|
-
//
|
30
|
+
// BOOTSTRAP
|
82
31
|
//
|
32
|
+
// The root namespace and some common utility methods are defined here. The
|
33
|
+
// rest of the methods go into the mixin defined below.
|
83
34
|
|
84
|
-
|
35
|
+
/**
|
36
|
+
@namespace
|
37
|
+
|
38
|
+
The SproutCore namespace. All SproutCore methods and functions are defined
|
39
|
+
inside of this namespace. You generally should not add new properties to
|
40
|
+
this namespace as it may be overwritten by future versions of SproutCore.
|
41
|
+
|
42
|
+
You can also use the shorthand "SC" instead of "SproutCore".
|
43
|
+
|
44
|
+
SproutCore-Base is a framework that provides core functions for SproutCore
|
45
|
+
including cross-platform functions, support for property observing and
|
46
|
+
objects. It's focus is on small size and performance. You can use this
|
47
|
+
in place of or along-side other cross-platform libraries such as jQuery or
|
48
|
+
Prototype.
|
49
|
+
|
50
|
+
The core Base framework is based on the jQuery API with a number of
|
51
|
+
performance optimizations.
|
52
|
+
*/
|
53
|
+
var SC = SC || {} ;
|
54
|
+
var SproutCore = SproutCore || SC ;
|
55
|
+
|
56
|
+
/**
|
57
|
+
Adds properties to a target object.
|
58
|
+
|
59
|
+
Takes the root object and adds the attributes for any additional
|
60
|
+
arguments passed. This can also perform a deep copy if the first param
|
61
|
+
is a bool that is YES. This is generally not very safe though and not
|
62
|
+
advised.
|
63
|
+
|
64
|
+
@param deep {Boolean} optional parameter. If true, triggers a deep copy.
|
65
|
+
@param target {Object} the target object to extend
|
66
|
+
@param properties {Object} one or more objects with properties to copy.
|
67
|
+
@returns {Object} the target object.
|
68
|
+
@static
|
69
|
+
*/
|
70
|
+
SC.mixin = function() {
|
71
|
+
// copy reference to target object
|
72
|
+
var target = arguments[0] || {};
|
73
|
+
var idx = 1;
|
74
|
+
var length = arguments.length ;
|
75
|
+
var deep = NO ;
|
76
|
+
var options ;
|
85
77
|
|
86
|
-
|
78
|
+
// Handle case where we have only one item...extend SC
|
79
|
+
if (length === 1) {
|
80
|
+
target = this || {};
|
81
|
+
idx=0;
|
87
82
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
83
|
+
// Handle a deep copy situation
|
84
|
+
} else if ((target===YES) || (target===NO)) {
|
85
|
+
deep = target;
|
86
|
+
target = arguments[1] || {};
|
87
|
+
idx = 2; // skip the boolean and the target
|
88
|
+
}
|
89
|
+
|
90
|
+
// Handle case when target is a string or something (possible in deep
|
91
|
+
// copy)
|
92
|
+
if ( typeof target != "object" && typeof target != "function" ) {
|
93
|
+
target = {};
|
94
|
+
}
|
95
|
+
|
96
|
+
// extend SC itself if only one argument is passed
|
97
|
+
if ( length === idx ) {
|
98
|
+
target = this;
|
99
|
+
idx = idx-1;
|
100
|
+
}
|
101
|
+
|
102
|
+
for ( ; idx < length; idx++ ) {
|
103
|
+
if (!(options = arguments[idx])) continue ;
|
104
|
+
for(var key in options) {
|
105
|
+
if (!options.hasOwnProperty(key)) continue ;
|
106
|
+
|
107
|
+
var src = target[key];
|
108
|
+
var copy = options[key] ;
|
109
|
+
if (target===copy) continue ; // prevent never-ending loop
|
110
|
+
|
111
|
+
// Recurse if we're merging object values
|
112
|
+
if ( deep && copy && (typeof copy === "object") && !copy.nodeType ) {
|
113
|
+
copy = SC.extend(deep,
|
114
|
+
src || (copy.length != null ? [ ] : { }), copy) ;
|
115
|
+
}
|
116
|
+
|
117
|
+
if (copy !== undefined) target[key] = copy ;
|
101
118
|
}
|
102
|
-
|
103
|
-
|
104
|
-
|
119
|
+
}
|
120
|
+
|
121
|
+
return target;
|
122
|
+
} ;
|
123
|
+
|
124
|
+
/**
|
125
|
+
Alternative to mixin. Provided for compatibility with jQuery.
|
126
|
+
@function
|
127
|
+
*/
|
128
|
+
SC.extend = SC.mixin ;
|
129
|
+
|
130
|
+
|
131
|
+
// Enough with the bootstrap code. Let's define some core functions
|
132
|
+
SC.mixin(/** @scope SC */ {
|
133
|
+
|
134
|
+
// ........................................
|
135
|
+
// GLOBAL CONSTANTS
|
136
|
+
//
|
137
|
+
T_ERROR: 'error',
|
138
|
+
T_OBJECT: 'object',
|
139
|
+
T_NULL: 'null',
|
140
|
+
T_CLASS: 'class',
|
141
|
+
T_HASH: 'hash',
|
142
|
+
T_FUNCTION: 'function',
|
143
|
+
T_UNDEFINED: 'undefined',
|
144
|
+
T_NUMBER: 'number',
|
145
|
+
T_BOOL: 'boolean',
|
146
|
+
T_ARRAY: 'array',
|
147
|
+
T_STRING: 'string',
|
148
|
+
|
149
|
+
// ........................................
|
150
|
+
// CORE HELPER METHODS
|
151
|
+
//
|
152
|
+
|
153
|
+
|
154
|
+
/**
|
155
|
+
Creates a clone of the passed object. This function can take just about
|
156
|
+
any type of object and create a clone of it, including primitive values
|
157
|
+
(which are not actually cloned because they are immutable).
|
158
|
+
|
159
|
+
If the passed object implements the clone() method, then this function
|
160
|
+
will simply call that method and return the result.
|
161
|
+
|
162
|
+
@param object {Object} the object to clone
|
163
|
+
@returns {Object} the cloned object
|
164
|
+
*/
|
165
|
+
clone: function(object) {
|
166
|
+
var ret = object ;
|
167
|
+
switch (SC.typeOf(object)) {
|
168
|
+
case T_ARRAY:
|
169
|
+
if (object.clone && SC.typeOf(object.clone) === SC.T_FUNCTION) {
|
170
|
+
ret = object.clone() ;
|
171
|
+
} else ret = object.slice() ;
|
172
|
+
break ;
|
173
|
+
|
174
|
+
case T_HASH:
|
175
|
+
case T_OBJECT:
|
176
|
+
if (object.clone && SC.typeOf(object.clone) === SC.T_FUNCTION) {
|
177
|
+
ret = object.clone() ;
|
178
|
+
} else {
|
179
|
+
ret = {} ;
|
180
|
+
for(var key in object) ret[key] = object[key] ;
|
181
|
+
}
|
105
182
|
}
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
183
|
+
|
184
|
+
return ret ;
|
185
|
+
},
|
186
|
+
|
187
|
+
/**
|
188
|
+
Call this method during setup of your app to queue up methods to be
|
189
|
+
called once the entire document has finished loading. If you call this
|
190
|
+
method once the document has already loaded, then the function will be
|
191
|
+
called immediately.
|
192
|
+
|
193
|
+
Any function you register with this method will be called just before
|
194
|
+
main.
|
195
|
+
|
196
|
+
@param target {Object} optional target object. Or just pass a method.
|
197
|
+
@param method {Function} the method to call.
|
198
|
+
@return {void}
|
199
|
+
*/
|
200
|
+
callOnLoad: function(target, method) {
|
201
|
+
|
202
|
+
// normalize parameters
|
203
|
+
if (method === undefined) { method = target; target = null; }
|
204
|
+
if (typeof(method) === 'string') {
|
205
|
+
if (target) {
|
206
|
+
method = target[method] ;
|
207
|
+
} else {
|
208
|
+
throw "You must pass a function to callOnLoad() (got: "+method+")";
|
209
|
+
}
|
113
210
|
}
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
// called once the entire document has finished loading. If you call this
|
120
|
-
// method once the document has already loaded, then the function will be
|
121
|
-
// called immediately.
|
122
|
-
callOnLoad: function(func) {
|
123
|
-
if (SC._onloadQueueFlushed) func.call(document);
|
124
|
-
var queue = SC._onloadQueue || [] ;
|
125
|
-
queue.push(func) ; SC._onloadQueue = queue ;
|
126
|
-
queue = null;
|
211
|
+
|
212
|
+
// invoke the method if the queue is flushed.
|
213
|
+
if (SC._onloadQueueFlushed) method.apply(target || window.document) ;
|
214
|
+
var queue = SC._onloadQueue = (SC._onloadQueue || []) ;
|
215
|
+
queue.push([target, method]) ;
|
127
216
|
},
|
128
217
|
|
129
218
|
// To flush the callOnLoad queue, you need to set window.onload=SC.didLoad
|
@@ -142,12 +231,17 @@ Object.extend(SC,{
|
|
142
231
|
if (window.callOnLoad instanceof Array) {
|
143
232
|
queue = window.callOnLoad ;
|
144
233
|
} else if (window.callOnLoad instanceof Function) {
|
145
|
-
queue = [window.callOnLoad] ;
|
234
|
+
queue = [window, window.callOnLoad] ;
|
146
235
|
}
|
147
236
|
} else queue = [] ;
|
148
237
|
queue = queue.concat(SC._onloadQueue) ;
|
149
238
|
var func = null ;
|
150
|
-
while(func = queue.shift())
|
239
|
+
while(func = queue.shift()) {
|
240
|
+
if (SC.typeOf(func) === T_FUNCTION) {
|
241
|
+
func.call(document) ;
|
242
|
+
} else func[1].call(func[0] || document) ;
|
243
|
+
}
|
244
|
+
|
151
245
|
SC._onloadQueueFlushed = true ;
|
152
246
|
|
153
247
|
// start the app; call main.
|
@@ -161,29 +255,35 @@ Object.extend(SC,{
|
|
161
255
|
}
|
162
256
|
|
163
257
|
SC.runLoop.endRunLoop();
|
258
|
+
|
164
259
|
//remove possible IE7 leak
|
165
260
|
b = null;
|
166
261
|
queue = null;
|
167
262
|
func = null;
|
168
263
|
},
|
169
264
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
265
|
+
/**
|
266
|
+
Returns a consistant type for the passed item.
|
267
|
+
|
268
|
+
Use this instead of the built-in typeOf() to get the type of an item.
|
269
|
+
It will return the same result across all browsers and includes a bit
|
270
|
+
more detail. Here is what will be returned:
|
271
|
+
|
272
|
+
| Return Value Constant | Meaning |
|
273
|
+
| SC.T_STRING | String primitive |
|
274
|
+
| SC.T_NUMBER | Number primitive |
|
275
|
+
| SC.T_BOOLEAN | Boolean primitive |
|
276
|
+
| SC.T_NULL | Null value |
|
277
|
+
| SC.T_UNDEFINED | Undefined value |
|
278
|
+
| SC.T_FUNCTION | A function |
|
279
|
+
| SC.T_ARRAY | An instance of Array |
|
280
|
+
| SC.T_CLASS | A SproutCore class (created using SC.Object.extend()) |
|
281
|
+
| SC.T_OBJECT | A SproutCore object instance |
|
282
|
+
| SC.T_HASH | A JavaScript object not inheriting from SC.Object |
|
283
|
+
|
284
|
+
@param item {Object} the item to check
|
285
|
+
@returns {String} the type
|
286
|
+
*/
|
187
287
|
typeOf: function(item) {
|
188
288
|
if (item === undefined) return T_UNDEFINED ;
|
189
289
|
if (item === null) return T_NULL ;
|
@@ -193,7 +293,12 @@ Object.extend(SC,{
|
|
193
293
|
ret = T_ARRAY ;
|
194
294
|
} else if (item instanceof Function) {
|
195
295
|
ret = (item.isClass) ? T_CLASS : T_FUNCTION ;
|
196
|
-
|
296
|
+
|
297
|
+
// NB: typeOf() may be called before SC.Error has had a chance to load
|
298
|
+
// so this code checks for the presence of SC.Error first just to make
|
299
|
+
// sure. No error instance can exist before the class loads anyway so
|
300
|
+
// this is safe.
|
301
|
+
} else if (SC.Error && (item instanceof SC.Error)) {
|
197
302
|
ret = T_ERROR ;
|
198
303
|
} else if (item.isObject === true) {
|
199
304
|
ret = T_OBJECT ;
|
@@ -202,35 +307,121 @@ Object.extend(SC,{
|
|
202
307
|
return ret ;
|
203
308
|
},
|
204
309
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
if
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
},
|
216
|
-
|
310
|
+
/**
|
311
|
+
Returns YES if the passed object is an array or array-like.
|
312
|
+
|
313
|
+
Unlike SC.$type this method returns true even if the passed object is
|
314
|
+
not formally array but appears to be array-like (i.e. has a length
|
315
|
+
property, responds to .objectAt, etc.)
|
316
|
+
|
317
|
+
@param obj {Object} the object to test
|
318
|
+
@returns {Boolean}
|
319
|
+
*/
|
217
320
|
isArray: function( obj )
|
218
321
|
{
|
219
|
-
return ($type(obj) === T_ARRAY) || (obj && obj.objectAt);
|
322
|
+
return ($type(obj) === T_ARRAY) || (obj && ((obj.length!==undefined) || obj.objectAt));
|
220
323
|
},
|
221
324
|
|
222
|
-
|
223
|
-
|
325
|
+
/**
|
326
|
+
Converts the passed object to an Array. If the object appears to be
|
327
|
+
array-like, a new array will be cloned from it. Otherwise, a new array
|
328
|
+
will be created with the item itself as the only item in the array.
|
329
|
+
|
330
|
+
This is an alias for Array.from() as well.
|
331
|
+
|
332
|
+
@param object {Object} any enumerable or array-like object.
|
333
|
+
@returns {Array} Array of items
|
334
|
+
*/
|
335
|
+
$A: function(obj) {
|
336
|
+
|
337
|
+
// null or undefined
|
338
|
+
if (obj == null) return [] ;
|
339
|
+
|
340
|
+
// primitive
|
341
|
+
if (obj.slice instanceof Function) return obj.slice() ;
|
342
|
+
|
343
|
+
// enumerable
|
344
|
+
if (obj.toArray) return obj.toArray() ;
|
345
|
+
|
346
|
+
// not array-like
|
347
|
+
if (obj.length===undefined || $type(obj) === SC.T_FUNCTION) return [obj];
|
348
|
+
|
349
|
+
// when all else fails, do a manual convert...
|
350
|
+
var len = obj.length;
|
351
|
+
var ret = [] ;
|
352
|
+
for(var idx=0;idx<len;idx++) ret[idx] = obj[idx];
|
353
|
+
return ret ;
|
354
|
+
},
|
355
|
+
|
224
356
|
/**
|
225
357
|
Returns a unique GUID for the object. If the object does not yet have
|
226
358
|
a guid, one will be assigned to it. You can call this on any object,
|
227
359
|
SC.Object-based or not, but be aware that it will add a _guid property.
|
360
|
+
|
361
|
+
@param obj {Object} any object, string, number or primitive
|
362
|
+
@returns {String} the unique guid for this instance.
|
228
363
|
*/
|
229
364
|
guidFor: function(obj) {
|
230
|
-
if (obj
|
231
|
-
|
365
|
+
if (obj === undefined) return "(undefined)" ;
|
366
|
+
if (obj === null) return '(null)' ;
|
367
|
+
if (obj._guid) return obj._guid ;
|
368
|
+
|
369
|
+
switch($type(obj)) {
|
370
|
+
case T_NUMBER:
|
371
|
+
return this._numberGuids[obj] = this._numberGuids[obj] || ("#" + obj);
|
372
|
+
break ;
|
373
|
+
case T_STRING:
|
374
|
+
return this._stringGuids[obj] = this._stringGuids[obj] || ("$" + obj);
|
375
|
+
break ;
|
376
|
+
case T_BOOL:
|
377
|
+
return (obj) ? "(true)" : "(false)" ;
|
378
|
+
break;
|
379
|
+
default:
|
380
|
+
return obj._guid = SC.generateGuid();
|
381
|
+
}
|
232
382
|
},
|
233
383
|
|
384
|
+
generateGuid: function() { return ("@" + (SC._nextGUID++)); },
|
385
|
+
_nextGUID: 0, _numberGuids: [], _stringGuids: {},
|
386
|
+
|
387
|
+
/**
|
388
|
+
Returns a unique hash code for the object. If the object implements
|
389
|
+
a hash() method, the value of that method will be returned. Otherwise,
|
390
|
+
this will return the same value as guidFor().
|
391
|
+
|
392
|
+
Unlike guidFor(), this method allows you to implement logic in your
|
393
|
+
code to cause two separate instances of the same object to be treated as
|
394
|
+
if they were equal for comparisons and other functions.
|
395
|
+
|
396
|
+
IMPORTANT: If you implement a hash() method, it MUST NOT return a number
|
397
|
+
or a string that contains only a number. Typically hash codes are strings
|
398
|
+
that begin with a "%".
|
399
|
+
|
400
|
+
@param obj {Object} the object
|
401
|
+
@returns {String} the hash code for this instance.
|
402
|
+
*/
|
403
|
+
hashFor: function(obj) {
|
404
|
+
return (obj && obj.hash && $type(obj.hash) === T_FUNCTION) ? obj.hash() : this.guidFor(obj) ;
|
405
|
+
},
|
406
|
+
|
407
|
+
/**
|
408
|
+
This will compare the two object values using their hash codes.
|
409
|
+
|
410
|
+
@param a {Object} first value to compare
|
411
|
+
@param b {Object} the second value to compare
|
412
|
+
@returns {Boolean} YES if the two have equal hash code values.
|
413
|
+
|
414
|
+
*/
|
415
|
+
isEqual: function(a,b) {
|
416
|
+
// shortcut a few places.
|
417
|
+
if (a === null) {
|
418
|
+
return b === null ;
|
419
|
+
} else if (a === undefined) {
|
420
|
+
return b === undefined ;
|
421
|
+
|
422
|
+
// finally, check their hash-codes
|
423
|
+
} else return SC.hashFor(a) === SC.hashFor(b) ;
|
424
|
+
},
|
234
425
|
|
235
426
|
/**
|
236
427
|
Convenience method to inspect an object by converting it to a hash.
|
@@ -332,6 +523,9 @@ Object.extend(SC,{
|
|
332
523
|
|
333
524
|
});
|
334
525
|
|
526
|
+
/** Alias for SC.typeOf() */
|
527
|
+
SC.$type = SC.typeOf ;
|
528
|
+
|
335
529
|
/** @deprecated Use guidFor() instead. */
|
336
530
|
SC.getGUID = SC.guidFor ;
|
337
531
|
|
@@ -346,23 +540,31 @@ SC.Platform.Browser = function() {
|
|
346
540
|
}
|
347
541
|
}() ;
|
348
542
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
543
|
+
// Export the type variables into the global space.
|
544
|
+
var T_ERROR = SC.T_ERROR ;
|
545
|
+
var T_OBJECT = SC.T_OBJECT ;
|
546
|
+
var T_NULL = SC.T_NULL ;
|
547
|
+
var T_CLASS = SC.T_CLASS ;
|
548
|
+
var T_HASH = SC.T_HASH ;
|
549
|
+
var T_FUNCTION = SC.T_FUNCTION ;
|
550
|
+
var T_UNDEFINED = SC.T_UNDEFINED ;
|
551
|
+
var T_NUMBER = SC.T_NUMBER ;
|
552
|
+
var T_BOOL = SC.T_BOOL ;
|
553
|
+
var T_ARRAY = SC.T_ARRAY ;
|
554
|
+
var T_STRING = SC.T_STRING ;
|
360
555
|
|
361
|
-
$type = SC.typeOf ;
|
362
556
|
|
557
|
+
// ........................................
|
558
|
+
// GLOBAL EXPORTS
|
559
|
+
//
|
560
|
+
// Global exports will be made optional in the future so you can avoid
|
561
|
+
// polluting the global namespace.
|
562
|
+
|
563
|
+
$type = SC.typeOf ;
|
363
564
|
$I = SC.inspect ;
|
364
565
|
|
365
|
-
|
566
|
+
// Legacy. Will retire.
|
567
|
+
SC.mixin(Object,{
|
366
568
|
|
367
569
|
// this will serialize a general JSON object into a URI.
|
368
570
|
serialize: function(obj) {
|
@@ -344,7 +344,7 @@ Test.Unit.Assertions.prototype = {
|
|
344
344
|
},
|
345
345
|
assertEnumEqual: function(expected, actual) {
|
346
346
|
var message = arguments[2] || "assertEnumEqual";
|
347
|
-
try {
|
347
|
+
try { SC.$A(expected).length == SC.$A(actual).length &&
|
348
348
|
expected.zip(actual).all(function(pair) { return pair[0] == pair[1]; }) ?
|
349
349
|
this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
|
350
350
|
', actual ' + Test.Unit.inspect(actual)); }
|
@@ -456,7 +456,7 @@ Test.Unit.Assertions.prototype = {
|
|
456
456
|
}
|
457
457
|
},
|
458
458
|
assertElementsMatch: function() {
|
459
|
-
var expressions =
|
459
|
+
var expressions = SC.$A(arguments), elements = SC.$A(expressions.shift());
|
460
460
|
if (elements.length != expressions.length) {
|
461
461
|
this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
|
462
462
|
return false;
|
@@ -573,7 +573,7 @@ Test.setupBDDExtensionMethods = function(){
|
|
573
573
|
Test.BDDMethods = {};
|
574
574
|
$H(METHODMAP).each(function(pair) {
|
575
575
|
Test.BDDMethods[pair.key] = function() {
|
576
|
-
var args =
|
576
|
+
var args = SC.$A(arguments);
|
577
577
|
var scope = args.shift();
|
578
578
|
makeAssertion.apply(scope, [pair.value, args, this]); };
|
579
579
|
});
|
@@ -5,7 +5,7 @@
|
|
5
5
|
// the browser, language, and platform. You can then call
|
6
6
|
// SC.setupBrowserClassNames() in a script tag after the body is defined to
|
7
7
|
// load the class names into the body.
|
8
|
-
|
8
|
+
var SC = SC || {} ;
|
9
9
|
SC.browser = (function() {
|
10
10
|
|
11
11
|
var userAgent = navigator.userAgent.toLowerCase();
|
@@ -55,12 +55,12 @@ body.sc-theme {
|
|
55
55
|
border-top: 1px solid white;
|
56
56
|
}
|
57
57
|
|
58
|
-
.sc-theme .sc-collection-view .sel {
|
58
|
+
.sc-theme .sc-collection-view .sc-collection-item.sel {
|
59
59
|
background-color: #ddd;
|
60
60
|
border-top: 1px solid #eee;
|
61
61
|
}
|
62
62
|
|
63
|
-
.sc-theme.focus .sc-collection-view.focus .sel {
|
63
|
+
.sc-theme.focus .sc-collection-view.focus .sc-collection-item.sel {
|
64
64
|
background-color: #40007e;
|
65
65
|
color: white ;
|
66
66
|
border-top: 1px solid #84788f;
|
@@ -105,7 +105,12 @@ SC.Application = SC.Responder.extend(
|
|
105
105
|
if (!action || ($type(action) != T_STRING)) return null;
|
106
106
|
|
107
107
|
// an explicit target was passed...
|
108
|
-
if (target)
|
108
|
+
if (target) {
|
109
|
+
if ($type(target) === T_STRING) {
|
110
|
+
target = SC.Object.objectForPropertyPath(target) ;
|
111
|
+
}
|
112
|
+
return target.respondsTo(action) ? target : null ;
|
113
|
+
}
|
109
114
|
|
110
115
|
// ok, no target was passed... try to find one in the responder chain
|
111
116
|
var keyPane = this.get('keyPane');
|