ember-source 1.3.2 → 1.4.0.beta.1

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.

data/dist/ember-debug.js CHANGED
@@ -7,7 +7,7 @@ var Ember = { assert: function() {}, FEATURES: { isEnabled: function() {} } };
7
7
  * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
8
8
  * @license Licensed under MIT license
9
9
  * See https://raw.github.com/emberjs/ember.js/master/LICENSE
10
- * @version 1.3.2
10
+ * @version 1.4.0-beta.1
11
11
  */
12
12
 
13
13
 
@@ -72,11 +72,6 @@ if (!('MANDATORY_SETTER' in Ember.ENV)) {
72
72
  */
73
73
  Ember.assert = function(desc, test) {
74
74
  if (!test) {
75
- Ember.Logger.assert(test, desc);
76
- }
77
-
78
- if (Ember.testing && !test) {
79
- // when testing, ensure test failures when assertions fail
80
75
  throw new Ember.Error("Assertion Failed: " + desc);
81
76
  }
82
77
  };
@@ -5,7 +5,7 @@
5
5
  * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
6
6
  * @license Licensed under MIT license
7
7
  * See https://raw.github.com/emberjs/ember.js/master/LICENSE
8
- * @version 1.3.2
8
+ * @version 1.4.0-beta.1+canary.64fee6ed
9
9
  */
10
10
 
11
11
 
@@ -70,11 +70,6 @@ if (!('MANDATORY_SETTER' in Ember.ENV)) {
70
70
  */
71
71
  Ember.assert = function(desc, test) {
72
72
  if (!test) {
73
- Ember.Logger.assert(test, desc);
74
- }
75
-
76
- if (Ember.testing && !test) {
77
- // when testing, ensure test failures when assertions fail
78
73
  throw new Ember.Error("Assertion Failed: " + desc);
79
74
  }
80
75
  };
@@ -203,7 +198,7 @@ if (!Ember.testing) {
203
198
  * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
204
199
  * @license Licensed under MIT license
205
200
  * See https://raw.github.com/emberjs/ember.js/master/LICENSE
206
- * @version 1.3.2
201
+ * @version 1.4.0-beta.1+canary.64fee6ed
207
202
  */
208
203
 
209
204
 
@@ -286,7 +281,7 @@ var define, requireModule, require, requirejs;
286
281
 
287
282
  @class Ember
288
283
  @static
289
- @version 1.3.2
284
+ @version 1.4.0-beta.1+canary.64fee6ed
290
285
  */
291
286
 
292
287
  if ('undefined' === typeof Ember) {
@@ -313,10 +308,10 @@ Ember.toString = function() { return "Ember"; };
313
308
  /**
314
309
  @property VERSION
315
310
  @type String
316
- @default '1.3.2'
311
+ @default '1.4.0-beta.1+canary.64fee6ed'
317
312
  @static
318
313
  */
319
- Ember.VERSION = '1.3.2';
314
+ Ember.VERSION = '1.4.0-beta.1+canary.64fee6ed';
320
315
 
321
316
  /**
322
317
  Standard environmental variables. You can define these in a global `EmberENV`
@@ -791,17 +786,19 @@ var arrayIndexOf = isNativeFunc(Array.prototype.indexOf) ? Array.prototype.index
791
786
  return -1;
792
787
  };
793
788
 
794
- /**
795
- Array polyfills to support ES5 features in older browsers.
796
789
 
797
- @namespace Ember
798
- @property ArrayPolyfills
799
- */
800
- Ember.ArrayPolyfills = {
801
- map: arrayMap,
802
- forEach: arrayForEach,
803
- indexOf: arrayIndexOf
804
- };
790
+ /**
791
+ Array polyfills to support ES5 features in older browsers.
792
+
793
+ @namespace Ember
794
+ @property ArrayPolyfills
795
+ */
796
+ Ember.ArrayPolyfills = {
797
+ map: arrayMap,
798
+ forEach: arrayForEach,
799
+ indexOf: arrayIndexOf
800
+ };
801
+
805
802
 
806
803
  if (Ember.SHIM_ES5) {
807
804
  if (!Array.prototype.map) {
@@ -1069,7 +1066,8 @@ Meta.prototype = {
1069
1066
  bindings: null,
1070
1067
  chains: null,
1071
1068
  chainWatchers: null,
1072
- values: null
1069
+ values: null,
1070
+ proto: null
1073
1071
  };
1074
1072
 
1075
1073
  if (isDefinePropertySimulated) {
@@ -1576,6 +1574,41 @@ Ember.typeOf = function(item) {
1576
1574
  return ret;
1577
1575
  };
1578
1576
 
1577
+ /**
1578
+ Convenience method to inspect an object. This method will attempt to
1579
+ convert the object into a useful string description.
1580
+
1581
+ It is a pretty simple implementation. If you want something more robust,
1582
+ use something like JSDump: https://github.com/NV/jsDump
1583
+
1584
+ @method inspect
1585
+ @for Ember
1586
+ @param {Object} obj The object you want to inspect.
1587
+ @return {String} A description of the object
1588
+ */
1589
+ Ember.inspect = function(obj) {
1590
+ var type = Ember.typeOf(obj);
1591
+ if (type === 'array') {
1592
+ return '[' + obj + ']';
1593
+ }
1594
+ if (type !== 'object') {
1595
+ return obj + '';
1596
+ }
1597
+
1598
+ var v, ret = [];
1599
+ for(var key in obj) {
1600
+ if (obj.hasOwnProperty(key)) {
1601
+ v = obj[key];
1602
+ if (v === 'toString') { continue; } // ignore useless items
1603
+ if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
1604
+ ret.push(key + ": " + v);
1605
+ }
1606
+ }
1607
+ return "{" + ret.join(", ") + "}";
1608
+ };
1609
+
1610
+
1611
+
1579
1612
  })();
1580
1613
 
1581
1614
 
@@ -1790,10 +1823,11 @@ Ember.subscribe = Ember.Instrumentation.subscribe;
1790
1823
 
1791
1824
 
1792
1825
  (function() {
1793
- var map, forEach, indexOf, splice;
1826
+ var map, forEach, indexOf, splice, filter;
1794
1827
  map = Array.prototype.map || Ember.ArrayPolyfills.map;
1795
1828
  forEach = Array.prototype.forEach || Ember.ArrayPolyfills.forEach;
1796
1829
  indexOf = Array.prototype.indexOf || Ember.ArrayPolyfills.indexOf;
1830
+ filter = Array.prototype.filter || Ember.ArrayPolyfills.filter;
1797
1831
  splice = Array.prototype.splice;
1798
1832
 
1799
1833
  var utils = Ember.EnumerableUtils = {
@@ -1805,6 +1839,10 @@ var utils = Ember.EnumerableUtils = {
1805
1839
  return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : forEach.call(obj, callback, thisArg);
1806
1840
  },
1807
1841
 
1842
+ filter: function(obj, callback, thisArg) {
1843
+ return obj.filter ? obj.filter.call(obj, callback, thisArg) : filter.call(obj, callback, thisArg);
1844
+ },
1845
+
1808
1846
  indexOf: function(obj, element, index) {
1809
1847
  return obj.indexOf ? obj.indexOf.call(obj, element, index) : indexOf.call(obj, element, index);
1810
1848
  },
@@ -1986,7 +2024,7 @@ var normalizeTuple = Ember.normalizeTuple = function(target, path) {
1986
2024
  }
1987
2025
 
1988
2026
  // must return some kind of path to be valid else other things will break.
1989
- if (!path || path.length===0) throw new Ember.Error('Invalid Path');
2027
+ if (!path || path.length===0) throw new Ember.Error('Path cannot be empty');
1990
2028
 
1991
2029
  return [ target, path ];
1992
2030
  };
@@ -3523,6 +3561,12 @@ Ember.defineProperty = function(obj, keyName, desc, data, meta) {
3523
3561
  } else {
3524
3562
  obj[keyName] = undefined; // make enumerable
3525
3563
  }
3564
+
3565
+
3566
+ if (desc.func && desc._dependentCPs) {
3567
+ addImplicitCPs(obj, desc._dependentCPs, meta);
3568
+ }
3569
+
3526
3570
  } else {
3527
3571
  descs[keyName] = undefined; // shadow descriptor in proto
3528
3572
  if (desc == null) {
@@ -3559,6 +3603,22 @@ Ember.defineProperty = function(obj, keyName, desc, data, meta) {
3559
3603
  };
3560
3604
 
3561
3605
 
3606
+ var addImplicitCPs = function defineImplicitCPs(obj, implicitCPs, meta) {
3607
+ var cp, key, length = implicitCPs.length;
3608
+
3609
+ for (var i=0; i<length; ++i) {
3610
+ cp = implicitCPs[i];
3611
+ key = cp.implicitCPKey;
3612
+
3613
+ Ember.defineProperty(obj, key, cp, undefined, meta);
3614
+
3615
+ if (cp._dependentCPs) {
3616
+ addImplicitCPs(obj, cp._dependentCPs, meta);
3617
+ }
3618
+ }
3619
+ };
3620
+
3621
+
3562
3622
  })();
3563
3623
 
3564
3624
 
@@ -4043,6 +4103,52 @@ Ember.finishChains = function(obj) {
4043
4103
 
4044
4104
  (function() {
4045
4105
 
4106
+ /**
4107
+ @module ember-metal
4108
+ */
4109
+
4110
+ var forEach = Ember.EnumerableUtils.forEach,
4111
+ BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/;
4112
+
4113
+ /**
4114
+ Expands `pattern`, invoking `callback` for each expansion.
4115
+
4116
+ The only pattern supported is brace-expansion, anything else will be passed
4117
+ once to `callback` directly. Brace expansion can only appear at the end of a
4118
+ pattern, for example as the last item in a chain.
4119
+
4120
+ Example
4121
+ ```js
4122
+ function echo(arg){ console.log(arg); }
4123
+
4124
+ Ember.expandProperties('foo.bar', echo); //=> 'foo.bar'
4125
+ Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar'
4126
+ Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz'
4127
+ Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz'
4128
+ ```
4129
+
4130
+ @method
4131
+ @private
4132
+ @param {string} pattern The property pattern to expand.
4133
+ @param {function} callback The callback to invoke. It is invoked once per
4134
+ expansion, and is passed the expansion.
4135
+ */
4136
+ Ember.expandProperties = function (pattern, callback) {
4137
+ var match, prefix, list;
4138
+
4139
+ if (match = BRACE_EXPANSION.exec(pattern)) {
4140
+ prefix = match[1];
4141
+ list = match[2];
4142
+
4143
+ forEach(list.split(','), function (suffix) {
4144
+ callback(prefix + suffix);
4145
+ });
4146
+ } else {
4147
+ callback(pattern);
4148
+ }
4149
+ };
4150
+
4151
+
4046
4152
  })();
4047
4153
 
4048
4154
 
@@ -4246,6 +4352,13 @@ var get = Ember.get,
4246
4352
  unwatch = Ember.unwatch;
4247
4353
 
4248
4354
 
4355
+
4356
+
4357
+
4358
+
4359
+ var expandProperties = Ember.expandProperties;
4360
+
4361
+
4249
4362
  // ..........................................................
4250
4363
  // DEPENDENT KEYS
4251
4364
  //
@@ -4404,9 +4517,10 @@ function removeDependentKeys(desc, obj, keyName, meta) {
4404
4517
  */
4405
4518
  function ComputedProperty(func, opts) {
4406
4519
  this.func = func;
4407
-
4520
+
4521
+ setDependentKeys(this, opts && opts.dependentKeys);
4522
+
4408
4523
  this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true;
4409
- this._dependentKeys = opts && opts.dependentKeys;
4410
4524
  this._readOnly = opts && (opts.readOnly !== undefined || !!opts.readOnly);
4411
4525
  }
4412
4526
 
@@ -4415,6 +4529,15 @@ ComputedProperty.prototype = new Ember.Descriptor();
4415
4529
 
4416
4530
  var ComputedPropertyPrototype = ComputedProperty.prototype;
4417
4531
 
4532
+
4533
+ ComputedPropertyPrototype.toString = function() {
4534
+ if (this.implicitCPKey) {
4535
+ return this.implicitCPKey;
4536
+ }
4537
+ return Ember.Descriptor.prototype.toString.apply(this, arguments);
4538
+ };
4539
+
4540
+
4418
4541
  /**
4419
4542
  Properties are cacheable by default. Computed property will automatically
4420
4543
  cache the return value of your function until one of the dependent keys changes.
@@ -4510,10 +4633,18 @@ ComputedPropertyPrototype.property = function() {
4510
4633
  var args;
4511
4634
 
4512
4635
 
4513
- args = a_slice.call(arguments);
4514
-
4636
+ var addArg = function (property) {
4637
+ args.push(property);
4638
+ };
4515
4639
 
4516
- this._dependentKeys = args;
4640
+ args = [];
4641
+ for (var i = 0, l = arguments.length; i < l; i++) {
4642
+ expandProperties(arguments[i], addArg);
4643
+ }
4644
+
4645
+
4646
+ setDependentKeys(this, args);
4647
+
4517
4648
  return this;
4518
4649
  };
4519
4650
 
@@ -4640,7 +4771,7 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) {
4640
4771
  funcArgLength, cachedValue, ret;
4641
4772
 
4642
4773
  if (this._readOnly) {
4643
- throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() );
4774
+ throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + Ember.inspect(obj));
4644
4775
  }
4645
4776
 
4646
4777
  this._suspended = obj;
@@ -4771,26 +4902,87 @@ function getProperties(self, propertyNames) {
4771
4902
  return ret;
4772
4903
  }
4773
4904
 
4774
- function registerComputed(name, macro) {
4775
- Ember.computed[name] = function(dependentKey) {
4776
- var args = a_slice.call(arguments);
4777
- return Ember.computed(dependentKey, function() {
4778
- return macro.apply(this, args);
4779
- });
4905
+ var registerComputed, registerComputedWithProperties;
4906
+
4907
+
4908
+ var guidFor = Ember.guidFor,
4909
+ map = Ember.EnumerableUtils.map,
4910
+ filter = Ember.EnumerableUtils.filter,
4911
+ typeOf = Ember.typeOf;
4912
+
4913
+ var implicitKey = function (cp) {
4914
+ return [guidFor(cp)].concat(cp._dependentKeys).join('_');
4780
4915
  };
4781
- }
4782
4916
 
4783
- function registerComputedWithProperties(name, macro) {
4784
- Ember.computed[name] = function() {
4785
- var properties = a_slice.call(arguments);
4917
+ var normalizeDependentKey = function (key) {
4918
+ if (key instanceof Ember.ComputedProperty) {
4919
+ return implicitKey(key);
4920
+ } else if (typeof key === 'string' || key instanceof String || typeof key === 'object' || typeof key === 'number') {
4921
+ return key;
4922
+ } else {
4923
+ Ember.assert('Unexpected dependent key ' + key + ' of type ' + typeof(key), false);
4924
+ }
4925
+ };
4786
4926
 
4787
- var computed = Ember.computed(function() {
4788
- return macro.apply(this, [getProperties(this, properties)]);
4927
+ var normalizeDependentKeys = function (keys) {
4928
+ return map(keys, function (key) {
4929
+ return normalizeDependentKey(key);
4789
4930
  });
4931
+ };
4790
4932
 
4791
- return computed.property.apply(computed, properties);
4933
+ var selectDependentCPs = function (keys) {
4934
+ return filter(keys, function (key) {
4935
+ return key instanceof Ember.ComputedProperty;
4936
+ });
4792
4937
  };
4793
- }
4938
+
4939
+ var setDependentKeys = function(cp, dependentKeys) {
4940
+ if (dependentKeys) {
4941
+ cp._dependentKeys = normalizeDependentKeys(dependentKeys);
4942
+ cp._dependentCPs = selectDependentCPs(dependentKeys);
4943
+ cp.implicitCPKey = implicitKey(cp);
4944
+ } else {
4945
+ cp._dependentKeys = cp._dependentCPs = [];
4946
+ delete cp.implicitCPKey;
4947
+ }
4948
+ };
4949
+ // expose `normalizeDependentKey[s]` so user CP macros can easily support
4950
+ // composition
4951
+ Ember.computed.normalizeDependentKey = normalizeDependentKey;
4952
+ Ember.computed.normalizeDependentKeys = normalizeDependentKeys;
4953
+
4954
+ registerComputed = function (name, macro) {
4955
+ Ember.computed[name] = function(dependentKey) {
4956
+ var args = normalizeDependentKeys(a_slice.call(arguments));
4957
+ return Ember.computed(dependentKey, function() {
4958
+ return macro.apply(this, args);
4959
+ });
4960
+ };
4961
+ };
4962
+
4963
+
4964
+
4965
+ registerComputedWithProperties = function(name, macro) {
4966
+ Ember.computed[name] = function() {
4967
+ var args = a_slice.call(arguments);
4968
+ var properties = normalizeDependentKeys(args);
4969
+
4970
+ var computed = Ember.computed(function() {
4971
+ return macro.apply(this, [getProperties(this, properties)]);
4972
+ });
4973
+
4974
+ return computed.property.apply(computed, args);
4975
+ };
4976
+ };
4977
+
4978
+
4979
+
4980
+ Ember.computed.literal = function (value) {
4981
+ return Ember.computed(function () {
4982
+ return value;
4983
+ });
4984
+ };
4985
+
4794
4986
 
4795
4987
  /**
4796
4988
  A computed property that returns true if the value of the dependent
@@ -5321,7 +5513,51 @@ Ember.computed.oneWay = function(dependentKey) {
5321
5513
  });
5322
5514
  };
5323
5515
 
5516
+ if (Ember.FEATURES.isEnabled('computed-read-only')) {
5517
+ /**
5518
+ Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides
5519
+ a readOnly one way binding. Very often when using `computed.oneWay` one does
5520
+ not also want changes to propogate back up, as they will replace the value.
5521
+
5522
+ This prevents the reverse flow, and also throws an exception when it occurs.
5523
+
5524
+ Example
5525
+
5526
+ ```javascript
5527
+ User = Ember.Object.extend({
5528
+ firstName: null,
5529
+ lastName: null,
5530
+ nickName: Ember.computed.readOnly('firstName')
5531
+ });
5324
5532
 
5533
+ user = User.create({
5534
+ firstName: 'Teddy',
5535
+ lastName: 'Zeenny'
5536
+ });
5537
+
5538
+ user.get('nickName');
5539
+ # 'Teddy'
5540
+
5541
+ user.set('nickName', 'TeddyBear');
5542
+ # throws Exception
5543
+ # throw new Ember.Error('Cannot Set: nickName on: <User:ember27288>' );`
5544
+
5545
+ user.get('firstName');
5546
+ # 'Teddy'
5547
+ ```
5548
+
5549
+ @method computed.readOnly
5550
+ @for Ember
5551
+ @param {String} dependentKey
5552
+ @return {Ember.ComputedProperty} computed property which creates a
5553
+ one way computed property to the original value for property.
5554
+ */
5555
+ Ember.computed.readOnly = function(dependentKey) {
5556
+ return Ember.computed(dependentKey, function() {
5557
+ return get(this, dependentKey);
5558
+ }).readOnly();
5559
+ };
5560
+ }
5325
5561
  /**
5326
5562
  A computed property that acts like a standard getter and setter,
5327
5563
  but returns the value at the provided `defaultPath` if the
@@ -6135,7 +6371,8 @@ var Backburner = requireModule('backburner').Backburner,
6135
6371
  onBegin: onBegin,
6136
6372
  onEnd: onEnd
6137
6373
  }),
6138
- slice = [].slice;
6374
+ slice = [].slice,
6375
+ concat = [].concat;
6139
6376
 
6140
6377
  // ..........................................................
6141
6378
  // Ember.run - this is ideally the only public API the dev sees
@@ -6221,7 +6458,7 @@ Ember.run = function(target, method) {
6221
6458
  @return {Object} Return value from invoking the passed function. Please note,
6222
6459
  when called within an existing loop, no return value is possible.
6223
6460
  */
6224
- Ember.run.join = function(target, method) {
6461
+ Ember.run.join = function(target, method /* args */) {
6225
6462
  if (!Ember.run.currentRunLoop) {
6226
6463
  return Ember.run.apply(Ember.run, arguments);
6227
6464
  }
@@ -6231,6 +6468,55 @@ Ember.run.join = function(target, method) {
6231
6468
  Ember.run.schedule.apply(Ember.run, args);
6232
6469
  };
6233
6470
 
6471
+
6472
+ /**
6473
+ Provides a useful utility for when integrating with non-Ember libraries
6474
+ that provide asynchronous callbacks.
6475
+
6476
+ Ember utilizes a run-loop to batch and coalesce changes. This works by
6477
+ marking the start and end of Ember-related Javascript execution.
6478
+
6479
+ When using events such as a View's click handler, Ember wraps the event
6480
+ handler in a run-loop, but when integrating with non-Ember libraries this
6481
+ can be tedious.
6482
+
6483
+ For example, the following is rather verbose but is the correct way to combine
6484
+ third-party events and Ember code.
6485
+
6486
+ ```javascript
6487
+ var that = this;
6488
+ jQuery(window).on('resize', function(){
6489
+ Ember.run(function(){
6490
+ that.handleResize();
6491
+ });
6492
+ });
6493
+ ```
6494
+
6495
+ To reduce the boilerplate, the following can be used to construct a
6496
+ run-loop-wrapped callback handler.
6497
+
6498
+ ```javascript
6499
+ jQuery(window).on('resize', Ember.run.bind(this, this.triggerResize));
6500
+ ```
6501
+
6502
+ @method bind
6503
+ @namespace Ember.run
6504
+ @param {Object} [target] target of method to call
6505
+ @param {Function|String} method Method to invoke.
6506
+ May be a function or a string. If you pass a string
6507
+ then it will be looked up on the passed target.
6508
+ @param {Object} [args*] Any additional arguments you wish to pass to the method.
6509
+ @return {Object} return value from invoking the passed function. Please note,
6510
+ when called within an existing loop, no return value is possible.
6511
+ */
6512
+ Ember.run.bind = function(target, method /* args*/) {
6513
+ var args = arguments;
6514
+ return function() {
6515
+ return Ember.run.join.apply(Ember.run, args);
6516
+ };
6517
+ };
6518
+
6519
+
6234
6520
  Ember.run.backburner = backburner;
6235
6521
 
6236
6522
  var run = Ember.run;
@@ -6400,7 +6686,7 @@ Ember.run.later = function(target, method) {
6400
6686
  If you pass a string it will be resolved on the
6401
6687
  target at the time the method is invoked.
6402
6688
  @param {Object} [args*] Optional arguments to pass to the timeout.
6403
- @return {Object} timer
6689
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
6404
6690
  */
6405
6691
  Ember.run.once = function(target, method) {
6406
6692
  checkAutoRun();
@@ -6451,7 +6737,7 @@ Ember.run.once = function(target, method) {
6451
6737
  If you pass a string it will be resolved on the
6452
6738
  target at the time the method is invoked.
6453
6739
  @param {Object} [args*] Optional arguments to pass to the timeout.
6454
- @return {Object} timer
6740
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
6455
6741
  */
6456
6742
  Ember.run.scheduleOnce = function(queue, target, method) {
6457
6743
  checkAutoRun();
@@ -6514,7 +6800,7 @@ Ember.run.scheduleOnce = function(queue, target, method) {
6514
6800
  If you pass a string it will be resolved on the
6515
6801
  target at the time the method is invoked.
6516
6802
  @param {Object} [args*] Optional arguments to pass to the timeout.
6517
- @return {Object} timer
6803
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
6518
6804
  */
6519
6805
  Ember.run.next = function() {
6520
6806
  var args = slice.call(arguments);
@@ -6524,7 +6810,8 @@ Ember.run.next = function() {
6524
6810
 
6525
6811
  /**
6526
6812
  Cancels a scheduled item. Must be a value returned by `Ember.run.later()`,
6527
- `Ember.run.once()`, or `Ember.run.next()`.
6813
+ `Ember.run.once()`, `Ember.run.next()`, `Ember.run.debounce()`, or
6814
+ `Ember.run.throttle()`.
6528
6815
 
6529
6816
  ```javascript
6530
6817
  var runNext = Ember.run.next(myContext, function() {
@@ -6541,11 +6828,29 @@ Ember.run.next = function() {
6541
6828
  // will not be executed
6542
6829
  });
6543
6830
  Ember.run.cancel(runOnce);
6831
+
6832
+ var throttle = Ember.run.throttle(myContext, function() {
6833
+ // will not be executed
6834
+ }, 1);
6835
+ Ember.run.cancel(throttle);
6836
+
6837
+ var debounce = Ember.run.debounce(myContext, function() {
6838
+ // will not be executed
6839
+ }, 1);
6840
+ Ember.run.cancel(debounce);
6841
+
6842
+ var debounceImmediate = Ember.run.debounce(myContext, function() {
6843
+ // will be executed since we passed in true (immediate)
6844
+ }, 100, true);
6845
+ // the 100ms delay until this method can be called again will be cancelled
6846
+ Ember.run.cancel(debounceImmediate);
6847
+ ```
6848
+ ```
6544
6849
  ```
6545
6850
 
6546
6851
  @method cancel
6547
6852
  @param {Object} timer Timer object to cancel
6548
- @return {void}
6853
+ @return {Boolean} true if cancelled or false/undefined if it wasn't found
6549
6854
  */
6550
6855
  Ember.run.cancel = function(timer) {
6551
6856
  return backburner.cancel(timer);
@@ -6577,6 +6882,34 @@ Ember.run.cancel = function(timer) {
6577
6882
  // console logs 'debounce ran.' one time.
6578
6883
  ```
6579
6884
 
6885
+ Immediate allows you to run the function immediately, but debounce
6886
+ other calls for this function until the wait time has elapsed. If
6887
+ `debounce` is called again before the specified time has elapsed,
6888
+ the timer is reset and the entire period msut pass again before
6889
+ the method can be called again.
6890
+
6891
+ ```javascript
6892
+ var myFunc = function() { console.log(this.name + ' ran.'); };
6893
+ var myContext = {name: 'debounce'};
6894
+
6895
+ Ember.run.debounce(myContext, myFunc, 150, true);
6896
+
6897
+ // console logs 'debounce ran.' one time immediately.
6898
+ // 100ms passes
6899
+
6900
+ Ember.run.debounce(myContext, myFunc, 150, true);
6901
+
6902
+ // 150ms passes and nothing else is logged to the console and
6903
+ // the debouncee is no longer being watched
6904
+
6905
+ Ember.run.debounce(myContext, myFunc, 150, true);
6906
+
6907
+ // console logs 'debounce ran.' one time immediately.
6908
+ // 150ms passes and nothing else is logged tot he console and
6909
+ // the debouncee is no longer being watched
6910
+
6911
+ ```
6912
+
6580
6913
  @method debounce
6581
6914
  @param {Object} [target] target of method to invoke
6582
6915
  @param {Function|String} method The method to invoke.
@@ -6585,7 +6918,7 @@ Ember.run.cancel = function(timer) {
6585
6918
  @param {Object} [args*] Optional arguments to pass to the timeout.
6586
6919
  @param {Number} wait Number of milliseconds to wait.
6587
6920
  @param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval.
6588
- @return {void}
6921
+ @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
6589
6922
  */
6590
6923
  Ember.run.debounce = function() {
6591
6924
  return backburner.debounce.apply(backburner, arguments);
@@ -6622,7 +6955,7 @@ Ember.run.debounce = function() {
6622
6955
  then it will be looked up on the passed target.
6623
6956
  @param {Object} [args*] Optional arguments to pass to the timeout.
6624
6957
  @param {Number} spacing Number of milliseconds to space out requests.
6625
- @return {void}
6958
+ @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
6626
6959
  */
6627
6960
  Ember.run.throttle = function() {
6628
6961
  return backburner.throttle.apply(backburner, arguments);
@@ -7133,6 +7466,9 @@ var Mixin, REQUIRED, Alias,
7133
7466
  guidFor = Ember.guidFor;
7134
7467
 
7135
7468
 
7469
+ var expandProperties = Ember.expandProperties;
7470
+
7471
+
7136
7472
  function mixinsMeta(obj) {
7137
7473
  var m = Ember.meta(obj, true), ret = m.mixins;
7138
7474
  if (!ret) {
@@ -7707,35 +8043,6 @@ Alias = function(methodName) {
7707
8043
  };
7708
8044
  Alias.prototype = new Ember.Descriptor();
7709
8045
 
7710
- /**
7711
- Makes a property or method available via an additional name.
7712
-
7713
- ```javascript
7714
- App.PaintSample = Ember.Object.extend({
7715
- color: 'red',
7716
- colour: Ember.alias('color'),
7717
- name: function() {
7718
- return "Zed";
7719
- },
7720
- moniker: Ember.alias("name")
7721
- });
7722
-
7723
- var paintSample = App.PaintSample.create()
7724
- paintSample.get('colour'); // 'red'
7725
- paintSample.moniker(); // 'Zed'
7726
- ```
7727
-
7728
- @method alias
7729
- @for Ember
7730
- @param {String} methodName name of the method or property to alias
7731
- @return {Ember.Descriptor}
7732
- @deprecated Use `Ember.aliasMethod` or `Ember.computed.alias` instead
7733
- */
7734
- Ember.alias = function(methodName) {
7735
- Ember.deprecate("Ember.alias is deprecated. Please use Ember.aliasMethod or Ember.computed.alias instead.");
7736
- return new Alias(methodName);
7737
- };
7738
-
7739
8046
  /**
7740
8047
  Makes a method available via an additional name.
7741
8048
 
@@ -7791,16 +8098,22 @@ Ember.observer = function() {
7791
8098
  var paths;
7792
8099
 
7793
8100
 
7794
- paths = a_slice.call(arguments, 0, -1);
8101
+ var addWatchedProperty = function (path) { paths.push(path); };
8102
+ var _paths = a_slice.call(arguments, 0, -1);
7795
8103
 
7796
8104
  if (typeof func !== "function") {
7797
8105
  // revert to old, soft-deprecated argument ordering
7798
8106
 
7799
8107
  func = arguments[0];
7800
- paths = a_slice.call(arguments, 1);
8108
+ _paths = a_slice.call(arguments, 1);
7801
8109
  }
7802
-
7803
8110
 
8111
+ paths = [];
8112
+
8113
+ for (var i=0; i<_paths.length; ++i) {
8114
+ expandProperties(_paths[i], addWatchedProperty);
8115
+ }
8116
+
7804
8117
  if (typeof func !== "function") {
7805
8118
  throw new Ember.Error("Ember.observer called without a function");
7806
8119
  }
@@ -7889,16 +8202,23 @@ Ember.beforeObserver = function() {
7889
8202
  var paths;
7890
8203
 
7891
8204
 
7892
- paths = a_slice.call(arguments, 0, -1);
8205
+ var addWatchedProperty = function(path) { paths.push(path); };
8206
+
8207
+ var _paths = a_slice.call(arguments, 0, -1);
7893
8208
 
7894
8209
  if (typeof func !== "function") {
7895
8210
  // revert to old, soft-deprecated argument ordering
7896
8211
 
7897
8212
  func = arguments[0];
7898
- paths = a_slice.call(arguments, 1);
8213
+ _paths = a_slice.call(arguments, 1);
7899
8214
  }
7900
-
7901
8215
 
8216
+ paths = [];
8217
+
8218
+ for (var i=0; i<_paths.length; ++i) {
8219
+ expandProperties(_paths[i], addWatchedProperty);
8220
+ }
8221
+
7902
8222
  if (typeof func !== "function") {
7903
8223
  throw new Ember.Error("Ember.beforeObserver called without a function");
7904
8224
  }
@@ -10135,6 +10455,7 @@ Ember.MODEL_FACTORY_INJECTIONS = false || !!Ember.ENV.MODEL_FACTORY_INJECTIONS;
10135
10455
  define("container",
10136
10456
  [],
10137
10457
  function() {
10458
+ "use strict";
10138
10459
 
10139
10460
  // A safe and simple inheriting object.
10140
10461
  function InheritingDict(parent) {
@@ -10256,7 +10577,8 @@ define("container",
10256
10577
 
10257
10578
  this.registry = new InheritingDict(parent && parent.registry);
10258
10579
  this.cache = new InheritingDict(parent && parent.cache);
10259
- this.factoryCache = new InheritingDict(parent && parent.cache);
10580
+ this.factoryCache = new InheritingDict(parent && parent.factoryCache);
10581
+ this.resolveCache = new InheritingDict(parent && parent.resolveCache);
10260
10582
  this.typeInjections = new InheritingDict(parent && parent.typeInjections);
10261
10583
  this.injections = {};
10262
10584
 
@@ -10377,9 +10699,7 @@ define("container",
10377
10699
  @param {Object} options
10378
10700
  */
10379
10701
  register: function(fullName, factory, options) {
10380
- if (fullName.indexOf(':') === -1) {
10381
- throw new TypeError("malformed fullName, expected: `type:name` got: " + fullName + "");
10382
- }
10702
+ validateFullName(fullName);
10383
10703
 
10384
10704
  if (factory === undefined) {
10385
10705
  throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
@@ -10412,11 +10732,14 @@ define("container",
10412
10732
  @param {String} fullName
10413
10733
  */
10414
10734
  unregister: function(fullName) {
10735
+ validateFullName(fullName);
10736
+
10415
10737
  var normalizedName = this.normalize(fullName);
10416
10738
 
10417
10739
  this.registry.remove(normalizedName);
10418
10740
  this.cache.remove(normalizedName);
10419
10741
  this.factoryCache.remove(normalizedName);
10742
+ this.resolveCache.remove(normalizedName);
10420
10743
  this._options.remove(normalizedName);
10421
10744
  },
10422
10745
 
@@ -10453,7 +10776,18 @@ define("container",
10453
10776
  @return {Function} fullName's factory
10454
10777
  */
10455
10778
  resolve: function(fullName) {
10456
- return this.resolver(fullName) || this.registry.get(fullName);
10779
+ validateFullName(fullName);
10780
+
10781
+ var normalizedName = this.normalize(fullName);
10782
+ var cached = this.resolveCache.get(normalizedName);
10783
+
10784
+ if (cached) { return cached; }
10785
+
10786
+ var resolved = this.resolver(normalizedName) || this.registry.get(normalizedName);
10787
+
10788
+ this.resolveCache.set(normalizedName, resolved);
10789
+
10790
+ return resolved;
10457
10791
  },
10458
10792
 
10459
10793
  /**
@@ -10534,23 +10868,8 @@ define("container",
10534
10868
  @return {any}
10535
10869
  */
10536
10870
  lookup: function(fullName, options) {
10537
- fullName = this.normalize(fullName);
10538
-
10539
- options = options || {};
10540
-
10541
- if (this.cache.has(fullName) && options.singleton !== false) {
10542
- return this.cache.get(fullName);
10543
- }
10544
-
10545
- var value = instantiate(this, fullName);
10546
-
10547
- if (value === undefined) { return; }
10548
-
10549
- if (isSingleton(this, fullName) && options.singleton !== false) {
10550
- this.cache.set(fullName, value);
10551
- }
10552
-
10553
- return value;
10871
+ validateFullName(fullName);
10872
+ return lookup(this, this.normalize(fullName), options);
10554
10873
  },
10555
10874
 
10556
10875
  /**
@@ -10561,7 +10880,8 @@ define("container",
10561
10880
  @return {any}
10562
10881
  */
10563
10882
  lookupFactory: function(fullName) {
10564
- return factoryFor(this, fullName);
10883
+ validateFullName(fullName);
10884
+ return factoryFor(this, this.normalize(fullName));
10565
10885
  },
10566
10886
 
10567
10887
  /**
@@ -10573,11 +10893,8 @@ define("container",
10573
10893
  @return {Boolean}
10574
10894
  */
10575
10895
  has: function(fullName) {
10576
- if (this.cache.has(fullName)) {
10577
- return true;
10578
- }
10579
-
10580
- return !!this.resolve(fullName);
10896
+ validateFullName(fullName);
10897
+ return has(this, this.normalize(fullName));
10581
10898
  },
10582
10899
 
10583
10900
  /**
@@ -10658,6 +10975,7 @@ define("container",
10658
10975
  @param {String} fullName
10659
10976
  */
10660
10977
  typeInjection: function(type, property, fullName) {
10978
+ validateFullName(fullName);
10661
10979
  if (this.parent) { illegalChildOperation('typeInjection'); }
10662
10980
 
10663
10981
  addTypeInjection(this.typeInjections, type, property, fullName);
@@ -10707,14 +11025,20 @@ define("container",
10707
11025
  @param {String} property
10708
11026
  @param {String} injectionName
10709
11027
  */
10710
- injection: function(factoryName, property, injectionName) {
11028
+ injection: function(fullName, property, injectionName) {
10711
11029
  if (this.parent) { illegalChildOperation('injection'); }
10712
11030
 
10713
- if (factoryName.indexOf(':') === -1) {
10714
- return this.typeInjection(factoryName, property, injectionName);
11031
+ validateFullName(injectionName);
11032
+ var normalizedInjectionName = this.normalize(injectionName);
11033
+
11034
+ if (fullName.indexOf(':') === -1) {
11035
+ return this.typeInjection(fullName, property, normalizedInjectionName);
10715
11036
  }
10716
11037
 
10717
- addInjection(this.injections, factoryName, property, injectionName);
11038
+ validateFullName(fullName);
11039
+ var normalizedName = this.normalize(fullName);
11040
+
11041
+ addInjection(this.injections, normalizedName, property, normalizedInjectionName);
10718
11042
  },
10719
11043
 
10720
11044
 
@@ -10750,7 +11074,7 @@ define("container",
10750
11074
  factoryTypeInjection: function(type, property, fullName) {
10751
11075
  if (this.parent) { illegalChildOperation('factoryTypeInjection'); }
10752
11076
 
10753
- addTypeInjection(this.factoryTypeInjections, type, property, fullName);
11077
+ addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName));
10754
11078
  },
10755
11079
 
10756
11080
  /**
@@ -10802,14 +11126,21 @@ define("container",
10802
11126
  @param {String} property
10803
11127
  @param {String} injectionName
10804
11128
  */
10805
- factoryInjection: function(factoryName, property, injectionName) {
11129
+ factoryInjection: function(fullName, property, injectionName) {
10806
11130
  if (this.parent) { illegalChildOperation('injection'); }
10807
11131
 
10808
- if (factoryName.indexOf(':') === -1) {
10809
- return this.factoryTypeInjection(factoryName, property, injectionName);
11132
+ var normalizedName = this.normalize(fullName);
11133
+ var normalizedInjectionName = this.normalize(injectionName);
11134
+
11135
+ validateFullName(injectionName);
11136
+
11137
+ if (fullName.indexOf(':') === -1) {
11138
+ return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName);
10810
11139
  }
10811
11140
 
10812
- addInjection(this.factoryInjections, factoryName, property, injectionName);
11141
+ validateFullName(fullName);
11142
+
11143
+ addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName);
10813
11144
  },
10814
11145
 
10815
11146
  /**
@@ -10819,7 +11150,6 @@ define("container",
10819
11150
  @method destroy
10820
11151
  */
10821
11152
  destroy: function() {
10822
-
10823
11153
  for (var i=0, l=this.children.length; i<l; i++) {
10824
11154
  this.children[i].destroy();
10825
11155
  }
@@ -10845,6 +11175,32 @@ define("container",
10845
11175
  }
10846
11176
  };
10847
11177
 
11178
+ function has(container, fullName){
11179
+ if (container.cache.has(fullName)) {
11180
+ return true;
11181
+ }
11182
+
11183
+ return !!container.resolve(fullName);
11184
+ }
11185
+
11186
+ function lookup(container, fullName, options) {
11187
+ options = options || {};
11188
+
11189
+ if (container.cache.has(fullName) && options.singleton !== false) {
11190
+ return container.cache.get(fullName);
11191
+ }
11192
+
11193
+ var value = instantiate(container, fullName);
11194
+
11195
+ if (value === undefined) { return; }
11196
+
11197
+ if (isSingleton(container, fullName) && options.singleton !== false) {
11198
+ container.cache.set(fullName, value);
11199
+ }
11200
+
11201
+ return value;
11202
+ }
11203
+
10848
11204
  function illegalChildOperation(operation) {
10849
11205
  throw new Error(operation + " is not currently supported on child containers");
10850
11206
  }
@@ -10860,14 +11216,14 @@ define("container",
10860
11216
 
10861
11217
  if (!injections) { return hash; }
10862
11218
 
10863
- var injection, lookup;
11219
+ var injection, injectable;
10864
11220
 
10865
11221
  for (var i=0, l=injections.length; i<l; i++) {
10866
11222
  injection = injections[i];
10867
- lookup = container.lookup(injection.fullName);
11223
+ injectable = lookup(container, injection.fullName);
10868
11224
 
10869
- if (lookup !== undefined) {
10870
- hash[injection.property] = lookup;
11225
+ if (injectable !== undefined) {
11226
+ hash[injection.property] = injectable;
10871
11227
  } else {
10872
11228
  throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`');
10873
11229
  }
@@ -10892,7 +11248,7 @@ define("container",
10892
11248
  }
10893
11249
 
10894
11250
  function factoryFor(container, fullName) {
10895
- var name = container.normalize(fullName);
11251
+ var name = fullName;
10896
11252
  var factory = container.resolve(name);
10897
11253
  var injectedFactory;
10898
11254
  var cache = container.factoryCache;
@@ -11002,6 +11358,13 @@ define("container",
11002
11358
  });
11003
11359
  }
11004
11360
 
11361
+ var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;
11362
+ function validateFullName(fullName) {
11363
+ if (!VALID_FULL_NAME_REGEXP.test(fullName)) {
11364
+ throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName);
11365
+ }
11366
+ }
11367
+
11005
11368
  function addInjection(rules, factoryName, property, injectionName) {
11006
11369
  var injections = rules[factoryName] = rules[factoryName] || [];
11007
11370
  injections.push({ property: property, fullName: injectionName });
@@ -11196,39 +11559,6 @@ Ember.copy = function(obj, deep) {
11196
11559
  return _copy(obj, deep, deep ? [] : null, deep ? [] : null);
11197
11560
  };
11198
11561
 
11199
- /**
11200
- Convenience method to inspect an object. This method will attempt to
11201
- convert the object into a useful string description.
11202
-
11203
- It is a pretty simple implementation. If you want something more robust,
11204
- use something like JSDump: https://github.com/NV/jsDump
11205
-
11206
- @method inspect
11207
- @for Ember
11208
- @param {Object} obj The object you want to inspect.
11209
- @return {String} A description of the object
11210
- */
11211
- Ember.inspect = function(obj) {
11212
- var type = Ember.typeOf(obj);
11213
- if (type === 'array') {
11214
- return '[' + obj + ']';
11215
- }
11216
- if (type !== 'object') {
11217
- return obj + '';
11218
- }
11219
-
11220
- var v, ret = [];
11221
- for(var key in obj) {
11222
- if (obj.hasOwnProperty(key)) {
11223
- v = obj[key];
11224
- if (v === 'toString') { continue; } // ignore useless items
11225
- if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
11226
- ret.push(key + ": " + v);
11227
- }
11228
- }
11229
- return "{" + ret.join(", ") + "}";
11230
- };
11231
-
11232
11562
  /**
11233
11563
  Compares two objects, returning true if they are logically equal. This is
11234
11564
  a deeper comparison than a simple triple equal. For sets it will compare the
@@ -11333,6 +11663,10 @@ var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g);
11333
11663
  var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g);
11334
11664
  var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g);
11335
11665
  var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g);
11666
+ var STRING_PARAMETERIZE_REGEXP_1 = (/[_|\/|\s]+/g);
11667
+ var STRING_PARAMETERIZE_REGEXP_2 = (/[^a-z0-9\-]+/gi);
11668
+ var STRING_PARAMETERIZE_REGEXP_3 = (/[\-]+/g);
11669
+ var STRING_PARAMETERIZE_REGEXP_4 = (/^-+|-+$/g);
11336
11670
 
11337
11671
  /**
11338
11672
  Defines the hash of localized strings for the current language. Used by
@@ -11571,6 +11905,54 @@ Ember.String = {
11571
11905
  }
11572
11906
  };
11573
11907
 
11908
+ if (Ember.FEATURES.isEnabled("string-humanize")) {
11909
+ /**
11910
+ Returns the Humanized form of a string
11911
+
11912
+ Replaces underscores with spaces, and capitializes first character
11913
+ of string. Also strips "_id" suffixes.
11914
+
11915
+ ```javascript
11916
+ 'first_name'.humanize() // 'First name'
11917
+ 'user_id'.humanize() // 'User'
11918
+ ```
11919
+
11920
+ @method humanize
11921
+ @param {String} str The string to humanize.
11922
+ @return {String} The humanized string.
11923
+ */
11924
+
11925
+ Ember.String.humanize = function(str) {
11926
+ return str.replace(/_id$/, '').
11927
+ replace(/_/g, ' ').
11928
+ replace(/^\w/g, function(s){
11929
+ return s.toUpperCase();
11930
+ });
11931
+ };
11932
+ }
11933
+
11934
+ if (Ember.FEATURES.isEnabled("string-parameterize")) {
11935
+ /**
11936
+ Transforms a string so that it may be used as part of a 'pretty' / SEO friendly URL.
11937
+
11938
+ ```javascript
11939
+ 'My favorite items.'.parameterize(); // 'my-favorite-items'
11940
+ 'action_name'.parameterize(); // 'action-name'
11941
+ '100 ways Ember.js is better than Angular.'.parameterize(); // '100-ways-emberjs-is-better-than-angular'
11942
+ ```
11943
+
11944
+ @method parameterize
11945
+ @param {String} str The string to parameterize.
11946
+ @return {String} the parameterized string.
11947
+ */
11948
+ Ember.String.parameterize = function(str) {
11949
+ return str.replace(STRING_PARAMETERIZE_REGEXP_1, '-') // replace underscores, slashes and spaces with separator
11950
+ .replace(STRING_PARAMETERIZE_REGEXP_2, '') // remove non-alphanumeric characters except the separator
11951
+ .replace(STRING_PARAMETERIZE_REGEXP_3, '-') // replace multiple occurring separators
11952
+ .replace(STRING_PARAMETERIZE_REGEXP_4, '') // trim leading and trailing separators
11953
+ .toLowerCase();
11954
+ };
11955
+ }
11574
11956
 
11575
11957
 
11576
11958
  })();
@@ -11595,6 +11977,13 @@ var fmt = Ember.String.fmt,
11595
11977
  capitalize = Ember.String.capitalize,
11596
11978
  classify = Ember.String.classify;
11597
11979
 
11980
+ if (Ember.FEATURES.isEnabled("string-humanize")) {
11981
+ var humanize = Ember.String.humanize;
11982
+ }
11983
+
11984
+ if (Ember.FEATURES.isEnabled("string-parameterize")) {
11985
+ var parameterize = Ember.String.parameterize;
11986
+ }
11598
11987
 
11599
11988
  if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
11600
11989
 
@@ -11688,7 +12077,30 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
11688
12077
  return capitalize(this);
11689
12078
  };
11690
12079
 
11691
-
12080
+ if (Ember.FEATURES.isEnabled("string-humanize")) {
12081
+ /**
12082
+ See [Ember.String.humanize](/api/classes/Ember.String.html#method_humanize).
12083
+
12084
+ @method humanize
12085
+ @for String
12086
+ */
12087
+ String.prototype.humanize = function() {
12088
+ return humanize(this);
12089
+ };
12090
+ }
12091
+
12092
+ if (Ember.FEATURES.isEnabled("string-parameterize")) {
12093
+ /**
12094
+ See [Ember.String.parameterize](/api/classes/Ember.String.html#method_parameterize).
12095
+
12096
+ @method parameterize
12097
+ @for String
12098
+ */
12099
+ String.prototype.parameterize = function() {
12100
+ return parameterize(this);
12101
+ };
12102
+ }
12103
+
11692
12104
  }
11693
12105
 
11694
12106
 
@@ -14062,7 +14474,7 @@ Ember.Enumerable = Ember.Mixin.create({
14062
14474
  var ret = initialValue;
14063
14475
 
14064
14476
  this.forEach(function(item, i) {
14065
- ret = callback.call(null, ret, item, i, this, reducerProperty);
14477
+ ret = callback(ret, item, i, this, reducerProperty);
14066
14478
  }, this);
14067
14479
 
14068
14480
  return ret;
@@ -14085,7 +14497,7 @@ Ember.Enumerable = Ember.Mixin.create({
14085
14497
  this.forEach(function(x, idx) {
14086
14498
  var method = x && x[methodName];
14087
14499
  if ('function' === typeof method) {
14088
- ret[idx] = args ? method.apply(x, args) : method.call(x);
14500
+ ret[idx] = args ? method.apply(x, args) : x[methodName]();
14089
14501
  }
14090
14502
  }, this);
14091
14503
 
@@ -14280,8 +14692,6 @@ Ember.Enumerable = Ember.Mixin.create({
14280
14692
  notify range observers.
14281
14693
 
14282
14694
  @method enumerableContentDidChange
14283
- @param {Number} [start] optional start offset for the content change.
14284
- For unordered enumerables, you should always pass -1.
14285
14695
  @param {Ember.Enumerable|Number} removing An enumerable of the objects to
14286
14696
  be removed or the number of items to be removed.
14287
14697
  @param {Ember.Enumerable|Number} adding An enumerable of the objects to
@@ -14491,7 +14901,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, {
14491
14901
 
14492
14902
  @method slice
14493
14903
  @param {Integer} beginIndex (Optional) index to begin slicing from.
14494
- @param {Integer} endIndex (Optional) index to end the slice at.
14904
+ @param {Integer} endIndex (Optional) index to end the slice at (but not included).
14495
14905
  @return {Array} New array with specified slice
14496
14906
  */
14497
14907
  slice: function(beginIndex, endIndex) {
@@ -14642,7 +15052,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, {
14642
15052
  Becomes true whenever the array currently has observers watching changes
14643
15053
  on the array.
14644
15054
 
14645
- @property Boolean
15055
+ @property {Boolean} hasArrayObservers
14646
15056
  */
14647
15057
  hasArrayObservers: Ember.computed(function() {
14648
15058
  return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before');
@@ -14792,6 +15202,9 @@ var e_get = Ember.get,
14792
15202
  arrayBracketPattern = /\.\[\]$/;
14793
15203
 
14794
15204
 
15205
+ var expandProperties = Ember.expandProperties;
15206
+
15207
+
14795
15208
  function get(obj, key) {
14796
15209
  if (key === '@this') {
14797
15210
  return obj;
@@ -15286,6 +15699,7 @@ function ReduceComputedProperty(options) {
15286
15699
  }, this);
15287
15700
  };
15288
15701
 
15702
+
15289
15703
  this.func = function (propertyName) {
15290
15704
  Ember.assert("Computed reduce values require at least one dependent key", cp._dependentKeys);
15291
15705
 
@@ -15373,10 +15787,13 @@ ReduceComputedProperty.prototype.property = function () {
15373
15787
  dependentArrayKey = match[1];
15374
15788
 
15375
15789
 
15376
- itemPropertyKey = match[2];
15377
- cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
15378
-
15379
- propertyArgs.add(dependentArrayKey);
15790
+ var itemPropertyKeyPattern = match[2],
15791
+ addItemPropertyKey = function (itemPropertyKey) {
15792
+ cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
15793
+ };
15794
+
15795
+ expandProperties(itemPropertyKeyPattern, addItemPropertyKey);
15796
+ propertyArgs.add(dependentArrayKey);
15380
15797
  } else {
15381
15798
  propertyArgs.add(dependentKey);
15382
15799
  }
@@ -15486,7 +15903,7 @@ ReduceComputedProperty.prototype.property = function () {
15486
15903
 
15487
15904
  ```javascript
15488
15905
  Ember.computed.max = function (dependentKey) {
15489
- return Ember.reduceComputed.call(null, dependentKey, {
15906
+ return Ember.reduceComputed(dependentKey, {
15490
15907
  initialValue: -Infinity,
15491
15908
 
15492
15909
  addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
@@ -15795,6 +16212,30 @@ var get = Ember.get,
15795
16212
  map = Ember.EnumerableUtils.map,
15796
16213
  SearchProxy;
15797
16214
 
16215
+ /**
16216
+ A computed property that returns the sum of the value
16217
+ in the dependent array.
16218
+
16219
+ @method computed.sum
16220
+ @for Ember
16221
+ @param {String} dependentKey
16222
+ @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array
16223
+ */
16224
+
16225
+ Ember.computed.sum = function(dependentKey){
16226
+ return Ember.reduceComputed(dependentKey, {
16227
+ initialValue: 0,
16228
+
16229
+ addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){
16230
+ return accumulatedValue + item;
16231
+ },
16232
+
16233
+ removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){
16234
+ return accumulatedValue - item;
16235
+ }
16236
+ });
16237
+ };
16238
+
15798
16239
  /**
15799
16240
  A computed property that calculates the maximum value in the
15800
16241
  dependent array. This will return `-Infinity` when the dependent
@@ -15828,7 +16269,7 @@ var get = Ember.get,
15828
16269
  @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array
15829
16270
  */
15830
16271
  Ember.computed.max = function (dependentKey) {
15831
- return Ember.reduceComputed.call(null, dependentKey, {
16272
+ return Ember.reduceComputed(dependentKey, {
15832
16273
  initialValue: -Infinity,
15833
16274
 
15834
16275
  addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
@@ -15876,7 +16317,7 @@ Ember.computed.max = function (dependentKey) {
15876
16317
  @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array
15877
16318
  */
15878
16319
  Ember.computed.min = function (dependentKey) {
15879
- return Ember.reduceComputed.call(null, dependentKey, {
16320
+ return Ember.reduceComputed(dependentKey, {
15880
16321
  initialValue: Infinity,
15881
16322
 
15882
16323
  addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
@@ -16161,7 +16602,7 @@ Ember.computed.union = Ember.computed.uniq;
16161
16602
 
16162
16603
  /**
16163
16604
  A computed property which returns a new array with all the duplicated
16164
- elements from two or more dependeny arrays.
16605
+ elements from two or more dependent arrays.
16165
16606
 
16166
16607
  Example
16167
16608
 
@@ -16267,7 +16708,7 @@ Ember.computed.setDiff = function (setAProperty, setBProperty) {
16267
16708
  if (arguments.length !== 2) {
16268
16709
  throw new Ember.Error("setDiff requires exactly two dependent arrays.");
16269
16710
  }
16270
- return Ember.arrayComputed.call(null, setAProperty, setBProperty, {
16711
+ return Ember.arrayComputed(setAProperty, setBProperty, {
16271
16712
  addedItem: function (array, item, changeMeta, instanceMeta) {
16272
16713
  var setA = get(this, setAProperty),
16273
16714
  setB = get(this, setBProperty);
@@ -16469,7 +16910,7 @@ Ember.computed.sort = function (itemsKey, sortDefinition) {
16469
16910
  };
16470
16911
  }
16471
16912
 
16472
- return Ember.arrayComputed.call(null, itemsKey, {
16913
+ return Ember.arrayComputed(itemsKey, {
16473
16914
  initialize: initFn,
16474
16915
 
16475
16916
  addedItem: function (array, item, changeMeta, instanceMeta) {
@@ -16533,6 +16974,9 @@ Ember.RSVP.on('error', Ember.RSVP.onerrorDefault);
16533
16974
  var a_slice = Array.prototype.slice;
16534
16975
 
16535
16976
 
16977
+ var expandProperties = Ember.expandProperties;
16978
+
16979
+
16536
16980
  if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
16537
16981
 
16538
16982
  /**
@@ -16629,9 +17073,15 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
16629
17073
  */
16630
17074
  Function.prototype.observes = function() {
16631
17075
 
16632
- this.__ember_observes__ = a_slice.call(arguments);
16633
-
17076
+ var addWatchedProperty = function (obs) { watched.push(obs); };
17077
+ var watched = [];
17078
+
17079
+ for (var i=0; i<arguments.length; ++i) {
17080
+ expandProperties(arguments[i], addWatchedProperty);
17081
+ }
16634
17082
 
17083
+ this.__ember_observes__ = watched;
17084
+
16635
17085
  return this;
16636
17086
  };
16637
17087
 
@@ -16694,9 +17144,15 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
16694
17144
  */
16695
17145
  Function.prototype.observesBefore = function() {
16696
17146
 
16697
- this.__ember_observesBefore__ = a_slice.call(arguments);
16698
-
17147
+ var addWatchedProperty = function (obs) { watched.push(obs); };
17148
+ var watched = [];
17149
+
17150
+ for (var i=0; i<arguments.length; ++i) {
17151
+ expandProperties(arguments[i], addWatchedProperty);
17152
+ }
16699
17153
 
17154
+ this.__ember_observesBefore__ = watched;
17155
+
16700
17156
  return this;
16701
17157
  };
16702
17158
 
@@ -17899,6 +18355,8 @@ Ember.ActionHandler = Ember.Mixin.create({
17899
18355
  var hashName;
17900
18356
 
17901
18357
  if (!props._actions) {
18358
+ Ember.assert(this + " 'actions' should not be a function", typeof(props.actions) !== 'function');
18359
+
17902
18360
  if (typeOf(props.actions) === 'object') {
17903
18361
  hashName = 'actions';
17904
18362
  } else if (typeOf(props.events) === 'object') {
@@ -17945,8 +18403,6 @@ Ember.ActionHandler = Ember.Mixin.create({
17945
18403
 
17946
18404
  (function() {
17947
18405
  var set = Ember.set, get = Ember.get,
17948
- resolve = Ember.RSVP.resolve,
17949
- rethrow = Ember.RSVP.rethrow,
17950
18406
  not = Ember.computed.not,
17951
18407
  or = Ember.computed.or;
17952
18408
 
@@ -17955,14 +18411,15 @@ var set = Ember.set, get = Ember.get,
17955
18411
  @submodule ember-runtime
17956
18412
  */
17957
18413
 
17958
- function observePromise(proxy, promise) {
17959
- promise.then(function(value) {
18414
+ function tap(proxy, promise) {
18415
+ return promise.then(function(value) {
17960
18416
  set(proxy, 'isFulfilled', true);
17961
18417
  set(proxy, 'content', value);
18418
+ return value;
17962
18419
  }, function(reason) {
17963
18420
  set(proxy, 'isRejected', true);
17964
18421
  set(proxy, 'reason', reason);
17965
- // don't re-throw, as we are merely observing
18422
+ throw reason;
17966
18423
  }, "Ember: PromiseProxy");
17967
18424
  }
17968
18425
 
@@ -18091,9 +18548,7 @@ Ember.PromiseProxyMixin = Ember.Mixin.create({
18091
18548
  */
18092
18549
  promise: Ember.computed(function(key, promise) {
18093
18550
  if (arguments.length === 2) {
18094
- promise = resolve(promise);
18095
- observePromise(this, promise);
18096
- return promise.then(); // fork the promise.
18551
+ return tap(this, promise);
18097
18552
  } else {
18098
18553
  throw new Ember.Error("PromiseProxy's promise must be set");
18099
18554
  }