ember-source 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ember-source might be problematic. Click here for more details.

@@ -1,5 +1,5 @@
1
- // Version: v1.0.0-rc.1-78-gd4e6a5c
2
- // Last commit: d4e6a5c (2013-02-26 10:34:28 -0500)
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-78-gd4e6a5c
154
- // Last commit: d4e6a5c (2013-02-26 10:34:28 -0500)
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 get use those.
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 GUID_KEY = Ember.GUID_KEY,
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, value) {
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
- var deps = meta.deps;
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 val === undefined || val === null || val === '' || (Ember.isArray(val) && get(val, 'length') === 0);
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 === 1) {
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 loop,
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
- an lower-level way to use a RunLoop instead of using `Ember.run()`.
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', 'timers']
4401
+ @default ['sync', 'actions', 'destroy']
4323
4402
  */
4324
- Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
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 at the end of the RunLoop, when bindings are synced
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 timers queue
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 || scheduledNext);
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
- var now = (+ new Date()), earliest = -1;
4450
- for (var key in timers) {
4451
- if (!timers.hasOwnProperty(key)) { continue; }
4452
- var timer = timers[key];
4453
- if (timer && timer.expires) {
4454
- if (now >= timer.expires) {
4455
- delete timers[key];
4456
- invoke(timer.target, timer.method, timer.args, 2);
4457
- } else {
4458
- if (earliest<0 || (timer.expires < earliest)) earliest=timer.expires;
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
- // schedule next timeout to fire...
4464
- if (earliest > 0) { scheduledLater = setTimeout(invokeLaterTimers, earliest-(+ new Date())); }
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
- run.once(timers, invokeLaterTimers);
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 often equivalent to calling `setTimeout(function() {}, 1)`.
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(target, method) {
4616
- var guid,
4617
- timer = {
4618
- target: target,
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
- var i, results = [];
6018
- var allPromise = new Promise();
6019
- var remaining = promises.length;
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
- var resolver = function(index) {
6026
- return function(value) {
6027
- resolve(index, value);
6028
- };
6029
- };
6141
+ var resolver = function(index) {
6142
+ return function(value) {
6143
+ resolve(index, value);
6144
+ };
6145
+ };
6030
6146
 
6031
- var resolve = function(index, value) {
6032
- results[index] = value;
6033
- if (--remaining === 0) {
6034
- allPromise.resolve(results);
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
- var reject = function(error) {
6039
- allPromise.reject(error);
6040
- };
6154
+ var reject = function(error) {
6155
+ allPromise.reject(error);
6156
+ };
6041
6157
 
6042
- for (i = 0; i < remaining; i++) {
6043
- promises[i].then(resolver(i), reject);
6044
- }
6045
- return allPromise;
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
- ret = cache[str];
6992
+ hit = cache.hasOwnProperty(str),
6993
+ ret;
6928
6994
 
6929
- if (ret) {
6930
- return ret;
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 lowerCaseCamel form of a string.
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() => 'InnerHTML'
7012
- 'action_name'.capitalize() => 'Action_name'
7013
- 'css-class-name'.capitalize() => 'Css-class-name'
7014
- 'my favorite items'.capitalize() => 'My favorite items'
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(); // "a"
7476
+ arr.get('firstObject'); // "a"
7412
7477
 
7413
7478
  var arr = [];
7414
- arr.firstObject(); // undefined
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(); // "c"
7502
+ arr.get('lastObject'); // "c"
7438
7503
 
7439
7504
  var arr = [];
7440
- arr.lastObject(); // undefined
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 notify = this.propertyDidChange, removeCnt, addCnt, hasDelta;
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, meta = Ember.meta, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor;
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 beginIndex {Integer} (Optional) index to begin slicing from.
8298
- @param endIndex {Integer} (Optional) index to end the slice at.
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, forEach = Ember.EnumerableUtils.forEach;
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, defineProperty = Ember.defineProperty;
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(); // #=> "<App.Teacher:ember1026:Tom Dale>"
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
- An unordered collection of objects.
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
- A Set works a bit like an array except that its items are not ordered. You
10485
- can create a set to efficiently test for membership for an object. You can
10486
- also iterate through a set just like an array, even accessing objects by
10487
- index, however there is no guarantee as to their order.
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
- All Sets are observable via the Enumerable Observer API - which works
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
- Finally, you can pass in an existing set and the set will be copied. You
10500
- can also create a copy of a set by calling `Ember.Set#copy()`.
10606
+ (function() {
10607
+ /**
10608
+ @module ember
10609
+ @submodule ember-runtime
10610
+ */
10501
10611
 
10502
- ```javascript
10503
- // creates a new empty set
10504
- var foundNames = new Ember.Set();
10612
+ var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
10505
10613
 
10506
- // creates a set with four names in it.
10507
- var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P
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
- // creates a copy of the names set.
10510
- var namesCopy = new Ember.Set(names);
10619
+ # Example Usage
10511
10620
 
10512
- // same as above.
10513
- var anotherNamesCopy = names.copy();
10621
+ ```javascript
10622
+ MyFramework = Ember.Namespace.create({
10623
+ VERSION: '1.0.0'
10624
+ });
10514
10625
  ```
10515
10626
 
10516
- ## Adding/Removing Objects
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
- You generally add or remove objects from a set using `add()` or
10519
- `remove()`. You can add any type of object including primitives such as
10520
- numbers, strings, and booleans.
10634
+ init: function() {
10635
+ Ember.Namespace.NAMESPACES.push(this);
10636
+ Ember.Namespace.PROCESSED = false;
10637
+ },
10521
10638
 
10522
- Unlike arrays, objects can only exist one time in a set. If you call `add()`
10523
- on a set with the same object multiple times, the object will only be added
10524
- once. Likewise, calling `remove()` with the same object multiple times will
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
- NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do
10529
- so will be ignored.
10643
+ findNamespaces();
10644
+ return this[Ember.GUID_KEY+'_name'];
10645
+ },
10530
10646
 
10531
- In addition to add/remove you can also call `push()`/`pop()`. Push behaves
10532
- just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary
10533
- object, remove it and return it. This is a good way to use a set as a job
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
- ## Testing for an Object
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
- To test for an object's presence in a set you simply call
10539
- `Ember.Set#contains()`.
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
- ## Observing changes
10669
+ return NAMESPACES_BY_ID[name];
10670
+ }
10671
+ });
10542
10672
 
10543
- When using `Ember.Set`, you can observe the `"[]"` property to be
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
- This is often unhelpful. If you are filtering sets of objects, for instance,
10550
- it is very inefficient to re-filter all of the items each time the set
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
- ## Other Methods
10678
+ function processNamespace(paths, root, seen) {
10679
+ var idx = paths.length;
10556
10680
 
10557
- `Ember.Set` primary implements other mixin APIs. For a complete reference
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
- Note that you can also use the `Ember.Copyable` and `Ember.Freezable`
10564
- APIs on `Ember.Set` as well. Once a set is frozen it can no longer be
10565
- modified. The benefit of this is that when you call `frozenCopy()` on it,
10566
- Ember will avoid making copies of the set. This allows you to write
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
- @class Set
10571
- @namespace Ember
10572
- @extends Ember.CoreObject
10573
- @uses Ember.MutableEnumerable
10574
- @uses Ember.Copyable
10575
- @uses Ember.Freezable
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
- // IMPLEMENT ENUMERABLE APIS
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
- This property will change as the number of objects in the set changes.
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
- @property length
10589
- @type number
10590
- @default 0
10591
- */
10592
- length: 0,
10708
+ // Process the child namespace
10709
+ processNamespace(paths, obj, seen);
10710
+ }
10711
+ }
10593
10712
 
10594
- /**
10595
- Clears the set. This is useful if you want to reuse an existing set
10596
- without having to recreate it.
10713
+ paths.length = idx; // cut out last item
10714
+ }
10597
10715
 
10598
- ```javascript
10599
- var colors = new Ember.Set(["red", "green", "blue"]);
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
- @method clear
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
- var len = get(this, 'length');
10612
- if (len === 0) { return this; }
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
- var guid;
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
- this.enumerableContentWillChange(len, 0);
10617
- Ember.propertyWillChange(this, 'firstObject');
10618
- Ember.propertyWillChange(this, 'lastObject');
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
- for (var i=0; i < len; i++){
10621
- guid = guidFor(this[i]);
10622
- delete this[guid];
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
- set(this, 'length', 0);
10747
+ var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
10627
10748
 
10628
- Ember.propertyDidChange(this, 'firstObject');
10629
- Ember.propertyDidChange(this, 'lastObject');
10630
- this.enumerableContentDidChange(len, 0);
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
- return this;
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
- ```javascript
10640
- var colors = ["red", "green", "blue"],
10641
- same_colors = new Ember.Set(colors);
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
- same_colors.isEqual(colors); // true
10644
- same_colors.isEqual(["purple", "brown"]); // false
10645
- ```
10778
+ return ret;
10779
+ }
10646
10780
 
10647
- @method isEqual
10648
- @param {Ember.Set} obj the other object.
10649
- @return {Boolean}
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
- var loc = get(this, 'length');
10656
- if (get(obj, 'length') !== loc) return false;
10785
+ if (unprocessedNamespaces) {
10786
+ findNamespaces();
10787
+ Namespace.PROCESSED = true;
10788
+ }
10657
10789
 
10658
- while(--loc >= 0) {
10659
- if (!obj.contains(this[loc])) return false;
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
- return true;
10663
- },
10797
+ Ember.anyUnprocessedMixins = false;
10798
+ }
10799
+ }
10664
10800
 
10665
- /**
10666
- Adds an object to the set. Only non-`null` objects can be added to a set
10667
- and those can only be added once. If the object is already in the set or
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
- This is an alias for `Ember.MutableEnumerable.addObject()`.
10805
+ Ember.Mixin.prototype.toString = classToString;
10671
10806
 
10672
- ```javascript
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
- ```javascript
10693
- var colors = new Ember.Set(["red", "green", "blue"]);
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
- @method remove
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
- @method pop
10716
- @return {Object} The removed object from the set or null.
10717
- */
10718
- pop: function() {
10719
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
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
- Inserts the given object on to the end of the set. It returns
10727
- the set itself.
10824
+ var OUT_OF_RANGE_EXCEPTION = "Index out of range";
10825
+ var EMPTY = [];
10728
10826
 
10729
- This is an alias for `Ember.MutableEnumerable.addObject()`.
10827
+ var get = Ember.get, set = Ember.set;
10730
10828
 
10731
- ```javascript
10732
- var colors = new Ember.Set();
10733
- colors.push("red"); // ["red"]
10734
- colors.push("green"); // ["red", "green"]
10735
- colors.push("blue"); // ["red", "green", "blue"]
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
- @method push
10739
- @return {Ember.Set} The set itself.
10740
- */
10741
- push: Ember.aliasMethod('addObject'),
10835
+ A simple example of usage:
10742
10836
 
10743
- /**
10744
- Removes the last element from the set and returns it, or `null` if it's empty.
10837
+ ```javascript
10838
+ var pets = ['dog', 'cat', 'fish'];
10839
+ var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
10745
10840
 
10746
- This is an alias for `Ember.Set.pop()`.
10841
+ ap.get('firstObject'); // 'dog'
10842
+ ap.set('content', ['amoeba', 'paramecium']);
10843
+ ap.get('firstObject'); // 'amoeba'
10844
+ ```
10747
10845
 
10748
- ```javascript
10749
- var colors = new Ember.Set(["green", "blue"]);
10750
- colors.shift(); // "blue"
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
- @method shift
10756
- @return {Object} The removed object from the set or null.
10757
- */
10758
- shift: Ember.aliasMethod('pop'),
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
- Inserts the given object on to the end of the set. It returns
10762
- the set itself.
10859
+ ap.get('firstObject'); // . 'DOG'
10860
+ ```
10763
10861
 
10764
- This is an alias of `Ember.Set.push()`
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
- ```javascript
10767
- var colors = new Ember.Set();
10768
- colors.unshift("red"); // ["red"]
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
- @method unshift
10774
- @return {Ember.Set} The set itself.
10874
+ @property content
10875
+ @type Ember.Array
10775
10876
  */
10776
- unshift: Ember.aliasMethod('push'),
10877
+ content: null,
10777
10878
 
10778
10879
  /**
10779
- Adds each object in the passed enumerable to the set.
10780
-
10781
- This is an alias of `Ember.MutableEnumerable.addObjects()`
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
- @method addEach
10789
- @param {Ember.Enumerable} objects the objects to add.
10790
- @return {Ember.Set} The set itself.
10884
+ @property arrangedContent
10791
10885
  */
10792
- addEach: Ember.aliasMethod('addObjects'),
10886
+ arrangedContent: Ember.computed.alias('content'),
10793
10887
 
10794
10888
  /**
10795
- Removes each object in the passed enumerable to the set.
10796
-
10797
- This is an alias of `Ember.MutableEnumerable.removeObjects()`
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
- ```javascript
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 removeEach
10805
- @param {Ember.Enumerable} objects the objects to remove.
10806
- @return {Ember.Set} The set itself.
10895
+ @method objectAtContent
10896
+ @param {Number} idx The index to retrieve.
10897
+ @return {Object} the value or undefined if none found
10807
10898
  */
10808
- removeEach: Ember.aliasMethod('removeObjects'),
10899
+ objectAtContent: function(idx) {
10900
+ return get(this, 'arrangedContent').objectAt(idx);
10901
+ },
10809
10902
 
10810
- // ..........................................................
10811
- // PRIVATE ENUMERABLE SUPPORT
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
- init: function(items) {
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
- // implement Ember.Enumerable
10820
- nextObject: function(idx) {
10821
- return this[idx];
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
- // more optimized version
10825
- firstObject: Ember.computed(function() {
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
- // implements Ember.MutableEnumerable
10835
- addObject: function(obj) {
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
- var guid = guidFor(obj),
10840
- idx = this[guid],
10841
- len = get(this, 'length'),
10842
- added ;
10927
+ @method _contentWillChange
10928
+ */
10929
+ _contentWillChange: Ember.beforeObserver(function() {
10930
+ this._teardownContent();
10931
+ }, 'content'),
10843
10932
 
10844
- if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
10933
+ _teardownContent: function() {
10934
+ var content = get(this, 'content');
10845
10935
 
10846
- added = [obj];
10936
+ if (content) {
10937
+ content.removeArrayObserver(this, {
10938
+ willChange: 'contentArrayWillChange',
10939
+ didChange: 'contentArrayDidChange'
10940
+ });
10941
+ }
10942
+ },
10847
10943
 
10848
- this.enumerableContentWillChange(null, added);
10849
- Ember.propertyWillChange(this, 'lastObject');
10944
+ contentArrayWillChange: Ember.K,
10945
+ contentArrayDidChange: Ember.K,
10850
10946
 
10851
- len = get(this, 'length');
10852
- this[guid] = len;
10853
- this[len] = obj;
10854
- set(this, 'length', len+1);
10947
+ /**
10948
+ @private
10855
10949
 
10856
- Ember.propertyDidChange(this, 'lastObject');
10857
- this.enumerableContentDidChange(null, added);
10950
+ Invoked when the content property changes. Notifies observers that the
10951
+ entire array content has changed.
10858
10952
 
10859
- return this;
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
- // implements Ember.MutableEnumerable
10863
- removeObject: function(obj) {
10864
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
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
- var guid = guidFor(obj),
10868
- idx = this[guid],
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
- if (idx>=0 && idx<len && (this[idx] === obj)) {
10876
- removed = [obj];
10984
+ _arrangedContentDidChange: Ember.observer(function() {
10985
+ var arrangedContent = get(this, 'arrangedContent'),
10986
+ len = arrangedContent ? get(arrangedContent, 'length') : 0;
10877
10987
 
10878
- this.enumerableContentWillChange(removed, null);
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
- // swap items - basically move the item to the end so it can be removed
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
- delete this[guid];
10890
- delete this[len-1];
10891
- set(this, 'length', len-1);
10992
+ this.arrangedContentDidChange(this);
10993
+ this.arrangedContentArrayDidChange(this, 0, undefined, len);
10994
+ }, 'arrangedContent'),
10892
10995
 
10893
- if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
10894
- if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
10895
- this.enumerableContentDidChange(removed, null);
10896
- }
10996
+ _setupArrangedContent: function() {
10997
+ var arrangedContent = get(this, 'arrangedContent');
10897
10998
 
10898
- return this;
10999
+ if (arrangedContent) {
11000
+ arrangedContent.addArrayObserver(this, {
11001
+ willChange: 'arrangedContentArrayWillChange',
11002
+ didChange: 'arrangedContentArrayDidChange'
11003
+ });
11004
+ }
10899
11005
  },
10900
11006
 
10901
- // optimized version
10902
- contains: function(obj) {
10903
- return this[guidFor(obj)]>=0;
10904
- },
11007
+ _teardownArrangedContent: function() {
11008
+ var arrangedContent = get(this, 'arrangedContent');
10905
11009
 
10906
- copy: function() {
10907
- var C = this.constructor, ret = new C(), loc = get(this, 'length');
10908
- set(ret, 'length', loc);
10909
- while(--loc>=0) {
10910
- ret[loc] = this[loc];
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
- toString: function() {
10917
- var len = this.length, idx, array = [];
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
- (function() {
10931
- /**
10932
- @module ember
10933
- @submodule ember-runtime
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
- `Ember.Object` is the main base class for all Ember objects. It is a subclass
10938
- of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details,
10939
- see the documentation for each of these.
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
- @class Object
10942
- @namespace Ember
10943
- @extends Ember.CoreObject
10944
- @uses Ember.Observable
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
- (function() {
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
- var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
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
- A Namespace is an object usually used to contain other objects or methods
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
- # Example Usage
11091
+ pushObject: function(obj) {
11092
+ this._insertAt(get(this, 'content.length'), obj) ;
11093
+ return obj ;
11094
+ },
10967
11095
 
10968
- ```javascript
10969
- MyFramework = Ember.Namespace.create({
10970
- VERSION: '1.0.0'
10971
- });
10972
- ```
11096
+ pushObjects: function(objects) {
11097
+ this._replace(get(this, 'length'), 0, objects);
11098
+ return this;
11099
+ },
10973
11100
 
10974
- @class Namespace
10975
- @namespace Ember
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
- init: function() {
10982
- Ember.Namespace.NAMESPACES.push(this);
10983
- Ember.Namespace.PROCESSED = false;
11104
+ var len = get(this, 'length');
11105
+ this._replace(0, len, objects);
11106
+ return this;
10984
11107
  },
10985
11108
 
10986
- toString: function() {
10987
- var name = get(this, 'name');
10988
- if (name) { return name; }
11109
+ unshiftObject: function(obj) {
11110
+ this._insertAt(0, obj) ;
11111
+ return obj ;
11112
+ },
10989
11113
 
10990
- findNamespaces();
10991
- return this[Ember.GUID_KEY+'_name'];
11114
+ unshiftObjects: function(objects) {
11115
+ this._replace(0, 0, objects);
11116
+ return this;
10992
11117
  },
10993
11118
 
10994
- nameClasses: function() {
10995
- processNamespace([this.toString()], this, {});
11119
+ slice: function() {
11120
+ var arr = this.toArray();
11121
+ return arr.slice.apply(arr, arguments);
10996
11122
  },
10997
11123
 
10998
- destroy: function() {
10999
- var namespaces = Ember.Namespace.NAMESPACES;
11000
- Ember.lookup[this.toString()] = undefined;
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
- Namespace.reopenClass({
11007
- NAMESPACES: [Ember],
11008
- NAMESPACES_BY_ID: {},
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
- return NAMESPACES_BY_ID[name];
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
- var hasOwnProp = ({}).hasOwnProperty,
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
- // Loop over all of the keys in the namespace, looking for classes
11031
- for(var key in root) {
11032
- if (!hasOwnProp.call(root, key)) { continue; }
11033
- var obj = root[key];
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
- // Support nested namespaces
11050
- } else if (obj && obj.isNamespace) {
11051
- // Skip aliased namespaces
11052
- if (seen[guidFor(obj)]) { continue; }
11053
- seen[guidFor(obj)] = true;
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
- // Process the child namespace
11056
- processNamespace(paths, obj, seen);
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
- paths.length = idx; // cut out last item
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
- function findNamespaces() {
11064
- var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace;
11177
+ /**
11178
+ `Ember.ObjectProxy` forwards all properties not defined by the proxy itself
11179
+ to a proxied `content` object.
11065
11180
 
11066
- if (Namespace.PROCESSED) { return; }
11181
+ ```javascript
11182
+ object = Ember.Object.create({
11183
+ name: 'Foo'
11184
+ });
11067
11185
 
11068
- for (var prop in lookup) {
11069
- // These don't raise exceptions but can cause warnings
11070
- if (prop === "parent" || prop === "top" || prop === "frameElement") { continue; }
11186
+ proxy = Ember.ObjectProxy.create({
11187
+ content: object
11188
+ });
11071
11189
 
11072
- // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
11073
- // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
11074
- if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; }
11075
- // Unfortunately, some versions of IE don't support window.hasOwnProperty
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
- // At times we are not allowed to access certain properties for security reasons.
11079
- // There are also times where even if we can access them, we are not allowed to access their properties.
11080
- try {
11081
- obj = Ember.lookup[prop];
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
- if (isNamespace) {
11088
- Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
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
- var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
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
- function superClassString(mixin) {
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
- function classToString() {
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
- var ret;
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
- if (this[NAME_KEY]) {
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
- return ret;
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
- function processAllNamespaces() {
11129
- var unprocessedNamespaces = !Namespace.PROCESSED,
11130
- unprocessedMixins = Ember.anyUnprocessedMixins;
11237
+ proxy.get('fullName'); // 'Tom Dale'
11238
+ ```
11131
11239
 
11132
- if (unprocessedNamespaces) {
11133
- findNamespaces();
11134
- Namespace.PROCESSED = true;
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
- if (unprocessedNamespaces || unprocessedMixins) {
11138
- var namespaces = Namespace.NAMESPACES, namespace;
11139
- for (var i=0, l=namespaces.length; i<l; i++) {
11140
- namespace = namespaces[i];
11141
- processNamespace([namespace.toString()], namespace, {});
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
- Ember.anyUnprocessedMixins = false;
11145
- }
11146
- }
11258
+ isTruthy: Ember.computed.bool('content'),
11147
11259
 
11148
- function makeToString(ret) {
11149
- return function() { return ret; };
11150
- }
11260
+ _debugContainerKey: null,
11151
11261
 
11152
- Ember.Mixin.prototype.toString = classToString;
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
- (function() {
11159
- Ember.Application = Ember.Namespace.extend();
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, set = Ember.set;
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
- A simple example of usage:
11321
+ var EachArray = Ember.Object.extend(Ember.Array, {
11181
11322
 
11182
- ```javascript
11183
- var pets = ['dog', 'cat', 'fish'];
11184
- var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
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
- ap.get('firstObject'); // 'dog'
11187
- ap.set('content', ['amoeba', 'paramecium']);
11188
- ap.get('firstObject'); // 'amoeba'
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
- ```javascript
11196
- var pets = ['dog', 'cat', 'fish'];
11197
- var ap = Ember.ArrayProxy.create({
11198
- content: Ember.A(pets),
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
- ap.get('firstObject'); // . 'DOG'
11205
- ```
11340
+ });
11206
11341
 
11207
- @class ArrayProxy
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
- The content array. Must be an object that implements `Ember.Array` and/or
11217
- `Ember.MutableArray.`
11344
+ function addObserverForContentKey(content, keyName, proxy, idx, loc) {
11345
+ var objects = proxy._objects, guid;
11346
+ if (!objects) objects = proxy._objects = {};
11218
11347
 
11219
- @property content
11220
- @type Ember.Array
11221
- */
11222
- content: null,
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
- The array that the proxy pretends to be. In the default `ArrayProxy`
11226
- implementation, this and `content` are the same. Subclasses of `ArrayProxy`
11227
- can override this property to provide things like sorting and filtering.
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
- @property arrangedContent
11230
- */
11231
- arrangedContent: Ember.computed.alias('content'),
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
- Should actually retrieve the object at the specified index from the
11235
- content. You can override this method in subclasses to transform the
11236
- content item to something new.
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
- This method will only be called if content is non-`null`.
11374
+ guid = guidFor(item);
11375
+ indicies = objects[guid];
11376
+ indicies[indicies.indexOf(loc)] = null;
11377
+ }
11378
+ }
11379
+ }
11239
11380
 
11240
- @method objectAtContent
11241
- @param {Number} idx The index to retrieve.
11242
- @return {Object} the value or undefined if none found
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
- Should actually replace the specified objects on the content array.
11250
- You can override this method in subclasses to transform the content item
11251
- into something new.
11386
+ @private
11387
+ @class EachProxy
11388
+ @namespace Ember
11389
+ @extends Ember.Object
11390
+ */
11391
+ Ember.EachProxy = Ember.Object.extend({
11252
11392
 
11253
- This method will only be called if content is non-`null`.
11393
+ init: function(content) {
11394
+ this._super();
11395
+ this._content = content;
11396
+ content.addArrayObserver(this);
11254
11397
 
11255
- @method replaceContent
11256
- @param {Number} idx The starting index
11257
- @param {Number} amt The number of items to remove from the content.
11258
- @param {Array} objects Optional array of objects to insert or null if no
11259
- objects.
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
- @private
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 _contentWillChange
11409
+ @method unknownProperty
11410
+ @param keyName {String}
11411
+ @param value {anything}
11273
11412
  */
11274
- _contentWillChange: Ember.beforeObserver(function() {
11275
- this._teardownContent();
11276
- }, 'content'),
11277
-
11278
- _teardownContent: function() {
11279
- var content = get(this, 'content');
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
- contentArrayWillChange: Ember.K,
11290
- contentArrayDidChange: Ember.K,
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
- @method _contentDidChange
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
- Ember.assert("Can't set ArrayProxy's content to itself", content !== this);
11428
+ lim = removedCnt>0 ? idx+removedCnt : -1;
11429
+ Ember.beginPropertyChanges(this);
11304
11430
 
11305
- this._setupContent();
11306
- }, 'content'),
11431
+ for(key in keys) {
11432
+ if (!keys.hasOwnProperty(key)) { continue; }
11307
11433
 
11308
- _setupContent: function() {
11309
- var content = get(this, 'content');
11434
+ if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
11310
11435
 
11311
- if (content) {
11312
- content.addArrayObserver(this, {
11313
- willChange: 'contentArrayWillChange',
11314
- didChange: 'contentArrayDidChange'
11315
- });
11436
+ Ember.propertyWillChange(this, key);
11316
11437
  }
11317
- },
11318
11438
 
11319
- _arrangedContentWillChange: Ember.beforeObserver(function() {
11320
- var arrangedContent = get(this, 'arrangedContent'),
11321
- len = arrangedContent ? get(arrangedContent, 'length') : 0;
11439
+ Ember.propertyWillChange(this._content, '@each');
11440
+ Ember.endPropertyChanges(this);
11441
+ },
11322
11442
 
11323
- this.arrangedContentArrayWillChange(this, 0, len, undefined);
11324
- this.arrangedContentWillChange(this);
11443
+ arrayDidChange: function(content, idx, removedCnt, addedCnt) {
11444
+ var keys = this._keys, key, lim;
11325
11445
 
11326
- this._teardownArrangedContent(arrangedContent);
11327
- }, 'arrangedContent'),
11446
+ lim = addedCnt>0 ? idx+addedCnt : -1;
11447
+ Ember.beginPropertyChanges(this);
11328
11448
 
11329
- _arrangedContentDidChange: Ember.observer(function() {
11330
- var arrangedContent = get(this, 'arrangedContent'),
11331
- len = arrangedContent ? get(arrangedContent, 'length') : 0;
11449
+ for(key in keys) {
11450
+ if (!keys.hasOwnProperty(key)) { continue; }
11332
11451
 
11333
- Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
11452
+ if (lim>0) addObserverForContentKey(content, key, this, idx, lim);
11334
11453
 
11335
- this._setupArrangedContent();
11454
+ Ember.propertyDidChange(this, key);
11455
+ }
11336
11456
 
11337
- this.arrangedContentDidChange(this);
11338
- this.arrangedContentArrayDidChange(this, 0, undefined, len);
11339
- }, 'arrangedContent'),
11457
+ Ember.propertyDidChange(this._content, '@each');
11458
+ Ember.endPropertyChanges(this);
11459
+ },
11340
11460
 
11341
- _setupArrangedContent: function() {
11342
- var arrangedContent = get(this, 'arrangedContent');
11461
+ // ..........................................................
11462
+ // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
11463
+ // Start monitoring keys based on who is listening...
11343
11464
 
11344
- if (arrangedContent) {
11345
- arrangedContent.addArrayObserver(this, {
11346
- willChange: 'arrangedContentArrayWillChange',
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
- _teardownArrangedContent: function() {
11353
- var arrangedContent = get(this, 'arrangedContent');
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
- arrangedContentWillChange: Ember.K,
11364
- arrangedContentDidChange: Ember.K,
11477
+ // ..........................................................
11478
+ // CONTENT KEY OBSERVING
11479
+ // Actual watch keys on the source content.
11365
11480
 
11366
- objectAt: function(idx) {
11367
- return get(this, 'content') && this.objectAtContent(idx);
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
- length: Ember.computed(function() {
11371
- var arrangedContent = get(this, 'arrangedContent');
11372
- return arrangedContent ? get(arrangedContent, 'length') : 0;
11373
- // No dependencies since Enumerable notifies length of change
11374
- }),
11375
-
11376
- replace: function(idx, amt, objects) {
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
- init: function() {
11391
- this._super();
11392
- this._setupContent();
11393
- this._setupArrangedContent();
11503
+ contentKeyWillChange: function(obj, keyName) {
11504
+ Ember.propertyWillChange(this, keyName);
11394
11505
  },
11395
11506
 
11396
- willDestroy: function() {
11397
- this._teardownArrangedContent();
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
- // Access and change existing properties
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
- // Create new 'description' property on `object`
11454
- proxy.set('description', 'Foo is a whizboo baz');
11455
- object.get('description') // 'Foo is a whizboo baz'
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
- While `content` is unset, setting a property to be delegated will throw an
11459
- Error.
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
- ```javascript
11462
- proxy = Ember.ObjectProxy.create({
11463
- content: null,
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
- Delegated properties can be bound to and will change when content is updated.
11545
+ // primitive for array support.
11546
+ replace: function(idx, amt, objects) {
11473
11547
 
11474
- Computed properties on the proxy itself can depend on delegated properties.
11548
+ if (this.isFrozen) throw Ember.FROZEN_ERROR ;
11475
11549
 
11476
- ```javascript
11477
- ProxyWithComputedProperty = Ember.ObjectProxy.extend({
11478
- fullName: function () {
11479
- var firstName = this.get('firstName'),
11480
- lastName = this.get('lastName');
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
- proxy = ProxyWithComputedProperty.create();
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
- proxy.get('fullName'); // undefined
11491
- proxy.set('content', {
11492
- firstName: 'Tom', lastName: 'Dale'
11493
- }); // triggers property change for fullName on proxy
11563
+ this.arrayContentDidChange(idx, amt, len);
11564
+ return this ;
11565
+ },
11494
11566
 
11495
- proxy.get('fullName'); // 'Tom Dale'
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
- @class ObjectProxy
11499
- @namespace Ember
11500
- @extends Ember.Object
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
- @property content
11508
- @type Ember.Object
11509
- @default null
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
- isTruthy: Ember.computed.bool('content'),
11586
+ for(idx=startAt;idx<len;idx++) {
11587
+ if (this[idx] === object) return idx ;
11588
+ }
11589
+ return -1;
11590
+ },
11517
11591
 
11518
- _debugContainerKey: null,
11592
+ lastIndexOf: function(object, startAt) {
11593
+ var idx, len = this.length;
11519
11594
 
11520
- willWatchProperty: function (key) {
11521
- var contentKey = 'content.' + key;
11522
- addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
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
- didUnwatchProperty: function (key) {
11527
- var contentKey = 'content.' + key;
11528
- removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
11529
- removeObserver(this, contentKey, null, contentPropertyDidChange);
11599
+ for(idx=startAt;idx>=0;idx--) {
11600
+ if (this[idx] === object) return idx ;
11601
+ }
11602
+ return -1;
11530
11603
  },
11531
11604
 
11532
- unknownProperty: function (key) {
11533
- var content = get(this, 'content');
11534
- if (content) {
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
- setUnknownProperty: function (key, value) {
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
- Ember.ObjectProxy.reopenClass({
11547
- create: function () {
11548
- var mixin, prototype, i, l, properties, keyName;
11549
- if (arguments.length) {
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
- @module ember
11572
- @submodule ember-runtime
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
- var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
11577
- var forEach = Ember.EnumerableUtils.forEach;
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
- var EachArray = Ember.Object.extend(Ember.Array, {
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
- init: function(content, keyName, owner) {
11582
- this._super();
11583
- this._keyName = keyName;
11584
- this._owner = owner;
11585
- this._content = content;
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
- objectAt: function(idx) {
11589
- var item = this._content.objectAt(idx);
11590
- return item && get(item, this._keyName);
11591
- },
11666
+ Ember.A = function(arr) { return arr || []; };
11667
+ };
11592
11668
 
11593
- length: Ember.computed(function() {
11594
- var content = this._content;
11595
- return content ? get(content, 'length') : 0;
11596
- })
11669
+ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
11670
+ Ember.NativeArray.activate();
11671
+ }
11597
11672
 
11598
- });
11599
11673
 
11600
- var IS_OBSERVER = /^.+:(before|change)$/;
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
- // keep track of the indicies each item was found at so we can map
11613
- // it back when the obj changes.
11614
- guid = guidFor(item);
11615
- if (!objects[guid]) objects[guid] = [];
11616
- objects[guid].push(loc);
11617
- }
11618
- }
11619
- }
11678
+ (function() {
11679
+ /**
11680
+ @module ember
11681
+ @submodule ember-runtime
11682
+ */
11620
11683
 
11621
- function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
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
- while(--loc>=idx) {
11627
- var item = content.objectAt(loc);
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
- guid = guidFor(item);
11633
- indicies = objects[guid];
11634
- indicies[indicies.indexOf(loc)] = null;
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
- This is the object instance returned when you get the `@each` property on an
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
- @private
11645
- @class EachProxy
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.Object
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.EachProxy = Ember.Object.extend({
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
- // in case someone is already observing some keys make sure they are
11657
- // added
11658
- forEach(Ember.watchedEvents(this), function(eventName) {
11659
- this.didAddListener(eventName);
11660
- }, this);
11661
- },
11786
+ // ..........................................................
11787
+ // IMPLEMENT ENUMERABLE APIS
11788
+ //
11662
11789
 
11663
11790
  /**
11664
- You can directly access mapped properties by simply requesting them.
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
- @method unknownProperty
11668
- @param keyName {String}
11669
- @param value {anything}
11793
+ @property length
11794
+ @type number
11795
+ @default 0
11670
11796
  */
11671
- unknownProperty: function(keyName, value) {
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
- // ARRAY CHANGES
11681
- // Invokes whenever the content array itself changes.
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
- arrayWillChange: function(content, idx, removedCnt, addedCnt) {
11684
- var keys = this._keys, key, array, lim;
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
- lim = removedCnt>0 ? idx+removedCnt : -1;
11687
- Ember.beginPropertyChanges(this);
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
- for(key in keys) {
11690
- if (!keys.hasOwnProperty(key)) { continue; }
11816
+ var len = get(this, 'length');
11817
+ if (len === 0) { return this; }
11691
11818
 
11692
- if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
11819
+ var guid;
11693
11820
 
11694
- Ember.propertyWillChange(this, key);
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
- Ember.propertyWillChange(this._content, '@each');
11698
- Ember.endPropertyChanges(this);
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
- arrayDidChange: function(content, idx, removedCnt, addedCnt) {
11702
- var keys = this._keys, key, array, lim;
11840
+ /**
11841
+ Returns true if the passed object is also an enumerable that contains the
11842
+ same objects as the receiver.
11703
11843
 
11704
- lim = addedCnt>0 ? idx+addedCnt : -1;
11705
- Ember.beginPropertyChanges(this);
11844
+ ```javascript
11845
+ var colors = ["red", "green", "blue"],
11846
+ same_colors = new Ember.Set(colors);
11706
11847
 
11707
- for(key in keys) {
11708
- if (!keys.hasOwnProperty(key)) { continue; }
11848
+ same_colors.isEqual(colors); // true
11849
+ same_colors.isEqual(["purple", "brown"]); // false
11850
+ ```
11709
11851
 
11710
- if (lim>0) addObserverForContentKey(content, key, this, idx, lim);
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
- Ember.propertyDidChange(this, key);
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
- Ember.propertyDidChange(this._content, '@each');
11716
- Ember.endPropertyChanges(this);
11867
+ return true;
11717
11868
  },
11718
11869
 
11719
- // ..........................................................
11720
- // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
11721
- // Start monitoring keys based on who is listening...
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
- didAddListener: function(eventName) {
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
- didRemoveListener: function(eventName) {
11730
- if (IS_OBSERVER.test(eventName)) {
11731
- this.stopObservingContentKey(eventName.slice(0, -7));
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
- // CONTENT KEY OBSERVING
11737
- // Actual watch keys on the source content.
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
- beginObservingContentKey: function(keyName) {
11740
- var keys = this._keys;
11741
- if (!keys) keys = this._keys = {};
11742
- if (!keys[keyName]) {
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
- stopObservingContentKey: function(keyName) {
11753
- var keys = this._keys;
11754
- if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) {
11755
- var content = this._content,
11756
- len = get(content, 'length');
11757
- removeObserverForContentKey(content, keyName, this, 0, len);
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
- contentKeyWillChange: function(obj, keyName) {
11762
- Ember.propertyWillChange(this, keyName);
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
- contentKeyDidChange: function(obj, keyName) {
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
- (function() {
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
- var get = Ember.get, set = Ember.set;
12004
+ ```javascript
12005
+ var colors = new Ember.Set(["red", "green", "blue"]);
12006
+ colors.removeEach(["red", "blue"]); // ["green"]
12007
+ ```
11785
12008
 
11786
- // Add Ember.Array to Array.prototype. Remove methods with native
11787
- // implementations and supply some more optimized versions of generic methods
11788
- // because they are so common.
11789
- var NativeArray = Ember.Mixin.create(Ember.MutableArray, Ember.Observable, Ember.Copyable, {
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
- // because length is a built-in property we need to know to just get the
11792
- // original property.
11793
- get: function(key) {
11794
- if (key==='length') return this.length;
11795
- else if ('number' === typeof key) return this[key];
11796
- else return this._super(key);
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
- objectAt: function(idx) {
12024
+ // implement Ember.Enumerable
12025
+ nextObject: function(idx) {
11800
12026
  return this[idx];
11801
12027
  },
11802
12028
 
11803
- // primitive for array support.
11804
- replace: function(idx, amt, objects) {
11805
-
11806
- if (this.isFrozen) throw Ember.FROZEN_ERROR ;
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
- if (!objects || objects.length === 0) {
11815
- this.splice(idx, amt) ;
11816
- } else {
11817
- var args = [idx, amt].concat(objects) ;
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
- this.arrayContentDidChange(idx, amt, len);
11822
- return this ;
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
- // If you ask for an unknown property, then try to collect the value
11826
- // from member items.
11827
- unknownProperty: function(key, value) {
11828
- var ret;// = this.reducedProperty(key, value) ;
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
- // If browser did not implement indexOf natively, then override with
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
- if (startAt === undefined) startAt = 0;
11841
- else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11842
- if (startAt < 0) startAt += len;
12051
+ added = [obj];
11843
12052
 
11844
- for(idx=startAt;idx<len;idx++) {
11845
- if (this[idx] === object) return idx ;
11846
- }
11847
- return -1;
11848
- },
12053
+ this.enumerableContentWillChange(null, added);
12054
+ Ember.propertyWillChange(this, 'lastObject');
11849
12055
 
11850
- lastIndexOf: function(object, startAt) {
11851
- var idx, len = this.length;
12056
+ len = get(this, 'length');
12057
+ this[guid] = len;
12058
+ this[len] = obj;
12059
+ set(this, 'length', len+1);
11852
12060
 
11853
- if (startAt === undefined) startAt = len-1;
11854
- else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11855
- if (startAt < 0) startAt += len;
12061
+ Ember.propertyDidChange(this, 'lastObject');
12062
+ this.enumerableContentDidChange(null, added);
11856
12063
 
11857
- for(idx=startAt;idx>=0;idx--) {
11858
- if (this[idx] === object) return idx ;
11859
- }
11860
- return -1;
12064
+ return this;
11861
12065
  },
11862
12066
 
11863
- copy: function(deep) {
11864
- if (deep) {
11865
- return this.map(function(item){ return Ember.copy(item, true); });
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
- return this.slice();
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 (ignore.length>0) {
11879
- NativeArray = NativeArray.without.apply(NativeArray, ignore);
11880
- }
12080
+ if (idx>=0 && idx<len && (this[idx] === obj)) {
12081
+ removed = [obj];
11881
12082
 
11882
- /**
11883
- The NativeArray mixin contains the properties needed to to make the native
11884
- Array support Ember.MutableArray and all of its dependent APIs. Unless you
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
- @class NativeArray
11890
- @namespace Ember
11891
- @extends Ember.Mixin
11892
- @uses Ember.MutableArray
11893
- @uses Ember.MutableEnumerable
11894
- @uses Ember.Copyable
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
- Creates an `Ember.NativeArray` from an Array like object.
11901
- Does not modify the original object.
12094
+ delete this[guid];
12095
+ delete this[len-1];
12096
+ set(this, 'length', len-1);
11902
12097
 
11903
- @method A
11904
- @for Ember
11905
- @return {Ember.NativeArray}
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
- Activates the mixin on the Array.prototype if not already applied. Calling
11914
- this method more than once is safe.
12103
+ return this;
12104
+ },
11915
12105
 
11916
- @method activate
11917
- @for Ember.NativeArray
11918
- @static
11919
- @return {void}
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
- Ember.A = function(arr) { return arr || []; };
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
- if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
11928
- Ember.NativeArray.activate();
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, isGlobalPath = Ember.isGlobalPath,
12333
- forEach = Ember.EnumerableUtils.forEach, replace = Ember.EnumerableUtils.replace;
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