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
@@ -0,0 +1,178 @@
|
|
1
|
+
// ========================================================================
|
2
|
+
// SproutCore
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
|
+
// ========================================================================
|
5
|
+
|
6
|
+
require('core') ;
|
7
|
+
require('server') ;
|
8
|
+
|
9
|
+
/**
|
10
|
+
@class
|
11
|
+
|
12
|
+
Usually you wouldn't need to call any of the methods on this class or it's
|
13
|
+
superclass, except for calling the +listFor+ method. The other methods are
|
14
|
+
called for you when you work with your model objects. For example, calling
|
15
|
+
myObject.commit(); will call the commitRecords method on this server if you
|
16
|
+
had defined this server to be to the +dataSource+ of myObject.
|
17
|
+
|
18
|
+
To have an SC model reflect data on a backend server attach an instance of
|
19
|
+
this class to your application. For example:
|
20
|
+
|
21
|
+
{{{
|
22
|
+
Contacts = SC.Object.create({
|
23
|
+
server: SC.RestServer.create({ prefix: ['Contacts'] })
|
24
|
+
}) ;
|
25
|
+
}}}
|
26
|
+
|
27
|
+
Then attach that server as the +dataSource+ to each model class that you
|
28
|
+
want to have reflected. Also define a +resourceURL+ which defines the URL
|
29
|
+
where the collection of your model can be queried. For example:
|
30
|
+
|
31
|
+
{{{
|
32
|
+
Contacts.Contact = SC.Record.extend(
|
33
|
+
dataSource: Contacts.server,
|
34
|
+
resourceURL: 'sc/contacts',
|
35
|
+
properties: ['guid','firstName','lastName'],
|
36
|
+
primaryKey: 'guid'
|
37
|
+
}) ;
|
38
|
+
}}}
|
39
|
+
|
40
|
+
When you work with your models, behind the scenes SC will use 5 main methods
|
41
|
+
on this server. Each is listed below, together with the HTTP method used in
|
42
|
+
the call to the backend server and the URL that is being called. The URL is
|
43
|
+
based on the example given above.
|
44
|
+
|
45
|
+
listFor GET /sc/contacts
|
46
|
+
|
47
|
+
createRecords POST /sc/contacts
|
48
|
+
|
49
|
+
refreshRecords
|
50
|
+
for one record GET /sc/contacts/12345
|
51
|
+
|
52
|
+
refreshRecords
|
53
|
+
for many records GET /sc/contacts?ids=1,2,3,4,5,6
|
54
|
+
|
55
|
+
commitRecords
|
56
|
+
for one record PUT /sc/contacts/12345
|
57
|
+
|
58
|
+
commitRecords
|
59
|
+
for many records PUT /sc/contacts?ids=1,2,3,4,5
|
60
|
+
|
61
|
+
destroyRecords
|
62
|
+
for one record DELETE /sc/contacts/12345
|
63
|
+
|
64
|
+
destroyRecords
|
65
|
+
for many records DELETE /sc/contacts?ids=1,2,3,4,5
|
66
|
+
|
67
|
+
The above is the default behaviour of this server. If you want different
|
68
|
+
URLs to be generated then extend this class and override the +urlFor+
|
69
|
+
method.
|
70
|
+
|
71
|
+
Another way to override the above is to tell SC where member resources can
|
72
|
+
be refreshed, committed and destroyed. For example, when SC calls
|
73
|
+
|
74
|
+
{{{
|
75
|
+
GET /sc/contacts
|
76
|
+
}}}
|
77
|
+
|
78
|
+
you could reply as follows:
|
79
|
+
|
80
|
+
{{{
|
81
|
+
records: [
|
82
|
+
{ guid: '123',
|
83
|
+
type: "Contact",
|
84
|
+
refreshURL: "/contacts?refresh=123",
|
85
|
+
updateURL: "/contacts/123?update=Y",
|
86
|
+
destroyURL: "/contacts/123",
|
87
|
+
firstName: "Charles",
|
88
|
+
...
|
89
|
+
}],
|
90
|
+
...
|
91
|
+
}
|
92
|
+
}}}
|
93
|
+
|
94
|
+
Then when contact 123 needs to be refreshed later on by SC, it will call:
|
95
|
+
|
96
|
+
{{{
|
97
|
+
GET /contacts?refresh=123
|
98
|
+
}}}
|
99
|
+
|
100
|
+
instead of GET /contacts/123. Note that this only works for members on your
|
101
|
+
resource. If a collection of contacts needed to be refreshed it would still
|
102
|
+
call for example GET /contacts?id=123,456,789 instead of making 3 separate
|
103
|
+
calls.
|
104
|
+
|
105
|
+
Because some browsers cannot actually perform an HTTP PUT or HTTP DELETE it
|
106
|
+
will actually perform an HTTP POST but will put an additional key,value pair
|
107
|
+
in the post data packet. For HTTP PUT it will add _method='put' and for
|
108
|
+
HTTP DELETE it will add _method='delete' in the post data.
|
109
|
+
|
110
|
+
Via the SC.Server#request method you can also call collection and member
|
111
|
+
functions on your resource. Use the +action+ parameter for this. For
|
112
|
+
example, server.request('contacts', 'archive', null, params, 'delete')
|
113
|
+
would call:
|
114
|
+
|
115
|
+
{{{
|
116
|
+
DELETE /contacts/archive
|
117
|
+
}}}
|
118
|
+
|
119
|
+
And server.request('contacts', 'give', [12345], {'amount': 1000}, 'put')
|
120
|
+
would call:
|
121
|
+
|
122
|
+
{{{
|
123
|
+
PUT /contacts/12345/give
|
124
|
+
}}}
|
125
|
+
|
126
|
+
with post data amount=1000.
|
127
|
+
|
128
|
+
Alternatively explicitely define the URL to use by setting the +url+
|
129
|
+
property in the +params+ argument that is passed to the server.request
|
130
|
+
method. For example:
|
131
|
+
|
132
|
+
{{{
|
133
|
+
Contacts.server.request(null,null,null, {url: '/sc/archive'}, 'delete')
|
134
|
+
}}}
|
135
|
+
|
136
|
+
would call:
|
137
|
+
|
138
|
+
{{{
|
139
|
+
DELETE /sc/archive
|
140
|
+
}}}
|
141
|
+
|
142
|
+
|
143
|
+
@extends SC.Server
|
144
|
+
@author Lawrence Pit
|
145
|
+
@copyright 2006-2008, Sprout Systems, Inc. and contributors.
|
146
|
+
@since SproutCore 1.0
|
147
|
+
*/
|
148
|
+
SC.RestServer = SC.Server.extend({
|
149
|
+
|
150
|
+
/**
|
151
|
+
@see SC.Server.urlFor
|
152
|
+
**/
|
153
|
+
urlFor: function(resource, action, ids, params, method) {
|
154
|
+
url = resource;
|
155
|
+
if (ids && ids.length == 1) url = url + '/' + ids[0];
|
156
|
+
if (action && action != '') url = url + '/' + action;
|
157
|
+
return url;
|
158
|
+
},
|
159
|
+
|
160
|
+
|
161
|
+
/* privates, overrides the values in SC.Server */
|
162
|
+
|
163
|
+
_listForAction: '',
|
164
|
+
_listForMethod: 'get',
|
165
|
+
|
166
|
+
_createAction: '',
|
167
|
+
_createMethod: 'post',
|
168
|
+
|
169
|
+
_refreshAction: '',
|
170
|
+
_refreshMethod: 'get',
|
171
|
+
|
172
|
+
_commitAction: '',
|
173
|
+
_commitMethod: 'put',
|
174
|
+
|
175
|
+
_destroyAction: '',
|
176
|
+
_destroyMethod: 'delete'
|
177
|
+
|
178
|
+
}) ;
|
@@ -62,8 +62,9 @@ SC.Server = SC.Object.extend({
|
|
62
62
|
// onFailure -- function invoked when request fails. Same format.
|
63
63
|
// requestContext -- simply passed back.
|
64
64
|
// cacheCode -- String indicating the time of the last refresh.
|
65
|
+
// url -- override the default url building with this url.
|
65
66
|
//
|
66
|
-
request: function(resource,
|
67
|
+
request: function(resource, action, ids, params, method) {
|
67
68
|
|
68
69
|
// Get Settings and Options
|
69
70
|
if (!params) params = {} ;
|
@@ -72,24 +73,29 @@ SC.Server = SC.Object.extend({
|
|
72
73
|
var onNotModified = params.onNotModified; delete params.onNotModified ;
|
73
74
|
var onFailure = params.onFailure ; delete params.onFailure ;
|
74
75
|
var context = params.requestContext ; delete params.requestContext ;
|
76
|
+
var accept = params.accept ; delete params.accept ;
|
75
77
|
var cacheCode = params.cacheCode; delete params.cacheCode ;
|
78
|
+
var url = params.url; delete params.url;
|
79
|
+
|
80
|
+
opts.requestHeaders = {'Accept': 'application/json, text/javascript, application/xml, text/xml, text/html, */*'}
|
81
|
+
if (accept) opts.requestHeaders['Accept'] = accept ;
|
82
|
+
if (cacheCode) opts.requestHeaders['Sproutit-Cache'] = cacheCode ;
|
83
|
+
opts.method = method || 'get' ;
|
84
|
+
|
85
|
+
if (!url) url = this.urlFor(resource, action, ids, params, opts.method) ;
|
76
86
|
|
77
87
|
// handle ids
|
78
|
-
|
79
|
-
if (ids) if (ids.length > 1) {
|
88
|
+
if (ids && ids.length > 1) {
|
80
89
|
params.ids = [ids].flatten().join(',') ;
|
81
|
-
}
|
82
|
-
idPart = '/' + ids[0] ;
|
83
|
-
}
|
90
|
+
}
|
84
91
|
|
92
|
+
// adds a custom HTTP header for remote requests
|
93
|
+
opts.requestHeaders = {'X-SproutCore-Version' : '1.0'}
|
94
|
+
|
85
95
|
// convert parameters.
|
86
96
|
var parameters = this._toQueryString(params) ;
|
87
97
|
if (parameters && parameters.length > 0) opts.parameters = parameters ;
|
88
98
|
|
89
|
-
// prepare request headers and options
|
90
|
-
if (cacheCode) opts.requestHeaders = ['Sproutit-Cache',cacheCode] ;
|
91
|
-
opts.method = method || 'get' ;
|
92
|
-
var url = this.urlFormat.format(resource,verb) + idPart;
|
93
99
|
var request = null ; //will container the ajax request
|
94
100
|
|
95
101
|
// Save callback functions.
|
@@ -107,10 +113,27 @@ SC.Server = SC.Object.extend({
|
|
107
113
|
if (onFailure) onFailure(transport.status, transport, cacheCode,context);
|
108
114
|
} ;
|
109
115
|
|
110
|
-
console.log('REQUEST: %@'.fmt(url)) ;
|
116
|
+
console.log('REQUEST: %@ %@'.fmt(opts.method, url)) ;
|
117
|
+
|
111
118
|
request = new Ajax.Request(url,opts) ;
|
112
119
|
},
|
113
120
|
|
121
|
+
/**
|
122
|
+
Generates the URL that is going to be called by this server. Note that you
|
123
|
+
should only return relative URLs. You can only call resources that are on
|
124
|
+
the same domain as where this script was downloaded from.
|
125
|
+
|
126
|
+
@param {String} resource the URL where the collection of the resource can be queried
|
127
|
+
@param {String} action the action that should be performed on the resource
|
128
|
+
@param {Array} ids array of identifiers of your model instances
|
129
|
+
@param {Array} params parameters that were passed to the SC.Server#request method
|
130
|
+
@param {String} method the HTTP method that will be used
|
131
|
+
@returns {String} the URL to use in the request to the backend server
|
132
|
+
**/
|
133
|
+
urlFor: function(resource, action, ids, params, method) {
|
134
|
+
var idPart = (ids && ids.length == 1) ? ids[0] : '';
|
135
|
+
return this.urlFormat.format(resource, action) + idPart;
|
136
|
+
},
|
114
137
|
|
115
138
|
// RECORD METHODS
|
116
139
|
// These methods do the basic record changes.
|
@@ -123,6 +146,7 @@ SC.Server = SC.Object.extend({
|
|
123
146
|
listFor: function(opts) {
|
124
147
|
var recordType = opts.recordType ;
|
125
148
|
var resource = recordType.resourceURL() ;
|
149
|
+
|
126
150
|
if (!resource) return false ;
|
127
151
|
|
128
152
|
var order = opts.order || 'id' ;
|
@@ -147,10 +171,12 @@ SC.Server = SC.Object.extend({
|
|
147
171
|
if (opts.offset) params.offset = opts.offset;
|
148
172
|
if (opts.limit) params.limit = opts.limit ;
|
149
173
|
if (order) params.order = order ;
|
150
|
-
|
151
|
-
this.request(resource,'list',null,params) ;
|
174
|
+
this.request(resource, this._listForAction, null, params, this._listMethod) ;
|
152
175
|
},
|
153
176
|
|
177
|
+
_listForAction: 'list',
|
178
|
+
_listMethod: 'get',
|
179
|
+
|
154
180
|
_listSuccess: function(status, transport, cacheCode, context) {
|
155
181
|
var json = eval('json='+transport.responseText) ;
|
156
182
|
if (!json) { console.log('invalid json!'); return; }
|
@@ -202,14 +228,17 @@ SC.Server = SC.Object.extend({
|
|
202
228
|
}) ;
|
203
229
|
|
204
230
|
// issue request
|
205
|
-
this.request(resource,
|
231
|
+
this.request(resource, this._createAction, null, {
|
206
232
|
requestContext: context,
|
207
233
|
onSuccess: this._createSuccess.bind(this),
|
208
234
|
onFailure: this._createFailure.bind(this),
|
209
235
|
records: data
|
210
|
-
},
|
236
|
+
}, this._createMethod) ;
|
211
237
|
}
|
212
238
|
},
|
239
|
+
|
240
|
+
_createAction: 'create',
|
241
|
+
_createMethod: 'post',
|
213
242
|
|
214
243
|
// This method is called when a create is successful. It first goes through
|
215
244
|
// and assigns the primaryKey to each record.
|
@@ -261,16 +290,23 @@ SC.Server = SC.Object.extend({
|
|
261
290
|
});
|
262
291
|
context._recordType = curRecords[0].recordType ; // default rec type.
|
263
292
|
|
264
|
-
|
265
|
-
this.request(resource,'show',ids,{
|
293
|
+
params = {
|
266
294
|
requestContext: context,
|
267
295
|
cacheCode: ((cacheCode=='') ? null : cacheCode),
|
268
296
|
onSuccess: this._refreshSuccess.bind(this),
|
269
297
|
onFailure: this._refreshFailure.bind(this)
|
270
|
-
}
|
298
|
+
};
|
299
|
+
|
300
|
+
if (ids.length == 1 && curRecords[0].refreshURL) params['url'] = curRecords[0].refreshURL;
|
301
|
+
|
302
|
+
// issue request
|
303
|
+
this.request(resource, this._refreshAction, ids, params, this._refreshMethod) ;
|
271
304
|
}
|
272
305
|
},
|
273
306
|
|
307
|
+
_refreshAction: 'show',
|
308
|
+
_refreshMethod: 'get',
|
309
|
+
|
274
310
|
// This method is called when a refresh is successful. It expects an array
|
275
311
|
// of hashes, which it will convert to records.
|
276
312
|
_refreshSuccess: function(status, transport, cacheCode, context) {
|
@@ -299,50 +335,58 @@ SC.Server = SC.Object.extend({
|
|
299
335
|
var server = this ;
|
300
336
|
|
301
337
|
// start format differences
|
338
|
+
var data = null;
|
302
339
|
switch(this.get('postFormat')){
|
303
340
|
case SC.URL_ENCODED_FORMAT:
|
304
|
-
|
341
|
+
data = curRecords.map(function(rec) {
|
305
342
|
return server._decamelizeData(rec.getPropertyData()) ;
|
306
343
|
}) ;
|
307
|
-
|
308
|
-
// issue request
|
309
|
-
this.request(resource,'update',null,{
|
310
|
-
requestContext: records,
|
311
|
-
onSuccess: this._commitSuccess.bind(this),
|
312
|
-
onFailure: this._commitFailure.bind(this),
|
313
|
-
records: data
|
314
|
-
},'post') ;
|
315
|
-
break;
|
316
|
-
|
344
|
+
break;
|
317
345
|
case SC.JSON_FORMAT:
|
318
346
|
// get all records and put them into an array
|
319
347
|
var objects = [];
|
320
348
|
for(rec in curRecords){
|
321
349
|
if (!curRecords.hasOwnProperty(rec)) continue ;
|
322
|
-
objects.push(curRecords[rec].get('attributes'));
|
350
|
+
objects.push(curRecords[rec].get('attributes') || {});
|
323
351
|
}
|
324
352
|
|
325
353
|
// convert to JSON and escape if this.escapeJSON is true
|
326
354
|
if(this.get('escapeJSON')){
|
327
|
-
|
355
|
+
data = escape(objects.toJSONString());
|
328
356
|
} else {
|
329
|
-
|
357
|
+
data = objects.toJSONString();
|
330
358
|
}
|
331
|
-
|
332
|
-
// issue request
|
333
|
-
this.request(resource,'update',null,{
|
334
|
-
requestContext: records,
|
335
|
-
onSuccess: this._commitSuccess.bind(this),
|
336
|
-
onFailure: this._commitFailure.bind(this),
|
337
|
-
records: data
|
338
|
-
},'post') ;
|
339
|
-
break;
|
359
|
+
break;
|
340
360
|
default:
|
341
361
|
break;
|
342
362
|
}
|
343
|
-
|
363
|
+
// end format differences
|
364
|
+
|
365
|
+
if (data) {
|
366
|
+
var ids = [];
|
367
|
+
if (curRecords.length == 1) {
|
368
|
+
var primaryKey = curRecords[0].get('primaryKey') ;
|
369
|
+
var key = curRecords[0].get(primaryKey);
|
370
|
+
if (key) ids.push(key);
|
371
|
+
}
|
372
|
+
|
373
|
+
params = {
|
374
|
+
requestContext: records,
|
375
|
+
onSuccess: this._commitSuccess.bind(this),
|
376
|
+
onFailure: this._commitFailure.bind(this),
|
377
|
+
records: data
|
378
|
+
};
|
379
|
+
|
380
|
+
if (ids.length == 1 && curRecords[0].updateURL) params['url'] = curRecords[0].updateURL;
|
381
|
+
|
382
|
+
// issue request
|
383
|
+
this.request(resource, this._commitAction, ids, params, this._commitMethod) ;
|
384
|
+
}
|
344
385
|
}
|
345
386
|
},
|
387
|
+
|
388
|
+
_commitAction: 'update',
|
389
|
+
_commitMethod: 'post',
|
346
390
|
|
347
391
|
// This method is called when a refresh is successful. It expects an array
|
348
392
|
// of hashes, which it will convert to records.
|
@@ -388,13 +432,22 @@ SC.Server = SC.Object.extend({
|
|
388
432
|
|
389
433
|
// issue request -- we may not have ids to send tho (for ex, if all
|
390
434
|
// records were newRecords.)
|
391
|
-
if (ids && ids.length > 0)
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
435
|
+
if (ids && ids.length > 0) {
|
436
|
+
params = {
|
437
|
+
requestContext: records,
|
438
|
+
onSuccess: this._destroySuccess.bind(this),
|
439
|
+
onFailure: this._destroyFailure.bind(this)
|
440
|
+
};
|
441
|
+
|
442
|
+
if (ids.length == 1 && curRecords[0].destroyURL) params['url'] = curRecords[0].destroyURL;
|
443
|
+
|
444
|
+
this.request(resource, this._destroyAction, ids, params, this._destroyMethod) ;
|
445
|
+
}
|
396
446
|
}
|
397
447
|
},
|
448
|
+
|
449
|
+
_destroyAction: 'destroy',
|
450
|
+
_destroyMethod: 'post',
|
398
451
|
|
399
452
|
_destroySuccess: function(status, transport, cacheCode, records) {
|
400
453
|
console.log('destroySuccess!') ;
|
@@ -420,7 +473,7 @@ SC.Server = SC.Object.extend({
|
|
420
473
|
|
421
474
|
// convert the 'id' property to 'guid'
|
422
475
|
if (data.id) { data.guid = data.id; delete data.id; }
|
423
|
-
|
476
|
+
|
424
477
|
// find the recordType
|
425
478
|
if (data.type) {
|
426
479
|
var recordName = data.type.capitalize() ;
|
@@ -0,0 +1,114 @@
|
|
1
|
+
<% content_for('final') do %>
|
2
|
+
<script>
|
3
|
+
|
4
|
+
Test.context("Object", {
|
5
|
+
|
6
|
+
setup: function() {
|
7
|
+
|
8
|
+
objectA = {} ;
|
9
|
+
objectB = {} ;
|
10
|
+
},
|
11
|
+
|
12
|
+
"should return same guid for same instance every time": function() {
|
13
|
+
assertEqual(SC.guidFor(objectA), SC.guidFor(objectA)) ;
|
14
|
+
},
|
15
|
+
|
16
|
+
"should return different guid for different instances": function() {
|
17
|
+
assertNotEqual(SC.guidFor(objectA), SC.guidFor(objectB)) ;
|
18
|
+
},
|
19
|
+
|
20
|
+
"guid should not parse to a number": function() {
|
21
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(objectA), 0)));
|
22
|
+
}
|
23
|
+
|
24
|
+
});
|
25
|
+
|
26
|
+
Test.context("String", {
|
27
|
+
|
28
|
+
setup: function() {
|
29
|
+
stringA = "string A" ;
|
30
|
+
stringACopy = "string A" ;
|
31
|
+
|
32
|
+
stringB = "string B" ;
|
33
|
+
},
|
34
|
+
|
35
|
+
"same string instance should have same guide every time": function() {
|
36
|
+
assertEqual(SC.guidFor(stringA), SC.guidFor(stringA)) ;
|
37
|
+
},
|
38
|
+
|
39
|
+
"two string instances with same value should have same guid": function() {
|
40
|
+
assertEqual(SC.guidFor(stringA), SC.guidFor(stringACopy)) ;
|
41
|
+
},
|
42
|
+
|
43
|
+
"two instances with different value should have different guid": function(){
|
44
|
+
assertNotEqual(SC.guidFor(stringA), SC.guidFor(stringB)) ;
|
45
|
+
},
|
46
|
+
|
47
|
+
"guid should not parse to a number": function() {
|
48
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(stringA), 0)));
|
49
|
+
}
|
50
|
+
|
51
|
+
});
|
52
|
+
|
53
|
+
Test.context("Number", {
|
54
|
+
|
55
|
+
setup: function() {
|
56
|
+
numberA = 23 ;
|
57
|
+
numberACopy = 23 ;
|
58
|
+
|
59
|
+
numberB = 34 ;
|
60
|
+
},
|
61
|
+
|
62
|
+
"same number instance should have same guide every time": function() {
|
63
|
+
assertEqual(SC.guidFor(numberA), SC.guidFor(numberA)) ;
|
64
|
+
},
|
65
|
+
|
66
|
+
"two number instances with same value should have same guid": function() {
|
67
|
+
assertEqual(SC.guidFor(numberA), SC.guidFor(numberACopy)) ;
|
68
|
+
},
|
69
|
+
|
70
|
+
"two instances with different value should have different guid": function(){
|
71
|
+
assertNotEqual(SC.guidFor(numberA), SC.guidFor(numberB)) ;
|
72
|
+
},
|
73
|
+
|
74
|
+
"guid should not parse to a number": function() {
|
75
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(numberA), 0)));
|
76
|
+
}
|
77
|
+
});
|
78
|
+
|
79
|
+
Test.context("Boolean", {
|
80
|
+
|
81
|
+
"should always have same guid": function() {
|
82
|
+
assertEqual(SC.guidFor(true), SC.guidFor(true)) ;
|
83
|
+
assertEqual(SC.guidFor(false), SC.guidFor(false)) ;
|
84
|
+
},
|
85
|
+
|
86
|
+
"true should have different guid than false": function() {
|
87
|
+
assertNotEqual(SC.guidFor(true), SC.guidFor(false)) ;
|
88
|
+
},
|
89
|
+
|
90
|
+
"guid should not parse to a number": function() {
|
91
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(true), 0)));
|
92
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(false), 0)));
|
93
|
+
}
|
94
|
+
});
|
95
|
+
|
96
|
+
Test.context("Null and Undefined", {
|
97
|
+
|
98
|
+
"should always have same guid": function() {
|
99
|
+
assertEqual(SC.guidFor(null), SC.guidFor(null)) ;
|
100
|
+
assertEqual(SC.guidFor(undefined), SC.guidFor(undefined)) ;
|
101
|
+
},
|
102
|
+
|
103
|
+
"null should have different guid than undefined": function() {
|
104
|
+
assertNotEqual(SC.guidFor(null), SC.guidFor(undefined)) ;
|
105
|
+
},
|
106
|
+
|
107
|
+
"guid should not parse to a number": function() {
|
108
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(null), 0)));
|
109
|
+
assertEqual(YES, isNaN(parseInt(SC.guidFor(undefined), 0)));
|
110
|
+
}
|
111
|
+
});
|
112
|
+
|
113
|
+
</script>
|
114
|
+
<% end %>
|
@@ -27,7 +27,7 @@ ArrayTests = function(factoryFunc) {
|
|
27
27
|
} ;
|
28
28
|
|
29
29
|
this.observe = function() {
|
30
|
-
var keys =
|
30
|
+
var keys = SC.$A(arguments) ;
|
31
31
|
var loc = keys.length ;
|
32
32
|
while(--loc >= 0) {
|
33
33
|
this.a.addObserver(keys[loc], this.observer) ;
|
@@ -157,15 +157,14 @@ ArrayTests = function(factoryFunc) {
|
|
157
157
|
|
158
158
|
var cnt = 0 ;
|
159
159
|
var items = [] ;
|
160
|
-
this.a.
|
160
|
+
this.a.forEach(function( item, idx ) {
|
161
161
|
items.push(item) ;
|
162
162
|
cnt++ ;
|
163
163
|
}) ;
|
164
|
-
|
165
|
-
items[0].shouldEqual('A') ;
|
166
|
-
items[1].shouldEqual('B') ;
|
167
|
-
items[2].shouldEqual('C') ;
|
168
164
|
cnt.shouldEqual(this.a.get('length')) ;
|
165
|
+
assertEqual('A', items[0]) ;
|
166
|
+
assertEqual('B', items[1]) ;
|
167
|
+
assertEqual('C',items[2]) ;
|
169
168
|
},
|
170
169
|
|
171
170
|
"ary.isEqual() should return true when array contents match": function() {
|
@@ -202,7 +201,7 @@ DummyArray = SC.Object.extend(SC.Array, {
|
|
202
201
|
this.content.replace(idx,amt,objects) ;
|
203
202
|
|
204
203
|
this.set('length', this.content.length) ;
|
205
|
-
this.
|
204
|
+
this.enumerableContentDidChange() ;
|
206
205
|
this.endPropertyChanges() ;
|
207
206
|
},
|
208
207
|
|