ember-source 1.0.0.rc1.2 → 1.0.0.rc1.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

@@ -1,5 +1,5 @@
1
- // Version: v1.0.0-pre.4-293-ge707ffa
2
- // Last commit: e707ffa (2013-02-23 17:35:13 -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-pre.4-293-ge707ffa
154
- // Last commit: e707ffa (2013-02-23 17:35:13 -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() {
@@ -297,6 +297,15 @@ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !
297
297
  */
298
298
  Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES;
299
299
 
300
+ /**
301
+ Determines whether Ember logs info about version of used libraries
302
+
303
+ @property LOG_VERSION
304
+ @type Boolean
305
+ @default true
306
+ */
307
+ Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true;
308
+
300
309
  /**
301
310
  Empty function. Useful for some operations.
302
311
 
@@ -409,6 +418,58 @@ Ember.merge = function(original, updates) {
409
418
  }
410
419
  };
411
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
+
412
473
  })();
413
474
 
414
475
 
@@ -1752,7 +1813,7 @@ var MapWithDefault = Ember.MapWithDefault = function(options) {
1752
1813
  @static
1753
1814
  @param [options]
1754
1815
  @param {anything} [options.defaultValue]
1755
- @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
1816
+ @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
1756
1817
  `Ember.MapWithDefault` otherwise returns `Ember.Map`
1757
1818
  */
1758
1819
  MapWithDefault.create = function(options) {
@@ -1815,7 +1876,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
1815
1876
  // ..........................................................
1816
1877
  // GET AND SET
1817
1878
  //
1818
- // 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.
1819
1880
  // Otherwise simulate accessors by looking up the property directly on the
1820
1881
  // object.
1821
1882
 
@@ -1826,7 +1887,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
1826
1887
 
1827
1888
  If you plan to run on IE8 and older browsers then you should use this
1828
1889
  method anytime you want to retrieve a property on an object that you don't
1829
- know for sure is private. (Properties beginning with an underscore '_'
1890
+ know for sure is private. (Properties beginning with an underscore '_'
1830
1891
  are considered private.)
1831
1892
 
1832
1893
  On all newer browsers, you only need to use this method to retrieve
@@ -1888,7 +1949,7 @@ get = function get(obj, keyName) {
1888
1949
 
1889
1950
  If you plan to run on IE8 and older browsers then you should use this
1890
1951
  method anytime you want to set a property on an object that you don't
1891
- know for sure is private. (Properties beginning with an underscore '_'
1952
+ know for sure is private. (Properties beginning with an underscore '_'
1892
1953
  are considered private.)
1893
1954
 
1894
1955
  On all newer browsers, you only need to use this method to set
@@ -2119,11 +2180,8 @@ Ember.isGlobalPath = function(path) {
2119
2180
  @module ember-metal
2120
2181
  */
2121
2182
 
2122
- var GUID_KEY = Ember.GUID_KEY,
2123
- META_KEY = Ember.META_KEY,
2124
- EMPTY_META = Ember.EMPTY_META,
2183
+ var META_KEY = Ember.META_KEY,
2125
2184
  metaFor = Ember.meta,
2126
- o_create = Ember.create,
2127
2185
  objectDefineProperty = Ember.platform.defineProperty;
2128
2186
 
2129
2187
  var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER;
@@ -2543,7 +2601,6 @@ var guidFor = Ember.guidFor, // utils.js
2543
2601
  META_KEY = Ember.META_KEY, // utils.js
2544
2602
  // circular reference observer depends on Ember.watch
2545
2603
  // we should move change events to this file or its own property_events.js
2546
- notifyObservers = Ember.notifyObservers, // observer.js
2547
2604
  forEach = Ember.ArrayPolyfills.forEach, // array.js
2548
2605
  FIRST_KEY = /^([^\.\*]+)/,
2549
2606
  IS_PATH = /[\.\*]/;
@@ -3083,7 +3140,7 @@ Ember.finishChains = function(obj) {
3083
3140
  @param {String} keyName The property key (or path) that will change.
3084
3141
  @return {void}
3085
3142
  */
3086
- function propertyWillChange(obj, keyName, value) {
3143
+ function propertyWillChange(obj, keyName) {
3087
3144
  var m = metaFor(obj, false),
3088
3145
  watching = m.watching[keyName] > 0 || keyName === 'length',
3089
3146
  proto = m.proto,
@@ -3191,7 +3248,6 @@ Ember.warn("The CP_DEFAULT_CACHEABLE flag has been removed and computed properti
3191
3248
  var get = Ember.get,
3192
3249
  set = Ember.set,
3193
3250
  metaFor = Ember.meta,
3194
- guidFor = Ember.guidFor,
3195
3251
  a_slice = [].slice,
3196
3252
  o_create = Ember.create,
3197
3253
  META_KEY = Ember.META_KEY,
@@ -3227,20 +3283,8 @@ function keysForDep(obj, depsMeta, depKey) {
3227
3283
  return keys;
3228
3284
  }
3229
3285
 
3230
- /* return obj[META_KEY].deps */
3231
3286
  function metaForDeps(obj, meta) {
3232
- var deps = meta.deps;
3233
- // If the current object has no dependencies...
3234
- if (!deps) {
3235
- // initialize the dependencies with a pointer back to
3236
- // the current object
3237
- deps = meta.deps = {};
3238
- } else if (!meta.hasOwnProperty('deps')) {
3239
- // otherwise if the dependencies are inherited from the
3240
- // object's superclass, clone the deps
3241
- deps = meta.deps = o_create(deps);
3242
- }
3243
- return deps;
3287
+ return keysForDep(obj, meta, 'deps');
3244
3288
  }
3245
3289
 
3246
3290
  function addDependentKeys(desc, obj, keyName, meta) {
@@ -3293,8 +3337,10 @@ function removeDependentKeys(desc, obj, keyName, meta) {
3293
3337
  */
3294
3338
  function ComputedProperty(func, opts) {
3295
3339
  this.func = func;
3340
+
3296
3341
  this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true;
3297
3342
  this._dependentKeys = opts && opts.dependentKeys;
3343
+ this._readOnly = opts && (opts.readOnly !== undefined || !!opts.readOnly);
3298
3344
  }
3299
3345
 
3300
3346
  Ember.ComputedProperty = ComputedProperty;
@@ -3349,6 +3395,28 @@ ComputedPropertyPrototype.volatile = function() {
3349
3395
  return this.cacheable(false);
3350
3396
  };
3351
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
+
3352
3420
  /**
3353
3421
  Sets the dependent keys on this computed property. Pass any number of
3354
3422
  arguments containing key paths that this computed property depends on.
@@ -3473,9 +3541,14 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) {
3473
3541
  cache = meta.cache,
3474
3542
  cachedValue, ret;
3475
3543
 
3544
+ if (this._readOnly) {
3545
+ throw new Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() );
3546
+ }
3547
+
3476
3548
  this._suspended = obj;
3477
3549
 
3478
3550
  try {
3551
+
3479
3552
  if (cacheable && cache.hasOwnProperty(keyName)) {
3480
3553
  cachedValue = cache[keyName];
3481
3554
  hadCachedValue = true;
@@ -3566,6 +3639,10 @@ Ember.computed = function(func) {
3566
3639
  func = a_slice.call(arguments, -1)[0];
3567
3640
  }
3568
3641
 
3642
+ if ( typeof func !== "function" ) {
3643
+ throw new Error("Computed Property declared without a property function");
3644
+ }
3645
+
3569
3646
  var cp = new ComputedProperty(func);
3570
3647
 
3571
3648
  if (args) {
@@ -3606,6 +3683,18 @@ Ember.computed.not = function(dependentKey) {
3606
3683
  });
3607
3684
  };
3608
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
+
3609
3698
  /**
3610
3699
  @method computed.empty
3611
3700
  @for Ember
@@ -3614,7 +3703,7 @@ Ember.computed.not = function(dependentKey) {
3614
3703
  Ember.computed.empty = function(dependentKey) {
3615
3704
  return Ember.computed(dependentKey, function(key) {
3616
3705
  var val = get(this, dependentKey);
3617
- return val === undefined || val === null || val === '' || (Ember.isArray(val) && get(val, 'length') === 0);
3706
+ return Ember.isEmpty(val);
3618
3707
  });
3619
3708
  };
3620
3709
 
@@ -3632,15 +3721,16 @@ Ember.computed.bool = function(dependentKey) {
3632
3721
  /**
3633
3722
  @method computed.alias
3634
3723
  @for Ember
3724
+
3635
3725
  @param {String} dependentKey
3636
3726
  */
3637
3727
  Ember.computed.alias = function(dependentKey) {
3638
3728
  return Ember.computed(dependentKey, function(key, value){
3639
- if (arguments.length === 1) {
3640
- return get(this, dependentKey);
3641
- } else {
3729
+ if (arguments.length > 1) {
3642
3730
  set(this, dependentKey, value);
3643
3731
  return value;
3732
+ } else {
3733
+ return get(this, dependentKey);
3644
3734
  }
3645
3735
  });
3646
3736
  };
@@ -3656,7 +3746,6 @@ Ember.computed.alias = function(dependentKey) {
3656
3746
 
3657
3747
  var o_create = Ember.create,
3658
3748
  metaFor = Ember.meta,
3659
- metaPath = Ember.metaPath,
3660
3749
  META_KEY = Ember.META_KEY;
3661
3750
 
3662
3751
  /*
@@ -4229,7 +4318,7 @@ Ember.RunLoop = RunLoop;
4229
4318
 
4230
4319
  ```javascript
4231
4320
  Ember.run(function(){
4232
- // code to be execute within a RunLoop
4321
+ // code to be execute within a RunLoop
4233
4322
  });
4234
4323
  ```
4235
4324
 
@@ -4245,8 +4334,7 @@ Ember.RunLoop = RunLoop;
4245
4334
  @return {Object} return value from invoking the passed function.
4246
4335
  */
4247
4336
  Ember.run = function(target, method) {
4248
- var loop,
4249
- args = arguments;
4337
+ var args = arguments;
4250
4338
  run.begin();
4251
4339
 
4252
4340
  function tryable() {
@@ -4264,11 +4352,11 @@ var run = Ember.run;
4264
4352
  /**
4265
4353
  Begins a new RunLoop. Any deferred actions invoked after the begin will
4266
4354
  be buffered until you invoke a matching call to `Ember.run.end()`. This is
4267
- 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()`.
4268
4356
 
4269
4357
  ```javascript
4270
4358
  Ember.run.begin();
4271
- // code to be execute within a RunLoop
4359
+ // code to be execute within a RunLoop
4272
4360
  Ember.run.end();
4273
4361
  ```
4274
4362
 
@@ -4286,7 +4374,7 @@ Ember.run.begin = function() {
4286
4374
 
4287
4375
  ```javascript
4288
4376
  Ember.run.begin();
4289
- // code to be execute within a RunLoop
4377
+ // code to be execute within a RunLoop
4290
4378
  Ember.run.end();
4291
4379
  ```
4292
4380
 
@@ -4310,9 +4398,9 @@ Ember.run.end = function() {
4310
4398
 
4311
4399
  @property queues
4312
4400
  @type Array
4313
- @default ['sync', 'actions', 'destroy', 'timers']
4401
+ @default ['sync', 'actions', 'destroy']
4314
4402
  */
4315
- Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
4403
+ Ember.run.queues = ['sync', 'actions', 'destroy'];
4316
4404
 
4317
4405
  /**
4318
4406
  Adds the passed target/method and any optional arguments to the named
@@ -4325,19 +4413,19 @@ Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
4325
4413
  the `run.queues` property.
4326
4414
 
4327
4415
  ```javascript
4328
- Ember.run.schedule('timers', this, function(){
4329
- // this will be executed at the end of the RunLoop, when timers are run
4330
- console.log("scheduled on timers queue");
4331
- });
4332
-
4333
4416
  Ember.run.schedule('sync', this, function(){
4334
- // 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
4335
4418
  console.log("scheduled on sync queue");
4336
4419
  });
4337
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
+
4338
4426
  // Note the functions will be run in order based on the run queues order. Output would be:
4339
4427
  // scheduled on sync queue
4340
- // scheduled on timers queue
4428
+ // scheduled on actions queue
4341
4429
  ```
4342
4430
 
4343
4431
  @method schedule
@@ -4363,7 +4451,7 @@ function autorun() {
4363
4451
 
4364
4452
  // Used by global test teardown
4365
4453
  Ember.run.hasScheduledTimers = function() {
4366
- return !!(scheduledAutorun || scheduledLater || scheduledNext);
4454
+ return !!(scheduledAutorun || scheduledLater);
4367
4455
  };
4368
4456
 
4369
4457
  // Used by global test teardown
@@ -4376,10 +4464,6 @@ Ember.run.cancelTimers = function () {
4376
4464
  clearTimeout(scheduledLater);
4377
4465
  scheduledLater = null;
4378
4466
  }
4379
- if (scheduledNext) {
4380
- clearTimeout(scheduledNext);
4381
- scheduledNext = null;
4382
- }
4383
4467
  timers = {};
4384
4468
  };
4385
4469
 
@@ -4414,7 +4498,8 @@ Ember.run.autorun = function() {
4414
4498
  bindings in the application to sync.
4415
4499
 
4416
4500
  You should call this method anytime you need any changed state to propagate
4417
- 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).
4418
4503
 
4419
4504
  ```javascript
4420
4505
  Ember.run.sync();
@@ -4434,25 +4519,30 @@ Ember.run.sync = function() {
4434
4519
 
4435
4520
  var timers = {}; // active timers...
4436
4521
 
4437
- var scheduledLater;
4522
+ var scheduledLater, scheduledLaterExpires;
4438
4523
  function invokeLaterTimers() {
4439
4524
  scheduledLater = null;
4440
- var now = (+ new Date()), earliest = -1;
4441
- for (var key in timers) {
4442
- if (!timers.hasOwnProperty(key)) { continue; }
4443
- var timer = timers[key];
4444
- if (timer && timer.expires) {
4445
- if (now >= timer.expires) {
4446
- delete timers[key];
4447
- invoke(timer.target, timer.method, timer.args, 2);
4448
- } else {
4449
- 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
+ }
4450
4537
  }
4451
4538
  }
4452
- }
4453
4539
 
4454
- // schedule next timeout to fire...
4455
- 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
+ });
4456
4546
  }
4457
4547
 
4458
4548
  /**
@@ -4500,7 +4590,19 @@ Ember.run.later = function(target, method) {
4500
4590
  timer = { target: target, method: method, expires: expires, args: args };
4501
4591
  guid = Ember.guidFor(timer);
4502
4592
  timers[guid] = timer;
4503
- 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
+
4504
4606
  return guid;
4505
4607
  };
4506
4608
 
@@ -4556,6 +4658,21 @@ function scheduleOnce(queue, target, method, args) {
4556
4658
  });
4557
4659
  ```
4558
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
+
4559
4676
  @method once
4560
4677
  @param {Object} [target] target of method to invoke
4561
4678
  @param {Function|String} method The method to invoke.
@@ -4572,22 +4689,9 @@ Ember.run.scheduleOnce = function(queue, target, method, args) {
4572
4689
  return scheduleOnce(queue, target, method, slice.call(arguments, 3));
4573
4690
  };
4574
4691
 
4575
- var scheduledNext;
4576
- function invokeNextTimers() {
4577
- scheduledNext = null;
4578
- for(var key in timers) {
4579
- if (!timers.hasOwnProperty(key)) { continue; }
4580
- var timer = timers[key];
4581
- if (timer.next) {
4582
- delete timers[key];
4583
- invoke(timer.target, timer.method, timer.args, 2);
4584
- }
4585
- }
4586
- }
4587
-
4588
4692
  /**
4589
4693
  Schedules an item to run after control has been returned to the system.
4590
- This is often equivalent to calling `setTimeout(function() {}, 1)`.
4694
+ This is equivalent to calling `Ember.run.later` with a wait time of 1ms.
4591
4695
 
4592
4696
  ```javascript
4593
4697
  Ember.run.next(myContext, function(){
@@ -4603,20 +4707,10 @@ function invokeNextTimers() {
4603
4707
  @param {Object} [args*] Optional arguments to pass to the timeout.
4604
4708
  @return {Object} timer
4605
4709
  */
4606
- Ember.run.next = function(target, method) {
4607
- var guid,
4608
- timer = {
4609
- target: target,
4610
- method: method,
4611
- args: slice.call(arguments),
4612
- next: true
4613
- };
4614
-
4615
- guid = Ember.guidFor(timer);
4616
- timers[guid] = timer;
4617
-
4618
- if (!scheduledNext) { scheduledNext = setTimeout(invokeNextTimers, 1); }
4619
- 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);
4620
4714
  };
4621
4715
 
4622
4716
  /**
@@ -5121,7 +5215,6 @@ var Mixin, REQUIRED, Alias,
5121
5215
  a_indexOf = Ember.ArrayPolyfills.indexOf,
5122
5216
  a_forEach = Ember.ArrayPolyfills.forEach,
5123
5217
  a_slice = [].slice,
5124
- EMPTY_META = {}, // dummy for non-writable meta
5125
5218
  o_create = Ember.create,
5126
5219
  defineProperty = Ember.defineProperty,
5127
5220
  guidFor = Ember.guidFor;
@@ -5490,6 +5583,38 @@ Mixin.finishPartial = finishPartial;
5490
5583
  Ember.anyUnprocessedMixins = false;
5491
5584
 
5492
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
+
5493
5618
  @method create
5494
5619
  @static
5495
5620
  @param arguments*
@@ -6005,35 +6130,35 @@ define("rsvp",
6005
6130
  }
6006
6131
 
6007
6132
  function all(promises) {
6008
- var i, results = [];
6009
- var allPromise = new Promise();
6010
- var remaining = promises.length;
6133
+ var i, results = [];
6134
+ var allPromise = new Promise();
6135
+ var remaining = promises.length;
6011
6136
 
6012
6137
  if (remaining === 0) {
6013
6138
  allPromise.resolve([]);
6014
6139
  }
6015
6140
 
6016
- var resolver = function(index) {
6017
- return function(value) {
6018
- resolve(index, value);
6019
- };
6020
- };
6141
+ var resolver = function(index) {
6142
+ return function(value) {
6143
+ resolve(index, value);
6144
+ };
6145
+ };
6021
6146
 
6022
- var resolve = function(index, value) {
6023
- results[index] = value;
6024
- if (--remaining === 0) {
6025
- allPromise.resolve(results);
6026
- }
6027
- };
6147
+ var resolve = function(index, value) {
6148
+ results[index] = value;
6149
+ if (--remaining === 0) {
6150
+ allPromise.resolve(results);
6151
+ }
6152
+ };
6028
6153
 
6029
- var reject = function(error) {
6030
- allPromise.reject(error);
6031
- };
6154
+ var reject = function(error) {
6155
+ allPromise.reject(error);
6156
+ };
6032
6157
 
6033
- for (i = 0; i < remaining; i++) {
6034
- promises[i].then(resolver(i), reject);
6035
- }
6036
- return allPromise;
6158
+ for (i = 0; i < remaining; i++) {
6159
+ promises[i].then(resolver(i), reject);
6160
+ }
6161
+ return allPromise;
6037
6162
  }
6038
6163
 
6039
6164
  EventTarget.mixin(Promise.prototype);
@@ -6409,57 +6534,6 @@ Ember.typeOf = function(item) {
6409
6534
  return ret;
6410
6535
  };
6411
6536
 
6412
- /**
6413
- Returns true if the passed value is null or undefined. This avoids errors
6414
- from JSLint complaining about use of ==, which can be technically
6415
- confusing.
6416
-
6417
- ```javascript
6418
- Ember.isNone(); // true
6419
- Ember.isNone(null); // true
6420
- Ember.isNone(undefined); // true
6421
- Ember.isNone(''); // false
6422
- Ember.isNone([]); // false
6423
- Ember.isNone(function(){}); // false
6424
- ```
6425
-
6426
- @method isNone
6427
- @for Ember
6428
- @param {Object} obj Value to test
6429
- @return {Boolean}
6430
- */
6431
- Ember.isNone = function(obj) {
6432
- return obj === null || obj === undefined;
6433
- };
6434
- Ember.none = Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.", Ember.isNone);
6435
-
6436
- /**
6437
- Verifies that a value is `null` or an empty string, empty array,
6438
- or empty function.
6439
-
6440
- Constrains the rules on `Ember.isNone` by returning false for empty
6441
- string and empty arrays.
6442
-
6443
- ```javascript
6444
- Ember.isEmpty(); // true
6445
- Ember.isEmpty(null); // true
6446
- Ember.isEmpty(undefined); // true
6447
- Ember.isEmpty(''); // true
6448
- Ember.isEmpty([]); // true
6449
- Ember.isEmpty('Adam Hawkins'); // false
6450
- Ember.isEmpty([0,1,2]); // false
6451
- ```
6452
-
6453
- @method isEmpty
6454
- @for Ember
6455
- @param {Object} obj Value to test
6456
- @return {Boolean}
6457
- */
6458
- Ember.isEmpty = function(obj) {
6459
- return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
6460
- };
6461
- Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ;
6462
-
6463
6537
  /**
6464
6538
  This will compare two javascript values of possibly different types.
6465
6539
  It will tell you which one is greater than the other by returning:
@@ -6753,6 +6827,20 @@ Ember.Error.prototype = Ember.create(Error.prototype);
6753
6827
 
6754
6828
 
6755
6829
 
6830
+ (function() {
6831
+ /**
6832
+ Expose RSVP implementation
6833
+
6834
+ @class RSVP
6835
+ @namespace Ember
6836
+ @constructor
6837
+ */
6838
+ Ember.RSVP = requireModule('rsvp');
6839
+
6840
+ })();
6841
+
6842
+
6843
+
6756
6844
  (function() {
6757
6845
  /**
6758
6846
  @module ember
@@ -6901,10 +6989,11 @@ Ember.String = {
6901
6989
  */
6902
6990
  dasherize: function(str) {
6903
6991
  var cache = STRING_DASHERIZE_CACHE,
6904
- ret = cache[str];
6992
+ hit = cache.hasOwnProperty(str),
6993
+ ret;
6905
6994
 
6906
- if (ret) {
6907
- return ret;
6995
+ if (hit) {
6996
+ return cache[str];
6908
6997
  } else {
6909
6998
  ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-');
6910
6999
  cache[str] = ret;
@@ -6914,7 +7003,7 @@ Ember.String = {
6914
7003
  },
6915
7004
 
6916
7005
  /**
6917
- Returns the lowerCaseCamel form of a string.
7006
+ Returns the lowerCamelCase form of a string.
6918
7007
 
6919
7008
  ```javascript
6920
7009
  'innerHTML'.camelize(); // 'innerHTML'
@@ -6985,10 +7074,10 @@ Ember.String = {
6985
7074
  /**
6986
7075
  Returns the Capitalized form of a string
6987
7076
 
6988
- 'innerHTML'.capitalize() => 'InnerHTML'
6989
- 'action_name'.capitalize() => 'Action_name'
6990
- 'css-class-name'.capitalize() => 'Css-class-name'
6991
- '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'
6992
7081
 
6993
7082
  @method capitalize
6994
7083
  @param {String} str
@@ -7332,8 +7421,7 @@ function iter(key, value) {
7332
7421
  @extends Ember.Mixin
7333
7422
  @since Ember 0.9
7334
7423
  */
7335
- Ember.Enumerable = Ember.Mixin.create(
7336
- /** @scope Ember.Enumerable.prototype */ {
7424
+ Ember.Enumerable = Ember.Mixin.create({
7337
7425
 
7338
7426
  // compatibility
7339
7427
  isEnumerable: true,
@@ -7366,7 +7454,7 @@ Ember.Enumerable = Ember.Mixin.create(
7366
7454
 
7367
7455
  @method nextObject
7368
7456
  @param {Number} index the current index of the iteration
7369
- @param {Object} previousObject the value returned by the last call to
7457
+ @param {Object} previousObject the value returned by the last call to
7370
7458
  `nextObject`.
7371
7459
  @param {Object} context a context object you can use to maintain state.
7372
7460
  @return {Object} the next object in the iteration or undefined
@@ -7385,10 +7473,10 @@ Ember.Enumerable = Ember.Mixin.create(
7385
7473
 
7386
7474
  ```javascript
7387
7475
  var arr = ["a", "b", "c"];
7388
- arr.firstObject(); // "a"
7476
+ arr.get('firstObject'); // "a"
7389
7477
 
7390
7478
  var arr = [];
7391
- arr.firstObject(); // undefined
7479
+ arr.get('firstObject'); // undefined
7392
7480
  ```
7393
7481
 
7394
7482
  @property firstObject
@@ -7411,10 +7499,10 @@ Ember.Enumerable = Ember.Mixin.create(
7411
7499
 
7412
7500
  ```javascript
7413
7501
  var arr = ["a", "b", "c"];
7414
- arr.lastObject(); // "c"
7502
+ arr.get('lastObject'); // "c"
7415
7503
 
7416
7504
  var arr = [];
7417
- arr.lastObject(); // undefined
7505
+ arr.get('lastObject'); // undefined
7418
7506
  ```
7419
7507
 
7420
7508
  @property lastObject
@@ -7547,7 +7635,7 @@ Ember.Enumerable = Ember.Mixin.create(
7547
7635
  @return {Array} The mapped array.
7548
7636
  */
7549
7637
  map: function(callback, target) {
7550
- var ret = [];
7638
+ var ret = Ember.A([]);
7551
7639
  this.forEach(function(x, idx, i) {
7552
7640
  ret[idx] = callback.call(target, x, idx,i);
7553
7641
  });
@@ -7597,7 +7685,7 @@ Ember.Enumerable = Ember.Mixin.create(
7597
7685
  @return {Array} A filtered array.
7598
7686
  */
7599
7687
  filter: function(callback, target) {
7600
- var ret = [];
7688
+ var ret = Ember.A([]);
7601
7689
  this.forEach(function(x, idx, i) {
7602
7690
  if (callback.call(target, x, idx, i)) ret.push(x);
7603
7691
  });
@@ -7886,7 +7974,7 @@ Ember.Enumerable = Ember.Mixin.create(
7886
7974
  @return {Array} return values from calling invoke.
7887
7975
  */
7888
7976
  invoke: function(methodName) {
7889
- var args, ret = [];
7977
+ var args, ret = Ember.A([]);
7890
7978
  if (arguments.length>1) args = a_slice.call(arguments, 1);
7891
7979
 
7892
7980
  this.forEach(function(x, idx) {
@@ -7907,7 +7995,7 @@ Ember.Enumerable = Ember.Mixin.create(
7907
7995
  @return {Array} the enumerable as an array.
7908
7996
  */
7909
7997
  toArray: function() {
7910
- var ret = [];
7998
+ var ret = Ember.A([]);
7911
7999
  this.forEach(function(o, idx) { ret[idx] = o; });
7912
8000
  return ret ;
7913
8001
  },
@@ -7941,7 +8029,7 @@ Ember.Enumerable = Ember.Mixin.create(
7941
8029
  */
7942
8030
  without: function(value) {
7943
8031
  if (!this.contains(value)) return this; // nothing to do
7944
- var ret = [] ;
8032
+ var ret = Ember.A([]);
7945
8033
  this.forEach(function(k) {
7946
8034
  if (k !== value) ret[ret.length] = k;
7947
8035
  }) ;
@@ -7961,7 +8049,7 @@ Ember.Enumerable = Ember.Mixin.create(
7961
8049
  @return {Ember.Enumerable}
7962
8050
  */
7963
8051
  uniq: function() {
7964
- var ret = [];
8052
+ var ret = Ember.A([]);
7965
8053
  this.forEach(function(k){
7966
8054
  if (a_indexOf(ret, k)<0) ret.push(k);
7967
8055
  });
@@ -7993,7 +8081,7 @@ Ember.Enumerable = Ember.Mixin.create(
7993
8081
 
7994
8082
  @method addEnumerableObserver
7995
8083
  @param {Object} target
7996
- @param {Hash} opts
8084
+ @param {Hash} [opts]
7997
8085
  */
7998
8086
  addEnumerableObserver: function(target, opts) {
7999
8087
  var willChange = (opts && opts.willChange) || 'enumerableWillChange',
@@ -8091,7 +8179,7 @@ Ember.Enumerable = Ember.Mixin.create(
8091
8179
  @chainable
8092
8180
  */
8093
8181
  enumerableContentDidChange: function(removing, adding) {
8094
- var notify = this.propertyDidChange, removeCnt, addCnt, hasDelta;
8182
+ var removeCnt, addCnt, hasDelta;
8095
8183
 
8096
8184
  if ('number' === typeof removing) removeCnt = removing;
8097
8185
  else if (removing) removeCnt = get(removing, 'length');
@@ -8129,7 +8217,7 @@ Ember.Enumerable = Ember.Mixin.create(
8129
8217
  // HELPERS
8130
8218
  //
8131
8219
 
8132
- 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;
8133
8221
 
8134
8222
  function none(obj) { return obj===null || obj===undefined; }
8135
8223
 
@@ -8271,15 +8359,19 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8271
8359
  ```
8272
8360
 
8273
8361
  @method slice
8274
- @param beginIndex {Integer} (Optional) index to begin slicing from.
8275
- @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.
8276
8364
  @return {Array} New array with specified slice
8277
8365
  */
8278
8366
  slice: function(beginIndex, endIndex) {
8279
- var ret = [];
8367
+ var ret = Ember.A([]);
8280
8368
  var length = get(this, 'length') ;
8281
8369
  if (none(beginIndex)) beginIndex = 0 ;
8282
8370
  if (none(endIndex) || (endIndex > length)) endIndex = length ;
8371
+
8372
+ if (beginIndex < 0) beginIndex = length + beginIndex;
8373
+ if (endIndex < 0) endIndex = length + endIndex;
8374
+
8283
8375
  while(beginIndex < endIndex) {
8284
8376
  ret[ret.length] = this.objectAt(beginIndex++) ;
8285
8377
  }
@@ -8433,9 +8525,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8433
8525
 
8434
8526
  @method arrayContentWillChange
8435
8527
  @param {Number} startIdx The starting index in the array that will change.
8436
- @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
8437
8529
  pass `null` assumes 0
8438
- @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
8439
8531
  pass `null` assumes 0.
8440
8532
  @return {Ember.Array} receiver
8441
8533
  */
@@ -8796,8 +8888,7 @@ var forEach = Ember.EnumerableUtils.forEach;
8796
8888
  @extends Ember.Mixin
8797
8889
  @uses Ember.Enumerable
8798
8890
  */
8799
- Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable,
8800
- /** @scope Ember.MutableEnumerable.prototype */ {
8891
+ Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, {
8801
8892
 
8802
8893
  /**
8803
8894
  __Required.__ You must implement this method to apply this mixin.
@@ -8882,7 +8973,7 @@ var EMPTY = [];
8882
8973
  // HELPERS
8883
8974
  //
8884
8975
 
8885
- var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
8976
+ var get = Ember.get, set = Ember.set;
8886
8977
 
8887
8978
  /**
8888
8979
  This mixin defines the API for modifying array-like objects. These methods
@@ -8909,11 +9000,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
8909
9000
  passed array. You should also call `this.enumerableContentDidChange()`
8910
9001
 
8911
9002
  @method replace
8912
- @param {Number} idx Starting index in the array to replace. If
9003
+ @param {Number} idx Starting index in the array to replace. If
8913
9004
  idx >= length, then append to the end of the array.
8914
- @param {Number} amt Number of elements that should be removed from
9005
+ @param {Number} amt Number of elements that should be removed from
8915
9006
  the array, starting at *idx*.
8916
- @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
8917
9008
  inserted into the array at *idx*
8918
9009
  */
8919
9010
  replace: Ember.required(),
@@ -9178,7 +9269,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
9178
9269
  @submodule ember-runtime
9179
9270
  */
9180
9271
 
9181
- var get = Ember.get, set = Ember.set, defineProperty = Ember.defineProperty;
9272
+ var get = Ember.get, set = Ember.set;
9182
9273
 
9183
9274
  /**
9184
9275
  ## Overview
@@ -9776,6 +9867,16 @@ Ember.TargetActionSupport = Ember.Mixin.create({
9776
9867
  // outputs: 'Our person has greeted'
9777
9868
  ```
9778
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
+
9779
9880
  @class Evented
9780
9881
  @namespace Ember
9781
9882
  @extends Ember.Mixin
@@ -9803,6 +9904,7 @@ Ember.Evented = Ember.Mixin.create({
9803
9904
  */
9804
9905
  on: function(name, target, method) {
9805
9906
  Ember.addListener(this, name, target, method);
9907
+ return this;
9806
9908
  },
9807
9909
 
9808
9910
  /**
@@ -9826,6 +9928,7 @@ Ember.Evented = Ember.Mixin.create({
9826
9928
  }
9827
9929
 
9828
9930
  Ember.addListener(this, name, target, method, true);
9931
+ return this;
9829
9932
  },
9830
9933
 
9831
9934
  /**
@@ -9869,6 +9972,7 @@ Ember.Evented = Ember.Mixin.create({
9869
9972
  */
9870
9973
  off: function(name, target, method) {
9871
9974
  Ember.removeListener(this, name, target, method);
9975
+ return this;
9872
9976
  },
9873
9977
 
9874
9978
  /**
@@ -9899,8 +10003,7 @@ RSVP.async = function(callback, binding) {
9899
10003
  @submodule ember-runtime
9900
10004
  */
9901
10005
 
9902
- var get = Ember.get,
9903
- slice = Array.prototype.slice;
10006
+ var get = Ember.get;
9904
10007
 
9905
10008
  /**
9906
10009
  @class Deferred
@@ -9976,7 +10079,6 @@ Ember.Container.set = Ember.set;
9976
10079
  var set = Ember.set, get = Ember.get,
9977
10080
  o_create = Ember.create,
9978
10081
  o_defineProperty = Ember.platform.defineProperty,
9979
- a_slice = Array.prototype.slice,
9980
10082
  GUID_KEY = Ember.GUID_KEY,
9981
10083
  guidFor = Ember.guidFor,
9982
10084
  generateGuid = Ember.generateGuid,
@@ -10124,6 +10226,37 @@ CoreObject.PrototypeMixin = Mixin.create({
10124
10226
 
10125
10227
  isInstance: true,
10126
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
+ */
10127
10260
  init: function() {},
10128
10261
 
10129
10262
  /**
@@ -10168,14 +10301,14 @@ CoreObject.PrototypeMixin = Mixin.create({
10168
10301
  view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
10169
10302
  ```
10170
10303
  Adding a single property that is not an array will just add it in the array:
10171
-
10304
+
10172
10305
  ```javascript
10173
10306
  var view = App.FooBarView.create({
10174
10307
  classNames: 'baz'
10175
10308
  })
10176
10309
  view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
10177
10310
  ```
10178
-
10311
+
10179
10312
  Using the `concatenatedProperties` property, we can tell to Ember that mix
10180
10313
  the content of the properties.
10181
10314
 
@@ -10274,7 +10407,7 @@ CoreObject.PrototypeMixin = Mixin.create({
10274
10407
  }
10275
10408
  });
10276
10409
  teacher = App.Teacher.create()
10277
- teacher.toString(); // #=> "<App.Teacher:ember1026:Tom Dale>"
10410
+ teacher.toString(); //=> "<App.Teacher:ember1026:Tom Dale>"
10278
10411
 
10279
10412
  @method toString
10280
10413
  @return {String} string representation
@@ -10453,687 +10586,723 @@ Ember.CoreObject = CoreObject;
10453
10586
  @submodule ember-runtime
10454
10587
  */
10455
10588
 
10456
- var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone;
10457
-
10458
10589
  /**
10459
- 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.
10460
10593
 
10461
- A Set works a bit like an array except that its items are not ordered. You
10462
- can create a set to efficiently test for membership for an object. You can
10463
- also iterate through a set just like an array, even accessing objects by
10464
- 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"; };
10465
10601
 
10466
- All Sets are observable via the Enumerable Observer API - which works
10467
- on any enumerable object including both Sets and Arrays.
10602
+ })();
10468
10603
 
10469
- ## Creating a Set
10470
10604
 
10471
- You can create a set like you would most objects using
10472
- `new Ember.Set()`. Most new sets you create will be empty, but you can
10473
- also initialize the set with some content by passing an array or other
10474
- enumerable of objects to the constructor.
10475
10605
 
10476
- Finally, you can pass in an existing set and the set will be copied. You
10477
- can also create a copy of a set by calling `Ember.Set#copy()`.
10606
+ (function() {
10607
+ /**
10608
+ @module ember
10609
+ @submodule ember-runtime
10610
+ */
10478
10611
 
10479
- ```javascript
10480
- // creates a new empty set
10481
- var foundNames = new Ember.Set();
10612
+ var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf;
10482
10613
 
10483
- // creates a set with four names in it.
10484
- 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.
10485
10618
 
10486
- // creates a copy of the names set.
10487
- var namesCopy = new Ember.Set(names);
10619
+ # Example Usage
10488
10620
 
10489
- // same as above.
10490
- var anotherNamesCopy = names.copy();
10621
+ ```javascript
10622
+ MyFramework = Ember.Namespace.create({
10623
+ VERSION: '1.0.0'
10624
+ });
10491
10625
  ```
10492
10626
 
10493
- ## Adding/Removing Objects
10494
-
10495
- You generally add or remove objects from a set using `add()` or
10496
- `remove()`. You can add any type of object including primitives such as
10497
- numbers, strings, and booleans.
10627
+ @class Namespace
10628
+ @namespace Ember
10629
+ @extends Ember.Object
10630
+ */
10631
+ var Namespace = Ember.Namespace = Ember.Object.extend({
10632
+ isNamespace: true,
10498
10633
 
10499
- Unlike arrays, objects can only exist one time in a set. If you call `add()`
10500
- on a set with the same object multiple times, the object will only be added
10501
- once. Likewise, calling `remove()` with the same object multiple times will
10502
- remove the object the first time and have no effect on future calls until
10503
- you add the object to the set again.
10634
+ init: function() {
10635
+ Ember.Namespace.NAMESPACES.push(this);
10636
+ Ember.Namespace.PROCESSED = false;
10637
+ },
10504
10638
 
10505
- NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do
10506
- so will be ignored.
10639
+ toString: function() {
10640
+ var name = get(this, 'name');
10641
+ if (name) { return name; }
10507
10642
 
10508
- In addition to add/remove you can also call `push()`/`pop()`. Push behaves
10509
- just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary
10510
- object, remove it and return it. This is a good way to use a set as a job
10511
- queue when you don't care which order the jobs are executed in.
10643
+ findNamespaces();
10644
+ return this[Ember.GUID_KEY+'_name'];
10645
+ },
10512
10646
 
10513
- ## Testing for an Object
10647
+ nameClasses: function() {
10648
+ processNamespace([this.toString()], this, {});
10649
+ },
10514
10650
 
10515
- To test for an object's presence in a set you simply call
10516
- `Ember.Set#contains()`.
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
+ });
10517
10658
 
10518
- ## Observing changes
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
+ }
10519
10668
 
10520
- When using `Ember.Set`, you can observe the `"[]"` property to be
10521
- alerted whenever the content changes. You can also add an enumerable
10522
- observer to the set to be notified of specific objects that are added and
10523
- removed from the set. See `Ember.Enumerable` for more information on
10524
- enumerables.
10669
+ return NAMESPACES_BY_ID[name];
10670
+ }
10671
+ });
10525
10672
 
10526
- This is often unhelpful. If you are filtering sets of objects, for instance,
10527
- it is very inefficient to re-filter all of the items each time the set
10528
- changes. It would be better if you could just adjust the filtered set based
10529
- on what was changed on the original set. The same issue applies to merging
10530
- sets, as well.
10673
+ var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
10531
10674
 
10532
- ## Other Methods
10675
+ var hasOwnProp = ({}).hasOwnProperty,
10676
+ guidFor = Ember.guidFor;
10533
10677
 
10534
- `Ember.Set` primary implements other mixin APIs. For a complete reference
10535
- on the methods you will use with `Ember.Set`, please consult these mixins.
10536
- The most useful ones will be `Ember.Enumerable` and
10537
- `Ember.MutableEnumerable` which implement most of the common iterator
10538
- methods you are used to on Array.
10678
+ function processNamespace(paths, root, seen) {
10679
+ var idx = paths.length;
10539
10680
 
10540
- Note that you can also use the `Ember.Copyable` and `Ember.Freezable`
10541
- APIs on `Ember.Set` as well. Once a set is frozen it can no longer be
10542
- modified. The benefit of this is that when you call `frozenCopy()` on it,
10543
- Ember will avoid making copies of the set. This allows you to write
10544
- code that can know with certainty when the underlying set data will or
10545
- will not be modified.
10681
+ NAMESPACES_BY_ID[paths.join('.')] = root;
10546
10682
 
10547
- @class Set
10548
- @namespace Ember
10549
- @extends Ember.CoreObject
10550
- @uses Ember.MutableEnumerable
10551
- @uses Ember.Copyable
10552
- @uses Ember.Freezable
10553
- @since Ember 0.9
10554
- */
10555
- Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
10556
- /** @scope Ember.Set.prototype */ {
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];
10557
10687
 
10558
- // ..........................................................
10559
- // IMPLEMENT ENUMERABLE APIS
10560
- //
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;
10561
10694
 
10562
- /**
10563
- This property will change as the number of objects in the set changes.
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('.');
10564
10701
 
10565
- @property length
10566
- @type number
10567
- @default 0
10568
- */
10569
- length: 0,
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;
10570
10707
 
10571
- /**
10572
- Clears the set. This is useful if you want to reuse an existing set
10573
- without having to recreate it.
10708
+ // Process the child namespace
10709
+ processNamespace(paths, obj, seen);
10710
+ }
10711
+ }
10574
10712
 
10575
- ```javascript
10576
- var colors = new Ember.Set(["red", "green", "blue"]);
10577
- colors.length; // 3
10578
- colors.clear();
10579
- colors.length; // 0
10580
- ```
10713
+ paths.length = idx; // cut out last item
10714
+ }
10581
10715
 
10582
- @method clear
10583
- @return {Ember.Set} An empty Set
10584
- */
10585
- clear: function() {
10586
- if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
10716
+ function findNamespaces() {
10717
+ var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace;
10587
10718
 
10588
- var len = get(this, 'length');
10589
- if (len === 0) { return this; }
10719
+ if (Namespace.PROCESSED) { return; }
10590
10720
 
10591
- var guid;
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; }
10592
10724
 
10593
- this.enumerableContentWillChange(len, 0);
10594
- Ember.propertyWillChange(this, 'firstObject');
10595
- Ember.propertyWillChange(this, 'lastObject');
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; }
10596
10730
 
10597
- for (var i=0; i < len; i++){
10598
- guid = guidFor(this[i]);
10599
- delete this[guid];
10600
- delete this[i];
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;
10601
10738
  }
10602
10739
 
10603
- set(this, 'length', 0);
10740
+ if (isNamespace) {
10741
+ Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
10742
+ obj[NAME_KEY] = prop;
10743
+ }
10744
+ }
10745
+ }
10604
10746
 
10605
- Ember.propertyDidChange(this, 'firstObject');
10606
- Ember.propertyDidChange(this, 'lastObject');
10607
- this.enumerableContentDidChange(len, 0);
10747
+ var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name';
10608
10748
 
10609
- return this;
10610
- },
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
+ }
10611
10758
 
10612
- /**
10613
- Returns true if the passed object is also an enumerable that contains the
10614
- same objects as the receiver.
10759
+ function classToString() {
10760
+ if (!Ember.BOOTED && !this[NAME_KEY]) {
10761
+ processAllNamespaces();
10762
+ }
10615
10763
 
10616
- ```javascript
10617
- var colors = ["red", "green", "blue"],
10618
- same_colors = new Ember.Set(colors);
10764
+ var ret;
10619
10765
 
10620
- same_colors.isEqual(colors); // true
10621
- same_colors.isEqual(["purple", "brown"]); // false
10622
- ```
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
+ }
10623
10777
 
10624
- @method isEqual
10625
- @param {Ember.Set} obj the other object.
10626
- @return {Boolean}
10627
- */
10628
- isEqual: function(obj) {
10629
- // fail fast
10630
- if (!Ember.Enumerable.detect(obj)) return false;
10778
+ return ret;
10779
+ }
10631
10780
 
10632
- var loc = get(this, 'length');
10633
- if (get(obj, 'length') !== loc) return false;
10781
+ function processAllNamespaces() {
10782
+ var unprocessedNamespaces = !Namespace.PROCESSED,
10783
+ unprocessedMixins = Ember.anyUnprocessedMixins;
10634
10784
 
10635
- while(--loc >= 0) {
10636
- if (!obj.contains(this[loc])) return false;
10785
+ if (unprocessedNamespaces) {
10786
+ findNamespaces();
10787
+ Namespace.PROCESSED = true;
10788
+ }
10789
+
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, {});
10637
10795
  }
10638
10796
 
10639
- return true;
10640
- },
10797
+ Ember.anyUnprocessedMixins = false;
10798
+ }
10799
+ }
10641
10800
 
10642
- /**
10643
- Adds an object to the set. Only non-`null` objects can be added to a set
10644
- and those can only be added once. If the object is already in the set or
10645
- the passed value is null this method will have no effect.
10801
+ function makeToString(ret) {
10802
+ return function() { return ret; };
10803
+ }
10646
10804
 
10647
- This is an alias for `Ember.MutableEnumerable.addObject()`.
10805
+ Ember.Mixin.prototype.toString = classToString;
10648
10806
 
10649
- ```javascript
10650
- var colors = new Ember.Set();
10651
- colors.add("blue"); // ["blue"]
10652
- colors.add("blue"); // ["blue"]
10653
- colors.add("red"); // ["blue", "red"]
10654
- colors.add(null); // ["blue", "red"]
10655
- colors.add(undefined); // ["blue", "red"]
10656
- ```
10807
+ })();
10657
10808
 
10658
- @method add
10659
- @param {Object} obj The object to add.
10660
- @return {Ember.Set} The set itself.
10661
- */
10662
- add: Ember.aliasMethod('addObject'),
10663
10809
 
10664
- /**
10665
- Removes the object from the set if it is found. If you pass a `null` value
10666
- or an object that is already not in the set, this method will have no
10667
- effect. This is an alias for `Ember.MutableEnumerable.removeObject()`.
10668
10810
 
10669
- ```javascript
10670
- var colors = new Ember.Set(["red", "green", "blue"]);
10671
- colors.remove("red"); // ["blue", "green"]
10672
- colors.remove("purple"); // ["blue", "green"]
10673
- colors.remove(null); // ["blue", "green"]
10674
- ```
10811
+ (function() {
10812
+ Ember.Application = Ember.Namespace.extend();
10675
10813
 
10676
- @method remove
10677
- @param {Object} obj The object to remove
10678
- @return {Ember.Set} The set itself.
10679
- */
10680
- remove: Ember.aliasMethod('removeObject'),
10814
+ })();
10681
10815
 
10682
- /**
10683
- Removes the last element from the set and returns it, or `null` if it's empty.
10684
10816
 
10685
- ```javascript
10686
- var colors = new Ember.Set(["green", "blue"]);
10687
- colors.pop(); // "blue"
10688
- colors.pop(); // "green"
10689
- colors.pop(); // null
10690
- ```
10691
10817
 
10692
- @method pop
10693
- @return {Object} The removed object from the set or null.
10694
- */
10695
- pop: function() {
10696
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
10697
- var obj = this.length > 0 ? this[this.length-1] : null;
10698
- this.remove(obj);
10699
- return obj;
10700
- },
10818
+ (function() {
10819
+ /**
10820
+ @module ember
10821
+ @submodule ember-runtime
10822
+ */
10701
10823
 
10702
- /**
10703
- Inserts the given object on to the end of the set. It returns
10704
- the set itself.
10824
+ var OUT_OF_RANGE_EXCEPTION = "Index out of range";
10825
+ var EMPTY = [];
10705
10826
 
10706
- This is an alias for `Ember.MutableEnumerable.addObject()`.
10827
+ var get = Ember.get, set = Ember.set;
10707
10828
 
10708
- ```javascript
10709
- var colors = new Ember.Set();
10710
- colors.push("red"); // ["red"]
10711
- colors.push("green"); // ["red", "green"]
10712
- colors.push("blue"); // ["red", "green", "blue"]
10713
- ```
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.
10714
10834
 
10715
- @method push
10716
- @return {Ember.Set} The set itself.
10717
- */
10718
- push: Ember.aliasMethod('addObject'),
10835
+ A simple example of usage:
10719
10836
 
10720
- /**
10721
- 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) });
10722
10840
 
10723
- 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
+ ```
10724
10845
 
10725
- ```javascript
10726
- var colors = new Ember.Set(["green", "blue"]);
10727
- colors.shift(); // "blue"
10728
- colors.shift(); // "green"
10729
- colors.shift(); // null
10730
- ```
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`:
10731
10849
 
10732
- @method shift
10733
- @return {Object} The removed object from the set or null.
10734
- */
10735
- 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
+ });
10736
10858
 
10737
- /**
10738
- Inserts the given object on to the end of the set. It returns
10739
- the set itself.
10859
+ ap.get('firstObject'); // . 'DOG'
10860
+ ```
10740
10861
 
10741
- 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 */ {
10742
10869
 
10743
- ```javascript
10744
- var colors = new Ember.Set();
10745
- colors.unshift("red"); // ["red"]
10746
- colors.unshift("green"); // ["red", "green"]
10747
- colors.unshift("blue"); // ["red", "green", "blue"]
10748
- ```
10870
+ /**
10871
+ The content array. Must be an object that implements `Ember.Array` and/or
10872
+ `Ember.MutableArray.`
10749
10873
 
10750
- @method unshift
10751
- @return {Ember.Set} The set itself.
10874
+ @property content
10875
+ @type Ember.Array
10752
10876
  */
10753
- unshift: Ember.aliasMethod('push'),
10877
+ content: null,
10754
10878
 
10755
10879
  /**
10756
- Adds each object in the passed enumerable to the set.
10757
-
10758
- This is an alias of `Ember.MutableEnumerable.addObjects()`
10759
-
10760
- ```javascript
10761
- var colors = new Ember.Set();
10762
- colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
10763
- ```
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.
10764
10883
 
10765
- @method addEach
10766
- @param {Ember.Enumerable} objects the objects to add.
10767
- @return {Ember.Set} The set itself.
10884
+ @property arrangedContent
10768
10885
  */
10769
- addEach: Ember.aliasMethod('addObjects'),
10886
+ arrangedContent: Ember.computed.alias('content'),
10770
10887
 
10771
10888
  /**
10772
- Removes each object in the passed enumerable to the set.
10773
-
10774
- 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.
10775
10892
 
10776
- ```javascript
10777
- var colors = new Ember.Set(["red", "green", "blue"]);
10778
- colors.removeEach(["red", "blue"]); // ["green"]
10779
- ```
10893
+ This method will only be called if content is non-`null`.
10780
10894
 
10781
- @method removeEach
10782
- @param {Ember.Enumerable} objects the objects to remove.
10783
- @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
10784
10898
  */
10785
- removeEach: Ember.aliasMethod('removeObjects'),
10899
+ objectAtContent: function(idx) {
10900
+ return get(this, 'arrangedContent').objectAt(idx);
10901
+ },
10786
10902
 
10787
- // ..........................................................
10788
- // PRIVATE ENUMERABLE SUPPORT
10789
- //
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.
10790
10907
 
10791
- init: function(items) {
10792
- this._super();
10793
- if (items) this.addObjects(items);
10794
- },
10908
+ This method will only be called if content is non-`null`.
10795
10909
 
10796
- // implement Ember.Enumerable
10797
- nextObject: function(idx) {
10798
- 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);
10799
10919
  },
10800
10920
 
10801
- // more optimized version
10802
- firstObject: Ember.computed(function() {
10803
- return this.length > 0 ? this[0] : undefined;
10804
- }),
10921
+ /**
10922
+ @private
10805
10923
 
10806
- // more optimized version
10807
- lastObject: Ember.computed(function() {
10808
- return this.length > 0 ? this[this.length-1] : undefined;
10809
- }),
10924
+ Invoked when the content property is about to change. Notifies observers that the
10925
+ entire array content will change.
10810
10926
 
10811
- // implements Ember.MutableEnumerable
10812
- addObject: function(obj) {
10813
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
10814
- if (none(obj)) return this; // nothing to do
10927
+ @method _contentWillChange
10928
+ */
10929
+ _contentWillChange: Ember.beforeObserver(function() {
10930
+ this._teardownContent();
10931
+ }, 'content'),
10815
10932
 
10816
- var guid = guidFor(obj),
10817
- idx = this[guid],
10818
- len = get(this, 'length'),
10819
- added ;
10933
+ _teardownContent: function() {
10934
+ var content = get(this, 'content');
10820
10935
 
10821
- if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
10936
+ if (content) {
10937
+ content.removeArrayObserver(this, {
10938
+ willChange: 'contentArrayWillChange',
10939
+ didChange: 'contentArrayDidChange'
10940
+ });
10941
+ }
10942
+ },
10822
10943
 
10823
- added = [obj];
10944
+ contentArrayWillChange: Ember.K,
10945
+ contentArrayDidChange: Ember.K,
10824
10946
 
10825
- this.enumerableContentWillChange(null, added);
10826
- Ember.propertyWillChange(this, 'lastObject');
10947
+ /**
10948
+ @private
10827
10949
 
10828
- len = get(this, 'length');
10829
- this[guid] = len;
10830
- this[len] = obj;
10831
- set(this, 'length', len+1);
10950
+ Invoked when the content property changes. Notifies observers that the
10951
+ entire array content has changed.
10832
10952
 
10833
- Ember.propertyDidChange(this, 'lastObject');
10834
- this.enumerableContentDidChange(null, added);
10953
+ @method _contentDidChange
10954
+ */
10955
+ _contentDidChange: Ember.observer(function() {
10956
+ var content = get(this, 'content');
10835
10957
 
10836
- return this;
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
+ }
10837
10972
  },
10838
10973
 
10839
- // implements Ember.MutableEnumerable
10840
- removeObject: function(obj) {
10841
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
10842
- 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;
10843
10977
 
10844
- var guid = guidFor(obj),
10845
- idx = this[guid],
10846
- len = get(this, 'length'),
10847
- isFirst = idx === 0,
10848
- isLast = idx === len-1,
10849
- last, removed;
10978
+ this.arrangedContentArrayWillChange(this, 0, len, undefined);
10979
+ this.arrangedContentWillChange(this);
10850
10980
 
10981
+ this._teardownArrangedContent(arrangedContent);
10982
+ }, 'arrangedContent'),
10851
10983
 
10852
- if (idx>=0 && idx<len && (this[idx] === obj)) {
10853
- removed = [obj];
10984
+ _arrangedContentDidChange: Ember.observer(function() {
10985
+ var arrangedContent = get(this, 'arrangedContent'),
10986
+ len = arrangedContent ? get(arrangedContent, 'length') : 0;
10854
10987
 
10855
- this.enumerableContentWillChange(removed, null);
10856
- if (isFirst) { Ember.propertyWillChange(this, 'firstObject'); }
10857
- if (isLast) { Ember.propertyWillChange(this, 'lastObject'); }
10988
+ Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
10858
10989
 
10859
- // swap items - basically move the item to the end so it can be removed
10860
- if (idx < len-1) {
10861
- last = this[len-1];
10862
- this[idx] = last;
10863
- this[guidFor(last)] = idx;
10864
- }
10990
+ this._setupArrangedContent();
10865
10991
 
10866
- delete this[guid];
10867
- delete this[len-1];
10868
- set(this, 'length', len-1);
10992
+ this.arrangedContentDidChange(this);
10993
+ this.arrangedContentArrayDidChange(this, 0, undefined, len);
10994
+ }, 'arrangedContent'),
10869
10995
 
10870
- if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
10871
- if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
10872
- this.enumerableContentDidChange(removed, null);
10873
- }
10996
+ _setupArrangedContent: function() {
10997
+ var arrangedContent = get(this, 'arrangedContent');
10874
10998
 
10875
- return this;
10999
+ if (arrangedContent) {
11000
+ arrangedContent.addArrayObserver(this, {
11001
+ willChange: 'arrangedContentArrayWillChange',
11002
+ didChange: 'arrangedContentArrayDidChange'
11003
+ });
11004
+ }
10876
11005
  },
10877
11006
 
10878
- // optimized version
10879
- contains: function(obj) {
10880
- return this[guidFor(obj)]>=0;
10881
- },
11007
+ _teardownArrangedContent: function() {
11008
+ var arrangedContent = get(this, 'arrangedContent');
10882
11009
 
10883
- copy: function() {
10884
- var C = this.constructor, ret = new C(), loc = get(this, 'length');
10885
- set(ret, 'length', loc);
10886
- while(--loc>=0) {
10887
- ret[loc] = this[loc];
10888
- ret[guidFor(this[loc])] = loc;
11010
+ if (arrangedContent) {
11011
+ arrangedContent.removeArrayObserver(this, {
11012
+ willChange: 'arrangedContentArrayWillChange',
11013
+ didChange: 'arrangedContentArrayDidChange'
11014
+ });
10889
11015
  }
10890
- return ret;
10891
11016
  },
10892
11017
 
10893
- toString: function() {
10894
- var len = this.length, idx, array = [];
10895
- for(idx = 0; idx < len; idx++) {
10896
- array[idx] = this[idx];
10897
- }
10898
- return "Ember.Set<%@>".fmt(array.join(','));
10899
- }
11018
+ arrangedContentWillChange: Ember.K,
11019
+ arrangedContentDidChange: Ember.K,
10900
11020
 
10901
- });
11021
+ objectAt: function(idx) {
11022
+ return get(this, 'content') && this.objectAtContent(idx);
11023
+ },
10902
11024
 
10903
- })();
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
+ }),
10904
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
+ },
10905
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
+ },
10906
11045
 
10907
- (function() {
10908
- /**
10909
- @module ember
10910
- @submodule ember-runtime
10911
- */
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
+ },
10912
11051
 
10913
- /**
10914
- `Ember.Object` is the main base class for all Ember objects. It is a subclass
10915
- of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details,
10916
- 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
+ },
10917
11059
 
10918
- @class Object
10919
- @namespace Ember
10920
- @extends Ember.CoreObject
10921
- @uses Ember.Observable
10922
- */
10923
- Ember.Object = Ember.CoreObject.extend(Ember.Observable);
10924
- 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;
10925
11065
 
10926
- })();
11066
+ if ((start < 0) || (start >= get(this, 'length'))) {
11067
+ throw new Error(OUT_OF_RANGE_EXCEPTION);
11068
+ }
10927
11069
 
11070
+ if (len === undefined) len = 1;
10928
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
+ }
10929
11077
 
10930
- (function() {
10931
- /**
10932
- @module ember
10933
- @submodule ember-runtime
10934
- */
11078
+ // Replace in reverse order since indices will change
11079
+ indices.sort(function(a,b) { return b - a; });
10935
11080
 
10936
- 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
+ }
10937
11087
 
10938
- /**
10939
- A Namespace is an object usually used to contain other objects or methods
10940
- such as an application or framework. Create a namespace anytime you want
10941
- to define one of these new containers.
11088
+ return this ;
11089
+ },
10942
11090
 
10943
- # Example Usage
11091
+ pushObject: function(obj) {
11092
+ this._insertAt(get(this, 'content.length'), obj) ;
11093
+ return obj ;
11094
+ },
10944
11095
 
10945
- ```javascript
10946
- MyFramework = Ember.Namespace.create({
10947
- VERSION: '1.0.0'
10948
- });
10949
- ```
11096
+ pushObjects: function(objects) {
11097
+ this._replace(get(this, 'length'), 0, objects);
11098
+ return this;
11099
+ },
10950
11100
 
10951
- @class Namespace
10952
- @namespace Ember
10953
- @extends Ember.Object
10954
- */
10955
- var Namespace = Ember.Namespace = Ember.Object.extend({
10956
- isNamespace: true,
11101
+ setObjects: function(objects) {
11102
+ if (objects.length === 0) return this.clear();
10957
11103
 
10958
- init: function() {
10959
- Ember.Namespace.NAMESPACES.push(this);
10960
- Ember.Namespace.PROCESSED = false;
11104
+ var len = get(this, 'length');
11105
+ this._replace(0, len, objects);
11106
+ return this;
10961
11107
  },
10962
11108
 
10963
- toString: function() {
10964
- var name = get(this, 'name');
10965
- if (name) { return name; }
11109
+ unshiftObject: function(obj) {
11110
+ this._insertAt(0, obj) ;
11111
+ return obj ;
11112
+ },
10966
11113
 
10967
- findNamespaces();
10968
- return this[Ember.GUID_KEY+'_name'];
11114
+ unshiftObjects: function(objects) {
11115
+ this._replace(0, 0, objects);
11116
+ return this;
10969
11117
  },
10970
11118
 
10971
- nameClasses: function() {
10972
- processNamespace([this.toString()], this, {});
11119
+ slice: function() {
11120
+ var arr = this.toArray();
11121
+ return arr.slice.apply(arr, arguments);
10973
11122
  },
10974
11123
 
10975
- destroy: function() {
10976
- var namespaces = Ember.Namespace.NAMESPACES;
10977
- Ember.lookup[this.toString()] = undefined;
10978
- namespaces.splice(indexOf.call(namespaces, this), 1);
11124
+ arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
11125
+ this.arrayContentWillChange(idx, removedCnt, addedCnt);
11126
+ },
11127
+
11128
+ arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
11129
+ this.arrayContentDidChange(idx, removedCnt, addedCnt);
11130
+ },
11131
+
11132
+ init: function() {
10979
11133
  this._super();
11134
+ this._setupContent();
11135
+ this._setupArrangedContent();
11136
+ },
11137
+
11138
+ willDestroy: function() {
11139
+ this._teardownArrangedContent();
11140
+ this._teardownContent();
10980
11141
  }
10981
11142
  });
10982
11143
 
10983
- Namespace.reopenClass({
10984
- NAMESPACES: [Ember],
10985
- NAMESPACES_BY_ID: {},
10986
- PROCESSED: false,
10987
- processAll: processAllNamespaces,
10988
- byName: function(name) {
10989
- if (!Ember.BOOTED) {
10990
- processAllNamespaces();
10991
- }
10992
-
10993
- return NAMESPACES_BY_ID[name];
10994
- }
10995
- });
10996
-
10997
- var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
10998
-
10999
- var hasOwnProp = ({}).hasOwnProperty,
11000
- guidFor = Ember.guidFor;
11001
-
11002
- function processNamespace(paths, root, seen) {
11003
- var idx = paths.length;
11004
11144
 
11005
- NAMESPACES_BY_ID[paths.join('.')] = root;
11145
+ })();
11006
11146
 
11007
- // Loop over all of the keys in the namespace, looking for classes
11008
- for(var key in root) {
11009
- if (!hasOwnProp.call(root, key)) { continue; }
11010
- var obj = root[key];
11011
11147
 
11012
- // If we are processing the `Ember` namespace, for example, the
11013
- // `paths` will start with `["Ember"]`. Every iteration through
11014
- // the loop will update the **second** element of this list with
11015
- // the key, so processing `Ember.View` will make the Array
11016
- // `['Ember', 'View']`.
11017
- paths[idx] = key;
11018
11148
 
11019
- // If we have found an unprocessed class
11020
- if (obj && obj.toString === classToString) {
11021
- // Replace the class' `toString` with the dot-separated path
11022
- // and set its `NAME_KEY`
11023
- obj.toString = makeToString(paths.join('.'));
11024
- obj[NAME_KEY] = paths.join('.');
11149
+ (function() {
11150
+ /**
11151
+ @module ember
11152
+ @submodule ember-runtime
11153
+ */
11025
11154
 
11026
- // Support nested namespaces
11027
- } else if (obj && obj.isNamespace) {
11028
- // Skip aliased namespaces
11029
- if (seen[guidFor(obj)]) { continue; }
11030
- 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;
11031
11164
 
11032
- // Process the child namespace
11033
- processNamespace(paths, obj, seen);
11034
- }
11035
- }
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
+ }
11036
11170
 
11037
- 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);
11038
11175
  }
11039
11176
 
11040
- function findNamespaces() {
11041
- 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.
11042
11180
 
11043
- if (Namespace.PROCESSED) { return; }
11181
+ ```javascript
11182
+ object = Ember.Object.create({
11183
+ name: 'Foo'
11184
+ });
11044
11185
 
11045
- for (var prop in lookup) {
11046
- // These don't raise exceptions but can cause warnings
11047
- if (prop === "parent" || prop === "top" || prop === "frameElement") { continue; }
11186
+ proxy = Ember.ObjectProxy.create({
11187
+ content: object
11188
+ });
11048
11189
 
11049
- // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
11050
- // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
11051
- if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; }
11052
- // Unfortunately, some versions of IE don't support window.hasOwnProperty
11053
- 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'
11054
11194
 
11055
- // At times we are not allowed to access certain properties for security reasons.
11056
- // There are also times where even if we can access them, we are not allowed to access their properties.
11057
- try {
11058
- obj = Ember.lookup[prop];
11059
- isNamespace = obj && obj.isNamespace;
11060
- } catch (e) {
11061
- continue;
11062
- }
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
+ ```
11063
11199
 
11064
- if (isNamespace) {
11065
- Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
11066
- obj[NAME_KEY] = prop;
11067
- }
11068
- }
11069
- }
11200
+ While `content` is unset, setting a property to be delegated will throw an
11201
+ Error.
11070
11202
 
11071
- 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
+ ```
11072
11213
 
11073
- function superClassString(mixin) {
11074
- var superclass = mixin.superclass;
11075
- if (superclass) {
11076
- if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; }
11077
- else { return superClassString(superclass); }
11078
- } else {
11079
- return;
11080
- }
11081
- }
11214
+ Delegated properties can be bound to and will change when content is updated.
11082
11215
 
11083
- function classToString() {
11084
- if (!Ember.BOOTED && !this[NAME_KEY]) {
11085
- processAllNamespaces();
11086
- }
11216
+ Computed properties on the proxy itself can depend on delegated properties.
11087
11217
 
11088
- 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
+ });
11089
11229
 
11090
- if (this[NAME_KEY]) {
11091
- ret = this[NAME_KEY];
11092
- } else {
11093
- var str = superClassString(this);
11094
- if (str) {
11095
- ret = "(subclass of " + str + ")";
11096
- } else {
11097
- ret = "(unknown mixin)";
11098
- }
11099
- this.toString = makeToString(ret);
11100
- }
11230
+ proxy = ProxyWithComputedProperty.create();
11101
11231
 
11102
- return ret;
11103
- }
11232
+ proxy.get('fullName'); // undefined
11233
+ proxy.set('content', {
11234
+ firstName: 'Tom', lastName: 'Dale'
11235
+ }); // triggers property change for fullName on proxy
11104
11236
 
11105
- function processAllNamespaces() {
11106
- var unprocessedNamespaces = !Namespace.PROCESSED,
11107
- unprocessedMixins = Ember.anyUnprocessedMixins;
11237
+ proxy.get('fullName'); // 'Tom Dale'
11238
+ ```
11108
11239
 
11109
- if (unprocessedNamespaces) {
11110
- findNamespaces();
11111
- Namespace.PROCESSED = true;
11112
- }
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.
11113
11248
 
11114
- if (unprocessedNamespaces || unprocessedMixins) {
11115
- var namespaces = Namespace.NAMESPACES, namespace;
11116
- for (var i=0, l=namespaces.length; i<l; i++) {
11117
- namespace = namespaces[i];
11118
- processNamespace([namespace.toString()], namespace, {});
11119
- }
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'),
11120
11257
 
11121
- Ember.anyUnprocessedMixins = false;
11122
- }
11123
- }
11258
+ isTruthy: Ember.computed.bool('content'),
11124
11259
 
11125
- function makeToString(ret) {
11126
- return function() { return ret; };
11127
- }
11260
+ _debugContainerKey: null,
11128
11261
 
11129
- 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
+ },
11130
11267
 
11131
- })();
11268
+ didUnwatchProperty: function (key) {
11269
+ var contentKey = 'content.' + key;
11270
+ removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
11271
+ removeObserver(this, contentKey, null, contentPropertyDidChange);
11272
+ },
11132
11273
 
11274
+ unknownProperty: function (key) {
11275
+ var content = get(this, 'content');
11276
+ if (content) {
11277
+ return get(content, key);
11278
+ }
11279
+ },
11133
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
+ });
11134
11287
 
11135
- (function() {
11136
- 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
+ });
11137
11306
 
11138
11307
  })();
11139
11308
 
@@ -11146,237 +11315,203 @@ Ember.Application = Ember.Namespace.extend();
11146
11315
  */
11147
11316
 
11148
11317
 
11149
- var get = Ember.get, set = Ember.set;
11150
-
11151
- /**
11152
- An ArrayProxy wraps any other object that implements `Ember.Array` and/or
11153
- `Ember.MutableArray,` forwarding all requests. This makes it very useful for
11154
- a number of binding use cases or other cases where being able to swap
11155
- out the underlying array is useful.
11318
+ var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
11319
+ var forEach = Ember.EnumerableUtils.forEach;
11156
11320
 
11157
- A simple example of usage:
11321
+ var EachArray = Ember.Object.extend(Ember.Array, {
11158
11322
 
11159
- ```javascript
11160
- var pets = ['dog', 'cat', 'fish'];
11161
- var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });
11162
-
11163
- ap.get('firstObject'); // 'dog'
11164
- ap.set('content', ['amoeba', 'paramecium']);
11165
- ap.get('firstObject'); // 'amoeba'
11166
- ```
11323
+ init: function(content, keyName, owner) {
11324
+ this._super();
11325
+ this._keyName = keyName;
11326
+ this._owner = owner;
11327
+ this._content = content;
11328
+ },
11167
11329
 
11168
- This class can also be useful as a layer to transform the contents of
11169
- an array, as they are accessed. This can be done by overriding
11170
- `objectAtContent`:
11330
+ objectAt: function(idx) {
11331
+ var item = this._content.objectAt(idx);
11332
+ return item && get(item, this._keyName);
11333
+ },
11171
11334
 
11172
- ```javascript
11173
- var pets = ['dog', 'cat', 'fish'];
11174
- var ap = Ember.ArrayProxy.create({
11175
- content: Ember.A(pets),
11176
- objectAtContent: function(idx) {
11177
- return this.get('content').objectAt(idx).toUpperCase();
11178
- }
11179
- });
11335
+ length: Ember.computed(function() {
11336
+ var content = this._content;
11337
+ return content ? get(content, 'length') : 0;
11338
+ })
11180
11339
 
11181
- ap.get('firstObject'); // . 'DOG'
11182
- ```
11340
+ });
11183
11341
 
11184
- @class ArrayProxy
11185
- @namespace Ember
11186
- @extends Ember.Object
11187
- @uses Ember.MutableArray
11188
- */
11189
- Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
11190
- /** @scope Ember.ArrayProxy.prototype */ {
11342
+ var IS_OBSERVER = /^.+:(before|change)$/;
11191
11343
 
11192
- /**
11193
- The content array. Must be an object that implements `Ember.Array` and/or
11194
- `Ember.MutableArray.`
11344
+ function addObserverForContentKey(content, keyName, proxy, idx, loc) {
11345
+ var objects = proxy._objects, guid;
11346
+ if (!objects) objects = proxy._objects = {};
11195
11347
 
11196
- @property content
11197
- @type Ember.Array
11198
- */
11199
- 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');
11200
11353
 
11201
- /**
11202
- The array that the proxy pretends to be. In the default `ArrayProxy`
11203
- implementation, this and `content` are the same. Subclasses of `ArrayProxy`
11204
- 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
+ }
11205
11362
 
11206
- @property arrangedContent
11207
- */
11208
- 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;
11209
11367
 
11210
- /**
11211
- Should actually retrieve the object at the specified index from the
11212
- content. You can override this method in subclasses to transform the
11213
- 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');
11214
11373
 
11215
- 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
+ }
11216
11380
 
11217
- @method objectAtContent
11218
- @param {Number} idx The index to retrieve.
11219
- @return {Object} the value or undefined if none found
11220
- */
11221
- objectAtContent: function(idx) {
11222
- return get(this, 'arrangedContent').objectAt(idx);
11223
- },
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.
11224
11385
 
11225
- /**
11226
- Should actually replace the specified objects on the content array.
11227
- You can override this method in subclasses to transform the content item
11228
- into something new.
11386
+ @private
11387
+ @class EachProxy
11388
+ @namespace Ember
11389
+ @extends Ember.Object
11390
+ */
11391
+ Ember.EachProxy = Ember.Object.extend({
11229
11392
 
11230
- 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);
11231
11397
 
11232
- @method replaceContent
11233
- @param {Number} idx The starting index
11234
- @param {Number} amt The number of items to remove from the content.
11235
- @param {Array} objects Optional array of objects to insert or null if no
11236
- objects.
11237
- @return {void}
11238
- */
11239
- replaceContent: function(idx, amt, objects) {
11240
- 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);
11241
11403
  },
11242
11404
 
11243
11405
  /**
11244
- @private
11245
-
11246
- Invoked when the content property is about to change. Notifies observers that the
11247
- 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.
11248
11408
 
11249
- @method _contentWillChange
11409
+ @method unknownProperty
11410
+ @param keyName {String}
11411
+ @param value {anything}
11250
11412
  */
11251
- _contentWillChange: Ember.beforeObserver(function() {
11252
- this._teardownContent();
11253
- }, 'content'),
11254
-
11255
- _teardownContent: function() {
11256
- var content = get(this, 'content');
11257
-
11258
- if (content) {
11259
- content.removeArrayObserver(this, {
11260
- willChange: 'contentArrayWillChange',
11261
- didChange: 'contentArrayDidChange'
11262
- });
11263
- }
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;
11264
11419
  },
11265
11420
 
11266
- contentArrayWillChange: Ember.K,
11267
- contentArrayDidChange: Ember.K,
11268
-
11269
- /**
11270
- @private
11271
-
11272
- Invoked when the content property changes. Notifies observers that the
11273
- entire array content has changed.
11421
+ // ..........................................................
11422
+ // ARRAY CHANGES
11423
+ // Invokes whenever the content array itself changes.
11274
11424
 
11275
- @method _contentDidChange
11276
- */
11277
- _contentDidChange: Ember.observer(function() {
11278
- var content = get(this, 'content');
11425
+ arrayWillChange: function(content, idx, removedCnt, addedCnt) {
11426
+ var keys = this._keys, key, lim;
11279
11427
 
11280
- Ember.assert("Can't set ArrayProxy's content to itself", content !== this);
11428
+ lim = removedCnt>0 ? idx+removedCnt : -1;
11429
+ Ember.beginPropertyChanges(this);
11281
11430
 
11282
- this._setupContent();
11283
- }, 'content'),
11431
+ for(key in keys) {
11432
+ if (!keys.hasOwnProperty(key)) { continue; }
11284
11433
 
11285
- _setupContent: function() {
11286
- var content = get(this, 'content');
11434
+ if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
11287
11435
 
11288
- if (content) {
11289
- content.addArrayObserver(this, {
11290
- willChange: 'contentArrayWillChange',
11291
- didChange: 'contentArrayDidChange'
11292
- });
11436
+ Ember.propertyWillChange(this, key);
11293
11437
  }
11294
- },
11295
11438
 
11296
- _arrangedContentWillChange: Ember.beforeObserver(function() {
11297
- var arrangedContent = get(this, 'arrangedContent'),
11298
- len = arrangedContent ? get(arrangedContent, 'length') : 0;
11439
+ Ember.propertyWillChange(this._content, '@each');
11440
+ Ember.endPropertyChanges(this);
11441
+ },
11299
11442
 
11300
- this.arrangedContentArrayWillChange(this, 0, len, undefined);
11301
- this.arrangedContentWillChange(this);
11443
+ arrayDidChange: function(content, idx, removedCnt, addedCnt) {
11444
+ var keys = this._keys, key, lim;
11302
11445
 
11303
- this._teardownArrangedContent(arrangedContent);
11304
- }, 'arrangedContent'),
11446
+ lim = addedCnt>0 ? idx+addedCnt : -1;
11447
+ Ember.beginPropertyChanges(this);
11305
11448
 
11306
- _arrangedContentDidChange: Ember.observer(function() {
11307
- var arrangedContent = get(this, 'arrangedContent'),
11308
- len = arrangedContent ? get(arrangedContent, 'length') : 0;
11449
+ for(key in keys) {
11450
+ if (!keys.hasOwnProperty(key)) { continue; }
11309
11451
 
11310
- Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);
11452
+ if (lim>0) addObserverForContentKey(content, key, this, idx, lim);
11311
11453
 
11312
- this._setupArrangedContent();
11454
+ Ember.propertyDidChange(this, key);
11455
+ }
11313
11456
 
11314
- this.arrangedContentDidChange(this);
11315
- this.arrangedContentArrayDidChange(this, 0, undefined, len);
11316
- }, 'arrangedContent'),
11457
+ Ember.propertyDidChange(this._content, '@each');
11458
+ Ember.endPropertyChanges(this);
11459
+ },
11317
11460
 
11318
- _setupArrangedContent: function() {
11319
- var arrangedContent = get(this, 'arrangedContent');
11461
+ // ..........................................................
11462
+ // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
11463
+ // Start monitoring keys based on who is listening...
11320
11464
 
11321
- if (arrangedContent) {
11322
- arrangedContent.addArrayObserver(this, {
11323
- willChange: 'arrangedContentArrayWillChange',
11324
- didChange: 'arrangedContentArrayDidChange'
11325
- });
11465
+ didAddListener: function(eventName) {
11466
+ if (IS_OBSERVER.test(eventName)) {
11467
+ this.beginObservingContentKey(eventName.slice(0, -7));
11326
11468
  }
11327
11469
  },
11328
11470
 
11329
- _teardownArrangedContent: function() {
11330
- var arrangedContent = get(this, 'arrangedContent');
11331
-
11332
- if (arrangedContent) {
11333
- arrangedContent.removeArrayObserver(this, {
11334
- willChange: 'arrangedContentArrayWillChange',
11335
- didChange: 'arrangedContentArrayDidChange'
11336
- });
11471
+ didRemoveListener: function(eventName) {
11472
+ if (IS_OBSERVER.test(eventName)) {
11473
+ this.stopObservingContentKey(eventName.slice(0, -7));
11337
11474
  }
11338
11475
  },
11339
11476
 
11340
- arrangedContentWillChange: Ember.K,
11341
- arrangedContentDidChange: Ember.K,
11342
-
11343
- objectAt: function(idx) {
11344
- return get(this, 'content') && this.objectAtContent(idx);
11345
- },
11477
+ // ..........................................................
11478
+ // CONTENT KEY OBSERVING
11479
+ // Actual watch keys on the source content.
11346
11480
 
11347
- length: Ember.computed(function() {
11348
- var arrangedContent = get(this, 'arrangedContent');
11349
- return arrangedContent ? get(arrangedContent, 'length') : 0;
11350
- // No dependencies since Enumerable notifies length of change
11351
- }),
11352
-
11353
- replace: function(idx, amt, objects) {
11354
- Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', this.get('content'));
11355
- if (get(this, 'content')) this.replaceContent(idx, amt, objects);
11356
- return this;
11357
- },
11358
-
11359
- arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
11360
- this.arrayContentWillChange(idx, removedCnt, addedCnt);
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
+ }
11361
11492
  },
11362
11493
 
11363
- arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
11364
- 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
+ }
11365
11501
  },
11366
11502
 
11367
- init: function() {
11368
- this._super();
11369
- this._setupContent();
11370
- this._setupArrangedContent();
11503
+ contentKeyWillChange: function(obj, keyName) {
11504
+ Ember.propertyWillChange(this, keyName);
11371
11505
  },
11372
11506
 
11373
- willDestroy: function() {
11374
- this._teardownArrangedContent();
11375
- this._teardownContent();
11507
+ contentKeyDidChange: function(obj, keyName) {
11508
+ Ember.propertyDidChange(this, keyName);
11376
11509
  }
11510
+
11377
11511
  });
11378
11512
 
11379
11513
 
11514
+
11380
11515
  })();
11381
11516
 
11382
11517
 
@@ -11387,505 +11522,611 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
11387
11522
  @submodule ember-runtime
11388
11523
  */
11389
11524
 
11390
- var get = Ember.get,
11391
- set = Ember.set,
11392
- fmt = Ember.String.fmt,
11393
- addBeforeObserver = Ember.addBeforeObserver,
11394
- addObserver = Ember.addObserver,
11395
- removeBeforeObserver = Ember.removeBeforeObserver,
11396
- removeObserver = Ember.removeObserver,
11397
- propertyWillChange = Ember.propertyWillChange,
11398
- propertyDidChange = Ember.propertyDidChange;
11399
-
11400
- function contentPropertyWillChange(content, contentKey) {
11401
- var key = contentKey.slice(8); // remove "content."
11402
- if (key in this) { return; } // if shadowed in proxy
11403
- propertyWillChange(this, key);
11404
- }
11405
-
11406
- function contentPropertyDidChange(content, contentKey) {
11407
- var key = contentKey.slice(8); // remove "content."
11408
- if (key in this) { return; } // if shadowed in proxy
11409
- propertyDidChange(this, key);
11410
- }
11411
-
11412
- /**
11413
- `Ember.ObjectProxy` forwards all properties not defined by the proxy itself
11414
- to a proxied `content` object.
11415
-
11416
- ```javascript
11417
- object = Ember.Object.create({
11418
- name: 'Foo'
11419
- });
11420
-
11421
- proxy = Ember.ObjectProxy.create({
11422
- content: object
11423
- });
11424
11525
 
11425
- // Access and change existing properties
11426
- proxy.get('name') // 'Foo'
11427
- proxy.set('name', 'Bar');
11428
- object.get('name') // 'Bar'
11526
+ var get = Ember.get, set = Ember.set;
11429
11527
 
11430
- // Create new 'description' property on `object`
11431
- proxy.set('description', 'Foo is a whizboo baz');
11432
- object.get('description') // 'Foo is a whizboo baz'
11433
- ```
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, {
11434
11532
 
11435
- While `content` is unset, setting a property to be delegated will throw an
11436
- 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
+ },
11437
11540
 
11438
- ```javascript
11439
- proxy = Ember.ObjectProxy.create({
11440
- content: null,
11441
- flag: null
11442
- });
11443
- proxy.set('flag', true);
11444
- proxy.get('flag'); // true
11445
- proxy.get('foo'); // undefined
11446
- proxy.set('foo', 'data'); // throws Error
11447
- ```
11541
+ objectAt: function(idx) {
11542
+ return this[idx];
11543
+ },
11448
11544
 
11449
- Delegated properties can be bound to and will change when content is updated.
11545
+ // primitive for array support.
11546
+ replace: function(idx, amt, objects) {
11450
11547
 
11451
- Computed properties on the proxy itself can depend on delegated properties.
11548
+ if (this.isFrozen) throw Ember.FROZEN_ERROR ;
11452
11549
 
11453
- ```javascript
11454
- ProxyWithComputedProperty = Ember.ObjectProxy.extend({
11455
- fullName: function () {
11456
- var firstName = this.get('firstName'),
11457
- lastName = this.get('lastName');
11458
- if (firstName && lastName) {
11459
- return firstName + ' ' + lastName;
11460
- }
11461
- return firstName || lastName;
11462
- }.property('firstName', 'lastName')
11463
- });
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);
11464
11555
 
11465
- 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
+ }
11466
11562
 
11467
- proxy.get('fullName'); // undefined
11468
- proxy.set('content', {
11469
- firstName: 'Tom', lastName: 'Dale'
11470
- }); // triggers property change for fullName on proxy
11563
+ this.arrayContentDidChange(idx, amt, len);
11564
+ return this ;
11565
+ },
11471
11566
 
11472
- proxy.get('fullName'); // 'Tom Dale'
11473
- ```
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
+ },
11474
11576
 
11475
- @class ObjectProxy
11476
- @namespace Ember
11477
- @extends Ember.Object
11478
- */
11479
- Ember.ObjectProxy = Ember.Object.extend(
11480
- /** @scope Ember.ObjectProxy.prototype */ {
11481
- /**
11482
- 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;
11483
11581
 
11484
- @property content
11485
- @type Ember.Object
11486
- @default null
11487
- */
11488
- content: null,
11489
- _contentDidChange: Ember.observer(function() {
11490
- Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
11491
- }, 'content'),
11582
+ if (startAt === undefined) startAt = 0;
11583
+ else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11584
+ if (startAt < 0) startAt += len;
11492
11585
 
11493
- isTruthy: Ember.computed.bool('content'),
11586
+ for(idx=startAt;idx<len;idx++) {
11587
+ if (this[idx] === object) return idx ;
11588
+ }
11589
+ return -1;
11590
+ },
11494
11591
 
11495
- _debugContainerKey: null,
11592
+ lastIndexOf: function(object, startAt) {
11593
+ var idx, len = this.length;
11496
11594
 
11497
- willWatchProperty: function (key) {
11498
- var contentKey = 'content.' + key;
11499
- addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
11500
- addObserver(this, contentKey, null, contentPropertyDidChange);
11501
- },
11595
+ if (startAt === undefined) startAt = len-1;
11596
+ else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11597
+ if (startAt < 0) startAt += len;
11502
11598
 
11503
- didUnwatchProperty: function (key) {
11504
- var contentKey = 'content.' + key;
11505
- removeBeforeObserver(this, contentKey, null, contentPropertyWillChange);
11506
- removeObserver(this, contentKey, null, contentPropertyDidChange);
11599
+ for(idx=startAt;idx>=0;idx--) {
11600
+ if (this[idx] === object) return idx ;
11601
+ }
11602
+ return -1;
11507
11603
  },
11508
11604
 
11509
- unknownProperty: function (key) {
11510
- var content = get(this, 'content');
11511
- if (content) {
11512
- return get(content, key);
11605
+ copy: function(deep) {
11606
+ if (deep) {
11607
+ return this.map(function(item){ return Ember.copy(item, true); });
11513
11608
  }
11514
- },
11515
11609
 
11516
- setUnknownProperty: function (key, value) {
11517
- var content = get(this, 'content');
11518
- Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
11519
- return set(content, key, value);
11610
+ return this.slice();
11520
11611
  }
11521
11612
  });
11522
11613
 
11523
- })();
11524
-
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);
11618
+ });
11525
11619
 
11620
+ if (ignore.length>0) {
11621
+ NativeArray = NativeArray.without.apply(NativeArray, ignore);
11622
+ }
11526
11623
 
11527
- (function() {
11528
11624
  /**
11529
- @module ember
11530
- @submodule ember-runtime
11531
- */
11532
-
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`.
11533
11630
 
11534
- var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
11535
- var forEach = Ember.EnumerableUtils.forEach;
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
11638
+ */
11639
+ Ember.NativeArray = NativeArray;
11536
11640
 
11537
- var EachArray = Ember.Object.extend(Ember.Array, {
11641
+ /**
11642
+ Creates an `Ember.NativeArray` from an Array like object.
11643
+ Does not modify the original object.
11538
11644
 
11539
- init: function(content, keyName, owner) {
11540
- this._super();
11541
- this._keyName = keyName;
11542
- this._owner = owner;
11543
- this._content = content;
11544
- },
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
+ };
11545
11653
 
11546
- objectAt: function(idx) {
11547
- var item = this._content.objectAt(idx);
11548
- return item && get(item, this._keyName);
11549
- },
11654
+ /**
11655
+ Activates the mixin on the Array.prototype if not already applied. Calling
11656
+ this method more than once is safe.
11550
11657
 
11551
- length: Ember.computed(function() {
11552
- var content = this._content;
11553
- return content ? get(content, 'length') : 0;
11554
- })
11658
+ @method activate
11659
+ @for Ember.NativeArray
11660
+ @static
11661
+ @return {void}
11662
+ */
11663
+ Ember.NativeArray.activate = function() {
11664
+ NativeArray.apply(Array.prototype);
11555
11665
 
11556
- });
11666
+ Ember.A = function(arr) { return arr || []; };
11667
+ };
11557
11668
 
11558
- var IS_OBSERVER = /^.+:(before|change)$/;
11669
+ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
11670
+ Ember.NativeArray.activate();
11671
+ }
11559
11672
 
11560
- function addObserverForContentKey(content, keyName, proxy, idx, loc) {
11561
- var objects = proxy._objects, guid;
11562
- if (!objects) objects = proxy._objects = {};
11563
11673
 
11564
- while(--loc>=idx) {
11565
- var item = content.objectAt(loc);
11566
- if (item) {
11567
- Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
11568
- Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange');
11674
+ })();
11569
11675
 
11570
- // keep track of the indicies each item was found at so we can map
11571
- // it back when the obj changes.
11572
- guid = guidFor(item);
11573
- if (!objects[guid]) objects[guid] = [];
11574
- objects[guid].push(loc);
11575
- }
11576
- }
11577
- }
11578
11676
 
11579
- function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
11580
- var objects = proxy._objects;
11581
- if (!objects) objects = proxy._objects = {};
11582
- var indicies, guid;
11583
11677
 
11584
- while(--loc>=idx) {
11585
- var item = content.objectAt(loc);
11586
- if (item) {
11587
- Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange');
11588
- Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange');
11678
+ (function() {
11679
+ /**
11680
+ @module ember
11681
+ @submodule ember-runtime
11682
+ */
11589
11683
 
11590
- guid = guidFor(item);
11591
- indicies = objects[guid];
11592
- indicies[indicies.indexOf(loc)] = null;
11593
- }
11594
- }
11595
- }
11684
+ var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone, fmt = Ember.String.fmt;
11596
11685
 
11597
11686
  /**
11598
- This is the object instance returned when you get the `@each` property on an
11599
- array. It uses the unknownProperty handler to automatically create
11600
- EachArray instances for property names.
11687
+ An unordered collection of objects.
11601
11688
 
11602
- @private
11603
- @class EachProxy
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.
11693
+
11694
+ All Sets are observable via the Enumerable Observer API - which works
11695
+ on any enumerable object including both Sets and Arrays.
11696
+
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
11604
11776
  @namespace Ember
11605
- @extends Ember.Object
11777
+ @extends Ember.CoreObject
11778
+ @uses Ember.MutableEnumerable
11779
+ @uses Ember.Copyable
11780
+ @uses Ember.Freezable
11781
+ @since Ember 0.9
11606
11782
  */
11607
- Ember.EachProxy = Ember.Object.extend({
11608
-
11609
- init: function(content) {
11610
- this._super();
11611
- this._content = content;
11612
- content.addArrayObserver(this);
11783
+ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable,
11784
+ /** @scope Ember.Set.prototype */ {
11613
11785
 
11614
- // in case someone is already observing some keys make sure they are
11615
- // added
11616
- forEach(Ember.watchedEvents(this), function(eventName) {
11617
- this.didAddListener(eventName);
11618
- }, this);
11619
- },
11786
+ // ..........................................................
11787
+ // IMPLEMENT ENUMERABLE APIS
11788
+ //
11620
11789
 
11621
11790
  /**
11622
- You can directly access mapped properties by simply requesting them.
11623
- The `unknownProperty` handler will generate an EachArray of each item.
11791
+ This property will change as the number of objects in the set changes.
11624
11792
 
11625
- @method unknownProperty
11626
- @param keyName {String}
11627
- @param value {anything}
11793
+ @property length
11794
+ @type number
11795
+ @default 0
11628
11796
  */
11629
- unknownProperty: function(keyName, value) {
11630
- var ret;
11631
- ret = new EachArray(this._content, keyName, this);
11632
- Ember.defineProperty(this, keyName, null, ret);
11633
- this.beginObservingContentKey(keyName);
11634
- return ret;
11635
- },
11797
+ length: 0,
11636
11798
 
11637
- // ..........................................................
11638
- // ARRAY CHANGES
11639
- // 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.
11640
11802
 
11641
- arrayWillChange: function(content, idx, removedCnt, addedCnt) {
11642
- 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
+ ```
11643
11809
 
11644
- lim = removedCnt>0 ? idx+removedCnt : -1;
11645
- 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); }
11646
11815
 
11647
- for(key in keys) {
11648
- if (!keys.hasOwnProperty(key)) { continue; }
11816
+ var len = get(this, 'length');
11817
+ if (len === 0) { return this; }
11649
11818
 
11650
- if (lim>0) removeObserverForContentKey(content, key, this, idx, lim);
11819
+ var guid;
11651
11820
 
11652
- 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];
11653
11829
  }
11654
11830
 
11655
- Ember.propertyWillChange(this._content, '@each');
11656
- 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;
11657
11838
  },
11658
11839
 
11659
- arrayDidChange: function(content, idx, removedCnt, addedCnt) {
11660
- 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.
11661
11843
 
11662
- lim = addedCnt>0 ? idx+addedCnt : -1;
11663
- Ember.beginPropertyChanges(this);
11844
+ ```javascript
11845
+ var colors = ["red", "green", "blue"],
11846
+ same_colors = new Ember.Set(colors);
11664
11847
 
11665
- for(key in keys) {
11666
- if (!keys.hasOwnProperty(key)) { continue; }
11848
+ same_colors.isEqual(colors); // true
11849
+ same_colors.isEqual(["purple", "brown"]); // false
11850
+ ```
11667
11851
 
11668
- 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;
11669
11859
 
11670
- 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;
11671
11865
  }
11672
11866
 
11673
- Ember.propertyDidChange(this._content, '@each');
11674
- Ember.endPropertyChanges(this);
11867
+ return true;
11675
11868
  },
11676
11869
 
11677
- // ..........................................................
11678
- // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS
11679
- // 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.
11680
11874
 
11681
- didAddListener: function(eventName) {
11682
- if (IS_OBSERVER.test(eventName)) {
11683
- this.beginObservingContentKey(eventName.slice(0, -7));
11684
- }
11685
- },
11875
+ This is an alias for `Ember.MutableEnumerable.addObject()`.
11686
11876
 
11687
- didRemoveListener: function(eventName) {
11688
- if (IS_OBSERVER.test(eventName)) {
11689
- this.stopObservingContentKey(eventName.slice(0, -7));
11690
- }
11691
- },
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
+ ```
11692
11885
 
11693
- // ..........................................................
11694
- // CONTENT KEY OBSERVING
11695
- // 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'),
11696
11891
 
11697
- beginObservingContentKey: function(keyName) {
11698
- var keys = this._keys;
11699
- if (!keys) keys = this._keys = {};
11700
- if (!keys[keyName]) {
11701
- keys[keyName] = 1;
11702
- var content = this._content,
11703
- len = get(content, 'length');
11704
- addObserverForContentKey(content, keyName, this, 0, len);
11705
- } else {
11706
- keys[keyName]++;
11707
- }
11708
- },
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()`.
11709
11896
 
11710
- stopObservingContentKey: function(keyName) {
11711
- var keys = this._keys;
11712
- if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) {
11713
- var content = this._content,
11714
- len = get(content, 'length');
11715
- removeObserverForContentKey(content, keyName, this, 0, len);
11716
- }
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;
11717
11928
  },
11718
11929
 
11719
- contentKeyWillChange: function(obj, keyName) {
11720
- Ember.propertyWillChange(this, keyName);
11721
- },
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.
11722
11968
 
11723
- contentKeyDidChange: function(obj, keyName) {
11724
- Ember.propertyDidChange(this, keyName);
11725
- }
11969
+ This is an alias of `Ember.Set.push()`
11726
11970
 
11727
- });
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
+ ```
11728
11977
 
11978
+ @method unshift
11979
+ @return {Ember.Set} The set itself.
11980
+ */
11981
+ unshift: Ember.aliasMethod('push'),
11729
11982
 
11983
+ /**
11984
+ Adds each object in the passed enumerable to the set.
11730
11985
 
11731
- })();
11986
+ This is an alias of `Ember.MutableEnumerable.addObjects()`
11732
11987
 
11988
+ ```javascript
11989
+ var colors = new Ember.Set();
11990
+ colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"]
11991
+ ```
11733
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'),
11734
11998
 
11735
- (function() {
11736
- /**
11737
- @module ember
11738
- @submodule ember-runtime
11739
- */
11999
+ /**
12000
+ Removes each object in the passed enumerable to the set.
11740
12001
 
12002
+ This is an alias of `Ember.MutableEnumerable.removeObjects()`
11741
12003
 
11742
- 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
+ ```
11743
12008
 
11744
- // Add Ember.Array to Array.prototype. Remove methods with native
11745
- // implementations and supply some more optimized versions of generic methods
11746
- // because they are so common.
11747
- 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'),
11748
12014
 
11749
- // because length is a built-in property we need to know to just get the
11750
- // original property.
11751
- get: function(key) {
11752
- if (key==='length') return this.length;
11753
- else if ('number' === typeof key) return this[key];
11754
- 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);
11755
12022
  },
11756
12023
 
11757
- objectAt: function(idx) {
12024
+ // implement Ember.Enumerable
12025
+ nextObject: function(idx) {
11758
12026
  return this[idx];
11759
12027
  },
11760
12028
 
11761
- // primitive for array support.
11762
- replace: function(idx, amt, objects) {
11763
-
11764
- if (this.isFrozen) throw Ember.FROZEN_ERROR ;
11765
-
11766
- // if we replaced exactly the same number of items, then pass only the
11767
- // replaced range. Otherwise, pass the full remaining array length
11768
- // since everything has shifted
11769
- var len = objects ? get(objects, 'length') : 0;
11770
- this.arrayContentWillChange(idx, amt, len);
12029
+ // more optimized version
12030
+ firstObject: Ember.computed(function() {
12031
+ return this.length > 0 ? this[0] : undefined;
12032
+ }),
11771
12033
 
11772
- if (!objects || objects.length === 0) {
11773
- this.splice(idx, amt) ;
11774
- } else {
11775
- var args = [idx, amt].concat(objects) ;
11776
- this.splice.apply(this,args) ;
11777
- }
12034
+ // more optimized version
12035
+ lastObject: Ember.computed(function() {
12036
+ return this.length > 0 ? this[this.length-1] : undefined;
12037
+ }),
11778
12038
 
11779
- this.arrayContentDidChange(idx, amt, len);
11780
- return this ;
11781
- },
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
11782
12043
 
11783
- // If you ask for an unknown property, then try to collect the value
11784
- // from member items.
11785
- unknownProperty: function(key, value) {
11786
- var ret;// = this.reducedProperty(key, value) ;
11787
- if ((value !== undefined) && ret === undefined) {
11788
- ret = this[key] = value;
11789
- }
11790
- return ret ;
11791
- },
12044
+ var guid = guidFor(obj),
12045
+ idx = this[guid],
12046
+ len = get(this, 'length'),
12047
+ added ;
11792
12048
 
11793
- // If browser did not implement indexOf natively, then override with
11794
- // specialized version
11795
- indexOf: function(object, startAt) {
11796
- var idx, len = this.length;
12049
+ if (idx>=0 && idx<len && (this[idx] === obj)) return this; // added
11797
12050
 
11798
- if (startAt === undefined) startAt = 0;
11799
- else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11800
- if (startAt < 0) startAt += len;
12051
+ added = [obj];
11801
12052
 
11802
- for(idx=startAt;idx<len;idx++) {
11803
- if (this[idx] === object) return idx ;
11804
- }
11805
- return -1;
11806
- },
12053
+ this.enumerableContentWillChange(null, added);
12054
+ Ember.propertyWillChange(this, 'lastObject');
11807
12055
 
11808
- lastIndexOf: function(object, startAt) {
11809
- var idx, len = this.length;
12056
+ len = get(this, 'length');
12057
+ this[guid] = len;
12058
+ this[len] = obj;
12059
+ set(this, 'length', len+1);
11810
12060
 
11811
- if (startAt === undefined) startAt = len-1;
11812
- else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt);
11813
- if (startAt < 0) startAt += len;
12061
+ Ember.propertyDidChange(this, 'lastObject');
12062
+ this.enumerableContentDidChange(null, added);
11814
12063
 
11815
- for(idx=startAt;idx>=0;idx--) {
11816
- if (this[idx] === object) return idx ;
11817
- }
11818
- return -1;
12064
+ return this;
11819
12065
  },
11820
12066
 
11821
- copy: function(deep) {
11822
- if (deep) {
11823
- return this.map(function(item){ return Ember.copy(item, true); });
11824
- }
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
11825
12071
 
11826
- return this.slice();
11827
- }
11828
- });
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;
11829
12078
 
11830
- // Remove any methods implemented natively so we don't override them
11831
- var ignore = ['length'];
11832
- Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) {
11833
- if (Array.prototype[methodName]) ignore.push(methodName);
11834
- });
11835
12079
 
11836
- if (ignore.length>0) {
11837
- NativeArray = NativeArray.without.apply(NativeArray, ignore);
11838
- }
12080
+ if (idx>=0 && idx<len && (this[idx] === obj)) {
12081
+ removed = [obj];
11839
12082
 
11840
- /**
11841
- The NativeArray mixin contains the properties needed to to make the native
11842
- Array support Ember.MutableArray and all of its dependent APIs. Unless you
11843
- have `Ember.EXTEND_PROTOTYPES or `Ember.EXTEND_PROTOTYPES.Array` set to
11844
- false, this will be applied automatically. Otherwise you can apply the mixin
11845
- 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'); }
11846
12086
 
11847
- @class NativeArray
11848
- @namespace Ember
11849
- @extends Ember.Mixin
11850
- @uses Ember.MutableArray
11851
- @uses Ember.MutableEnumerable
11852
- @uses Ember.Copyable
11853
- @uses Ember.Freezable
11854
- */
11855
- 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
+ }
11856
12093
 
11857
- /**
11858
- Creates an `Ember.NativeArray` from an Array like object.
11859
- Does not modify the original object.
12094
+ delete this[guid];
12095
+ delete this[len-1];
12096
+ set(this, 'length', len-1);
11860
12097
 
11861
- @method A
11862
- @for Ember
11863
- @return {Ember.NativeArray}
11864
- */
11865
- Ember.A = function(arr){
11866
- if (arr === undefined) { arr = []; }
11867
- return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr);
11868
- };
12098
+ if (isFirst) { Ember.propertyDidChange(this, 'firstObject'); }
12099
+ if (isLast) { Ember.propertyDidChange(this, 'lastObject'); }
12100
+ this.enumerableContentDidChange(removed, null);
12101
+ }
11869
12102
 
11870
- /**
11871
- Activates the mixin on the Array.prototype if not already applied. Calling
11872
- this method more than once is safe.
12103
+ return this;
12104
+ },
11873
12105
 
11874
- @method activate
11875
- @for Ember.NativeArray
11876
- @static
11877
- @return {void}
11878
- */
11879
- Ember.NativeArray.activate = function() {
11880
- NativeArray.apply(Array.prototype);
12106
+ // optimized version
12107
+ contains: function(obj) {
12108
+ return this[guidFor(obj)]>=0;
12109
+ },
11881
12110
 
11882
- Ember.A = function(arr) { return arr || []; };
11883
- };
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
+ },
11884
12120
 
11885
- if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
11886
- Ember.NativeArray.activate();
11887
- }
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
+ }
11888
12128
 
12129
+ });
11889
12130
 
11890
12131
  })();
11891
12132
 
@@ -11893,7 +12134,6 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) {
11893
12134
 
11894
12135
  (function() {
11895
12136
  var DeferredMixin = Ember.DeferredMixin, // mixins/deferred
11896
- EmberObject = Ember.Object, // system/object
11897
12137
  get = Ember.get;
11898
12138
 
11899
12139
  var Deferred = Ember.Object.extend(DeferredMixin);
@@ -12217,7 +12457,6 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
12217
12457
 
12218
12458
  if (isSorted) {
12219
12459
  var addedObjects = array.slice(idx, idx+addedCount);
12220
- var arrangedContent = get(this, 'arrangedContent');
12221
12460
 
12222
12461
  forEach(addedObjects, function(item) {
12223
12462
  this.insertItemSorted(item);
@@ -12287,8 +12526,8 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
12287
12526
  @submodule ember-runtime
12288
12527
  */
12289
12528
 
12290
- var get = Ember.get, set = Ember.set, isGlobalPath = Ember.isGlobalPath,
12291
- 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;
12292
12531
 
12293
12532
  /**
12294
12533
  `Ember.ArrayController` provides a way for you to publish a collection of
@@ -12611,7 +12850,7 @@ Ember.State = Ember.Object.extend(Ember.Evented,
12611
12850
  },
12612
12851
 
12613
12852
  init: function() {
12614
- var states = get(this, 'states'), foundStates;
12853
+ var states = get(this, 'states');
12615
12854
  set(this, 'childStates', Ember.A());
12616
12855
  set(this, 'eventTransitions', get(this, 'eventTransitions') || {});
12617
12856
 
@@ -12761,7 +13000,7 @@ Ember.State.reopenClass({
12761
13000
  transitionTo: function(target) {
12762
13001
 
12763
13002
  var transitionFunction = function(stateManager, contextOrEvent) {
12764
- var contexts = [], transitionArgs,
13003
+ var contexts = [],
12765
13004
  Event = Ember.$ && Ember.$.Event;
12766
13005
 
12767
13006
  if (contextOrEvent && (Event && contextOrEvent instanceof Event)) {