ember-source 0.0.1 → 0.0.2

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

Potentially problematic release.


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

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