ember-source 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ember-source might be problematic. Click here for more details.
- data/dist/ember-data-deps.js +1506 -1309
- data/dist/ember-data-deps.min.js +5 -5
- data/dist/ember-data-deps.prod.js +1499 -1302
- data/dist/ember-debug.js +2 -2
- data/dist/ember-old-router.js +2864 -4816
- data/dist/ember-old-router.min.js +8 -9
- data/dist/ember-old-router.prod.js +2849 -4801
- data/dist/ember-runtime.js +1505 -1308
- data/dist/ember-runtime.min.js +5 -5
- data/dist/ember-runtime.prod.js +1492 -1295
- data/dist/ember-spade.js +1 -1
- data/dist/ember-template-compiler.js +3 -3
- data/dist/ember-template-compiler.min.js +2 -2
- data/dist/ember-template-compiler.prod.js +1 -1
- data/dist/ember-tests.js +1 -1
- data/dist/ember.js +2746 -4636
- data/dist/ember.min.js +8 -9
- data/dist/ember.prod.js +2750 -4640
- metadata +2 -2
data/dist/ember-runtime.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
// Version: v1.0.0-rc.1-
|
2
|
-
// Last commit:
|
1
|
+
// Version: v1.0.0-rc.1-188-gb6bb967
|
2
|
+
// Last commit: b6bb967 (2013-03-16 18:09:42 -0700)
|
3
3
|
|
4
4
|
|
5
5
|
(function() {
|
@@ -150,8 +150,8 @@ Ember.deprecateFunc = function(message, func) {
|
|
150
150
|
|
151
151
|
})();
|
152
152
|
|
153
|
-
// Version: v1.0.0-rc.1-
|
154
|
-
// Last commit:
|
153
|
+
// Version: v1.0.0-rc.1-188-gb6bb967
|
154
|
+
// Last commit: b6bb967 (2013-03-16 18:09:42 -0700)
|
155
155
|
|
156
156
|
|
157
157
|
(function() {
|
@@ -418,6 +418,58 @@ Ember.merge = function(original, updates) {
|
|
418
418
|
}
|
419
419
|
};
|
420
420
|
|
421
|
+
/**
|
422
|
+
Returns true if the passed value is null or undefined. This avoids errors
|
423
|
+
from JSLint complaining about use of ==, which can be technically
|
424
|
+
confusing.
|
425
|
+
|
426
|
+
```javascript
|
427
|
+
Ember.isNone(); // true
|
428
|
+
Ember.isNone(null); // true
|
429
|
+
Ember.isNone(undefined); // true
|
430
|
+
Ember.isNone(''); // false
|
431
|
+
Ember.isNone([]); // false
|
432
|
+
Ember.isNone(function(){}); // false
|
433
|
+
```
|
434
|
+
|
435
|
+
@method isNone
|
436
|
+
@for Ember
|
437
|
+
@param {Object} obj Value to test
|
438
|
+
@return {Boolean}
|
439
|
+
*/
|
440
|
+
Ember.isNone = function(obj) {
|
441
|
+
return obj === null || obj === undefined;
|
442
|
+
};
|
443
|
+
Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone);
|
444
|
+
|
445
|
+
/**
|
446
|
+
Verifies that a value is `null` or an empty string, empty array,
|
447
|
+
or empty function.
|
448
|
+
|
449
|
+
Constrains the rules on `Ember.isNone` by returning false for empty
|
450
|
+
string and empty arrays.
|
451
|
+
|
452
|
+
```javascript
|
453
|
+
Ember.isEmpty(); // true
|
454
|
+
Ember.isEmpty(null); // true
|
455
|
+
Ember.isEmpty(undefined); // true
|
456
|
+
Ember.isEmpty(''); // true
|
457
|
+
Ember.isEmpty([]); // true
|
458
|
+
Ember.isEmpty('Adam Hawkins'); // false
|
459
|
+
Ember.isEmpty([0,1,2]); // false
|
460
|
+
```
|
461
|
+
|
462
|
+
@method isEmpty
|
463
|
+
@for Ember
|
464
|
+
@param {Object} obj Value to test
|
465
|
+
@return {Boolean}
|
466
|
+
*/
|
467
|
+
Ember.isEmpty = function(obj) {
|
468
|
+
return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
|
469
|
+
};
|
470
|
+
Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ;
|
471
|
+
|
472
|
+
|
421
473
|
})();
|
422
474
|
|
423
475
|
|
@@ -1761,7 +1813,7 @@ var MapWithDefault = Ember.MapWithDefault = function(options) {
|
|
1761
1813
|
@static
|
1762
1814
|
@param [options]
|
1763
1815
|
@param {anything} [options.defaultValue]
|
1764
|
-
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
|
1816
|
+
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
|
1765
1817
|
`Ember.MapWithDefault` otherwise returns `Ember.Map`
|
1766
1818
|
*/
|
1767
1819
|
MapWithDefault.create = function(options) {
|
@@ -1824,7 +1876,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
|
|
1824
1876
|
// ..........................................................
|
1825
1877
|
// GET AND SET
|
1826
1878
|
//
|
1827
|
-
// If we are on a platform that supports accessors we can
|
1879
|
+
// If we are on a platform that supports accessors we can use those.
|
1828
1880
|
// Otherwise simulate accessors by looking up the property directly on the
|
1829
1881
|
// object.
|
1830
1882
|
|
@@ -1835,7 +1887,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
|
|
1835
1887
|
|
1836
1888
|
If you plan to run on IE8 and older browsers then you should use this
|
1837
1889
|
method anytime you want to retrieve a property on an object that you don't
|
1838
|
-
know for sure is private. (Properties beginning with an underscore '_'
|
1890
|
+
know for sure is private. (Properties beginning with an underscore '_'
|
1839
1891
|
are considered private.)
|
1840
1892
|
|
1841
1893
|
On all newer browsers, you only need to use this method to retrieve
|
@@ -1897,7 +1949,7 @@ get = function get(obj, keyName) {
|
|
1897
1949
|
|
1898
1950
|
If you plan to run on IE8 and older browsers then you should use this
|
1899
1951
|
method anytime you want to set a property on an object that you don't
|
1900
|
-
know for sure is private. (Properties beginning with an underscore '_'
|
1952
|
+
know for sure is private. (Properties beginning with an underscore '_'
|
1901
1953
|
are considered private.)
|
1902
1954
|
|
1903
1955
|
On all newer browsers, you only need to use this method to set
|
@@ -2128,11 +2180,8 @@ Ember.isGlobalPath = function(path) {
|
|
2128
2180
|
@module ember-metal
|
2129
2181
|
*/
|
2130
2182
|
|
2131
|
-
var
|
2132
|
-
META_KEY = Ember.META_KEY,
|
2133
|
-
EMPTY_META = Ember.EMPTY_META,
|
2183
|
+
var META_KEY = Ember.META_KEY,
|
2134
2184
|
metaFor = Ember.meta,
|
2135
|
-
o_create = Ember.create,
|
2136
2185
|
objectDefineProperty = Ember.platform.defineProperty;
|
2137
2186
|
|
2138
2187
|
var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
|
@@ -2552,7 +2601,6 @@ var guidFor = Ember.guidFor, // utils.js
|
|
2552
2601
|
META_KEY = Ember.META_KEY, // utils.js
|
2553
2602
|
// circular reference observer depends on Ember.watch
|
2554
2603
|
// we should move change events to this file or its own property_events.js
|
2555
|
-
notifyObservers = Ember.notifyObservers, // observer.js
|
2556
2604
|
forEach = Ember.ArrayPolyfills.forEach, // array.js
|
2557
2605
|
FIRST_KEY = /^([^\.\*]+)/,
|
2558
2606
|
IS_PATH = /[\.\*]/;
|
@@ -3092,7 +3140,7 @@ Ember.finishChains = function(obj) {
|
|
3092
3140
|
@param {String} keyName The property key (or path) that will change.
|
3093
3141
|
@return {void}
|
3094
3142
|
*/
|
3095
|
-
function propertyWillChange(obj, keyName
|
3143
|
+
function propertyWillChange(obj, keyName) {
|
3096
3144
|
var m = metaFor(obj, false),
|
3097
3145
|
watching = m.watching[keyName] > 0 || keyName === 'length',
|
3098
3146
|
proto = m.proto,
|
@@ -3200,7 +3248,6 @@ Ember.warn("The CP_DEFAULT_CACHEABLE flag has been removed and computed properti
|
|
3200
3248
|
var get = Ember.get,
|
3201
3249
|
set = Ember.set,
|
3202
3250
|
metaFor = Ember.meta,
|
3203
|
-
guidFor = Ember.guidFor,
|
3204
3251
|
a_slice = [].slice,
|
3205
3252
|
o_create = Ember.create,
|
3206
3253
|
META_KEY = Ember.META_KEY,
|
@@ -3236,20 +3283,8 @@ function keysForDep(obj, depsMeta, depKey) {
|
|
3236
3283
|
return keys;
|
3237
3284
|
}
|
3238
3285
|
|
3239
|
-
/* return obj[META_KEY].deps */
|
3240
3286
|
function metaForDeps(obj, meta) {
|
3241
|
-
|
3242
|
-
// If the current object has no dependencies...
|
3243
|
-
if (!deps) {
|
3244
|
-
// initialize the dependencies with a pointer back to
|
3245
|
-
// the current object
|
3246
|
-
deps = meta.deps = {};
|
3247
|
-
} else if (!meta.hasOwnProperty('deps')) {
|
3248
|
-
// otherwise if the dependencies are inherited from the
|
3249
|
-
// object's superclass, clone the deps
|
3250
|
-
deps = meta.deps = o_create(deps);
|
3251
|
-
}
|
3252
|
-
return deps;
|
3287
|
+
return keysForDep(obj, meta, 'deps');
|
3253
3288
|
}
|
3254
3289
|
|
3255
3290
|
function addDependentKeys(desc, obj, keyName, meta) {
|
@@ -3302,8 +3337,10 @@ function removeDependentKeys(desc, obj, keyName, meta) {
|
|
3302
3337
|
*/
|
3303
3338
|
function ComputedProperty(func, opts) {
|
3304
3339
|
this.func = func;
|
3340
|
+
|
3305
3341
|
this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true;
|
3306
3342
|
this._dependentKeys = opts && opts.dependentKeys;
|
3343
|
+
this._readOnly = opts && (opts.readOnly !== undefined || !!opts.readOnly);
|
3307
3344
|
}
|
3308
3345
|
|
3309
3346
|
Ember.ComputedProperty = ComputedProperty;
|
@@ -3358,6 +3395,28 @@ ComputedPropertyPrototype.volatile = function() {
|
|
3358
3395
|
return this.cacheable(false);
|
3359
3396
|
};
|
3360
3397
|
|
3398
|
+
/**
|
3399
|
+
Call on a computed property to set it into read-only mode. When in this
|
3400
|
+
mode the computed property will throw an error when set.
|
3401
|
+
|
3402
|
+
```javascript
|
3403
|
+
MyApp.person = Ember.Object.create({
|
3404
|
+
guid: function() {
|
3405
|
+
return 'guid-guid-guid';
|
3406
|
+
}.property().readOnly()
|
3407
|
+
});
|
3408
|
+
|
3409
|
+
MyApp.person.set('guid', 'new-guid'); // will throw an exception
|
3410
|
+
```
|
3411
|
+
|
3412
|
+
@method readOnly
|
3413
|
+
@chainable
|
3414
|
+
*/
|
3415
|
+
ComputedPropertyPrototype.readOnly = function(readOnly) {
|
3416
|
+
this._readOnly = readOnly === undefined || !!readOnly;
|
3417
|
+
return this;
|
3418
|
+
};
|
3419
|
+
|
3361
3420
|
/**
|
3362
3421
|
Sets the dependent keys on this computed property. Pass any number of
|
3363
3422
|
arguments containing key paths that this computed property depends on.
|
@@ -3482,9 +3541,14 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) {
|
|
3482
3541
|
cache = meta.cache,
|
3483
3542
|
cachedValue, ret;
|
3484
3543
|
|
3544
|
+
if (this._readOnly) {
|
3545
|
+
throw new Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() );
|
3546
|
+
}
|
3547
|
+
|
3485
3548
|
this._suspended = obj;
|
3486
3549
|
|
3487
3550
|
try {
|
3551
|
+
|
3488
3552
|
if (cacheable && cache.hasOwnProperty(keyName)) {
|
3489
3553
|
cachedValue = cache[keyName];
|
3490
3554
|
hadCachedValue = true;
|
@@ -3575,6 +3639,10 @@ Ember.computed = function(func) {
|
|
3575
3639
|
func = a_slice.call(arguments, -1)[0];
|
3576
3640
|
}
|
3577
3641
|
|
3642
|
+
if ( typeof func !== "function" ) {
|
3643
|
+
throw new Error("Computed Property declared without a property function");
|
3644
|
+
}
|
3645
|
+
|
3578
3646
|
var cp = new ComputedProperty(func);
|
3579
3647
|
|
3580
3648
|
if (args) {
|
@@ -3615,6 +3683,18 @@ Ember.computed.not = function(dependentKey) {
|
|
3615
3683
|
});
|
3616
3684
|
};
|
3617
3685
|
|
3686
|
+
/**
|
3687
|
+
@method computed.none
|
3688
|
+
@for Ember
|
3689
|
+
@param {String} dependentKey
|
3690
|
+
*/
|
3691
|
+
Ember.computed.none = function(dependentKey) {
|
3692
|
+
return Ember.computed(dependentKey, function(key) {
|
3693
|
+
var val = get(this, dependentKey);
|
3694
|
+
return Ember.isNone(val);
|
3695
|
+
});
|
3696
|
+
};
|
3697
|
+
|
3618
3698
|
/**
|
3619
3699
|
@method computed.empty
|
3620
3700
|
@for Ember
|
@@ -3623,7 +3703,7 @@ Ember.computed.not = function(dependentKey) {
|
|
3623
3703
|
Ember.computed.empty = function(dependentKey) {
|
3624
3704
|
return Ember.computed(dependentKey, function(key) {
|
3625
3705
|
var val = get(this, dependentKey);
|
3626
|
-
return
|
3706
|
+
return Ember.isEmpty(val);
|
3627
3707
|
});
|
3628
3708
|
};
|
3629
3709
|
|
@@ -3641,15 +3721,16 @@ Ember.computed.bool = function(dependentKey) {
|
|
3641
3721
|
/**
|
3642
3722
|
@method computed.alias
|
3643
3723
|
@for Ember
|
3724
|
+
|
3644
3725
|
@param {String} dependentKey
|
3645
3726
|
*/
|
3646
3727
|
Ember.computed.alias = function(dependentKey) {
|
3647
3728
|
return Ember.computed(dependentKey, function(key, value){
|
3648
|
-
if (arguments.length
|
3649
|
-
return get(this, dependentKey);
|
3650
|
-
} else {
|
3729
|
+
if (arguments.length > 1) {
|
3651
3730
|
set(this, dependentKey, value);
|
3652
3731
|
return value;
|
3732
|
+
} else {
|
3733
|
+
return get(this, dependentKey);
|
3653
3734
|
}
|
3654
3735
|
});
|
3655
3736
|
};
|
@@ -3665,7 +3746,6 @@ Ember.computed.alias = function(dependentKey) {
|
|
3665
3746
|
|
3666
3747
|
var o_create = Ember.create,
|
3667
3748
|
metaFor = Ember.meta,
|
3668
|
-
metaPath = Ember.metaPath,
|
3669
3749
|
META_KEY = Ember.META_KEY;
|
3670
3750
|
|
3671
3751
|
/*
|
@@ -4238,7 +4318,7 @@ Ember.RunLoop = RunLoop;
|
|
4238
4318
|
|
4239
4319
|
```javascript
|
4240
4320
|
Ember.run(function(){
|
4241
|
-
// code to be execute within a RunLoop
|
4321
|
+
// code to be execute within a RunLoop
|
4242
4322
|
});
|
4243
4323
|
```
|
4244
4324
|
|
@@ -4254,8 +4334,7 @@ Ember.RunLoop = RunLoop;
|
|
4254
4334
|
@return {Object} return value from invoking the passed function.
|
4255
4335
|
*/
|
4256
4336
|
Ember.run = function(target, method) {
|
4257
|
-
var
|
4258
|
-
args = arguments;
|
4337
|
+
var args = arguments;
|
4259
4338
|
run.begin();
|
4260
4339
|
|
4261
4340
|
function tryable() {
|
@@ -4273,11 +4352,11 @@ var run = Ember.run;
|
|
4273
4352
|
/**
|
4274
4353
|
Begins a new RunLoop. Any deferred actions invoked after the begin will
|
4275
4354
|
be buffered until you invoke a matching call to `Ember.run.end()`. This is
|
4276
|
-
|
4355
|
+
a lower-level way to use a RunLoop instead of using `Ember.run()`.
|
4277
4356
|
|
4278
4357
|
```javascript
|
4279
4358
|
Ember.run.begin();
|
4280
|
-
// code to be execute within a RunLoop
|
4359
|
+
// code to be execute within a RunLoop
|
4281
4360
|
Ember.run.end();
|
4282
4361
|
```
|
4283
4362
|
|
@@ -4295,7 +4374,7 @@ Ember.run.begin = function() {
|
|
4295
4374
|
|
4296
4375
|
```javascript
|
4297
4376
|
Ember.run.begin();
|
4298
|
-
// code to be execute within a RunLoop
|
4377
|
+
// code to be execute within a RunLoop
|
4299
4378
|
Ember.run.end();
|
4300
4379
|
```
|
4301
4380
|
|
@@ -4319,9 +4398,9 @@ Ember.run.end = function() {
|
|
4319
4398
|
|
4320
4399
|
@property queues
|
4321
4400
|
@type Array
|
4322
|
-
@default ['sync', 'actions', 'destroy'
|
4401
|
+
@default ['sync', 'actions', 'destroy']
|
4323
4402
|
*/
|
4324
|
-
Ember.run.queues = ['sync', 'actions', 'destroy'
|
4403
|
+
Ember.run.queues = ['sync', 'actions', 'destroy'];
|
4325
4404
|
|
4326
4405
|
/**
|
4327
4406
|
Adds the passed target/method and any optional arguments to the named
|
@@ -4334,19 +4413,19 @@ Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
|
|
4334
4413
|
the `run.queues` property.
|
4335
4414
|
|
4336
4415
|
```javascript
|
4337
|
-
Ember.run.schedule('timers', this, function(){
|
4338
|
-
// this will be executed at the end of the RunLoop, when timers are run
|
4339
|
-
console.log("scheduled on timers queue");
|
4340
|
-
});
|
4341
|
-
|
4342
4416
|
Ember.run.schedule('sync', this, function(){
|
4343
|
-
// this will be executed
|
4417
|
+
// this will be executed in the first RunLoop queue, when bindings are synced
|
4344
4418
|
console.log("scheduled on sync queue");
|
4345
4419
|
});
|
4346
4420
|
|
4421
|
+
Ember.run.schedule('actions', this, function(){
|
4422
|
+
// this will be executed in the 'actions' queue, after bindings have synced.
|
4423
|
+
console.log("scheduled on actions queue");
|
4424
|
+
});
|
4425
|
+
|
4347
4426
|
// Note the functions will be run in order based on the run queues order. Output would be:
|
4348
4427
|
// scheduled on sync queue
|
4349
|
-
// scheduled on
|
4428
|
+
// scheduled on actions queue
|
4350
4429
|
```
|
4351
4430
|
|
4352
4431
|
@method schedule
|
@@ -4372,7 +4451,7 @@ function autorun() {
|
|
4372
4451
|
|
4373
4452
|
// Used by global test teardown
|
4374
4453
|
Ember.run.hasScheduledTimers = function() {
|
4375
|
-
return !!(scheduledAutorun || scheduledLater
|
4454
|
+
return !!(scheduledAutorun || scheduledLater);
|
4376
4455
|
};
|
4377
4456
|
|
4378
4457
|
// Used by global test teardown
|
@@ -4385,10 +4464,6 @@ Ember.run.cancelTimers = function () {
|
|
4385
4464
|
clearTimeout(scheduledLater);
|
4386
4465
|
scheduledLater = null;
|
4387
4466
|
}
|
4388
|
-
if (scheduledNext) {
|
4389
|
-
clearTimeout(scheduledNext);
|
4390
|
-
scheduledNext = null;
|
4391
|
-
}
|
4392
4467
|
timers = {};
|
4393
4468
|
};
|
4394
4469
|
|
@@ -4423,7 +4498,8 @@ Ember.run.autorun = function() {
|
|
4423
4498
|
bindings in the application to sync.
|
4424
4499
|
|
4425
4500
|
You should call this method anytime you need any changed state to propagate
|
4426
|
-
throughout the app immediately without repainting the UI
|
4501
|
+
throughout the app immediately without repainting the UI (which happens
|
4502
|
+
in the later 'render' queue added by the `ember-views` package).
|
4427
4503
|
|
4428
4504
|
```javascript
|
4429
4505
|
Ember.run.sync();
|
@@ -4443,25 +4519,30 @@ Ember.run.sync = function() {
|
|
4443
4519
|
|
4444
4520
|
var timers = {}; // active timers...
|
4445
4521
|
|
4446
|
-
var scheduledLater;
|
4522
|
+
var scheduledLater, scheduledLaterExpires;
|
4447
4523
|
function invokeLaterTimers() {
|
4448
4524
|
scheduledLater = null;
|
4449
|
-
|
4450
|
-
|
4451
|
-
|
4452
|
-
|
4453
|
-
|
4454
|
-
if (
|
4455
|
-
|
4456
|
-
|
4457
|
-
|
4458
|
-
|
4525
|
+
run(function() {
|
4526
|
+
var now = (+ new Date()), earliest = -1;
|
4527
|
+
for (var key in timers) {
|
4528
|
+
if (!timers.hasOwnProperty(key)) { continue; }
|
4529
|
+
var timer = timers[key];
|
4530
|
+
if (timer && timer.expires) {
|
4531
|
+
if (now >= timer.expires) {
|
4532
|
+
delete timers[key];
|
4533
|
+
invoke(timer.target, timer.method, timer.args, 2);
|
4534
|
+
} else {
|
4535
|
+
if (earliest < 0 || (timer.expires < earliest)) { earliest = timer.expires; }
|
4536
|
+
}
|
4459
4537
|
}
|
4460
4538
|
}
|
4461
|
-
}
|
4462
4539
|
|
4463
|
-
|
4464
|
-
|
4540
|
+
// schedule next timeout to fire when the earliest timer expires
|
4541
|
+
if (earliest > 0) {
|
4542
|
+
scheduledLater = setTimeout(invokeLaterTimers, earliest - now);
|
4543
|
+
scheduledLaterExpires = earliest;
|
4544
|
+
}
|
4545
|
+
});
|
4465
4546
|
}
|
4466
4547
|
|
4467
4548
|
/**
|
@@ -4509,7 +4590,19 @@ Ember.run.later = function(target, method) {
|
|
4509
4590
|
timer = { target: target, method: method, expires: expires, args: args };
|
4510
4591
|
guid = Ember.guidFor(timer);
|
4511
4592
|
timers[guid] = timer;
|
4512
|
-
|
4593
|
+
|
4594
|
+
if(scheduledLater && expires < scheduledLaterExpires) {
|
4595
|
+
// Cancel later timer (then reschedule earlier timer below)
|
4596
|
+
clearTimeout(scheduledLater);
|
4597
|
+
scheduledLater = null;
|
4598
|
+
}
|
4599
|
+
|
4600
|
+
if (!scheduledLater) {
|
4601
|
+
// Schedule later timers to be run.
|
4602
|
+
scheduledLater = setTimeout(invokeLaterTimers, wait);
|
4603
|
+
scheduledLaterExpires = expires;
|
4604
|
+
}
|
4605
|
+
|
4513
4606
|
return guid;
|
4514
4607
|
};
|
4515
4608
|
|
@@ -4565,6 +4658,21 @@ function scheduleOnce(queue, target, method, args) {
|
|
4565
4658
|
});
|
4566
4659
|
```
|
4567
4660
|
|
4661
|
+
Also note that passing an anonymous function to `Ember.run.once` will
|
4662
|
+
not prevent additional calls with an identical anonymous function from
|
4663
|
+
scheduling the items multiple times, e.g.:
|
4664
|
+
|
4665
|
+
```javascript
|
4666
|
+
function scheduleIt() {
|
4667
|
+
Ember.run.once(myContext, function() { console.log("Closure"); });
|
4668
|
+
}
|
4669
|
+
scheduleIt();
|
4670
|
+
scheduleIt();
|
4671
|
+
// "Closure" will print twice, even though we're using `Ember.run.once`,
|
4672
|
+
// because the function we pass to it is anonymous and won't match the
|
4673
|
+
// previously scheduled operation.
|
4674
|
+
```
|
4675
|
+
|
4568
4676
|
@method once
|
4569
4677
|
@param {Object} [target] target of method to invoke
|
4570
4678
|
@param {Function|String} method The method to invoke.
|
@@ -4581,22 +4689,9 @@ Ember.run.scheduleOnce = function(queue, target, method, args) {
|
|
4581
4689
|
return scheduleOnce(queue, target, method, slice.call(arguments, 3));
|
4582
4690
|
};
|
4583
4691
|
|
4584
|
-
var scheduledNext;
|
4585
|
-
function invokeNextTimers() {
|
4586
|
-
scheduledNext = null;
|
4587
|
-
for(var key in timers) {
|
4588
|
-
if (!timers.hasOwnProperty(key)) { continue; }
|
4589
|
-
var timer = timers[key];
|
4590
|
-
if (timer.next) {
|
4591
|
-
delete timers[key];
|
4592
|
-
invoke(timer.target, timer.method, timer.args, 2);
|
4593
|
-
}
|
4594
|
-
}
|
4595
|
-
}
|
4596
|
-
|
4597
4692
|
/**
|
4598
4693
|
Schedules an item to run after control has been returned to the system.
|
4599
|
-
This is
|
4694
|
+
This is equivalent to calling `Ember.run.later` with a wait time of 1ms.
|
4600
4695
|
|
4601
4696
|
```javascript
|
4602
4697
|
Ember.run.next(myContext, function(){
|
@@ -4612,20 +4707,10 @@ function invokeNextTimers() {
|
|
4612
4707
|
@param {Object} [args*] Optional arguments to pass to the timeout.
|
4613
4708
|
@return {Object} timer
|
4614
4709
|
*/
|
4615
|
-
Ember.run.next = function(
|
4616
|
-
var
|
4617
|
-
|
4618
|
-
|
4619
|
-
method: method,
|
4620
|
-
args: slice.call(arguments),
|
4621
|
-
next: true
|
4622
|
-
};
|
4623
|
-
|
4624
|
-
guid = Ember.guidFor(timer);
|
4625
|
-
timers[guid] = timer;
|
4626
|
-
|
4627
|
-
if (!scheduledNext) { scheduledNext = setTimeout(invokeNextTimers, 1); }
|
4628
|
-
return guid;
|
4710
|
+
Ember.run.next = function() {
|
4711
|
+
var args = slice.call(arguments);
|
4712
|
+
args.push(1); // 1 millisecond wait
|
4713
|
+
return run.later.apply(this, args);
|
4629
4714
|
};
|
4630
4715
|
|
4631
4716
|
/**
|
@@ -5130,7 +5215,6 @@ var Mixin, REQUIRED, Alias,
|
|
5130
5215
|
a_indexOf = Ember.ArrayPolyfills.indexOf,
|
5131
5216
|
a_forEach = Ember.ArrayPolyfills.forEach,
|
5132
5217
|
a_slice = [].slice,
|
5133
|
-
EMPTY_META = {}, // dummy for non-writable meta
|
5134
5218
|
o_create = Ember.create,
|
5135
5219
|
defineProperty = Ember.defineProperty,
|
5136
5220
|
guidFor = Ember.guidFor;
|
@@ -5499,6 +5583,38 @@ Mixin.finishPartial = finishPartial;
|
|
5499
5583
|
Ember.anyUnprocessedMixins = false;
|
5500
5584
|
|
5501
5585
|
/**
|
5586
|
+
Creates an instance of a class. Accepts either no arguments, or an object
|
5587
|
+
containing values to initialize the newly instantiated object with.
|
5588
|
+
|
5589
|
+
```javascript
|
5590
|
+
App.Person = Ember.Object.extend({
|
5591
|
+
helloWorld: function() {
|
5592
|
+
alert("Hi, my name is " + this.get('name'));
|
5593
|
+
}
|
5594
|
+
});
|
5595
|
+
|
5596
|
+
var tom = App.Person.create({
|
5597
|
+
name: 'Tom Dale'
|
5598
|
+
});
|
5599
|
+
|
5600
|
+
tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
|
5601
|
+
```
|
5602
|
+
|
5603
|
+
`create` will call the `init` function if defined during
|
5604
|
+
`Ember.AnyObject.extend`
|
5605
|
+
|
5606
|
+
If no arguments are passed to `create`, it will not set values to the new
|
5607
|
+
instance during initialization:
|
5608
|
+
|
5609
|
+
```javascript
|
5610
|
+
var noName = App.Person.create();
|
5611
|
+
noName.helloWorld(); // alerts undefined
|
5612
|
+
```
|
5613
|
+
|
5614
|
+
NOTE: For performance reasons, you cannot declare methods or computed
|
5615
|
+
properties during `create`. You should instead declare methods and computed
|
5616
|
+
properties when using `extend`.
|
5617
|
+
|
5502
5618
|
@method create
|
5503
5619
|
@static
|
5504
5620
|
@param arguments*
|
@@ -6014,35 +6130,35 @@ define("rsvp",
|
|
6014
6130
|
}
|
6015
6131
|
|
6016
6132
|
function all(promises) {
|
6017
|
-
|
6018
|
-
|
6019
|
-
|
6133
|
+
var i, results = [];
|
6134
|
+
var allPromise = new Promise();
|
6135
|
+
var remaining = promises.length;
|
6020
6136
|
|
6021
6137
|
if (remaining === 0) {
|
6022
6138
|
allPromise.resolve([]);
|
6023
6139
|
}
|
6024
6140
|
|
6025
|
-
|
6026
|
-
|
6027
|
-
|
6028
|
-
|
6029
|
-
|
6141
|
+
var resolver = function(index) {
|
6142
|
+
return function(value) {
|
6143
|
+
resolve(index, value);
|
6144
|
+
};
|
6145
|
+
};
|
6030
6146
|
|
6031
|
-
|
6032
|
-
|
6033
|
-
|
6034
|
-
|
6035
|
-
|
6036
|
-
|
6147
|
+
var resolve = function(index, value) {
|
6148
|
+
results[index] = value;
|
6149
|
+
if (--remaining === 0) {
|
6150
|
+
allPromise.resolve(results);
|
6151
|
+
}
|
6152
|
+
};
|
6037
6153
|
|
6038
|
-
|
6039
|
-
|
6040
|
-
|
6154
|
+
var reject = function(error) {
|
6155
|
+
allPromise.reject(error);
|
6156
|
+
};
|
6041
6157
|
|
6042
|
-
|
6043
|
-
|
6044
|
-
|
6045
|
-
|
6158
|
+
for (i = 0; i < remaining; i++) {
|
6159
|
+
promises[i].then(resolver(i), reject);
|
6160
|
+
}
|
6161
|
+
return allPromise;
|
6046
6162
|
}
|
6047
6163
|
|
6048
6164
|
EventTarget.mixin(Promise.prototype);
|
@@ -6418,57 +6534,6 @@ Ember.typeOf = function(item) {
|
|
6418
6534
|
return ret;
|
6419
6535
|
};
|
6420
6536
|
|
6421
|
-
/**
|
6422
|
-
Returns true if the passed value is null or undefined. This avoids errors
|
6423
|
-
from JSLint complaining about use of ==, which can be technically
|
6424
|
-
confusing.
|
6425
|
-
|
6426
|
-
```javascript
|
6427
|
-
Ember.isNone(); // true
|
6428
|
-
Ember.isNone(null); // true
|
6429
|
-
Ember.isNone(undefined); // true
|
6430
|
-
Ember.isNone(''); // false
|
6431
|
-
Ember.isNone([]); // false
|
6432
|
-
Ember.isNone(function(){}); // false
|
6433
|
-
```
|
6434
|
-
|
6435
|
-
@method isNone
|
6436
|
-
@for Ember
|
6437
|
-
@param {Object} obj Value to test
|
6438
|
-
@return {Boolean}
|
6439
|
-
*/
|
6440
|
-
Ember.isNone = function(obj) {
|
6441
|
-
return obj === null || obj === undefined;
|
6442
|
-
};
|
6443
|
-
Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone);
|
6444
|
-
|
6445
|
-
/**
|
6446
|
-
Verifies that a value is `null` or an empty string, empty array,
|
6447
|
-
or empty function.
|
6448
|
-
|
6449
|
-
Constrains the rules on `Ember.isNone` by returning false for empty
|
6450
|
-
string and empty arrays.
|
6451
|
-
|
6452
|
-
```javascript
|
6453
|
-
Ember.isEmpty(); // true
|
6454
|
-
Ember.isEmpty(null); // true
|
6455
|
-
Ember.isEmpty(undefined); // true
|
6456
|
-
Ember.isEmpty(''); // true
|
6457
|
-
Ember.isEmpty([]); // true
|
6458
|
-
Ember.isEmpty('Adam Hawkins'); // false
|
6459
|
-
Ember.isEmpty([0,1,2]); // false
|
6460
|
-
```
|
6461
|
-
|
6462
|
-
@method isEmpty
|
6463
|
-
@for Ember
|
6464
|
-
@param {Object} obj Value to test
|
6465
|
-
@return {Boolean}
|
6466
|
-
*/
|
6467
|
-
Ember.isEmpty = function(obj) {
|
6468
|
-
return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
|
6469
|
-
};
|
6470
|
-
Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ;
|
6471
|
-
|
6472
6537
|
/**
|
6473
6538
|
This will compare two javascript values of possibly different types.
|
6474
6539
|
It will tell you which one is greater than the other by returning:
|
@@ -6924,10 +6989,11 @@ Ember.String = {
|
|
6924
6989
|
*/
|
6925
6990
|
dasherize: function(str) {
|
6926
6991
|
var cache = STRING_DASHERIZE_CACHE,
|
6927
|
-
|
6992
|
+
hit = cache.hasOwnProperty(str),
|
6993
|
+
ret;
|
6928
6994
|
|
6929
|
-
if (
|
6930
|
-
return
|
6995
|
+
if (hit) {
|
6996
|
+
return cache[str];
|
6931
6997
|
} else {
|
6932
6998
|
ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-');
|
6933
6999
|
cache[str] = ret;
|
@@ -6937,7 +7003,7 @@ Ember.String = {
|
|
6937
7003
|
},
|
6938
7004
|
|
6939
7005
|
/**
|
6940
|
-
Returns the
|
7006
|
+
Returns the lowerCamelCase form of a string.
|
6941
7007
|
|
6942
7008
|
```javascript
|
6943
7009
|
'innerHTML'.camelize(); // 'innerHTML'
|
@@ -7008,10 +7074,10 @@ Ember.String = {
|
|
7008
7074
|
/**
|
7009
7075
|
Returns the Capitalized form of a string
|
7010
7076
|
|
7011
|
-
'innerHTML'.capitalize()
|
7012
|
-
'action_name'.capitalize()
|
7013
|
-
'css-class-name'.capitalize()
|
7014
|
-
'my favorite items'.capitalize()
|
7077
|
+
'innerHTML'.capitalize() // 'InnerHTML'
|
7078
|
+
'action_name'.capitalize() // 'Action_name'
|
7079
|
+
'css-class-name'.capitalize() // 'Css-class-name'
|
7080
|
+
'my favorite items'.capitalize() // 'My favorite items'
|
7015
7081
|
|
7016
7082
|
@method capitalize
|
7017
7083
|
@param {String} str
|
@@ -7355,8 +7421,7 @@ function iter(key, value) {
|
|
7355
7421
|
@extends Ember.Mixin
|
7356
7422
|
@since Ember 0.9
|
7357
7423
|
*/
|
7358
|
-
Ember.Enumerable = Ember.Mixin.create(
|
7359
|
-
/** @scope Ember.Enumerable.prototype */ {
|
7424
|
+
Ember.Enumerable = Ember.Mixin.create({
|
7360
7425
|
|
7361
7426
|
// compatibility
|
7362
7427
|
isEnumerable: true,
|
@@ -7389,7 +7454,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7389
7454
|
|
7390
7455
|
@method nextObject
|
7391
7456
|
@param {Number} index the current index of the iteration
|
7392
|
-
@param {Object} previousObject the value returned by the last call to
|
7457
|
+
@param {Object} previousObject the value returned by the last call to
|
7393
7458
|
`nextObject`.
|
7394
7459
|
@param {Object} context a context object you can use to maintain state.
|
7395
7460
|
@return {Object} the next object in the iteration or undefined
|
@@ -7408,10 +7473,10 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7408
7473
|
|
7409
7474
|
```javascript
|
7410
7475
|
var arr = ["a", "b", "c"];
|
7411
|
-
arr.firstObject
|
7476
|
+
arr.get('firstObject'); // "a"
|
7412
7477
|
|
7413
7478
|
var arr = [];
|
7414
|
-
arr.firstObject
|
7479
|
+
arr.get('firstObject'); // undefined
|
7415
7480
|
```
|
7416
7481
|
|
7417
7482
|
@property firstObject
|
@@ -7434,10 +7499,10 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7434
7499
|
|
7435
7500
|
```javascript
|
7436
7501
|
var arr = ["a", "b", "c"];
|
7437
|
-
arr.lastObject
|
7502
|
+
arr.get('lastObject'); // "c"
|
7438
7503
|
|
7439
7504
|
var arr = [];
|
7440
|
-
arr.lastObject
|
7505
|
+
arr.get('lastObject'); // undefined
|
7441
7506
|
```
|
7442
7507
|
|
7443
7508
|
@property lastObject
|
@@ -7570,7 +7635,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7570
7635
|
@return {Array} The mapped array.
|
7571
7636
|
*/
|
7572
7637
|
map: function(callback, target) {
|
7573
|
-
var ret = [];
|
7638
|
+
var ret = Ember.A([]);
|
7574
7639
|
this.forEach(function(x, idx, i) {
|
7575
7640
|
ret[idx] = callback.call(target, x, idx,i);
|
7576
7641
|
});
|
@@ -7620,7 +7685,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7620
7685
|
@return {Array} A filtered array.
|
7621
7686
|
*/
|
7622
7687
|
filter: function(callback, target) {
|
7623
|
-
var ret = [];
|
7688
|
+
var ret = Ember.A([]);
|
7624
7689
|
this.forEach(function(x, idx, i) {
|
7625
7690
|
if (callback.call(target, x, idx, i)) ret.push(x);
|
7626
7691
|
});
|
@@ -7909,7 +7974,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7909
7974
|
@return {Array} return values from calling invoke.
|
7910
7975
|
*/
|
7911
7976
|
invoke: function(methodName) {
|
7912
|
-
var args, ret = [];
|
7977
|
+
var args, ret = Ember.A([]);
|
7913
7978
|
if (arguments.length>1) args = a_slice.call(arguments, 1);
|
7914
7979
|
|
7915
7980
|
this.forEach(function(x, idx) {
|
@@ -7930,7 +7995,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7930
7995
|
@return {Array} the enumerable as an array.
|
7931
7996
|
*/
|
7932
7997
|
toArray: function() {
|
7933
|
-
var ret = [];
|
7998
|
+
var ret = Ember.A([]);
|
7934
7999
|
this.forEach(function(o, idx) { ret[idx] = o; });
|
7935
8000
|
return ret ;
|
7936
8001
|
},
|
@@ -7964,7 +8029,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7964
8029
|
*/
|
7965
8030
|
without: function(value) {
|
7966
8031
|
if (!this.contains(value)) return this; // nothing to do
|
7967
|
-
var ret = []
|
8032
|
+
var ret = Ember.A([]);
|
7968
8033
|
this.forEach(function(k) {
|
7969
8034
|
if (k !== value) ret[ret.length] = k;
|
7970
8035
|
}) ;
|
@@ -7984,7 +8049,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
7984
8049
|
@return {Ember.Enumerable}
|
7985
8050
|
*/
|
7986
8051
|
uniq: function() {
|
7987
|
-
var ret = [];
|
8052
|
+
var ret = Ember.A([]);
|
7988
8053
|
this.forEach(function(k){
|
7989
8054
|
if (a_indexOf(ret, k)<0) ret.push(k);
|
7990
8055
|
});
|
@@ -8016,7 +8081,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
8016
8081
|
|
8017
8082
|
@method addEnumerableObserver
|
8018
8083
|
@param {Object} target
|
8019
|
-
@param {Hash} opts
|
8084
|
+
@param {Hash} [opts]
|
8020
8085
|
*/
|
8021
8086
|
addEnumerableObserver: function(target, opts) {
|
8022
8087
|
var willChange = (opts && opts.willChange) || 'enumerableWillChange',
|
@@ -8114,7 +8179,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
8114
8179
|
@chainable
|
8115
8180
|
*/
|
8116
8181
|
enumerableContentDidChange: function(removing, adding) {
|
8117
|
-
var
|
8182
|
+
var removeCnt, addCnt, hasDelta;
|
8118
8183
|
|
8119
8184
|
if ('number' === typeof removing) removeCnt = removing;
|
8120
8185
|
else if (removing) removeCnt = get(removing, 'length');
|
@@ -8152,7 +8217,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
|
8152
8217
|
// HELPERS
|
8153
8218
|
//
|
8154
8219
|
|
8155
|
-
var get = Ember.get, set = Ember.set,
|
8220
|
+
var get = Ember.get, set = Ember.set, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
|
8156
8221
|
|
8157
8222
|
function none(obj) { return obj===null || obj===undefined; }
|
8158
8223
|
|
@@ -8294,15 +8359,19 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
|
|
8294
8359
|
```
|
8295
8360
|
|
8296
8361
|
@method slice
|
8297
|
-
@param
|
8298
|
-
@param
|
8362
|
+
@param {Integer} beginIndex (Optional) index to begin slicing from.
|
8363
|
+
@param {Integer} endIndex (Optional) index to end the slice at.
|
8299
8364
|
@return {Array} New array with specified slice
|
8300
8365
|
*/
|
8301
8366
|
slice: function(beginIndex, endIndex) {
|
8302
|
-
var ret = [];
|
8367
|
+
var ret = Ember.A([]);
|
8303
8368
|
var length = get(this, 'length') ;
|
8304
8369
|
if (none(beginIndex)) beginIndex = 0 ;
|
8305
8370
|
if (none(endIndex) || (endIndex > length)) endIndex = length ;
|
8371
|
+
|
8372
|
+
if (beginIndex < 0) beginIndex = length + beginIndex;
|
8373
|
+
if (endIndex < 0) endIndex = length + endIndex;
|
8374
|
+
|
8306
8375
|
while(beginIndex < endIndex) {
|
8307
8376
|
ret[ret.length] = this.objectAt(beginIndex++) ;
|
8308
8377
|
}
|
@@ -8456,9 +8525,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
|
|
8456
8525
|
|
8457
8526
|
@method arrayContentWillChange
|
8458
8527
|
@param {Number} startIdx The starting index in the array that will change.
|
8459
|
-
@param {Number} removeAmt The number of items that will be removed. If you
|
8528
|
+
@param {Number} removeAmt The number of items that will be removed. If you
|
8460
8529
|
pass `null` assumes 0
|
8461
|
-
@param {Number} addAmt The number of items that will be added If you
|
8530
|
+
@param {Number} addAmt The number of items that will be added If you
|
8462
8531
|
pass `null` assumes 0.
|
8463
8532
|
@return {Ember.Array} receiver
|
8464
8533
|
*/
|
@@ -8819,8 +8888,7 @@ var forEach = Ember.EnumerableUtils.forEach;
|
|
8819
8888
|
@extends Ember.Mixin
|
8820
8889
|
@uses Ember.Enumerable
|
8821
8890
|
*/
|
8822
|
-
Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable,
|
8823
|
-
/** @scope Ember.MutableEnumerable.prototype */ {
|
8891
|
+
Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, {
|
8824
8892
|
|
8825
8893
|
/**
|
8826
8894
|
__Required.__ You must implement this method to apply this mixin.
|
@@ -8905,7 +8973,7 @@ var EMPTY = [];
|
|
8905
8973
|
// HELPERS
|
8906
8974
|
//
|
8907
8975
|
|
8908
|
-
var get = Ember.get, set = Ember.set
|
8976
|
+
var get = Ember.get, set = Ember.set;
|
8909
8977
|
|
8910
8978
|
/**
|
8911
8979
|
This mixin defines the API for modifying array-like objects. These methods
|
@@ -8932,11 +9000,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
|
|
8932
9000
|
passed array. You should also call `this.enumerableContentDidChange()`
|
8933
9001
|
|
8934
9002
|
@method replace
|
8935
|
-
@param {Number} idx Starting index in the array to replace. If
|
9003
|
+
@param {Number} idx Starting index in the array to replace. If
|
8936
9004
|
idx >= length, then append to the end of the array.
|
8937
|
-
@param {Number} amt Number of elements that should be removed from
|
9005
|
+
@param {Number} amt Number of elements that should be removed from
|
8938
9006
|
the array, starting at *idx*.
|
8939
|
-
@param {Array} objects An array of zero or more objects that should be
|
9007
|
+
@param {Array} objects An array of zero or more objects that should be
|
8940
9008
|
inserted into the array at *idx*
|
8941
9009
|
*/
|
8942
9010
|
replace: Ember.required(),
|
@@ -9201,7 +9269,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
|
|
9201
9269
|
@submodule ember-runtime
|
9202
9270
|
*/
|
9203
9271
|
|
9204
|
-
var get = Ember.get, set = Ember.set
|
9272
|
+
var get = Ember.get, set = Ember.set;
|
9205
9273
|
|
9206
9274
|
/**
|
9207
9275
|
## Overview
|
@@ -9799,6 +9867,16 @@ Ember.TargetActionSupport = Ember.Mixin.create({
|
|
9799
9867
|
// outputs: 'Our person has greeted'
|
9800
9868
|
```
|
9801
9869
|
|
9870
|
+
You can also chain multiple event subscriptions:
|
9871
|
+
|
9872
|
+
```javascript
|
9873
|
+
person.on('greet', function() {
|
9874
|
+
console.log('Our person has greeted');
|
9875
|
+
}).one('greet', function() {
|
9876
|
+
console.log('Offer one-time special');
|
9877
|
+
}).off('event', this, forgetThis);
|
9878
|
+
```
|
9879
|
+
|
9802
9880
|
@class Evented
|
9803
9881
|
@namespace Ember
|
9804
9882
|
@extends Ember.Mixin
|
@@ -9826,6 +9904,7 @@ Ember.Evented = Ember.Mixin.create({
|
|
9826
9904
|
*/
|
9827
9905
|
on: function(name, target, method) {
|
9828
9906
|
Ember.addListener(this, name, target, method);
|
9907
|
+
return this;
|
9829
9908
|
},
|
9830
9909
|
|
9831
9910
|
/**
|
@@ -9849,6 +9928,7 @@ Ember.Evented = Ember.Mixin.create({
|
|
9849
9928
|
}
|
9850
9929
|
|
9851
9930
|
Ember.addListener(this, name, target, method, true);
|
9931
|
+
return this;
|
9852
9932
|
},
|
9853
9933
|
|
9854
9934
|
/**
|
@@ -9892,6 +9972,7 @@ Ember.Evented = Ember.Mixin.create({
|
|
9892
9972
|
*/
|
9893
9973
|
off: function(name, target, method) {
|
9894
9974
|
Ember.removeListener(this, name, target, method);
|
9975
|
+
return this;
|
9895
9976
|
},
|
9896
9977
|
|
9897
9978
|
/**
|
@@ -9922,8 +10003,7 @@ RSVP.async = function(callback, binding) {
|
|
9922
10003
|
@submodule ember-runtime
|
9923
10004
|
*/
|
9924
10005
|
|
9925
|
-
var get = Ember.get
|
9926
|
-
slice = Array.prototype.slice;
|
10006
|
+
var get = Ember.get;
|
9927
10007
|
|
9928
10008
|
/**
|
9929
10009
|
@class Deferred
|
@@ -9999,7 +10079,6 @@ Ember.Container.set = Ember.set;
|
|
9999
10079
|
var set = Ember.set, get = Ember.get,
|
10000
10080
|
o_create = Ember.create,
|
10001
10081
|
o_defineProperty = Ember.platform.defineProperty,
|
10002
|
-
a_slice = Array.prototype.slice,
|
10003
10082
|
GUID_KEY = Ember.GUID_KEY,
|
10004
10083
|
guidFor = Ember.guidFor,
|
10005
10084
|
generateGuid = Ember.generateGuid,
|
@@ -10147,6 +10226,37 @@ CoreObject.PrototypeMixin = Mixin.create({
|
|
10147
10226
|
|
10148
10227
|
isInstance: true,
|
10149
10228
|
|
10229
|
+
/**
|
10230
|
+
An overridable method called when objects are instantiated. By default,
|
10231
|
+
does nothing unless it is overridden during class definition.
|
10232
|
+
|
10233
|
+
Example:
|
10234
|
+
|
10235
|
+
```javascript
|
10236
|
+
App.Person = Ember.Object.extend({
|
10237
|
+
init: function() {
|
10238
|
+
this._super();
|
10239
|
+
alert('Name is ' + this.get('name'));
|
10240
|
+
}
|
10241
|
+
});
|
10242
|
+
|
10243
|
+
var steve = App.Person.create({
|
10244
|
+
name: "Steve"
|
10245
|
+
});
|
10246
|
+
|
10247
|
+
// alerts 'Name is Steve'.
|
10248
|
+
```
|
10249
|
+
|
10250
|
+
NOTE: If you do override `init` for a framework class like `Ember.View` or
|
10251
|
+
`Ember.ArrayController`, be sure to call `this._super()` in your
|
10252
|
+
`init` declaration! If you don't, Ember may not have an opportunity to
|
10253
|
+
do important setup work, and you'll see strange behavior in your
|
10254
|
+
application.
|
10255
|
+
|
10256
|
+
```
|
10257
|
+
|
10258
|
+
@method init
|
10259
|
+
*/
|
10150
10260
|
init: function() {},
|
10151
10261
|
|
10152
10262
|
/**
|
@@ -10191,14 +10301,14 @@ CoreObject.PrototypeMixin = Mixin.create({
|
|
10191
10301
|
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
|
10192
10302
|
```
|
10193
10303
|
Adding a single property that is not an array will just add it in the array:
|
10194
|
-
|
10304
|
+
|
10195
10305
|
```javascript
|
10196
10306
|
var view = App.FooBarView.create({
|
10197
10307
|
classNames: 'baz'
|
10198
10308
|
})
|
10199
10309
|
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
|
10200
10310
|
```
|
10201
|
-
|
10311
|
+
|
10202
10312
|
Using the `concatenatedProperties` property, we can tell to Ember that mix
|
10203
10313
|
the content of the properties.
|
10204
10314
|
|
@@ -10297,7 +10407,7 @@ CoreObject.PrototypeMixin = Mixin.create({
|
|
10297
10407
|
}
|
10298
10408
|
});
|
10299
10409
|
teacher = App.Teacher.create()
|
10300
|
-
teacher.toString();
|
10410
|
+
teacher.toString(); //=> "<App.Teacher:ember1026:Tom Dale>"
|
10301
10411
|
|
10302
10412
|
@method toString
|
10303
10413
|
@return {String} string representation
|
@@ -10476,687 +10586,723 @@ Ember.CoreObject = CoreObject;
|
|
10476
10586
|
@submodule ember-runtime
|
10477
10587
|
*/
|
10478
10588
|
|
10479
|
-
var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone;
|
10480
|
-
|
10481
10589
|
/**
|
10482
|
-
|
10590
|
+
`Ember.Object` is the main base class for all Ember objects. It is a subclass
|
10591
|
+
of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details,
|
10592
|
+
see the documentation for each of these.
|
10483
10593
|
|
10484
|
-
|
10485
|
-
|
10486
|
-
|
10487
|
-
|
10594
|
+
@class Object
|
10595
|
+
@namespace Ember
|
10596
|
+
@extends Ember.CoreObject
|
10597
|
+
@uses Ember.Observable
|
10598
|
+
*/
|
10599
|
+
Ember.Object = Ember.CoreObject.extend(Ember.Observable);
|
10600
|
+
Ember.Object.toString = function() { return "Ember.Object"; };
|
10488
10601
|
|
10489
|
-
|
10490
|
-
on any enumerable object including both Sets and Arrays.
|
10602
|
+
})();
|
10491
10603
|
|
10492
|
-
## Creating a Set
|
10493
10604
|
|
10494
|
-
You can create a set like you would most objects using
|
10495
|
-
`new Ember.Set()`. Most new sets you create will be empty, but you can
|
10496
|
-
also initialize the set with some content by passing an array or other
|
10497
|
-
enumerable of objects to the constructor.
|
10498
10605
|
|
10499
|
-
|
10500
|
-
|
10606
|
+
(function() {
|
10607
|
+
/**
|
10608
|
+
@module ember
|
10609
|
+
@submodule ember-runtime
|
10610
|
+
*/
|
10501
10611
|
|
10502
|
-
|
10503
|
-
// creates a new empty set
|
10504
|
-
var foundNames = new Ember.Set();
|
10612
|
+
var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
|
10505
10613
|
|
10506
|
-
|
10507
|
-
|
10614
|
+
/**
|
10615
|
+
A Namespace is an object usually used to contain other objects or methods
|
10616
|
+
such as an application or framework. Create a namespace anytime you want
|
10617
|
+
to define one of these new containers.
|
10508
10618
|
|
10509
|
-
|
10510
|
-
var namesCopy = new Ember.Set(names);
|
10619
|
+
# Example Usage
|
10511
10620
|
|
10512
|
-
|
10513
|
-
|
10621
|
+
```javascript
|
10622
|
+
MyFramework = Ember.Namespace.create({
|
10623
|
+
VERSION: '1.0.0'
|
10624
|
+
});
|
10514
10625
|
```
|
10515
10626
|
|
10516
|
-
|
10627
|
+
@class Namespace
|
10628
|
+
@namespace Ember
|
10629
|
+
@extends Ember.Object
|
10630
|
+
*/
|
10631
|
+
var Namespace = Ember.Namespace = Ember.Object.extend({
|
10632
|
+
isNamespace: true,
|
10517
10633
|
|
10518
|
-
|
10519
|
-
|
10520
|
-
|
10634
|
+
init: function() {
|
10635
|
+
Ember.Namespace.NAMESPACES.push(this);
|
10636
|
+
Ember.Namespace.PROCESSED = false;
|
10637
|
+
},
|
10521
10638
|
|
10522
|
-
|
10523
|
-
|
10524
|
-
|
10525
|
-
remove the object the first time and have no effect on future calls until
|
10526
|
-
you add the object to the set again.
|
10639
|
+
toString: function() {
|
10640
|
+
var name = get(this, 'name');
|
10641
|
+
if (name) { return name; }
|
10527
10642
|
|
10528
|
-
|
10529
|
-
|
10643
|
+
findNamespaces();
|
10644
|
+
return this[Ember.GUID_KEY+'_name'];
|
10645
|
+
},
|
10530
10646
|
|
10531
|
-
|
10532
|
-
|
10533
|
-
|
10534
|
-
queue when you don't care which order the jobs are executed in.
|
10647
|
+
nameClasses: function() {
|
10648
|
+
processNamespace([this.toString()], this, {});
|
10649
|
+
},
|
10535
10650
|
|
10536
|
-
|
10651
|
+
destroy: function() {
|
10652
|
+
var namespaces = Ember.Namespace.NAMESPACES;
|
10653
|
+
Ember.lookup[this.toString()] = undefined;
|
10654
|
+
namespaces.splice(indexOf.call(namespaces, this), 1);
|
10655
|
+
this._super();
|
10656
|
+
}
|
10657
|
+
});
|
10537
10658
|
|
10538
|
-
|
10539
|
-
|
10659
|
+
Namespace.reopenClass({
|
10660
|
+
NAMESPACES: [Ember],
|
10661
|
+
NAMESPACES_BY_ID: {},
|
10662
|
+
PROCESSED: false,
|
10663
|
+
processAll: processAllNamespaces,
|
10664
|
+
byName: function(name) {
|
10665
|
+
if (!Ember.BOOTED) {
|
10666
|
+
processAllNamespaces();
|
10667
|
+
}
|
10540
10668
|
|
10541
|
-
|
10669
|
+
return NAMESPACES_BY_ID[name];
|
10670
|
+
}
|
10671
|
+
});
|
10542
10672
|
|
10543
|
-
|
10544
|
-
alerted whenever the content changes. You can also add an enumerable
|
10545
|
-
observer to the set to be notified of specific objects that are added and
|
10546
|
-
removed from the set. See `Ember.Enumerable` for more information on
|
10547
|
-
enumerables.
|
10673
|
+
var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
|
10548
10674
|
|
10549
|
-
|
10550
|
-
|
10551
|
-
changes. It would be better if you could just adjust the filtered set based
|
10552
|
-
on what was changed on the original set. The same issue applies to merging
|
10553
|
-
sets, as well.
|
10675
|
+
var hasOwnProp = ({}).hasOwnProperty,
|
10676
|
+
guidFor = Ember.guidFor;
|
10554
10677
|
|
10555
|
-
|
10678
|
+
function processNamespace(paths, root, seen) {
|
10679
|
+
var idx = paths.length;
|
10556
10680
|
|
10557
|
-
|
10558
|
-
on the methods you will use with `Ember.Set`, please consult these mixins.
|
10559
|
-
The most useful ones will be `Ember.Enumerable` and
|
10560
|
-
`Ember.MutableEnumerable` which implement most of the common iterator
|
10561
|
-
methods you are used to on Array.
|
10681
|
+
NAMESPACES_BY_ID[paths.join('.')] = root;
|
10562
10682
|
|
10563
|
-
|
10564
|
-
|
10565
|
-
|
10566
|
-
|
10567
|
-
code that can know with certainty when the underlying set data will or
|
10568
|
-
will not be modified.
|
10683
|
+
// Loop over all of the keys in the namespace, looking for classes
|
10684
|
+
for(var key in root) {
|
10685
|
+
if (!hasOwnProp.call(root, key)) { continue; }
|
10686
|
+
var obj = root[key];
|
10569
10687
|
|
10570
|
-
|
10571
|
-
|
10572
|
-
|
10573
|
-
|
10574
|
-
|
10575
|
-
|
10576
|
-
@since Ember 0.9
|
10577
|
-
*/
|
10578
|
-
Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
|
10579
|
-
/** @scope Ember.Set.prototype */ {
|
10688
|
+
// If we are processing the `Ember` namespace, for example, the
|
10689
|
+
// `paths` will start with `["Ember"]`. Every iteration through
|
10690
|
+
// the loop will update the **second** element of this list with
|
10691
|
+
// the key, so processing `Ember.View` will make the Array
|
10692
|
+
// `['Ember', 'View']`.
|
10693
|
+
paths[idx] = key;
|
10580
10694
|
|
10581
|
-
|
10582
|
-
|
10583
|
-
|
10695
|
+
// If we have found an unprocessed class
|
10696
|
+
if (obj && obj.toString === classToString) {
|
10697
|
+
// Replace the class' `toString` with the dot-separated path
|
10698
|
+
// and set its `NAME_KEY`
|
10699
|
+
obj.toString = makeToString(paths.join('.'));
|
10700
|
+
obj[NAME_KEY] = paths.join('.');
|
10584
10701
|
|
10585
|
-
|
10586
|
-
|
10702
|
+
// Support nested namespaces
|
10703
|
+
} else if (obj && obj.isNamespace) {
|
10704
|
+
// Skip aliased namespaces
|
10705
|
+
if (seen[guidFor(obj)]) { continue; }
|
10706
|
+
seen[guidFor(obj)] = true;
|
10587
10707
|
|
10588
|
-
|
10589
|
-
|
10590
|
-
|
10591
|
-
|
10592
|
-
length: 0,
|
10708
|
+
// Process the child namespace
|
10709
|
+
processNamespace(paths, obj, seen);
|
10710
|
+
}
|
10711
|
+
}
|
10593
10712
|
|
10594
|
-
|
10595
|
-
|
10596
|
-
without having to recreate it.
|
10713
|
+
paths.length = idx; // cut out last item
|
10714
|
+
}
|
10597
10715
|
|
10598
|
-
|
10599
|
-
|
10600
|
-
colors.length; // 3
|
10601
|
-
colors.clear();
|
10602
|
-
colors.length; // 0
|
10603
|
-
```
|
10716
|
+
function findNamespaces() {
|
10717
|
+
var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace;
|
10604
10718
|
|
10605
|
-
|
10606
|
-
@return {Ember.Set} An empty Set
|
10607
|
-
*/
|
10608
|
-
clear: function() {
|
10609
|
-
if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
|
10719
|
+
if (Namespace.PROCESSED) { return; }
|
10610
10720
|
|
10611
|
-
|
10612
|
-
|
10721
|
+
for (var prop in lookup) {
|
10722
|
+
// These don't raise exceptions but can cause warnings
|
10723
|
+
if (prop === "parent" || prop === "top" || prop === "frameElement") { continue; }
|
10613
10724
|
|
10614
|
-
|
10725
|
+
// get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
|
10726
|
+
// globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
|
10727
|
+
if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; }
|
10728
|
+
// Unfortunately, some versions of IE don't support window.hasOwnProperty
|
10729
|
+
if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; }
|
10615
10730
|
|
10616
|
-
|
10617
|
-
|
10618
|
-
|
10731
|
+
// At times we are not allowed to access certain properties for security reasons.
|
10732
|
+
// There are also times where even if we can access them, we are not allowed to access their properties.
|
10733
|
+
try {
|
10734
|
+
obj = Ember.lookup[prop];
|
10735
|
+
isNamespace = obj && obj.isNamespace;
|
10736
|
+
} catch (e) {
|
10737
|
+
continue;
|
10738
|
+
}
|
10619
10739
|
|
10620
|
-
|
10621
|
-
|
10622
|
-
|
10623
|
-
delete this[i];
|
10740
|
+
if (isNamespace) {
|
10741
|
+
Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
|
10742
|
+
obj[NAME_KEY] = prop;
|
10624
10743
|
}
|
10744
|
+
}
|
10745
|
+
}
|
10625
10746
|
|
10626
|
-
|
10747
|
+
var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
|
10627
10748
|
|
10628
|
-
|
10629
|
-
|
10630
|
-
|
10749
|
+
function superClassString(mixin) {
|
10750
|
+
var superclass = mixin.superclass;
|
10751
|
+
if (superclass) {
|
10752
|
+
if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; }
|
10753
|
+
else { return superClassString(superclass); }
|
10754
|
+
} else {
|
10755
|
+
return;
|
10756
|
+
}
|
10757
|
+
}
|
10631
10758
|
|
10632
|
-
|
10633
|
-
|
10759
|
+
function classToString() {
|
10760
|
+
if (!Ember.BOOTED && !this[NAME_KEY]) {
|
10761
|
+
processAllNamespaces();
|
10762
|
+
}
|
10634
10763
|
|
10635
|
-
|
10636
|
-
Returns true if the passed object is also an enumerable that contains the
|
10637
|
-
same objects as the receiver.
|
10764
|
+
var ret;
|
10638
10765
|
|
10639
|
-
|
10640
|
-
|
10641
|
-
|
10766
|
+
if (this[NAME_KEY]) {
|
10767
|
+
ret = this[NAME_KEY];
|
10768
|
+
} else {
|
10769
|
+
var str = superClassString(this);
|
10770
|
+
if (str) {
|
10771
|
+
ret = "(subclass of " + str + ")";
|
10772
|
+
} else {
|
10773
|
+
ret = "(unknown mixin)";
|
10774
|
+
}
|
10775
|
+
this.toString = makeToString(ret);
|
10776
|
+
}
|
10642
10777
|
|
10643
|
-
|
10644
|
-
|
10645
|
-
```
|
10778
|
+
return ret;
|
10779
|
+
}
|
10646
10780
|
|
10647
|
-
|
10648
|
-
|
10649
|
-
|
10650
|
-
*/
|
10651
|
-
isEqual: function(obj) {
|
10652
|
-
// fail fast
|
10653
|
-
if (!Ember.Enumerable.detect(obj)) return false;
|
10781
|
+
function processAllNamespaces() {
|
10782
|
+
var unprocessedNamespaces = !Namespace.PROCESSED,
|
10783
|
+
unprocessedMixins = Ember.anyUnprocessedMixins;
|
10654
10784
|
|
10655
|
-
|
10656
|
-
|
10785
|
+
if (unprocessedNamespaces) {
|
10786
|
+
findNamespaces();
|
10787
|
+
Namespace.PROCESSED = true;
|
10788
|
+
}
|
10657
10789
|
|
10658
|
-
|
10659
|
-
|
10790
|
+
if (unprocessedNamespaces || unprocessedMixins) {
|
10791
|
+
var namespaces = Namespace.NAMESPACES, namespace;
|
10792
|
+
for (var i=0, l=namespaces.length; i<l; i++) {
|
10793
|
+
namespace = namespaces[i];
|
10794
|
+
processNamespace([namespace.toString()], namespace, {});
|
10660
10795
|
}
|
10661
10796
|
|
10662
|
-
|
10663
|
-
}
|
10797
|
+
Ember.anyUnprocessedMixins = false;
|
10798
|
+
}
|
10799
|
+
}
|
10664
10800
|
|
10665
|
-
|
10666
|
-
|
10667
|
-
|
10668
|
-
the passed value is null this method will have no effect.
|
10801
|
+
function makeToString(ret) {
|
10802
|
+
return function() { return ret; };
|
10803
|
+
}
|
10669
10804
|
|
10670
|
-
|
10805
|
+
Ember.Mixin.prototype.toString = classToString;
|
10671
10806
|
|
10672
|
-
|
10673
|
-
var colors = new Ember.Set();
|
10674
|
-
colors.add("blue"); // ["blue"]
|
10675
|
-
colors.add("blue"); // ["blue"]
|
10676
|
-
colors.add("red"); // ["blue", "red"]
|
10677
|
-
colors.add(null); // ["blue", "red"]
|
10678
|
-
colors.add(undefined); // ["blue", "red"]
|
10679
|
-
```
|
10807
|
+
})();
|
10680
10808
|
|
10681
|
-
@method add
|
10682
|
-
@param {Object} obj The object to add.
|
10683
|
-
@return {Ember.Set} The set itself.
|
10684
|
-
*/
|
10685
|
-
add: Ember.aliasMethod('addObject'),
|
10686
10809
|
|
10687
|
-
/**
|
10688
|
-
Removes the object from the set if it is found. If you pass a `null` value
|
10689
|
-
or an object that is already not in the set, this method will have no
|
10690
|
-
effect. This is an alias for `Ember.MutableEnumerable.removeObject()`.
|
10691
10810
|
|
10692
|
-
|
10693
|
-
|
10694
|
-
colors.remove("red"); // ["blue", "green"]
|
10695
|
-
colors.remove("purple"); // ["blue", "green"]
|
10696
|
-
colors.remove(null); // ["blue", "green"]
|
10697
|
-
```
|
10811
|
+
(function() {
|
10812
|
+
Ember.Application = Ember.Namespace.extend();
|
10698
10813
|
|
10699
|
-
|
10700
|
-
@param {Object} obj The object to remove
|
10701
|
-
@return {Ember.Set} The set itself.
|
10702
|
-
*/
|
10703
|
-
remove: Ember.aliasMethod('removeObject'),
|
10814
|
+
})();
|
10704
10815
|
|
10705
|
-
/**
|
10706
|
-
Removes the last element from the set and returns it, or `null` if it's empty.
|
10707
10816
|
|
10708
|
-
```javascript
|
10709
|
-
var colors = new Ember.Set(["green", "blue"]);
|
10710
|
-
colors.pop(); // "blue"
|
10711
|
-
colors.pop(); // "green"
|
10712
|
-
colors.pop(); // null
|
10713
|
-
```
|
10714
10817
|
|
10715
|
-
|
10716
|
-
|
10717
|
-
|
10718
|
-
|
10719
|
-
|
10720
|
-
var obj = this.length > 0 ? this[this.length-1] : null;
|
10721
|
-
this.remove(obj);
|
10722
|
-
return obj;
|
10723
|
-
},
|
10818
|
+
(function() {
|
10819
|
+
/**
|
10820
|
+
@module ember
|
10821
|
+
@submodule ember-runtime
|
10822
|
+
*/
|
10724
10823
|
|
10725
|
-
|
10726
|
-
|
10727
|
-
the set itself.
|
10824
|
+
var OUT_OF_RANGE_EXCEPTION = "Index out of range";
|
10825
|
+
var EMPTY = [];
|
10728
10826
|
|
10729
|
-
|
10827
|
+
var get = Ember.get, set = Ember.set;
|
10730
10828
|
|
10731
|
-
|
10732
|
-
|
10733
|
-
|
10734
|
-
|
10735
|
-
|
10736
|
-
```
|
10829
|
+
/**
|
10830
|
+
An ArrayProxy wraps any other object that implements `Ember.Array` and/or
|
10831
|
+
`Ember.MutableArray,` forwarding all requests. This makes it very useful for
|
10832
|
+
a number of binding use cases or other cases where being able to swap
|
10833
|
+
out the underlying array is useful.
|
10737
10834
|
|
10738
|
-
|
10739
|
-
@return {Ember.Set} The set itself.
|
10740
|
-
*/
|
10741
|
-
push: Ember.aliasMethod('addObject'),
|
10835
|
+
A simple example of usage:
|
10742
10836
|
|
10743
|
-
|
10744
|
-
|
10837
|
+
```javascript
|
10838
|
+
var pets = ['dog', 'cat', 'fish'];
|
10839
|
+
var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
|
10745
10840
|
|
10746
|
-
|
10841
|
+
ap.get('firstObject'); // 'dog'
|
10842
|
+
ap.set('content', ['amoeba', 'paramecium']);
|
10843
|
+
ap.get('firstObject'); // 'amoeba'
|
10844
|
+
```
|
10747
10845
|
|
10748
|
-
|
10749
|
-
|
10750
|
-
|
10751
|
-
colors.shift(); // "green"
|
10752
|
-
colors.shift(); // null
|
10753
|
-
```
|
10846
|
+
This class can also be useful as a layer to transform the contents of
|
10847
|
+
an array, as they are accessed. This can be done by overriding
|
10848
|
+
`objectAtContent`:
|
10754
10849
|
|
10755
|
-
|
10756
|
-
|
10757
|
-
|
10758
|
-
|
10850
|
+
```javascript
|
10851
|
+
var pets = ['dog', 'cat', 'fish'];
|
10852
|
+
var ap = Ember.ArrayProxy.create({
|
10853
|
+
content: Ember.A(pets),
|
10854
|
+
objectAtContent: function(idx) {
|
10855
|
+
return this.get('content').objectAt(idx).toUpperCase();
|
10856
|
+
}
|
10857
|
+
});
|
10759
10858
|
|
10760
|
-
|
10761
|
-
|
10762
|
-
the set itself.
|
10859
|
+
ap.get('firstObject'); // . 'DOG'
|
10860
|
+
```
|
10763
10861
|
|
10764
|
-
|
10862
|
+
@class ArrayProxy
|
10863
|
+
@namespace Ember
|
10864
|
+
@extends Ember.Object
|
10865
|
+
@uses Ember.MutableArray
|
10866
|
+
*/
|
10867
|
+
Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
|
10868
|
+
/** @scope Ember.ArrayProxy.prototype */ {
|
10765
10869
|
|
10766
|
-
|
10767
|
-
|
10768
|
-
|
10769
|
-
colors.unshift("green"); // ["red", "green"]
|
10770
|
-
colors.unshift("blue"); // ["red", "green", "blue"]
|
10771
|
-
```
|
10870
|
+
/**
|
10871
|
+
The content array. Must be an object that implements `Ember.Array` and/or
|
10872
|
+
`Ember.MutableArray.`
|
10772
10873
|
|
10773
|
-
@
|
10774
|
-
@
|
10874
|
+
@property content
|
10875
|
+
@type Ember.Array
|
10775
10876
|
*/
|
10776
|
-
|
10877
|
+
content: null,
|
10777
10878
|
|
10778
10879
|
/**
|
10779
|
-
|
10780
|
-
|
10781
|
-
|
10782
|
-
|
10783
|
-
```javascript
|
10784
|
-
var colors = new Ember.Set();
|
10785
|
-
colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
|
10786
|
-
```
|
10880
|
+
The array that the proxy pretends to be. In the default `ArrayProxy`
|
10881
|
+
implementation, this and `content` are the same. Subclasses of `ArrayProxy`
|
10882
|
+
can override this property to provide things like sorting and filtering.
|
10787
10883
|
|
10788
|
-
|
10789
|
-
@param {Ember.Enumerable} objects the objects to add.
|
10790
|
-
@return {Ember.Set} The set itself.
|
10884
|
+
@property arrangedContent
|
10791
10885
|
*/
|
10792
|
-
|
10886
|
+
arrangedContent: Ember.computed.alias('content'),
|
10793
10887
|
|
10794
10888
|
/**
|
10795
|
-
|
10796
|
-
|
10797
|
-
|
10889
|
+
Should actually retrieve the object at the specified index from the
|
10890
|
+
content. You can override this method in subclasses to transform the
|
10891
|
+
content item to something new.
|
10798
10892
|
|
10799
|
-
|
10800
|
-
var colors = new Ember.Set(["red", "green", "blue"]);
|
10801
|
-
colors.removeEach(["red", "blue"]); // ["green"]
|
10802
|
-
```
|
10893
|
+
This method will only be called if content is non-`null`.
|
10803
10894
|
|
10804
|
-
@method
|
10805
|
-
@param {
|
10806
|
-
@return {
|
10895
|
+
@method objectAtContent
|
10896
|
+
@param {Number} idx The index to retrieve.
|
10897
|
+
@return {Object} the value or undefined if none found
|
10807
10898
|
*/
|
10808
|
-
|
10899
|
+
objectAtContent: function(idx) {
|
10900
|
+
return get(this, 'arrangedContent').objectAt(idx);
|
10901
|
+
},
|
10809
10902
|
|
10810
|
-
|
10811
|
-
|
10812
|
-
|
10903
|
+
/**
|
10904
|
+
Should actually replace the specified objects on the content array.
|
10905
|
+
You can override this method in subclasses to transform the content item
|
10906
|
+
into something new.
|
10813
10907
|
|
10814
|
-
|
10815
|
-
this._super();
|
10816
|
-
if (items) this.addObjects(items);
|
10817
|
-
},
|
10908
|
+
This method will only be called if content is non-`null`.
|
10818
10909
|
|
10819
|
-
|
10820
|
-
|
10821
|
-
|
10910
|
+
@method replaceContent
|
10911
|
+
@param {Number} idx The starting index
|
10912
|
+
@param {Number} amt The number of items to remove from the content.
|
10913
|
+
@param {Array} objects Optional array of objects to insert or null if no
|
10914
|
+
objects.
|
10915
|
+
@return {void}
|
10916
|
+
*/
|
10917
|
+
replaceContent: function(idx, amt, objects) {
|
10918
|
+
get(this, 'content').replace(idx, amt, objects);
|
10822
10919
|
},
|
10823
10920
|
|
10824
|
-
|
10825
|
-
|
10826
|
-
return this.length > 0 ? this[0] : undefined;
|
10827
|
-
}),
|
10828
|
-
|
10829
|
-
// more optimized version
|
10830
|
-
lastObject: Ember.computed(function() {
|
10831
|
-
return this.length > 0 ? this[this.length-1] : undefined;
|
10832
|
-
}),
|
10921
|
+
/**
|
10922
|
+
@private
|
10833
10923
|
|
10834
|
-
|
10835
|
-
|
10836
|
-
if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
|
10837
|
-
if (none(obj)) return this; // nothing to do
|
10924
|
+
Invoked when the content property is about to change. Notifies observers that the
|
10925
|
+
entire array content will change.
|
10838
10926
|
|
10839
|
-
|
10840
|
-
|
10841
|
-
|
10842
|
-
|
10927
|
+
@method _contentWillChange
|
10928
|
+
*/
|
10929
|
+
_contentWillChange: Ember.beforeObserver(function() {
|
10930
|
+
this._teardownContent();
|
10931
|
+
}, 'content'),
|
10843
10932
|
|
10844
|
-
|
10933
|
+
_teardownContent: function() {
|
10934
|
+
var content = get(this, 'content');
|
10845
10935
|
|
10846
|
-
|
10936
|
+
if (content) {
|
10937
|
+
content.removeArrayObserver(this, {
|
10938
|
+
willChange: 'contentArrayWillChange',
|
10939
|
+
didChange: 'contentArrayDidChange'
|
10940
|
+
});
|
10941
|
+
}
|
10942
|
+
},
|
10847
10943
|
|
10848
|
-
|
10849
|
-
|
10944
|
+
contentArrayWillChange: Ember.K,
|
10945
|
+
contentArrayDidChange: Ember.K,
|
10850
10946
|
|
10851
|
-
|
10852
|
-
|
10853
|
-
this[len] = obj;
|
10854
|
-
set(this, 'length', len+1);
|
10947
|
+
/**
|
10948
|
+
@private
|
10855
10949
|
|
10856
|
-
|
10857
|
-
|
10950
|
+
Invoked when the content property changes. Notifies observers that the
|
10951
|
+
entire array content has changed.
|
10858
10952
|
|
10859
|
-
|
10953
|
+
@method _contentDidChange
|
10954
|
+
*/
|
10955
|
+
_contentDidChange: Ember.observer(function() {
|
10956
|
+
var content = get(this, 'content');
|
10957
|
+
|
10958
|
+
Ember.assert("Can't set ArrayProxy's content to itself", content !== this);
|
10959
|
+
|
10960
|
+
this._setupContent();
|
10961
|
+
}, 'content'),
|
10962
|
+
|
10963
|
+
_setupContent: function() {
|
10964
|
+
var content = get(this, 'content');
|
10965
|
+
|
10966
|
+
if (content) {
|
10967
|
+
content.addArrayObserver(this, {
|
10968
|
+
willChange: 'contentArrayWillChange',
|
10969
|
+
didChange: 'contentArrayDidChange'
|
10970
|
+
});
|
10971
|
+
}
|
10860
10972
|
},
|
10861
10973
|
|
10862
|
-
|
10863
|
-
|
10864
|
-
|
10865
|
-
if (none(obj)) return this; // nothing to do
|
10974
|
+
_arrangedContentWillChange: Ember.beforeObserver(function() {
|
10975
|
+
var arrangedContent = get(this, 'arrangedContent'),
|
10976
|
+
len = arrangedContent ? get(arrangedContent, 'length') : 0;
|
10866
10977
|
|
10867
|
-
|
10868
|
-
|
10869
|
-
len = get(this, 'length'),
|
10870
|
-
isFirst = idx === 0,
|
10871
|
-
isLast = idx === len-1,
|
10872
|
-
last, removed;
|
10978
|
+
this.arrangedContentArrayWillChange(this, 0, len, undefined);
|
10979
|
+
this.arrangedContentWillChange(this);
|
10873
10980
|
|
10981
|
+
this._teardownArrangedContent(arrangedContent);
|
10982
|
+
}, 'arrangedContent'),
|
10874
10983
|
|
10875
|
-
|
10876
|
-
|
10984
|
+
_arrangedContentDidChange: Ember.observer(function() {
|
10985
|
+
var arrangedContent = get(this, 'arrangedContent'),
|
10986
|
+
len = arrangedContent ? get(arrangedContent, 'length') : 0;
|
10877
10987
|
|
10878
|
-
|
10879
|
-
if (isFirst) { Ember.propertyWillChange(this, 'firstObject'); }
|
10880
|
-
if (isLast) { Ember.propertyWillChange(this, 'lastObject'); }
|
10988
|
+
Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
|
10881
10989
|
|
10882
|
-
|
10883
|
-
if (idx < len-1) {
|
10884
|
-
last = this[len-1];
|
10885
|
-
this[idx] = last;
|
10886
|
-
this[guidFor(last)] = idx;
|
10887
|
-
}
|
10990
|
+
this._setupArrangedContent();
|
10888
10991
|
|
10889
|
-
|
10890
|
-
|
10891
|
-
|
10992
|
+
this.arrangedContentDidChange(this);
|
10993
|
+
this.arrangedContentArrayDidChange(this, 0, undefined, len);
|
10994
|
+
}, 'arrangedContent'),
|
10892
10995
|
|
10893
|
-
|
10894
|
-
|
10895
|
-
this.enumerableContentDidChange(removed, null);
|
10896
|
-
}
|
10996
|
+
_setupArrangedContent: function() {
|
10997
|
+
var arrangedContent = get(this, 'arrangedContent');
|
10897
10998
|
|
10898
|
-
|
10999
|
+
if (arrangedContent) {
|
11000
|
+
arrangedContent.addArrayObserver(this, {
|
11001
|
+
willChange: 'arrangedContentArrayWillChange',
|
11002
|
+
didChange: 'arrangedContentArrayDidChange'
|
11003
|
+
});
|
11004
|
+
}
|
10899
11005
|
},
|
10900
11006
|
|
10901
|
-
|
10902
|
-
|
10903
|
-
return this[guidFor(obj)]>=0;
|
10904
|
-
},
|
11007
|
+
_teardownArrangedContent: function() {
|
11008
|
+
var arrangedContent = get(this, 'arrangedContent');
|
10905
11009
|
|
10906
|
-
|
10907
|
-
|
10908
|
-
|
10909
|
-
|
10910
|
-
|
10911
|
-
ret[guidFor(this[loc])] = loc;
|
11010
|
+
if (arrangedContent) {
|
11011
|
+
arrangedContent.removeArrayObserver(this, {
|
11012
|
+
willChange: 'arrangedContentArrayWillChange',
|
11013
|
+
didChange: 'arrangedContentArrayDidChange'
|
11014
|
+
});
|
10912
11015
|
}
|
10913
|
-
return ret;
|
10914
11016
|
},
|
10915
11017
|
|
10916
|
-
|
10917
|
-
|
10918
|
-
for(idx = 0; idx < len; idx++) {
|
10919
|
-
array[idx] = this[idx];
|
10920
|
-
}
|
10921
|
-
return "Ember.Set<%@>".fmt(array.join(','));
|
10922
|
-
}
|
11018
|
+
arrangedContentWillChange: Ember.K,
|
11019
|
+
arrangedContentDidChange: Ember.K,
|
10923
11020
|
|
10924
|
-
|
11021
|
+
objectAt: function(idx) {
|
11022
|
+
return get(this, 'content') && this.objectAtContent(idx);
|
11023
|
+
},
|
10925
11024
|
|
10926
|
-
|
11025
|
+
length: Ember.computed(function() {
|
11026
|
+
var arrangedContent = get(this, 'arrangedContent');
|
11027
|
+
return arrangedContent ? get(arrangedContent, 'length') : 0;
|
11028
|
+
// No dependencies since Enumerable notifies length of change
|
11029
|
+
}),
|
10927
11030
|
|
11031
|
+
_replace: function(idx, amt, objects) {
|
11032
|
+
var content = get(this, 'content');
|
11033
|
+
Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content);
|
11034
|
+
if (content) this.replaceContent(idx, amt, objects);
|
11035
|
+
return this;
|
11036
|
+
},
|
10928
11037
|
|
11038
|
+
replace: function() {
|
11039
|
+
if (get(this, 'arrangedContent') === get(this, 'content')) {
|
11040
|
+
this._replace.apply(this, arguments);
|
11041
|
+
} else {
|
11042
|
+
throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed.");
|
11043
|
+
}
|
11044
|
+
},
|
10929
11045
|
|
10930
|
-
|
10931
|
-
|
10932
|
-
|
10933
|
-
|
10934
|
-
|
11046
|
+
_insertAt: function(idx, object) {
|
11047
|
+
if (idx > get(this, 'content.length')) throw new Error(OUT_OF_RANGE_EXCEPTION);
|
11048
|
+
this._replace(idx, 0, [object]);
|
11049
|
+
return this;
|
11050
|
+
},
|
10935
11051
|
|
10936
|
-
|
10937
|
-
|
10938
|
-
|
10939
|
-
|
11052
|
+
insertAt: function(idx, object) {
|
11053
|
+
if (get(this, 'arrangedContent') === get(this, 'content')) {
|
11054
|
+
return this._insertAt(idx, object);
|
11055
|
+
} else {
|
11056
|
+
throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed.");
|
11057
|
+
}
|
11058
|
+
},
|
10940
11059
|
|
10941
|
-
|
10942
|
-
|
10943
|
-
|
10944
|
-
|
10945
|
-
|
10946
|
-
Ember.Object = Ember.CoreObject.extend(Ember.Observable);
|
10947
|
-
Ember.Object.toString = function() { return "Ember.Object"; };
|
11060
|
+
removeAt: function(start, len) {
|
11061
|
+
if ('number' === typeof start) {
|
11062
|
+
var content = get(this, 'content'),
|
11063
|
+
arrangedContent = get(this, 'arrangedContent'),
|
11064
|
+
indices = [], i;
|
10948
11065
|
|
10949
|
-
|
11066
|
+
if ((start < 0) || (start >= get(this, 'length'))) {
|
11067
|
+
throw new Error(OUT_OF_RANGE_EXCEPTION);
|
11068
|
+
}
|
10950
11069
|
|
11070
|
+
if (len === undefined) len = 1;
|
10951
11071
|
|
11072
|
+
// Get a list of indices in original content to remove
|
11073
|
+
for (i=start; i<start+len; i++) {
|
11074
|
+
// Use arrangedContent here so we avoid confusion with objects transformed by objectAtContent
|
11075
|
+
indices.push(content.indexOf(arrangedContent.objectAt(i)));
|
11076
|
+
}
|
10952
11077
|
|
10953
|
-
|
10954
|
-
|
10955
|
-
@module ember
|
10956
|
-
@submodule ember-runtime
|
10957
|
-
*/
|
11078
|
+
// Replace in reverse order since indices will change
|
11079
|
+
indices.sort(function(a,b) { return b - a; });
|
10958
11080
|
|
10959
|
-
|
11081
|
+
Ember.beginPropertyChanges();
|
11082
|
+
for (i=0; i<indices.length; i++) {
|
11083
|
+
this._replace(indices[i], 1, EMPTY);
|
11084
|
+
}
|
11085
|
+
Ember.endPropertyChanges();
|
11086
|
+
}
|
10960
11087
|
|
10961
|
-
|
10962
|
-
|
10963
|
-
such as an application or framework. Create a namespace anytime you want
|
10964
|
-
to define one of these new containers.
|
11088
|
+
return this ;
|
11089
|
+
},
|
10965
11090
|
|
10966
|
-
|
11091
|
+
pushObject: function(obj) {
|
11092
|
+
this._insertAt(get(this, 'content.length'), obj) ;
|
11093
|
+
return obj ;
|
11094
|
+
},
|
10967
11095
|
|
10968
|
-
|
10969
|
-
|
10970
|
-
|
10971
|
-
}
|
10972
|
-
```
|
11096
|
+
pushObjects: function(objects) {
|
11097
|
+
this._replace(get(this, 'length'), 0, objects);
|
11098
|
+
return this;
|
11099
|
+
},
|
10973
11100
|
|
10974
|
-
|
10975
|
-
|
10976
|
-
@extends Ember.Object
|
10977
|
-
*/
|
10978
|
-
var Namespace = Ember.Namespace = Ember.Object.extend({
|
10979
|
-
isNamespace: true,
|
11101
|
+
setObjects: function(objects) {
|
11102
|
+
if (objects.length === 0) return this.clear();
|
10980
11103
|
|
10981
|
-
|
10982
|
-
|
10983
|
-
|
11104
|
+
var len = get(this, 'length');
|
11105
|
+
this._replace(0, len, objects);
|
11106
|
+
return this;
|
10984
11107
|
},
|
10985
11108
|
|
10986
|
-
|
10987
|
-
|
10988
|
-
|
11109
|
+
unshiftObject: function(obj) {
|
11110
|
+
this._insertAt(0, obj) ;
|
11111
|
+
return obj ;
|
11112
|
+
},
|
10989
11113
|
|
10990
|
-
|
10991
|
-
|
11114
|
+
unshiftObjects: function(objects) {
|
11115
|
+
this._replace(0, 0, objects);
|
11116
|
+
return this;
|
10992
11117
|
},
|
10993
11118
|
|
10994
|
-
|
10995
|
-
|
11119
|
+
slice: function() {
|
11120
|
+
var arr = this.toArray();
|
11121
|
+
return arr.slice.apply(arr, arguments);
|
10996
11122
|
},
|
10997
11123
|
|
10998
|
-
|
10999
|
-
|
11000
|
-
|
11001
|
-
namespaces.splice(indexOf.call(namespaces, this), 1);
|
11002
|
-
this._super();
|
11003
|
-
}
|
11004
|
-
});
|
11124
|
+
arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
|
11125
|
+
this.arrayContentWillChange(idx, removedCnt, addedCnt);
|
11126
|
+
},
|
11005
11127
|
|
11006
|
-
|
11007
|
-
|
11008
|
-
|
11009
|
-
PROCESSED: false,
|
11010
|
-
processAll: processAllNamespaces,
|
11011
|
-
byName: function(name) {
|
11012
|
-
if (!Ember.BOOTED) {
|
11013
|
-
processAllNamespaces();
|
11014
|
-
}
|
11128
|
+
arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
|
11129
|
+
this.arrayContentDidChange(idx, removedCnt, addedCnt);
|
11130
|
+
},
|
11015
11131
|
|
11016
|
-
|
11132
|
+
init: function() {
|
11133
|
+
this._super();
|
11134
|
+
this._setupContent();
|
11135
|
+
this._setupArrangedContent();
|
11136
|
+
},
|
11137
|
+
|
11138
|
+
willDestroy: function() {
|
11139
|
+
this._teardownArrangedContent();
|
11140
|
+
this._teardownContent();
|
11017
11141
|
}
|
11018
11142
|
});
|
11019
11143
|
|
11020
|
-
var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
|
11021
11144
|
|
11022
|
-
|
11023
|
-
guidFor = Ember.guidFor;
|
11145
|
+
})();
|
11024
11146
|
|
11025
|
-
function processNamespace(paths, root, seen) {
|
11026
|
-
var idx = paths.length;
|
11027
11147
|
|
11028
|
-
NAMESPACES_BY_ID[paths.join('.')] = root;
|
11029
11148
|
|
11030
|
-
|
11031
|
-
|
11032
|
-
|
11033
|
-
|
11034
|
-
|
11035
|
-
// If we are processing the `Ember` namespace, for example, the
|
11036
|
-
// `paths` will start with `["Ember"]`. Every iteration through
|
11037
|
-
// the loop will update the **second** element of this list with
|
11038
|
-
// the key, so processing `Ember.View` will make the Array
|
11039
|
-
// `['Ember', 'View']`.
|
11040
|
-
paths[idx] = key;
|
11041
|
-
|
11042
|
-
// If we have found an unprocessed class
|
11043
|
-
if (obj && obj.toString === classToString) {
|
11044
|
-
// Replace the class' `toString` with the dot-separated path
|
11045
|
-
// and set its `NAME_KEY`
|
11046
|
-
obj.toString = makeToString(paths.join('.'));
|
11047
|
-
obj[NAME_KEY] = paths.join('.');
|
11149
|
+
(function() {
|
11150
|
+
/**
|
11151
|
+
@module ember
|
11152
|
+
@submodule ember-runtime
|
11153
|
+
*/
|
11048
11154
|
|
11049
|
-
|
11050
|
-
|
11051
|
-
|
11052
|
-
|
11053
|
-
|
11155
|
+
var get = Ember.get,
|
11156
|
+
set = Ember.set,
|
11157
|
+
fmt = Ember.String.fmt,
|
11158
|
+
addBeforeObserver = Ember.addBeforeObserver,
|
11159
|
+
addObserver = Ember.addObserver,
|
11160
|
+
removeBeforeObserver = Ember.removeBeforeObserver,
|
11161
|
+
removeObserver = Ember.removeObserver,
|
11162
|
+
propertyWillChange = Ember.propertyWillChange,
|
11163
|
+
propertyDidChange = Ember.propertyDidChange;
|
11054
11164
|
|
11055
|
-
|
11056
|
-
|
11057
|
-
|
11058
|
-
|
11165
|
+
function contentPropertyWillChange(content, contentKey) {
|
11166
|
+
var key = contentKey.slice(8); // remove "content."
|
11167
|
+
if (key in this) { return; } // if shadowed in proxy
|
11168
|
+
propertyWillChange(this, key);
|
11169
|
+
}
|
11059
11170
|
|
11060
|
-
|
11171
|
+
function contentPropertyDidChange(content, contentKey) {
|
11172
|
+
var key = contentKey.slice(8); // remove "content."
|
11173
|
+
if (key in this) { return; } // if shadowed in proxy
|
11174
|
+
propertyDidChange(this, key);
|
11061
11175
|
}
|
11062
11176
|
|
11063
|
-
|
11064
|
-
|
11177
|
+
/**
|
11178
|
+
`Ember.ObjectProxy` forwards all properties not defined by the proxy itself
|
11179
|
+
to a proxied `content` object.
|
11065
11180
|
|
11066
|
-
|
11181
|
+
```javascript
|
11182
|
+
object = Ember.Object.create({
|
11183
|
+
name: 'Foo'
|
11184
|
+
});
|
11067
11185
|
|
11068
|
-
|
11069
|
-
|
11070
|
-
|
11186
|
+
proxy = Ember.ObjectProxy.create({
|
11187
|
+
content: object
|
11188
|
+
});
|
11071
11189
|
|
11072
|
-
|
11073
|
-
|
11074
|
-
|
11075
|
-
|
11076
|
-
if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; }
|
11190
|
+
// Access and change existing properties
|
11191
|
+
proxy.get('name') // 'Foo'
|
11192
|
+
proxy.set('name', 'Bar');
|
11193
|
+
object.get('name') // 'Bar'
|
11077
11194
|
|
11078
|
-
|
11079
|
-
|
11080
|
-
|
11081
|
-
|
11082
|
-
isNamespace = obj && obj.isNamespace;
|
11083
|
-
} catch (e) {
|
11084
|
-
continue;
|
11085
|
-
}
|
11195
|
+
// Create new 'description' property on `object`
|
11196
|
+
proxy.set('description', 'Foo is a whizboo baz');
|
11197
|
+
object.get('description') // 'Foo is a whizboo baz'
|
11198
|
+
```
|
11086
11199
|
|
11087
|
-
|
11088
|
-
|
11089
|
-
obj[NAME_KEY] = prop;
|
11090
|
-
}
|
11091
|
-
}
|
11092
|
-
}
|
11200
|
+
While `content` is unset, setting a property to be delegated will throw an
|
11201
|
+
Error.
|
11093
11202
|
|
11094
|
-
|
11203
|
+
```javascript
|
11204
|
+
proxy = Ember.ObjectProxy.create({
|
11205
|
+
content: null,
|
11206
|
+
flag: null
|
11207
|
+
});
|
11208
|
+
proxy.set('flag', true);
|
11209
|
+
proxy.get('flag'); // true
|
11210
|
+
proxy.get('foo'); // undefined
|
11211
|
+
proxy.set('foo', 'data'); // throws Error
|
11212
|
+
```
|
11095
11213
|
|
11096
|
-
|
11097
|
-
var superclass = mixin.superclass;
|
11098
|
-
if (superclass) {
|
11099
|
-
if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; }
|
11100
|
-
else { return superClassString(superclass); }
|
11101
|
-
} else {
|
11102
|
-
return;
|
11103
|
-
}
|
11104
|
-
}
|
11214
|
+
Delegated properties can be bound to and will change when content is updated.
|
11105
11215
|
|
11106
|
-
|
11107
|
-
if (!Ember.BOOTED && !this[NAME_KEY]) {
|
11108
|
-
processAllNamespaces();
|
11109
|
-
}
|
11216
|
+
Computed properties on the proxy itself can depend on delegated properties.
|
11110
11217
|
|
11111
|
-
|
11218
|
+
```javascript
|
11219
|
+
ProxyWithComputedProperty = Ember.ObjectProxy.extend({
|
11220
|
+
fullName: function () {
|
11221
|
+
var firstName = this.get('firstName'),
|
11222
|
+
lastName = this.get('lastName');
|
11223
|
+
if (firstName && lastName) {
|
11224
|
+
return firstName + ' ' + lastName;
|
11225
|
+
}
|
11226
|
+
return firstName || lastName;
|
11227
|
+
}.property('firstName', 'lastName')
|
11228
|
+
});
|
11112
11229
|
|
11113
|
-
|
11114
|
-
ret = this[NAME_KEY];
|
11115
|
-
} else {
|
11116
|
-
var str = superClassString(this);
|
11117
|
-
if (str) {
|
11118
|
-
ret = "(subclass of " + str + ")";
|
11119
|
-
} else {
|
11120
|
-
ret = "(unknown mixin)";
|
11121
|
-
}
|
11122
|
-
this.toString = makeToString(ret);
|
11123
|
-
}
|
11230
|
+
proxy = ProxyWithComputedProperty.create();
|
11124
11231
|
|
11125
|
-
|
11126
|
-
|
11232
|
+
proxy.get('fullName'); // undefined
|
11233
|
+
proxy.set('content', {
|
11234
|
+
firstName: 'Tom', lastName: 'Dale'
|
11235
|
+
}); // triggers property change for fullName on proxy
|
11127
11236
|
|
11128
|
-
|
11129
|
-
|
11130
|
-
unprocessedMixins = Ember.anyUnprocessedMixins;
|
11237
|
+
proxy.get('fullName'); // 'Tom Dale'
|
11238
|
+
```
|
11131
11239
|
|
11132
|
-
|
11133
|
-
|
11134
|
-
|
11135
|
-
|
11240
|
+
@class ObjectProxy
|
11241
|
+
@namespace Ember
|
11242
|
+
@extends Ember.Object
|
11243
|
+
*/
|
11244
|
+
Ember.ObjectProxy = Ember.Object.extend(
|
11245
|
+
/** @scope Ember.ObjectProxy.prototype */ {
|
11246
|
+
/**
|
11247
|
+
The object whose properties will be forwarded.
|
11136
11248
|
|
11137
|
-
|
11138
|
-
|
11139
|
-
|
11140
|
-
|
11141
|
-
|
11142
|
-
|
11249
|
+
@property content
|
11250
|
+
@type Ember.Object
|
11251
|
+
@default null
|
11252
|
+
*/
|
11253
|
+
content: null,
|
11254
|
+
_contentDidChange: Ember.observer(function() {
|
11255
|
+
Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
|
11256
|
+
}, 'content'),
|
11143
11257
|
|
11144
|
-
|
11145
|
-
}
|
11146
|
-
}
|
11258
|
+
isTruthy: Ember.computed.bool('content'),
|
11147
11259
|
|
11148
|
-
|
11149
|
-
return function() { return ret; };
|
11150
|
-
}
|
11260
|
+
_debugContainerKey: null,
|
11151
11261
|
|
11152
|
-
|
11262
|
+
willWatchProperty: function (key) {
|
11263
|
+
var contentKey = 'content.' + key;
|
11264
|
+
addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
|
11265
|
+
addObserver(this, contentKey, null, contentPropertyDidChange);
|
11266
|
+
},
|
11153
11267
|
|
11154
|
-
|
11268
|
+
didUnwatchProperty: function (key) {
|
11269
|
+
var contentKey = 'content.' + key;
|
11270
|
+
removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
|
11271
|
+
removeObserver(this, contentKey, null, contentPropertyDidChange);
|
11272
|
+
},
|
11155
11273
|
|
11274
|
+
unknownProperty: function (key) {
|
11275
|
+
var content = get(this, 'content');
|
11276
|
+
if (content) {
|
11277
|
+
return get(content, key);
|
11278
|
+
}
|
11279
|
+
},
|
11156
11280
|
|
11281
|
+
setUnknownProperty: function (key, value) {
|
11282
|
+
var content = get(this, 'content');
|
11283
|
+
Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
|
11284
|
+
return set(content, key, value);
|
11285
|
+
}
|
11286
|
+
});
|
11157
11287
|
|
11158
|
-
(
|
11159
|
-
|
11288
|
+
Ember.ObjectProxy.reopenClass({
|
11289
|
+
create: function () {
|
11290
|
+
var mixin, prototype, i, l, properties, keyName;
|
11291
|
+
if (arguments.length) {
|
11292
|
+
prototype = this.proto();
|
11293
|
+
for (i = 0, l = arguments.length; i < l; i++) {
|
11294
|
+
properties = arguments[i];
|
11295
|
+
for (keyName in properties) {
|
11296
|
+
if (!properties.hasOwnProperty(keyName) || keyName in prototype) { continue; }
|
11297
|
+
if (!mixin) mixin = {};
|
11298
|
+
mixin[keyName] = null;
|
11299
|
+
}
|
11300
|
+
}
|
11301
|
+
if (mixin) this._initMixins([mixin]);
|
11302
|
+
}
|
11303
|
+
return this._super.apply(this, arguments);
|
11304
|
+
}
|
11305
|
+
});
|
11160
11306
|
|
11161
11307
|
})();
|
11162
11308
|
|
@@ -11169,237 +11315,203 @@ Ember.Application = Ember.Namespace.extend();
|
|
11169
11315
|
*/
|
11170
11316
|
|
11171
11317
|
|
11172
|
-
var get = Ember.get,
|
11173
|
-
|
11174
|
-
/**
|
11175
|
-
An ArrayProxy wraps any other object that implements `Ember.Array` and/or
|
11176
|
-
`Ember.MutableArray,` forwarding all requests. This makes it very useful for
|
11177
|
-
a number of binding use cases or other cases where being able to swap
|
11178
|
-
out the underlying array is useful.
|
11318
|
+
var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
|
11319
|
+
var forEach = Ember.EnumerableUtils.forEach;
|
11179
11320
|
|
11180
|
-
|
11321
|
+
var EachArray = Ember.Object.extend(Ember.Array, {
|
11181
11322
|
|
11182
|
-
|
11183
|
-
|
11184
|
-
|
11323
|
+
init: function(content, keyName, owner) {
|
11324
|
+
this._super();
|
11325
|
+
this._keyName = keyName;
|
11326
|
+
this._owner = owner;
|
11327
|
+
this._content = content;
|
11328
|
+
},
|
11185
11329
|
|
11186
|
-
|
11187
|
-
|
11188
|
-
|
11189
|
-
|
11190
|
-
|
11191
|
-
This class can also be useful as a layer to transform the contents of
|
11192
|
-
an array, as they are accessed. This can be done by overriding
|
11193
|
-
`objectAtContent`:
|
11330
|
+
objectAt: function(idx) {
|
11331
|
+
var item = this._content.objectAt(idx);
|
11332
|
+
return item && get(item, this._keyName);
|
11333
|
+
},
|
11194
11334
|
|
11195
|
-
|
11196
|
-
|
11197
|
-
|
11198
|
-
|
11199
|
-
objectAtContent: function(idx) {
|
11200
|
-
return this.get('content').objectAt(idx).toUpperCase();
|
11201
|
-
}
|
11202
|
-
});
|
11335
|
+
length: Ember.computed(function() {
|
11336
|
+
var content = this._content;
|
11337
|
+
return content ? get(content, 'length') : 0;
|
11338
|
+
})
|
11203
11339
|
|
11204
|
-
|
11205
|
-
```
|
11340
|
+
});
|
11206
11341
|
|
11207
|
-
|
11208
|
-
@namespace Ember
|
11209
|
-
@extends Ember.Object
|
11210
|
-
@uses Ember.MutableArray
|
11211
|
-
*/
|
11212
|
-
Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
|
11213
|
-
/** @scope Ember.ArrayProxy.prototype */ {
|
11342
|
+
var IS_OBSERVER = /^.+:(before|change)$/;
|
11214
11343
|
|
11215
|
-
|
11216
|
-
|
11217
|
-
|
11344
|
+
function addObserverForContentKey(content, keyName, proxy, idx, loc) {
|
11345
|
+
var objects = proxy._objects, guid;
|
11346
|
+
if (!objects) objects = proxy._objects = {};
|
11218
11347
|
|
11219
|
-
|
11220
|
-
|
11221
|
-
|
11222
|
-
|
11348
|
+
while(--loc>=idx) {
|
11349
|
+
var item = content.objectAt(loc);
|
11350
|
+
if (item) {
|
11351
|
+
Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
|
11352
|
+
Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange');
|
11223
11353
|
|
11224
|
-
|
11225
|
-
|
11226
|
-
|
11227
|
-
|
11354
|
+
// keep track of the index each item was found at so we can map
|
11355
|
+
// it back when the obj changes.
|
11356
|
+
guid = guidFor(item);
|
11357
|
+
if (!objects[guid]) objects[guid] = [];
|
11358
|
+
objects[guid].push(loc);
|
11359
|
+
}
|
11360
|
+
}
|
11361
|
+
}
|
11228
11362
|
|
11229
|
-
|
11230
|
-
|
11231
|
-
|
11363
|
+
function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
|
11364
|
+
var objects = proxy._objects;
|
11365
|
+
if (!objects) objects = proxy._objects = {};
|
11366
|
+
var indicies, guid;
|
11232
11367
|
|
11233
|
-
|
11234
|
-
|
11235
|
-
|
11236
|
-
|
11368
|
+
while(--loc>=idx) {
|
11369
|
+
var item = content.objectAt(loc);
|
11370
|
+
if (item) {
|
11371
|
+
Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
|
11372
|
+
Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange');
|
11237
11373
|
|
11238
|
-
|
11374
|
+
guid = guidFor(item);
|
11375
|
+
indicies = objects[guid];
|
11376
|
+
indicies[indicies.indexOf(loc)] = null;
|
11377
|
+
}
|
11378
|
+
}
|
11379
|
+
}
|
11239
11380
|
|
11240
|
-
|
11241
|
-
|
11242
|
-
|
11243
|
-
|
11244
|
-
objectAtContent: function(idx) {
|
11245
|
-
return get(this, 'arrangedContent').objectAt(idx);
|
11246
|
-
},
|
11381
|
+
/**
|
11382
|
+
This is the object instance returned when you get the `@each` property on an
|
11383
|
+
array. It uses the unknownProperty handler to automatically create
|
11384
|
+
EachArray instances for property names.
|
11247
11385
|
|
11248
|
-
|
11249
|
-
|
11250
|
-
|
11251
|
-
|
11386
|
+
@private
|
11387
|
+
@class EachProxy
|
11388
|
+
@namespace Ember
|
11389
|
+
@extends Ember.Object
|
11390
|
+
*/
|
11391
|
+
Ember.EachProxy = Ember.Object.extend({
|
11252
11392
|
|
11253
|
-
|
11393
|
+
init: function(content) {
|
11394
|
+
this._super();
|
11395
|
+
this._content = content;
|
11396
|
+
content.addArrayObserver(this);
|
11254
11397
|
|
11255
|
-
|
11256
|
-
|
11257
|
-
|
11258
|
-
|
11259
|
-
|
11260
|
-
@return {void}
|
11261
|
-
*/
|
11262
|
-
replaceContent: function(idx, amt, objects) {
|
11263
|
-
get(this, 'content').replace(idx, amt, objects);
|
11398
|
+
// in case someone is already observing some keys make sure they are
|
11399
|
+
// added
|
11400
|
+
forEach(Ember.watchedEvents(this), function(eventName) {
|
11401
|
+
this.didAddListener(eventName);
|
11402
|
+
}, this);
|
11264
11403
|
},
|
11265
11404
|
|
11266
11405
|
/**
|
11267
|
-
|
11268
|
-
|
11269
|
-
Invoked when the content property is about to change. Notifies observers that the
|
11270
|
-
entire array content will change.
|
11406
|
+
You can directly access mapped properties by simply requesting them.
|
11407
|
+
The `unknownProperty` handler will generate an EachArray of each item.
|
11271
11408
|
|
11272
|
-
@method
|
11409
|
+
@method unknownProperty
|
11410
|
+
@param keyName {String}
|
11411
|
+
@param value {anything}
|
11273
11412
|
*/
|
11274
|
-
|
11275
|
-
|
11276
|
-
|
11277
|
-
|
11278
|
-
|
11279
|
-
|
11280
|
-
|
11281
|
-
if (content) {
|
11282
|
-
content.removeArrayObserver(this, {
|
11283
|
-
willChange: 'contentArrayWillChange',
|
11284
|
-
didChange: 'contentArrayDidChange'
|
11285
|
-
});
|
11286
|
-
}
|
11413
|
+
unknownProperty: function(keyName, value) {
|
11414
|
+
var ret;
|
11415
|
+
ret = new EachArray(this._content, keyName, this);
|
11416
|
+
Ember.defineProperty(this, keyName, null, ret);
|
11417
|
+
this.beginObservingContentKey(keyName);
|
11418
|
+
return ret;
|
11287
11419
|
},
|
11288
11420
|
|
11289
|
-
|
11290
|
-
|
11291
|
-
|
11292
|
-
/**
|
11293
|
-
@private
|
11294
|
-
|
11295
|
-
Invoked when the content property changes. Notifies observers that the
|
11296
|
-
entire array content has changed.
|
11421
|
+
// ..........................................................
|
11422
|
+
// ARRAY CHANGES
|
11423
|
+
// Invokes whenever the content array itself changes.
|
11297
11424
|
|
11298
|
-
|
11299
|
-
|
11300
|
-
_contentDidChange: Ember.observer(function() {
|
11301
|
-
var content = get(this, 'content');
|
11425
|
+
arrayWillChange: function(content, idx, removedCnt, addedCnt) {
|
11426
|
+
var keys = this._keys, key, lim;
|
11302
11427
|
|
11303
|
-
|
11428
|
+
lim = removedCnt>0 ? idx+removedCnt : -1;
|
11429
|
+
Ember.beginPropertyChanges(this);
|
11304
11430
|
|
11305
|
-
|
11306
|
-
|
11431
|
+
for(key in keys) {
|
11432
|
+
if (!keys.hasOwnProperty(key)) { continue; }
|
11307
11433
|
|
11308
|
-
|
11309
|
-
var content = get(this, 'content');
|
11434
|
+
if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
|
11310
11435
|
|
11311
|
-
|
11312
|
-
content.addArrayObserver(this, {
|
11313
|
-
willChange: 'contentArrayWillChange',
|
11314
|
-
didChange: 'contentArrayDidChange'
|
11315
|
-
});
|
11436
|
+
Ember.propertyWillChange(this, key);
|
11316
11437
|
}
|
11317
|
-
},
|
11318
11438
|
|
11319
|
-
|
11320
|
-
|
11321
|
-
|
11439
|
+
Ember.propertyWillChange(this._content, '@each');
|
11440
|
+
Ember.endPropertyChanges(this);
|
11441
|
+
},
|
11322
11442
|
|
11323
|
-
|
11324
|
-
this.
|
11443
|
+
arrayDidChange: function(content, idx, removedCnt, addedCnt) {
|
11444
|
+
var keys = this._keys, key, lim;
|
11325
11445
|
|
11326
|
-
|
11327
|
-
|
11446
|
+
lim = addedCnt>0 ? idx+addedCnt : -1;
|
11447
|
+
Ember.beginPropertyChanges(this);
|
11328
11448
|
|
11329
|
-
|
11330
|
-
|
11331
|
-
len = arrangedContent ? get(arrangedContent, 'length') : 0;
|
11449
|
+
for(key in keys) {
|
11450
|
+
if (!keys.hasOwnProperty(key)) { continue; }
|
11332
11451
|
|
11333
|
-
|
11452
|
+
if (lim>0) addObserverForContentKey(content, key, this, idx, lim);
|
11334
11453
|
|
11335
|
-
|
11454
|
+
Ember.propertyDidChange(this, key);
|
11455
|
+
}
|
11336
11456
|
|
11337
|
-
|
11338
|
-
|
11339
|
-
},
|
11457
|
+
Ember.propertyDidChange(this._content, '@each');
|
11458
|
+
Ember.endPropertyChanges(this);
|
11459
|
+
},
|
11340
11460
|
|
11341
|
-
|
11342
|
-
|
11461
|
+
// ..........................................................
|
11462
|
+
// LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
|
11463
|
+
// Start monitoring keys based on who is listening...
|
11343
11464
|
|
11344
|
-
|
11345
|
-
|
11346
|
-
|
11347
|
-
didChange: 'arrangedContentArrayDidChange'
|
11348
|
-
});
|
11465
|
+
didAddListener: function(eventName) {
|
11466
|
+
if (IS_OBSERVER.test(eventName)) {
|
11467
|
+
this.beginObservingContentKey(eventName.slice(0, -7));
|
11349
11468
|
}
|
11350
11469
|
},
|
11351
11470
|
|
11352
|
-
|
11353
|
-
|
11354
|
-
|
11355
|
-
if (arrangedContent) {
|
11356
|
-
arrangedContent.removeArrayObserver(this, {
|
11357
|
-
willChange: 'arrangedContentArrayWillChange',
|
11358
|
-
didChange: 'arrangedContentArrayDidChange'
|
11359
|
-
});
|
11471
|
+
didRemoveListener: function(eventName) {
|
11472
|
+
if (IS_OBSERVER.test(eventName)) {
|
11473
|
+
this.stopObservingContentKey(eventName.slice(0, -7));
|
11360
11474
|
}
|
11361
11475
|
},
|
11362
11476
|
|
11363
|
-
|
11364
|
-
|
11477
|
+
// ..........................................................
|
11478
|
+
// CONTENT KEY OBSERVING
|
11479
|
+
// Actual watch keys on the source content.
|
11365
11480
|
|
11366
|
-
|
11367
|
-
|
11481
|
+
beginObservingContentKey: function(keyName) {
|
11482
|
+
var keys = this._keys;
|
11483
|
+
if (!keys) keys = this._keys = {};
|
11484
|
+
if (!keys[keyName]) {
|
11485
|
+
keys[keyName] = 1;
|
11486
|
+
var content = this._content,
|
11487
|
+
len = get(content, 'length');
|
11488
|
+
addObserverForContentKey(content, keyName, this, 0, len);
|
11489
|
+
} else {
|
11490
|
+
keys[keyName]++;
|
11491
|
+
}
|
11368
11492
|
},
|
11369
11493
|
|
11370
|
-
|
11371
|
-
var
|
11372
|
-
|
11373
|
-
|
11374
|
-
|
11375
|
-
|
11376
|
-
|
11377
|
-
Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', this.get('content'));
|
11378
|
-
if (get(this, 'content')) this.replaceContent(idx, amt, objects);
|
11379
|
-
return this;
|
11380
|
-
},
|
11381
|
-
|
11382
|
-
arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
|
11383
|
-
this.arrayContentWillChange(idx, removedCnt, addedCnt);
|
11384
|
-
},
|
11385
|
-
|
11386
|
-
arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
|
11387
|
-
this.arrayContentDidChange(idx, removedCnt, addedCnt);
|
11494
|
+
stopObservingContentKey: function(keyName) {
|
11495
|
+
var keys = this._keys;
|
11496
|
+
if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) {
|
11497
|
+
var content = this._content,
|
11498
|
+
len = get(content, 'length');
|
11499
|
+
removeObserverForContentKey(content, keyName, this, 0, len);
|
11500
|
+
}
|
11388
11501
|
},
|
11389
11502
|
|
11390
|
-
|
11391
|
-
|
11392
|
-
this._setupContent();
|
11393
|
-
this._setupArrangedContent();
|
11503
|
+
contentKeyWillChange: function(obj, keyName) {
|
11504
|
+
Ember.propertyWillChange(this, keyName);
|
11394
11505
|
},
|
11395
11506
|
|
11396
|
-
|
11397
|
-
|
11398
|
-
this._teardownContent();
|
11507
|
+
contentKeyDidChange: function(obj, keyName) {
|
11508
|
+
Ember.propertyDidChange(this, keyName);
|
11399
11509
|
}
|
11510
|
+
|
11400
11511
|
});
|
11401
11512
|
|
11402
11513
|
|
11514
|
+
|
11403
11515
|
})();
|
11404
11516
|
|
11405
11517
|
|
@@ -11410,524 +11522,611 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
|
|
11410
11522
|
@submodule ember-runtime
|
11411
11523
|
*/
|
11412
11524
|
|
11413
|
-
var get = Ember.get,
|
11414
|
-
set = Ember.set,
|
11415
|
-
fmt = Ember.String.fmt,
|
11416
|
-
addBeforeObserver = Ember.addBeforeObserver,
|
11417
|
-
addObserver = Ember.addObserver,
|
11418
|
-
removeBeforeObserver = Ember.removeBeforeObserver,
|
11419
|
-
removeObserver = Ember.removeObserver,
|
11420
|
-
propertyWillChange = Ember.propertyWillChange,
|
11421
|
-
propertyDidChange = Ember.propertyDidChange;
|
11422
|
-
|
11423
|
-
function contentPropertyWillChange(content, contentKey) {
|
11424
|
-
var key = contentKey.slice(8); // remove "content."
|
11425
|
-
if (key in this) { return; } // if shadowed in proxy
|
11426
|
-
propertyWillChange(this, key);
|
11427
|
-
}
|
11428
|
-
|
11429
|
-
function contentPropertyDidChange(content, contentKey) {
|
11430
|
-
var key = contentKey.slice(8); // remove "content."
|
11431
|
-
if (key in this) { return; } // if shadowed in proxy
|
11432
|
-
propertyDidChange(this, key);
|
11433
|
-
}
|
11434
|
-
|
11435
|
-
/**
|
11436
|
-
`Ember.ObjectProxy` forwards all properties not defined by the proxy itself
|
11437
|
-
to a proxied `content` object.
|
11438
|
-
|
11439
|
-
```javascript
|
11440
|
-
object = Ember.Object.create({
|
11441
|
-
name: 'Foo'
|
11442
|
-
});
|
11443
|
-
|
11444
|
-
proxy = Ember.ObjectProxy.create({
|
11445
|
-
content: object
|
11446
|
-
});
|
11447
11525
|
|
11448
|
-
|
11449
|
-
proxy.get('name') // 'Foo'
|
11450
|
-
proxy.set('name', 'Bar');
|
11451
|
-
object.get('name') // 'Bar'
|
11526
|
+
var get = Ember.get, set = Ember.set;
|
11452
11527
|
|
11453
|
-
|
11454
|
-
|
11455
|
-
|
11456
|
-
|
11528
|
+
// Add Ember.Array to Array.prototype. Remove methods with native
|
11529
|
+
// implementations and supply some more optimized versions of generic methods
|
11530
|
+
// because they are so common.
|
11531
|
+
var NativeArray = Ember.Mixin.create(Ember.MutableArray, Ember.Observable, Ember.Copyable, {
|
11457
11532
|
|
11458
|
-
|
11459
|
-
|
11533
|
+
// because length is a built-in property we need to know to just get the
|
11534
|
+
// original property.
|
11535
|
+
get: function(key) {
|
11536
|
+
if (key==='length') return this.length;
|
11537
|
+
else if ('number' === typeof key) return this[key];
|
11538
|
+
else return this._super(key);
|
11539
|
+
},
|
11460
11540
|
|
11461
|
-
|
11462
|
-
|
11463
|
-
|
11464
|
-
flag: null
|
11465
|
-
});
|
11466
|
-
proxy.set('flag', true);
|
11467
|
-
proxy.get('flag'); // true
|
11468
|
-
proxy.get('foo'); // undefined
|
11469
|
-
proxy.set('foo', 'data'); // throws Error
|
11470
|
-
```
|
11541
|
+
objectAt: function(idx) {
|
11542
|
+
return this[idx];
|
11543
|
+
},
|
11471
11544
|
|
11472
|
-
|
11545
|
+
// primitive for array support.
|
11546
|
+
replace: function(idx, amt, objects) {
|
11473
11547
|
|
11474
|
-
|
11548
|
+
if (this.isFrozen) throw Ember.FROZEN_ERROR ;
|
11475
11549
|
|
11476
|
-
|
11477
|
-
|
11478
|
-
|
11479
|
-
|
11480
|
-
|
11481
|
-
if (firstName && lastName) {
|
11482
|
-
return firstName + ' ' + lastName;
|
11483
|
-
}
|
11484
|
-
return firstName || lastName;
|
11485
|
-
}.property('firstName', 'lastName')
|
11486
|
-
});
|
11550
|
+
// if we replaced exactly the same number of items, then pass only the
|
11551
|
+
// replaced range. Otherwise, pass the full remaining array length
|
11552
|
+
// since everything has shifted
|
11553
|
+
var len = objects ? get(objects, 'length') : 0;
|
11554
|
+
this.arrayContentWillChange(idx, amt, len);
|
11487
11555
|
|
11488
|
-
|
11556
|
+
if (!objects || objects.length === 0) {
|
11557
|
+
this.splice(idx, amt) ;
|
11558
|
+
} else {
|
11559
|
+
var args = [idx, amt].concat(objects) ;
|
11560
|
+
this.splice.apply(this,args) ;
|
11561
|
+
}
|
11489
11562
|
|
11490
|
-
|
11491
|
-
|
11492
|
-
|
11493
|
-
}); // triggers property change for fullName on proxy
|
11563
|
+
this.arrayContentDidChange(idx, amt, len);
|
11564
|
+
return this ;
|
11565
|
+
},
|
11494
11566
|
|
11495
|
-
|
11496
|
-
|
11567
|
+
// If you ask for an unknown property, then try to collect the value
|
11568
|
+
// from member items.
|
11569
|
+
unknownProperty: function(key, value) {
|
11570
|
+
var ret;// = this.reducedProperty(key, value) ;
|
11571
|
+
if ((value !== undefined) && ret === undefined) {
|
11572
|
+
ret = this[key] = value;
|
11573
|
+
}
|
11574
|
+
return ret ;
|
11575
|
+
},
|
11497
11576
|
|
11498
|
-
|
11499
|
-
|
11500
|
-
|
11501
|
-
|
11502
|
-
Ember.ObjectProxy = Ember.Object.extend(
|
11503
|
-
/** @scope Ember.ObjectProxy.prototype */ {
|
11504
|
-
/**
|
11505
|
-
The object whose properties will be forwarded.
|
11577
|
+
// If browser did not implement indexOf natively, then override with
|
11578
|
+
// specialized version
|
11579
|
+
indexOf: function(object, startAt) {
|
11580
|
+
var idx, len = this.length;
|
11506
11581
|
|
11507
|
-
|
11508
|
-
|
11509
|
-
|
11510
|
-
*/
|
11511
|
-
content: null,
|
11512
|
-
_contentDidChange: Ember.observer(function() {
|
11513
|
-
Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
|
11514
|
-
}, 'content'),
|
11582
|
+
if (startAt === undefined) startAt = 0;
|
11583
|
+
else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
|
11584
|
+
if (startAt < 0) startAt += len;
|
11515
11585
|
|
11516
|
-
|
11586
|
+
for(idx=startAt;idx<len;idx++) {
|
11587
|
+
if (this[idx] === object) return idx ;
|
11588
|
+
}
|
11589
|
+
return -1;
|
11590
|
+
},
|
11517
11591
|
|
11518
|
-
|
11592
|
+
lastIndexOf: function(object, startAt) {
|
11593
|
+
var idx, len = this.length;
|
11519
11594
|
|
11520
|
-
|
11521
|
-
|
11522
|
-
|
11523
|
-
addObserver(this, contentKey, null, contentPropertyDidChange);
|
11524
|
-
},
|
11595
|
+
if (startAt === undefined) startAt = len-1;
|
11596
|
+
else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
|
11597
|
+
if (startAt < 0) startAt += len;
|
11525
11598
|
|
11526
|
-
|
11527
|
-
|
11528
|
-
|
11529
|
-
|
11599
|
+
for(idx=startAt;idx>=0;idx--) {
|
11600
|
+
if (this[idx] === object) return idx ;
|
11601
|
+
}
|
11602
|
+
return -1;
|
11530
11603
|
},
|
11531
11604
|
|
11532
|
-
|
11533
|
-
|
11534
|
-
|
11535
|
-
return get(content, key);
|
11605
|
+
copy: function(deep) {
|
11606
|
+
if (deep) {
|
11607
|
+
return this.map(function(item){ return Ember.copy(item, true); });
|
11536
11608
|
}
|
11537
|
-
},
|
11538
11609
|
|
11539
|
-
|
11540
|
-
var content = get(this, 'content');
|
11541
|
-
Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
|
11542
|
-
return set(content, key, value);
|
11610
|
+
return this.slice();
|
11543
11611
|
}
|
11544
11612
|
});
|
11545
11613
|
|
11546
|
-
|
11547
|
-
|
11548
|
-
|
11549
|
-
|
11550
|
-
prototype = this.proto();
|
11551
|
-
for (i = 0, l = arguments.length; i < l; i++) {
|
11552
|
-
properties = arguments[i];
|
11553
|
-
for (keyName in properties) {
|
11554
|
-
if (!properties.hasOwnProperty(keyName) || keyName in prototype) { continue; }
|
11555
|
-
if (!mixin) mixin = {};
|
11556
|
-
mixin[keyName] = null;
|
11557
|
-
}
|
11558
|
-
}
|
11559
|
-
if (mixin) this._initMixins([mixin]);
|
11560
|
-
}
|
11561
|
-
return this._super.apply(this, arguments);
|
11562
|
-
}
|
11614
|
+
// Remove any methods implemented natively so we don't override them
|
11615
|
+
var ignore = ['length'];
|
11616
|
+
Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) {
|
11617
|
+
if (Array.prototype[methodName]) ignore.push(methodName);
|
11563
11618
|
});
|
11564
11619
|
|
11565
|
-
|
11566
|
-
|
11567
|
-
|
11620
|
+
if (ignore.length>0) {
|
11621
|
+
NativeArray = NativeArray.without.apply(NativeArray, ignore);
|
11622
|
+
}
|
11568
11623
|
|
11569
|
-
(function() {
|
11570
11624
|
/**
|
11571
|
-
|
11572
|
-
|
11625
|
+
The NativeArray mixin contains the properties needed to to make the native
|
11626
|
+
Array support Ember.MutableArray and all of its dependent APIs. Unless you
|
11627
|
+
have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
|
11628
|
+
false, this will be applied automatically. Otherwise you can apply the mixin
|
11629
|
+
at anytime by calling `Ember.NativeArray.activate`.
|
11630
|
+
|
11631
|
+
@class NativeArray
|
11632
|
+
@namespace Ember
|
11633
|
+
@extends Ember.Mixin
|
11634
|
+
@uses Ember.MutableArray
|
11635
|
+
@uses Ember.MutableEnumerable
|
11636
|
+
@uses Ember.Copyable
|
11637
|
+
@uses Ember.Freezable
|
11573
11638
|
*/
|
11639
|
+
Ember.NativeArray = NativeArray;
|
11574
11640
|
|
11641
|
+
/**
|
11642
|
+
Creates an `Ember.NativeArray` from an Array like object.
|
11643
|
+
Does not modify the original object.
|
11575
11644
|
|
11576
|
-
|
11577
|
-
|
11645
|
+
@method A
|
11646
|
+
@for Ember
|
11647
|
+
@return {Ember.NativeArray}
|
11648
|
+
*/
|
11649
|
+
Ember.A = function(arr){
|
11650
|
+
if (arr === undefined) { arr = []; }
|
11651
|
+
return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr);
|
11652
|
+
};
|
11578
11653
|
|
11579
|
-
|
11654
|
+
/**
|
11655
|
+
Activates the mixin on the Array.prototype if not already applied. Calling
|
11656
|
+
this method more than once is safe.
|
11580
11657
|
|
11581
|
-
|
11582
|
-
|
11583
|
-
|
11584
|
-
|
11585
|
-
|
11586
|
-
|
11658
|
+
@method activate
|
11659
|
+
@for Ember.NativeArray
|
11660
|
+
@static
|
11661
|
+
@return {void}
|
11662
|
+
*/
|
11663
|
+
Ember.NativeArray.activate = function() {
|
11664
|
+
NativeArray.apply(Array.prototype);
|
11587
11665
|
|
11588
|
-
|
11589
|
-
|
11590
|
-
return item && get(item, this._keyName);
|
11591
|
-
},
|
11666
|
+
Ember.A = function(arr) { return arr || []; };
|
11667
|
+
};
|
11592
11668
|
|
11593
|
-
|
11594
|
-
|
11595
|
-
|
11596
|
-
})
|
11669
|
+
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
|
11670
|
+
Ember.NativeArray.activate();
|
11671
|
+
}
|
11597
11672
|
|
11598
|
-
});
|
11599
11673
|
|
11600
|
-
|
11674
|
+
})();
|
11601
11675
|
|
11602
|
-
function addObserverForContentKey(content, keyName, proxy, idx, loc) {
|
11603
|
-
var objects = proxy._objects, guid;
|
11604
|
-
if (!objects) objects = proxy._objects = {};
|
11605
11676
|
|
11606
|
-
while(--loc>=idx) {
|
11607
|
-
var item = content.objectAt(loc);
|
11608
|
-
if (item) {
|
11609
|
-
Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
|
11610
|
-
Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange');
|
11611
11677
|
|
11612
|
-
|
11613
|
-
|
11614
|
-
|
11615
|
-
|
11616
|
-
|
11617
|
-
}
|
11618
|
-
}
|
11619
|
-
}
|
11678
|
+
(function() {
|
11679
|
+
/**
|
11680
|
+
@module ember
|
11681
|
+
@submodule ember-runtime
|
11682
|
+
*/
|
11620
11683
|
|
11621
|
-
|
11622
|
-
var objects = proxy._objects;
|
11623
|
-
if (!objects) objects = proxy._objects = {};
|
11624
|
-
var indicies, guid;
|
11684
|
+
var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone, fmt = Ember.String.fmt;
|
11625
11685
|
|
11626
|
-
|
11627
|
-
|
11628
|
-
if (item) {
|
11629
|
-
Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
|
11630
|
-
Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange');
|
11686
|
+
/**
|
11687
|
+
An unordered collection of objects.
|
11631
11688
|
|
11632
|
-
|
11633
|
-
|
11634
|
-
|
11635
|
-
|
11636
|
-
}
|
11637
|
-
}
|
11689
|
+
A Set works a bit like an array except that its items are not ordered. You
|
11690
|
+
can create a set to efficiently test for membership for an object. You can
|
11691
|
+
also iterate through a set just like an array, even accessing objects by
|
11692
|
+
index, however there is no guarantee as to their order.
|
11638
11693
|
|
11639
|
-
|
11640
|
-
|
11641
|
-
array. It uses the unknownProperty handler to automatically create
|
11642
|
-
EachArray instances for property names.
|
11694
|
+
All Sets are observable via the Enumerable Observer API - which works
|
11695
|
+
on any enumerable object including both Sets and Arrays.
|
11643
11696
|
|
11644
|
-
|
11645
|
-
|
11697
|
+
## Creating a Set
|
11698
|
+
|
11699
|
+
You can create a set like you would most objects using
|
11700
|
+
`new Ember.Set()`. Most new sets you create will be empty, but you can
|
11701
|
+
also initialize the set with some content by passing an array or other
|
11702
|
+
enumerable of objects to the constructor.
|
11703
|
+
|
11704
|
+
Finally, you can pass in an existing set and the set will be copied. You
|
11705
|
+
can also create a copy of a set by calling `Ember.Set#copy()`.
|
11706
|
+
|
11707
|
+
```javascript
|
11708
|
+
// creates a new empty set
|
11709
|
+
var foundNames = new Ember.Set();
|
11710
|
+
|
11711
|
+
// creates a set with four names in it.
|
11712
|
+
var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P
|
11713
|
+
|
11714
|
+
// creates a copy of the names set.
|
11715
|
+
var namesCopy = new Ember.Set(names);
|
11716
|
+
|
11717
|
+
// same as above.
|
11718
|
+
var anotherNamesCopy = names.copy();
|
11719
|
+
```
|
11720
|
+
|
11721
|
+
## Adding/Removing Objects
|
11722
|
+
|
11723
|
+
You generally add or remove objects from a set using `add()` or
|
11724
|
+
`remove()`. You can add any type of object including primitives such as
|
11725
|
+
numbers, strings, and booleans.
|
11726
|
+
|
11727
|
+
Unlike arrays, objects can only exist one time in a set. If you call `add()`
|
11728
|
+
on a set with the same object multiple times, the object will only be added
|
11729
|
+
once. Likewise, calling `remove()` with the same object multiple times will
|
11730
|
+
remove the object the first time and have no effect on future calls until
|
11731
|
+
you add the object to the set again.
|
11732
|
+
|
11733
|
+
NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do
|
11734
|
+
so will be ignored.
|
11735
|
+
|
11736
|
+
In addition to add/remove you can also call `push()`/`pop()`. Push behaves
|
11737
|
+
just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary
|
11738
|
+
object, remove it and return it. This is a good way to use a set as a job
|
11739
|
+
queue when you don't care which order the jobs are executed in.
|
11740
|
+
|
11741
|
+
## Testing for an Object
|
11742
|
+
|
11743
|
+
To test for an object's presence in a set you simply call
|
11744
|
+
`Ember.Set#contains()`.
|
11745
|
+
|
11746
|
+
## Observing changes
|
11747
|
+
|
11748
|
+
When using `Ember.Set`, you can observe the `"[]"` property to be
|
11749
|
+
alerted whenever the content changes. You can also add an enumerable
|
11750
|
+
observer to the set to be notified of specific objects that are added and
|
11751
|
+
removed from the set. See `Ember.Enumerable` for more information on
|
11752
|
+
enumerables.
|
11753
|
+
|
11754
|
+
This is often unhelpful. If you are filtering sets of objects, for instance,
|
11755
|
+
it is very inefficient to re-filter all of the items each time the set
|
11756
|
+
changes. It would be better if you could just adjust the filtered set based
|
11757
|
+
on what was changed on the original set. The same issue applies to merging
|
11758
|
+
sets, as well.
|
11759
|
+
|
11760
|
+
## Other Methods
|
11761
|
+
|
11762
|
+
`Ember.Set` primary implements other mixin APIs. For a complete reference
|
11763
|
+
on the methods you will use with `Ember.Set`, please consult these mixins.
|
11764
|
+
The most useful ones will be `Ember.Enumerable` and
|
11765
|
+
`Ember.MutableEnumerable` which implement most of the common iterator
|
11766
|
+
methods you are used to on Array.
|
11767
|
+
|
11768
|
+
Note that you can also use the `Ember.Copyable` and `Ember.Freezable`
|
11769
|
+
APIs on `Ember.Set` as well. Once a set is frozen it can no longer be
|
11770
|
+
modified. The benefit of this is that when you call `frozenCopy()` on it,
|
11771
|
+
Ember will avoid making copies of the set. This allows you to write
|
11772
|
+
code that can know with certainty when the underlying set data will or
|
11773
|
+
will not be modified.
|
11774
|
+
|
11775
|
+
@class Set
|
11646
11776
|
@namespace Ember
|
11647
|
-
@extends Ember.
|
11777
|
+
@extends Ember.CoreObject
|
11778
|
+
@uses Ember.MutableEnumerable
|
11779
|
+
@uses Ember.Copyable
|
11780
|
+
@uses Ember.Freezable
|
11781
|
+
@since Ember 0.9
|
11648
11782
|
*/
|
11649
|
-
Ember.
|
11650
|
-
|
11651
|
-
init: function(content) {
|
11652
|
-
this._super();
|
11653
|
-
this._content = content;
|
11654
|
-
content.addArrayObserver(this);
|
11783
|
+
Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
|
11784
|
+
/** @scope Ember.Set.prototype */ {
|
11655
11785
|
|
11656
|
-
|
11657
|
-
|
11658
|
-
|
11659
|
-
this.didAddListener(eventName);
|
11660
|
-
}, this);
|
11661
|
-
},
|
11786
|
+
// ..........................................................
|
11787
|
+
// IMPLEMENT ENUMERABLE APIS
|
11788
|
+
//
|
11662
11789
|
|
11663
11790
|
/**
|
11664
|
-
|
11665
|
-
The `unknownProperty` handler will generate an EachArray of each item.
|
11791
|
+
This property will change as the number of objects in the set changes.
|
11666
11792
|
|
11667
|
-
@
|
11668
|
-
@
|
11669
|
-
@
|
11793
|
+
@property length
|
11794
|
+
@type number
|
11795
|
+
@default 0
|
11670
11796
|
*/
|
11671
|
-
|
11672
|
-
var ret;
|
11673
|
-
ret = new EachArray(this._content, keyName, this);
|
11674
|
-
Ember.defineProperty(this, keyName, null, ret);
|
11675
|
-
this.beginObservingContentKey(keyName);
|
11676
|
-
return ret;
|
11677
|
-
},
|
11797
|
+
length: 0,
|
11678
11798
|
|
11679
|
-
|
11680
|
-
|
11681
|
-
|
11799
|
+
/**
|
11800
|
+
Clears the set. This is useful if you want to reuse an existing set
|
11801
|
+
without having to recreate it.
|
11682
11802
|
|
11683
|
-
|
11684
|
-
var
|
11803
|
+
```javascript
|
11804
|
+
var colors = new Ember.Set(["red", "green", "blue"]);
|
11805
|
+
colors.length; // 3
|
11806
|
+
colors.clear();
|
11807
|
+
colors.length; // 0
|
11808
|
+
```
|
11685
11809
|
|
11686
|
-
|
11687
|
-
Ember.
|
11810
|
+
@method clear
|
11811
|
+
@return {Ember.Set} An empty Set
|
11812
|
+
*/
|
11813
|
+
clear: function() {
|
11814
|
+
if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
|
11688
11815
|
|
11689
|
-
|
11690
|
-
|
11816
|
+
var len = get(this, 'length');
|
11817
|
+
if (len === 0) { return this; }
|
11691
11818
|
|
11692
|
-
|
11819
|
+
var guid;
|
11693
11820
|
|
11694
|
-
|
11821
|
+
this.enumerableContentWillChange(len, 0);
|
11822
|
+
Ember.propertyWillChange(this, 'firstObject');
|
11823
|
+
Ember.propertyWillChange(this, 'lastObject');
|
11824
|
+
|
11825
|
+
for (var i=0; i < len; i++){
|
11826
|
+
guid = guidFor(this[i]);
|
11827
|
+
delete this[guid];
|
11828
|
+
delete this[i];
|
11695
11829
|
}
|
11696
11830
|
|
11697
|
-
|
11698
|
-
|
11831
|
+
set(this, 'length', 0);
|
11832
|
+
|
11833
|
+
Ember.propertyDidChange(this, 'firstObject');
|
11834
|
+
Ember.propertyDidChange(this, 'lastObject');
|
11835
|
+
this.enumerableContentDidChange(len, 0);
|
11836
|
+
|
11837
|
+
return this;
|
11699
11838
|
},
|
11700
11839
|
|
11701
|
-
|
11702
|
-
|
11840
|
+
/**
|
11841
|
+
Returns true if the passed object is also an enumerable that contains the
|
11842
|
+
same objects as the receiver.
|
11703
11843
|
|
11704
|
-
|
11705
|
-
|
11844
|
+
```javascript
|
11845
|
+
var colors = ["red", "green", "blue"],
|
11846
|
+
same_colors = new Ember.Set(colors);
|
11706
11847
|
|
11707
|
-
|
11708
|
-
|
11848
|
+
same_colors.isEqual(colors); // true
|
11849
|
+
same_colors.isEqual(["purple", "brown"]); // false
|
11850
|
+
```
|
11709
11851
|
|
11710
|
-
|
11852
|
+
@method isEqual
|
11853
|
+
@param {Ember.Set} obj the other object.
|
11854
|
+
@return {Boolean}
|
11855
|
+
*/
|
11856
|
+
isEqual: function(obj) {
|
11857
|
+
// fail fast
|
11858
|
+
if (!Ember.Enumerable.detect(obj)) return false;
|
11711
11859
|
|
11712
|
-
|
11860
|
+
var loc = get(this, 'length');
|
11861
|
+
if (get(obj, 'length') !== loc) return false;
|
11862
|
+
|
11863
|
+
while(--loc >= 0) {
|
11864
|
+
if (!obj.contains(this[loc])) return false;
|
11713
11865
|
}
|
11714
11866
|
|
11715
|
-
|
11716
|
-
Ember.endPropertyChanges(this);
|
11867
|
+
return true;
|
11717
11868
|
},
|
11718
11869
|
|
11719
|
-
|
11720
|
-
|
11721
|
-
|
11870
|
+
/**
|
11871
|
+
Adds an object to the set. Only non-`null` objects can be added to a set
|
11872
|
+
and those can only be added once. If the object is already in the set or
|
11873
|
+
the passed value is null this method will have no effect.
|
11722
11874
|
|
11723
|
-
|
11724
|
-
if (IS_OBSERVER.test(eventName)) {
|
11725
|
-
this.beginObservingContentKey(eventName.slice(0, -7));
|
11726
|
-
}
|
11727
|
-
},
|
11875
|
+
This is an alias for `Ember.MutableEnumerable.addObject()`.
|
11728
11876
|
|
11729
|
-
|
11730
|
-
|
11731
|
-
|
11732
|
-
|
11733
|
-
|
11877
|
+
```javascript
|
11878
|
+
var colors = new Ember.Set();
|
11879
|
+
colors.add("blue"); // ["blue"]
|
11880
|
+
colors.add("blue"); // ["blue"]
|
11881
|
+
colors.add("red"); // ["blue", "red"]
|
11882
|
+
colors.add(null); // ["blue", "red"]
|
11883
|
+
colors.add(undefined); // ["blue", "red"]
|
11884
|
+
```
|
11734
11885
|
|
11735
|
-
|
11736
|
-
|
11737
|
-
|
11886
|
+
@method add
|
11887
|
+
@param {Object} obj The object to add.
|
11888
|
+
@return {Ember.Set} The set itself.
|
11889
|
+
*/
|
11890
|
+
add: Ember.aliasMethod('addObject'),
|
11738
11891
|
|
11739
|
-
|
11740
|
-
|
11741
|
-
|
11742
|
-
|
11743
|
-
keys[keyName] = 1;
|
11744
|
-
var content = this._content,
|
11745
|
-
len = get(content, 'length');
|
11746
|
-
addObserverForContentKey(content, keyName, this, 0, len);
|
11747
|
-
} else {
|
11748
|
-
keys[keyName]++;
|
11749
|
-
}
|
11750
|
-
},
|
11892
|
+
/**
|
11893
|
+
Removes the object from the set if it is found. If you pass a `null` value
|
11894
|
+
or an object that is already not in the set, this method will have no
|
11895
|
+
effect. This is an alias for `Ember.MutableEnumerable.removeObject()`.
|
11751
11896
|
|
11752
|
-
|
11753
|
-
var
|
11754
|
-
|
11755
|
-
|
11756
|
-
|
11757
|
-
|
11758
|
-
|
11897
|
+
```javascript
|
11898
|
+
var colors = new Ember.Set(["red", "green", "blue"]);
|
11899
|
+
colors.remove("red"); // ["blue", "green"]
|
11900
|
+
colors.remove("purple"); // ["blue", "green"]
|
11901
|
+
colors.remove(null); // ["blue", "green"]
|
11902
|
+
```
|
11903
|
+
|
11904
|
+
@method remove
|
11905
|
+
@param {Object} obj The object to remove
|
11906
|
+
@return {Ember.Set} The set itself.
|
11907
|
+
*/
|
11908
|
+
remove: Ember.aliasMethod('removeObject'),
|
11909
|
+
|
11910
|
+
/**
|
11911
|
+
Removes the last element from the set and returns it, or `null` if it's empty.
|
11912
|
+
|
11913
|
+
```javascript
|
11914
|
+
var colors = new Ember.Set(["green", "blue"]);
|
11915
|
+
colors.pop(); // "blue"
|
11916
|
+
colors.pop(); // "green"
|
11917
|
+
colors.pop(); // null
|
11918
|
+
```
|
11919
|
+
|
11920
|
+
@method pop
|
11921
|
+
@return {Object} The removed object from the set or null.
|
11922
|
+
*/
|
11923
|
+
pop: function() {
|
11924
|
+
if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
|
11925
|
+
var obj = this.length > 0 ? this[this.length-1] : null;
|
11926
|
+
this.remove(obj);
|
11927
|
+
return obj;
|
11759
11928
|
},
|
11760
11929
|
|
11761
|
-
|
11762
|
-
|
11763
|
-
|
11930
|
+
/**
|
11931
|
+
Inserts the given object on to the end of the set. It returns
|
11932
|
+
the set itself.
|
11933
|
+
|
11934
|
+
This is an alias for `Ember.MutableEnumerable.addObject()`.
|
11935
|
+
|
11936
|
+
```javascript
|
11937
|
+
var colors = new Ember.Set();
|
11938
|
+
colors.push("red"); // ["red"]
|
11939
|
+
colors.push("green"); // ["red", "green"]
|
11940
|
+
colors.push("blue"); // ["red", "green", "blue"]
|
11941
|
+
```
|
11942
|
+
|
11943
|
+
@method push
|
11944
|
+
@return {Ember.Set} The set itself.
|
11945
|
+
*/
|
11946
|
+
push: Ember.aliasMethod('addObject'),
|
11947
|
+
|
11948
|
+
/**
|
11949
|
+
Removes the last element from the set and returns it, or `null` if it's empty.
|
11950
|
+
|
11951
|
+
This is an alias for `Ember.Set.pop()`.
|
11952
|
+
|
11953
|
+
```javascript
|
11954
|
+
var colors = new Ember.Set(["green", "blue"]);
|
11955
|
+
colors.shift(); // "blue"
|
11956
|
+
colors.shift(); // "green"
|
11957
|
+
colors.shift(); // null
|
11958
|
+
```
|
11959
|
+
|
11960
|
+
@method shift
|
11961
|
+
@return {Object} The removed object from the set or null.
|
11962
|
+
*/
|
11963
|
+
shift: Ember.aliasMethod('pop'),
|
11964
|
+
|
11965
|
+
/**
|
11966
|
+
Inserts the given object on to the end of the set. It returns
|
11967
|
+
the set itself.
|
11764
11968
|
|
11765
|
-
|
11766
|
-
Ember.propertyDidChange(this, keyName);
|
11767
|
-
}
|
11969
|
+
This is an alias of `Ember.Set.push()`
|
11768
11970
|
|
11769
|
-
|
11971
|
+
```javascript
|
11972
|
+
var colors = new Ember.Set();
|
11973
|
+
colors.unshift("red"); // ["red"]
|
11974
|
+
colors.unshift("green"); // ["red", "green"]
|
11975
|
+
colors.unshift("blue"); // ["red", "green", "blue"]
|
11976
|
+
```
|
11770
11977
|
|
11978
|
+
@method unshift
|
11979
|
+
@return {Ember.Set} The set itself.
|
11980
|
+
*/
|
11981
|
+
unshift: Ember.aliasMethod('push'),
|
11771
11982
|
|
11983
|
+
/**
|
11984
|
+
Adds each object in the passed enumerable to the set.
|
11772
11985
|
|
11773
|
-
|
11986
|
+
This is an alias of `Ember.MutableEnumerable.addObjects()`
|
11774
11987
|
|
11988
|
+
```javascript
|
11989
|
+
var colors = new Ember.Set();
|
11990
|
+
colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
|
11991
|
+
```
|
11775
11992
|
|
11993
|
+
@method addEach
|
11994
|
+
@param {Ember.Enumerable} objects the objects to add.
|
11995
|
+
@return {Ember.Set} The set itself.
|
11996
|
+
*/
|
11997
|
+
addEach: Ember.aliasMethod('addObjects'),
|
11776
11998
|
|
11777
|
-
|
11778
|
-
|
11779
|
-
@module ember
|
11780
|
-
@submodule ember-runtime
|
11781
|
-
*/
|
11999
|
+
/**
|
12000
|
+
Removes each object in the passed enumerable to the set.
|
11782
12001
|
|
12002
|
+
This is an alias of `Ember.MutableEnumerable.removeObjects()`
|
11783
12003
|
|
11784
|
-
|
12004
|
+
```javascript
|
12005
|
+
var colors = new Ember.Set(["red", "green", "blue"]);
|
12006
|
+
colors.removeEach(["red", "blue"]); // ["green"]
|
12007
|
+
```
|
11785
12008
|
|
11786
|
-
|
11787
|
-
|
11788
|
-
|
11789
|
-
|
12009
|
+
@method removeEach
|
12010
|
+
@param {Ember.Enumerable} objects the objects to remove.
|
12011
|
+
@return {Ember.Set} The set itself.
|
12012
|
+
*/
|
12013
|
+
removeEach: Ember.aliasMethod('removeObjects'),
|
11790
12014
|
|
11791
|
-
//
|
11792
|
-
//
|
11793
|
-
|
11794
|
-
|
11795
|
-
|
11796
|
-
|
12015
|
+
// ..........................................................
|
12016
|
+
// PRIVATE ENUMERABLE SUPPORT
|
12017
|
+
//
|
12018
|
+
|
12019
|
+
init: function(items) {
|
12020
|
+
this._super();
|
12021
|
+
if (items) this.addObjects(items);
|
11797
12022
|
},
|
11798
12023
|
|
11799
|
-
|
12024
|
+
// implement Ember.Enumerable
|
12025
|
+
nextObject: function(idx) {
|
11800
12026
|
return this[idx];
|
11801
12027
|
},
|
11802
12028
|
|
11803
|
-
//
|
11804
|
-
|
11805
|
-
|
11806
|
-
|
11807
|
-
|
11808
|
-
// if we replaced exactly the same number of items, then pass only the
|
11809
|
-
// replaced range. Otherwise, pass the full remaining array length
|
11810
|
-
// since everything has shifted
|
11811
|
-
var len = objects ? get(objects, 'length') : 0;
|
11812
|
-
this.arrayContentWillChange(idx, amt, len);
|
12029
|
+
// more optimized version
|
12030
|
+
firstObject: Ember.computed(function() {
|
12031
|
+
return this.length > 0 ? this[0] : undefined;
|
12032
|
+
}),
|
11813
12033
|
|
11814
|
-
|
11815
|
-
|
11816
|
-
|
11817
|
-
|
11818
|
-
this.splice.apply(this,args) ;
|
11819
|
-
}
|
12034
|
+
// more optimized version
|
12035
|
+
lastObject: Ember.computed(function() {
|
12036
|
+
return this.length > 0 ? this[this.length-1] : undefined;
|
12037
|
+
}),
|
11820
12038
|
|
11821
|
-
|
11822
|
-
|
11823
|
-
|
12039
|
+
// implements Ember.MutableEnumerable
|
12040
|
+
addObject: function(obj) {
|
12041
|
+
if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
|
12042
|
+
if (none(obj)) return this; // nothing to do
|
11824
12043
|
|
11825
|
-
|
11826
|
-
|
11827
|
-
|
11828
|
-
|
11829
|
-
if ((value !== undefined) && ret === undefined) {
|
11830
|
-
ret = this[key] = value;
|
11831
|
-
}
|
11832
|
-
return ret ;
|
11833
|
-
},
|
12044
|
+
var guid = guidFor(obj),
|
12045
|
+
idx = this[guid],
|
12046
|
+
len = get(this, 'length'),
|
12047
|
+
added ;
|
11834
12048
|
|
11835
|
-
|
11836
|
-
// specialized version
|
11837
|
-
indexOf: function(object, startAt) {
|
11838
|
-
var idx, len = this.length;
|
12049
|
+
if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
|
11839
12050
|
|
11840
|
-
|
11841
|
-
else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
|
11842
|
-
if (startAt < 0) startAt += len;
|
12051
|
+
added = [obj];
|
11843
12052
|
|
11844
|
-
|
11845
|
-
|
11846
|
-
}
|
11847
|
-
return -1;
|
11848
|
-
},
|
12053
|
+
this.enumerableContentWillChange(null, added);
|
12054
|
+
Ember.propertyWillChange(this, 'lastObject');
|
11849
12055
|
|
11850
|
-
|
11851
|
-
|
12056
|
+
len = get(this, 'length');
|
12057
|
+
this[guid] = len;
|
12058
|
+
this[len] = obj;
|
12059
|
+
set(this, 'length', len+1);
|
11852
12060
|
|
11853
|
-
|
11854
|
-
|
11855
|
-
if (startAt < 0) startAt += len;
|
12061
|
+
Ember.propertyDidChange(this, 'lastObject');
|
12062
|
+
this.enumerableContentDidChange(null, added);
|
11856
12063
|
|
11857
|
-
|
11858
|
-
if (this[idx] === object) return idx ;
|
11859
|
-
}
|
11860
|
-
return -1;
|
12064
|
+
return this;
|
11861
12065
|
},
|
11862
12066
|
|
11863
|
-
|
11864
|
-
|
11865
|
-
|
11866
|
-
|
12067
|
+
// implements Ember.MutableEnumerable
|
12068
|
+
removeObject: function(obj) {
|
12069
|
+
if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
|
12070
|
+
if (none(obj)) return this; // nothing to do
|
11867
12071
|
|
11868
|
-
|
11869
|
-
|
11870
|
-
|
12072
|
+
var guid = guidFor(obj),
|
12073
|
+
idx = this[guid],
|
12074
|
+
len = get(this, 'length'),
|
12075
|
+
isFirst = idx === 0,
|
12076
|
+
isLast = idx === len-1,
|
12077
|
+
last, removed;
|
11871
12078
|
|
11872
|
-
// Remove any methods implemented natively so we don't override them
|
11873
|
-
var ignore = ['length'];
|
11874
|
-
Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) {
|
11875
|
-
if (Array.prototype[methodName]) ignore.push(methodName);
|
11876
|
-
});
|
11877
12079
|
|
11878
|
-
if (
|
11879
|
-
|
11880
|
-
}
|
12080
|
+
if (idx>=0 && idx<len && (this[idx] === obj)) {
|
12081
|
+
removed = [obj];
|
11881
12082
|
|
11882
|
-
|
11883
|
-
|
11884
|
-
|
11885
|
-
have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
|
11886
|
-
false, this will be applied automatically. Otherwise you can apply the mixin
|
11887
|
-
at anytime by calling `Ember.NativeArray.activate`.
|
12083
|
+
this.enumerableContentWillChange(removed, null);
|
12084
|
+
if (isFirst) { Ember.propertyWillChange(this, 'firstObject'); }
|
12085
|
+
if (isLast) { Ember.propertyWillChange(this, 'lastObject'); }
|
11888
12086
|
|
11889
|
-
|
11890
|
-
|
11891
|
-
|
11892
|
-
|
11893
|
-
|
11894
|
-
|
11895
|
-
@uses Ember.Freezable
|
11896
|
-
*/
|
11897
|
-
Ember.NativeArray = NativeArray;
|
12087
|
+
// swap items - basically move the item to the end so it can be removed
|
12088
|
+
if (idx < len-1) {
|
12089
|
+
last = this[len-1];
|
12090
|
+
this[idx] = last;
|
12091
|
+
this[guidFor(last)] = idx;
|
12092
|
+
}
|
11898
12093
|
|
11899
|
-
|
11900
|
-
|
11901
|
-
|
12094
|
+
delete this[guid];
|
12095
|
+
delete this[len-1];
|
12096
|
+
set(this, 'length', len-1);
|
11902
12097
|
|
11903
|
-
|
11904
|
-
|
11905
|
-
|
11906
|
-
|
11907
|
-
Ember.A = function(arr){
|
11908
|
-
if (arr === undefined) { arr = []; }
|
11909
|
-
return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr);
|
11910
|
-
};
|
12098
|
+
if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
|
12099
|
+
if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
|
12100
|
+
this.enumerableContentDidChange(removed, null);
|
12101
|
+
}
|
11911
12102
|
|
11912
|
-
|
11913
|
-
|
11914
|
-
this method more than once is safe.
|
12103
|
+
return this;
|
12104
|
+
},
|
11915
12105
|
|
11916
|
-
|
11917
|
-
|
11918
|
-
|
11919
|
-
|
11920
|
-
*/
|
11921
|
-
Ember.NativeArray.activate = function() {
|
11922
|
-
NativeArray.apply(Array.prototype);
|
12106
|
+
// optimized version
|
12107
|
+
contains: function(obj) {
|
12108
|
+
return this[guidFor(obj)]>=0;
|
12109
|
+
},
|
11923
12110
|
|
11924
|
-
|
11925
|
-
|
12111
|
+
copy: function() {
|
12112
|
+
var C = this.constructor, ret = new C(), loc = get(this, 'length');
|
12113
|
+
set(ret, 'length', loc);
|
12114
|
+
while(--loc>=0) {
|
12115
|
+
ret[loc] = this[loc];
|
12116
|
+
ret[guidFor(this[loc])] = loc;
|
12117
|
+
}
|
12118
|
+
return ret;
|
12119
|
+
},
|
11926
12120
|
|
11927
|
-
|
11928
|
-
|
11929
|
-
|
12121
|
+
toString: function() {
|
12122
|
+
var len = this.length, idx, array = [];
|
12123
|
+
for(idx = 0; idx < len; idx++) {
|
12124
|
+
array[idx] = this[idx];
|
12125
|
+
}
|
12126
|
+
return fmt("Ember.Set<%@>", [array.join(',')]);
|
12127
|
+
}
|
11930
12128
|
|
12129
|
+
});
|
11931
12130
|
|
11932
12131
|
})();
|
11933
12132
|
|
@@ -11935,7 +12134,6 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
|
|
11935
12134
|
|
11936
12135
|
(function() {
|
11937
12136
|
var DeferredMixin = Ember.DeferredMixin, // mixins/deferred
|
11938
|
-
EmberObject = Ember.Object, // system/object
|
11939
12137
|
get = Ember.get;
|
11940
12138
|
|
11941
12139
|
var Deferred = Ember.Object.extend(DeferredMixin);
|
@@ -12259,7 +12457,6 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
|
|
12259
12457
|
|
12260
12458
|
if (isSorted) {
|
12261
12459
|
var addedObjects = array.slice(idx, idx+addedCount);
|
12262
|
-
var arrangedContent = get(this, 'arrangedContent');
|
12263
12460
|
|
12264
12461
|
forEach(addedObjects, function(item) {
|
12265
12462
|
this.insertItemSorted(item);
|
@@ -12329,8 +12526,8 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
|
|
12329
12526
|
@submodule ember-runtime
|
12330
12527
|
*/
|
12331
12528
|
|
12332
|
-
var get = Ember.get, set = Ember.set,
|
12333
|
-
|
12529
|
+
var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach,
|
12530
|
+
replace = Ember.EnumerableUtils.replace;
|
12334
12531
|
|
12335
12532
|
/**
|
12336
12533
|
`Ember.ArrayController` provides a way for you to publish a collection of
|