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

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

Potentially problematic release.


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

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