embient 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,7 +42,7 @@ Ember.RouteManager = Ember.StateManager.extend({
42
42
 
43
43
  You will also need to make sure that baseURI is properly configured, as
44
44
  well as your server so that your routes are properly pointing to your
45
- SproutCore application.
45
+ Ember application.
46
46
 
47
47
  @see http://dev.w3.org/html5/spec/history.html#the-history-interface
48
48
  @property
@@ -193,13 +193,12 @@ Ember.RouteManager = Ember.StateManager.extend({
193
193
  },
194
194
 
195
195
  /**
196
- You usually don't need to call this method. It is done automatically after
197
- the application has been initialized.
198
-
199
- It registers for the hashchange event if available. If not, it creates a
196
+ Start this routemanager.
197
+
198
+ Registers for the hashchange event if available. If not, it creates a
200
199
  timer that looks for location changes every 150ms.
201
200
  */
202
- ping: function() {
201
+ start: function() {
203
202
  if(!this._didSetup) {
204
203
  this._didSetup = true;
205
204
  var state;
@@ -250,8 +249,11 @@ Ember.RouteManager = Ember.StateManager.extend({
250
249
  }
251
250
  }
252
251
  },
253
-
254
- destroy: function() {
252
+
253
+ /**
254
+ Stop this routemanager
255
+ */
256
+ stop: function() {
255
257
  if(this._didSetup) {
256
258
  if(get(this, 'wantsHistory') && supportsHistory) {
257
259
  jQuery(window).unbind('popstate', this.popState);
@@ -262,19 +264,13 @@ Ember.RouteManager = Ember.StateManager.extend({
262
264
  clearTimeout(this._timerId);
263
265
  }
264
266
  }
267
+ this._didSetup = false;
265
268
  }
266
- this._super();
267
269
  },
268
270
 
269
- /**
270
- Ember.RouteManager currently automatically starts listening
271
- for browser location changes when created.
272
- */
273
- init: function() {
271
+ destroy: function() {
272
+ this.stop();
274
273
  this._super();
275
- if(!this._didSetup) {
276
- this.ping();
277
- }
278
274
  },
279
275
 
280
276
  /**
@@ -1,4 +1,4 @@
1
- (function(exports) {
1
+ (function() {
2
2
  /*global __fail__*/
3
3
  /**
4
4
  Define an assertion that will throw an exception if the condition is not
@@ -31,7 +31,7 @@
31
31
  will be executed. If the function returns false an exception will be
32
32
  thrown.
33
33
  */
34
- window.ember_assert = window.sc_assert = function ember_assert(desc, test) {
34
+ window.ember_assert = function ember_assert(desc, test) {
35
35
  if ('function' === typeof test) test = test()!==false;
36
36
  if (!test) throw new Error("assertion failed: "+desc);
37
37
  };
@@ -126,9 +126,9 @@ window.ember_deprecateFunc = function(message, func) {
126
126
  };
127
127
  };
128
128
 
129
- })({});
129
+ })();
130
130
 
131
- (function(exports) {
131
+ (function() {
132
132
  // lib/handlebars/base.js
133
133
  var Handlebars = {};
134
134
 
@@ -367,7 +367,7 @@ parse: function parse(input) {
367
367
 
368
368
  var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
369
369
  while (true) {
370
- // retreive state number from top of stack
370
+ // retrieve state number from top of stack
371
371
  state = stack[stack.length-1];
372
372
 
373
373
  // use default actions if available
@@ -1723,9 +1723,9 @@ Handlebars.template = Handlebars.VM.template;
1723
1723
  ;
1724
1724
 
1725
1725
 
1726
- })({});
1726
+ })();
1727
1727
 
1728
- (function(exports) {
1728
+ (function() {
1729
1729
  // ==========================================================================
1730
1730
  // Project: Ember Metal
1731
1731
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -1737,7 +1737,7 @@ if ('undefined' === typeof Ember) {
1737
1737
  /**
1738
1738
  @namespace
1739
1739
  @name Ember
1740
- @version 0.9.5
1740
+ @version 0.9.6
1741
1741
 
1742
1742
  All Ember methods and functions are defined inside of this namespace.
1743
1743
  You generally should not add new properties to this namespace as it may be
@@ -1769,10 +1769,10 @@ if ('undefined' !== typeof window) {
1769
1769
  /**
1770
1770
  @static
1771
1771
  @type String
1772
- @default '0.9.5'
1772
+ @default '0.9.6'
1773
1773
  @constant
1774
1774
  */
1775
- Ember.VERSION = '0.9.5';
1775
+ Ember.VERSION = '0.9.6';
1776
1776
 
1777
1777
  /**
1778
1778
  @static
@@ -1861,9 +1861,11 @@ if ('undefined' === typeof ember_deprecateFunc) {
1861
1861
  */
1862
1862
  Ember.Logger = window.console || { log: Ember.K, warn: Ember.K, error: Ember.K };
1863
1863
 
1864
- })({});
1864
+ })();
1865
+
1866
+
1865
1867
 
1866
- (function(exports) {
1868
+ (function() {
1867
1869
  // ==========================================================================
1868
1870
  // Project: Ember Metal
1869
1871
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -2015,9 +2017,11 @@ if (!platform.defineProperty) {
2015
2017
  platform.defineProperty.isSimulated = true;
2016
2018
  }
2017
2019
 
2018
- })({});
2020
+ })();
2021
+
2022
+
2019
2023
 
2020
- (function(exports) {
2024
+ (function() {
2021
2025
  // ==========================================================================
2022
2026
  // Project: Ember Metal
2023
2027
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -2318,8 +2322,6 @@ Ember.wrap = function(func, superFunc) {
2318
2322
  };
2319
2323
 
2320
2324
  /**
2321
- @function
2322
-
2323
2325
  Returns true if the passed object is an array or Array-like.
2324
2326
 
2325
2327
  Ember Array Protocol:
@@ -2331,6 +2333,11 @@ Ember.wrap = function(func, superFunc) {
2331
2333
  Unlike Ember.typeOf this method returns true even if the passed object is
2332
2334
  not formally array but appears to be array-like (i.e. implements Ember.Array)
2333
2335
 
2336
+ Ember.isArray(); // false
2337
+ Ember.isArray([]); // true
2338
+ Ember.isArray( Ember.ArrayProxy.create({ content: [] }) ); // true
2339
+
2340
+ @name Ember.isArray
2334
2341
  @param {Object} obj The object to test
2335
2342
  @returns {Boolean}
2336
2343
  */
@@ -2347,6 +2354,15 @@ Ember.isArray = function(obj) {
2347
2354
  an array or array-like, returns the object. Otherwise adds the object to
2348
2355
  an array. If obj is null or undefined, returns an empty array.
2349
2356
 
2357
+ Ember.makeArray(); => []
2358
+ Ember.makeArray(null); => []
2359
+ Ember.makeArray(undefined); => []
2360
+ Ember.makeArray('lindsay'); => ['lindsay']
2361
+ Ember.makeArray([1,2,42]); => [1,2,42]
2362
+
2363
+ var controller = Ember.ArrayProxy.create({ content: [] });
2364
+ Ember.makeArray(controller) === controller; => true
2365
+
2350
2366
  @param {Object} obj the object
2351
2367
  @returns {Array}
2352
2368
  */
@@ -2357,9 +2373,11 @@ Ember.makeArray = function(obj) {
2357
2373
 
2358
2374
 
2359
2375
 
2360
- })({});
2376
+ })();
2377
+
2378
+
2361
2379
 
2362
- (function(exports) {
2380
+ (function() {
2363
2381
  // ==========================================================================
2364
2382
  // Project: Ember Metal
2365
2383
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -2746,9 +2764,11 @@ Ember.isGlobalPath = function(path) {
2746
2764
  return !HAS_THIS.test(path) && IS_GLOBAL.test(path);
2747
2765
  };
2748
2766
 
2749
- })({});
2767
+ })();
2768
+
2750
2769
 
2751
- (function(exports) {
2770
+
2771
+ (function() {
2752
2772
  // ==========================================================================
2753
2773
  // Project: Ember Metal
2754
2774
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -3108,7 +3128,7 @@ Ember.defineProperty = function(obj, keyName, desc, val) {
3108
3128
  that support it, this uses the built in Object.create method. Else one is
3109
3129
  simulated for you.
3110
3130
 
3111
- This method is a better choice thant Object.create() because it will make
3131
+ This method is a better choice than Object.create() because it will make
3112
3132
  sure that any observers, event listeners, and computed properties are
3113
3133
  inherited from the parent as well.
3114
3134
 
@@ -3157,9 +3177,11 @@ Ember.createPrototype = function(obj, props) {
3157
3177
  return ret;
3158
3178
  };
3159
3179
 
3160
- })({});
3180
+ })();
3181
+
3161
3182
 
3162
- (function(exports) {
3183
+
3184
+ (function() {
3163
3185
  // ==========================================================================
3164
3186
  // Project: Ember Metal
3165
3187
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -3499,9 +3521,30 @@ Ember.computed = function(func) {
3499
3521
  return cp;
3500
3522
  };
3501
3523
 
3502
- })({});
3524
+ /**
3525
+ Returns the cached value for a property, if one exists.
3526
+ This can be useful for peeking at the value of a computed
3527
+ property that is generated lazily, without accidentally causing
3528
+ it to be created.
3529
+
3530
+ @param {Object} obj the object whose property you want to check
3531
+ @param {String} key the name of the property whose cached value you want
3532
+ to return
3533
+
3534
+ */
3535
+ Ember.cacheFor = function(obj, key) {
3536
+ var cache = meta(obj, false).cache;
3537
+
3538
+ if (cache && cache[key]) {
3539
+ return cache[key];
3540
+ }
3541
+ };
3542
+
3543
+ })();
3544
+
3503
3545
 
3504
- (function(exports) {
3546
+
3547
+ (function() {
3505
3548
  /*jshint newcap:false*/
3506
3549
 
3507
3550
  // NOTE: There is a bug in jshint that doesn't recognize `Object()` without `new`
@@ -3592,6 +3635,13 @@ Ember.ArrayUtils = {
3592
3635
  return obj.indexOf ? obj.indexOf.apply(obj, args) : arrayIndexOf.apply(obj, args);
3593
3636
  },
3594
3637
 
3638
+ indexesOf: function(obj) {
3639
+ var args = Array.prototype.slice.call(arguments, 1);
3640
+ return args[0] === undefined ? [] : Ember.ArrayUtils.map(args[0], function(item) {
3641
+ return Ember.ArrayUtils.indexOf(obj, item);
3642
+ });
3643
+ },
3644
+
3595
3645
  removeObject: function(array, item) {
3596
3646
  var index = this.indexOf(array, item);
3597
3647
  if (index !== -1) { array.splice(index, 1); }
@@ -3616,9 +3666,11 @@ if (Ember.SHIM_ES5) {
3616
3666
  }
3617
3667
  }
3618
3668
 
3619
- })({});
3669
+ })();
3670
+
3620
3671
 
3621
- (function(exports) {
3672
+
3673
+ (function() {
3622
3674
  // ==========================================================================
3623
3675
  // Project: Ember Metal
3624
3676
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -3870,9 +3922,11 @@ Ember.notifyBeforeObservers = function(obj, keyName) {
3870
3922
  };
3871
3923
 
3872
3924
 
3873
- })({});
3925
+ })();
3926
+
3927
+
3874
3928
 
3875
- (function(exports) {
3929
+ (function() {
3876
3930
  // ==========================================================================
3877
3931
  // Project: Ember Metal
3878
3932
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -4482,9 +4536,11 @@ Ember.destroy = function (obj) {
4482
4536
  }
4483
4537
  };
4484
4538
 
4485
- })({});
4539
+ })();
4540
+
4486
4541
 
4487
- (function(exports) {
4542
+
4543
+ (function() {
4488
4544
  // ==========================================================================
4489
4545
  // Project: Ember Metal
4490
4546
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -4698,6 +4754,7 @@ function sendEvent(obj, eventName) {
4698
4754
  return true;
4699
4755
  }
4700
4756
 
4757
+ /** @memberOf Ember */
4701
4758
  function deferEvent(obj, eventName) {
4702
4759
  var targetSet = targetSetFor(obj, eventName), actions = [], params = arguments;
4703
4760
  iterateSet(targetSet, function (action) {
@@ -4746,9 +4803,11 @@ Ember.hasListeners = hasListeners;
4746
4803
  Ember.watchedEvents = watchedEvents;
4747
4804
  Ember.listenersFor = listenersFor;
4748
4805
  Ember.deferEvent = deferEvent;
4749
- })({});
4806
+ })();
4750
4807
 
4751
- (function(exports) {
4808
+
4809
+
4810
+ (function() {
4752
4811
  // ==========================================================================
4753
4812
  // Project: Ember Runtime
4754
4813
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -5179,14 +5238,17 @@ function findNamespaces() {
5179
5238
  // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
5180
5239
  // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
5181
5240
  if (prop === "globalStorage" && window.StorageList && window.globalStorage instanceof window.StorageList) { continue; }
5182
- // Don't access properties on parent window, which will throw "Access/Permission Denied" in IE/Firefox for windows on different domains
5183
- if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "content") { continue; }
5184
5241
  // Unfortunately, some versions of IE don't support window.hasOwnProperty
5185
5242
  if (window.hasOwnProperty && !window.hasOwnProperty(prop)) { continue; }
5186
5243
 
5187
- obj = window[prop];
5244
+ try {
5245
+ obj = window[prop];
5246
+ } catch (e) {
5247
+ continue;
5248
+ }
5188
5249
 
5189
5250
  if (obj && get(obj, 'isNamespace')) {
5251
+ ember_deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop));
5190
5252
  obj[NAME_KEY] = prop;
5191
5253
  }
5192
5254
  }
@@ -5305,9 +5367,11 @@ Ember.beforeObserver = function(func) {
5305
5367
 
5306
5368
 
5307
5369
 
5308
- })({});
5370
+ })();
5371
+
5372
+
5309
5373
 
5310
- (function(exports) {
5374
+ (function() {
5311
5375
  // ==========================================================================
5312
5376
  // Project: Ember Runtime
5313
5377
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -5425,7 +5489,7 @@ RunLoop.prototype = {
5425
5489
  while (this._queues && (queue = this._queues[queueName])) {
5426
5490
  this._queues[queueName] = null;
5427
5491
 
5428
- // the sync phase is to allow property changes to propogate. don't
5492
+ // the sync phase is to allow property changes to propagate. don't
5429
5493
  // invoke observers until that is finished.
5430
5494
  if (queueName === 'sync') {
5431
5495
  log = Ember.LOG_BINDINGS;
@@ -5455,7 +5519,7 @@ RunLoop.prototype = {
5455
5519
  queue = queues[queueName];
5456
5520
 
5457
5521
  if (queue) {
5458
- // the sync phase is to allow property changes to propogate. don't
5522
+ // the sync phase is to allow property changes to propagate. don't
5459
5523
  // invoke observers until that is finished.
5460
5524
  if (queueName === 'sync') {
5461
5525
  log = Ember.LOG_BINDINGS;
@@ -5489,9 +5553,14 @@ Ember.RunLoop = RunLoop;
5489
5553
  // ..........................................................
5490
5554
  // Ember.run - this is ideally the only public API the dev sees
5491
5555
  //
5556
+ /**
5557
+ * @namespace Ember.run is both a function and a namespace for
5558
+ * RunLoop-related functions.
5559
+ * @name Ember.run
5560
+ */
5492
5561
 
5493
5562
  /**
5494
- Runs the passed target and method inside of a runloop, ensuring any
5563
+ Runs the passed target and method inside of a RunLoop, ensuring any
5495
5564
  deferred actions including bindings and views updates are flushed at the
5496
5565
  end.
5497
5566
 
@@ -5500,7 +5569,12 @@ Ember.RunLoop = RunLoop;
5500
5569
  libraries or plugins, you should probably wrap all of your code inside this
5501
5570
  call.
5502
5571
 
5503
- @function
5572
+ Ember.run(function(){
5573
+ // code to be execute within a RunLoop
5574
+ });
5575
+
5576
+ @name run^2
5577
+ @methodOf Ember.run
5504
5578
  @param {Object} target
5505
5579
  (Optional) target of method to call
5506
5580
 
@@ -5534,6 +5608,11 @@ var run = Ember.run;
5534
5608
  be buffered until you invoke a matching call to Ember.run.end(). This is
5535
5609
  an lower-level way to use a RunLoop instead of using Ember.run().
5536
5610
 
5611
+ Ember.run.begin();
5612
+ // code to be execute within a RunLoop
5613
+ Ember.run.end();
5614
+
5615
+
5537
5616
  @returns {void}
5538
5617
  */
5539
5618
  Ember.run.begin = function() {
@@ -5545,6 +5624,10 @@ Ember.run.begin = function() {
5545
5624
  to flush any deferred actions. This is a lower-level way to use a RunLoop
5546
5625
  instead of using Ember.run().
5547
5626
 
5627
+ Ember.run.begin();
5628
+ // code to be execute within a RunLoop
5629
+ Ember.run.end();
5630
+
5548
5631
  @returns {void}
5549
5632
  */
5550
5633
  Ember.run.end = function() {
@@ -5564,6 +5647,7 @@ Ember.run.end = function() {
5564
5647
  to inspect or modify this property.
5565
5648
 
5566
5649
  @property {String}
5650
+ @default ['sync', 'actions', 'destroy', 'timers']
5567
5651
  */
5568
5652
  Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
5569
5653
 
@@ -5577,6 +5661,18 @@ Ember.run.queues = ['sync', 'actions', 'destroy', 'timers'];
5577
5661
  Methods will be invoked in an order matching the named queues defined in
5578
5662
  the run.queues property.
5579
5663
 
5664
+ Ember.run.schedule('timers', this, function(){
5665
+ // this will be executed at the end of the RunLoop, when timers are run
5666
+ console.log("scheduled on timers queue");
5667
+ });
5668
+ Ember.run.schedule('sync', this, function(){
5669
+ // this will be executed at the end of the RunLoop, when bindings are synced
5670
+ console.log("scheduled on sync queue");
5671
+ });
5672
+ // Note the functions will be run in order based on the run queues order. Output would be:
5673
+ // scheduled on sync queue
5674
+ // scheduled on timers queue
5675
+
5580
5676
  @param {String} queue
5581
5677
  The name of the queue to schedule against. Default queues are 'sync' and
5582
5678
  'actions'
@@ -5613,6 +5709,8 @@ function autorun() {
5613
5709
  ensure the RunLoop always finishes. You normally do not need to call this
5614
5710
  method directly. Instead use Ember.run().
5615
5711
 
5712
+ Ember.run.autorun();
5713
+
5616
5714
  @returns {Ember.RunLoop} the new current RunLoop
5617
5715
  */
5618
5716
  Ember.run.autorun = function() {
@@ -5636,9 +5734,11 @@ Ember.run.autorun = function() {
5636
5734
  use this queue so this method is a useful way to immediately force all
5637
5735
  bindings in the application to sync.
5638
5736
 
5639
- You should call this method anytime you need any changed state to propogate
5737
+ You should call this method anytime you need any changed state to propagate
5640
5738
  throughout the app immediately without repainting the UI.
5641
5739
 
5740
+ Ember.run.sync();
5741
+
5642
5742
  @returns {void}
5643
5743
  */
5644
5744
  Ember.run.sync = function() {
@@ -5679,10 +5779,14 @@ function invokeLaterTimers() {
5679
5779
  of milliseconds.
5680
5780
 
5681
5781
  You should use this method whenever you need to run some action after a
5682
- period of time inside of using setTimeout(). This method will ensure that
5782
+ period of time instead of using setTimeout(). This method will ensure that
5683
5783
  items that expire during the same script execution cycle all execute
5684
5784
  together, which is often more efficient than using a real setTimeout.
5685
5785
 
5786
+ Ember.run.later(myContext, function(){
5787
+ // code here will execute within a RunLoop in about 500ms with this == myContext
5788
+ }, 500);
5789
+
5686
5790
  @param {Object} target
5687
5791
  (optional) target of method to invoke
5688
5792
 
@@ -5736,6 +5840,13 @@ function invokeOnceTimer(guid, onceTimers) {
5736
5840
  considered when looking for duplicates. New arguments will replace previous
5737
5841
  calls.
5738
5842
 
5843
+ Ember.run(function(){
5844
+ var doFoo = function() { foo(); }
5845
+ Ember.run.once(myContext, doFoo);
5846
+ Ember.run.once(myContext, doFoo);
5847
+ // doFoo will only be executed once at the end of the RunLoop
5848
+ });
5849
+
5739
5850
  @param {Object} target
5740
5851
  (optional) target of method to invoke
5741
5852
 
@@ -5795,6 +5906,10 @@ function invokeNextTimers() {
5795
5906
  Schedules an item to run after control has been returned to the system.
5796
5907
  This is often equivalent to calling setTimeout(function...,1).
5797
5908
 
5909
+ Ember.run.next(myContext, function(){
5910
+ // code to be executed in the next RunLoop, which will be scheduled after the current one
5911
+ });
5912
+
5798
5913
  @param {Object} target
5799
5914
  (optional) target of method to invoke
5800
5915
 
@@ -5828,6 +5943,21 @@ Ember.run.next = function(target, method) {
5828
5943
  Cancels a scheduled item. Must be a value returned by `Ember.run.later()`,
5829
5944
  `Ember.run.once()`, or `Ember.run.next()`.
5830
5945
 
5946
+ var runNext = Ember.run.next(myContext, function(){
5947
+ // will not be executed
5948
+ });
5949
+ Ember.run.cancel(runNext);
5950
+
5951
+ var runLater = Ember.run.next(myContext, function(){
5952
+ // will not be executed
5953
+ }, 500);
5954
+ Ember.run.cancel(runLater);
5955
+
5956
+ var runOnce = Ember.run.once(myContext, function(){
5957
+ // will not be executed
5958
+ });
5959
+ Ember.run.cancel(runOnce);
5960
+
5831
5961
  @param {Object} timer
5832
5962
  Timer object to cancel
5833
5963
 
@@ -5842,10 +5972,9 @@ Ember.run.cancel = function(timer) {
5842
5972
  //
5843
5973
 
5844
5974
  /**
5845
- @namespace
5975
+ @namespace Compatibility for Ember.run
5846
5976
  @name Ember.RunLoop
5847
5977
  @deprecated
5848
- @description Compatibility for Ember.run
5849
5978
  */
5850
5979
 
5851
5980
  /**
@@ -5866,9 +5995,11 @@ Ember.RunLoop.end = ember_deprecateFunc("Use Ember.run.end instead of Ember.RunL
5866
5995
 
5867
5996
 
5868
5997
 
5869
- })({});
5998
+ })();
5999
+
6000
+
5870
6001
 
5871
- (function(exports) {
6002
+ (function() {
5872
6003
  // ==========================================================================
5873
6004
  // Project: Ember Runtime
5874
6005
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -6097,7 +6228,7 @@ Binding.prototype = /** @scope Ember.Binding.prototype */ {
6097
6228
 
6098
6229
  /**
6099
6230
  This will set the "to" property path to the specified value. It will not
6100
- attempt to reoslve this property path to an actual object until you
6231
+ attempt to resolve this property path to an actual object until you
6101
6232
  connect the binding.
6102
6233
 
6103
6234
  The binding will search for the property path starting at the root object
@@ -6470,9 +6601,9 @@ mixinProperties(Binding,
6470
6601
  /**
6471
6602
  @see Ember.Binding.prototype.single
6472
6603
  */
6473
- single: function(from) {
6604
+ single: function(from, placeholder) {
6474
6605
  var C = this, binding = new C(null, from);
6475
- return binding.single();
6606
+ return binding.single(placeholder);
6476
6607
  },
6477
6608
 
6478
6609
  /**
@@ -6486,8 +6617,12 @@ mixinProperties(Binding,
6486
6617
  /**
6487
6618
  @see Ember.Binding.prototype.transform
6488
6619
  */
6489
- transform: function(func) {
6490
- var C = this, binding = new C();
6620
+ transform: function(from, func) {
6621
+ if (!func) {
6622
+ func = from;
6623
+ from = null;
6624
+ }
6625
+ var C = this, binding = new C(null, from);
6491
6626
  return binding.transform(func);
6492
6627
  },
6493
6628
 
@@ -6499,6 +6634,15 @@ mixinProperties(Binding,
6499
6634
  return binding.notEmpty(placeholder);
6500
6635
  },
6501
6636
 
6637
+ /**
6638
+ @see Ember.Binding.prototype.notNull
6639
+ */
6640
+ notNull: function(from, placeholder) {
6641
+ var C = this, binding = new C(null, from);
6642
+ return binding.notNull(placeholder);
6643
+ },
6644
+
6645
+
6502
6646
  /**
6503
6647
  @see Ember.Binding.prototype.bool
6504
6648
  */
@@ -6515,6 +6659,14 @@ mixinProperties(Binding,
6515
6659
  return binding.not();
6516
6660
  },
6517
6661
 
6662
+ /**
6663
+ @see Ember.Binding.prototype.isNull
6664
+ */
6665
+ isNull: function(from) {
6666
+ var C = this, binding = new C(null, from);
6667
+ return binding.isNull();
6668
+ },
6669
+
6518
6670
  /**
6519
6671
  Adds a transform that forwards the logical 'AND' of values at 'pathA' and
6520
6672
  'pathB' whenever either source changes. Note that the transform acts
@@ -6756,18 +6908,20 @@ Ember.oneWay = function(obj, to, from) {
6756
6908
  return new Ember.Binding(to, from).oneWay().connect(obj);
6757
6909
  };
6758
6910
 
6759
- })({});
6911
+ })();
6912
+
6760
6913
 
6761
- (function(exports) {
6914
+
6915
+ (function() {
6762
6916
  // ==========================================================================
6763
6917
  // Project: Ember Metal
6764
6918
  // Copyright: ©2011 Strobe Inc. and contributors.
6765
6919
  // License: Licensed under MIT license (see license.js)
6766
6920
  // ==========================================================================
6767
6921
 
6768
- })({});
6922
+ })();
6769
6923
 
6770
- (function(exports) {
6924
+ (function() {
6771
6925
  /**
6772
6926
  * @license
6773
6927
  * ==========================================================================
@@ -6798,9 +6952,11 @@ Ember.oneWay = function(obj, to, from) {
6798
6952
  * ==========================================================================
6799
6953
  */
6800
6954
 
6801
- })({});
6955
+ })();
6956
+
6802
6957
 
6803
- (function(exports) {
6958
+
6959
+ (function() {
6804
6960
  // ==========================================================================
6805
6961
  // Project: Ember Runtime
6806
6962
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -6839,18 +6995,36 @@ var toString = Object.prototype.toString;
6839
6995
  It will return the same result across all browsers and includes a bit
6840
6996
  more detail. Here is what will be returned:
6841
6997
 
6842
- | Return Value Constant | Meaning |
6843
- | 'string' | String primitive |
6844
- | 'number' | Number primitive |
6845
- | 'boolean' | Boolean primitive |
6846
- | 'null' | Null value |
6847
- | 'undefined' | Undefined value |
6848
- | 'function' | A function |
6849
- | 'array' | An instance of Array |
6850
- | 'class' | A Ember class (created using Ember.Object.extend()) |
6851
- | 'instance' | A Ember object instance |
6852
- | 'error' | An instance of the Error object |
6853
- | 'object' | A JavaScript object not inheriting from Ember.Object |
6998
+ | Return Value | Meaning |
6999
+ |---------------|------------------------------------------------------|
7000
+ | 'string' | String primitive |
7001
+ | 'number' | Number primitive |
7002
+ | 'boolean' | Boolean primitive |
7003
+ | 'null' | Null value |
7004
+ | 'undefined' | Undefined value |
7005
+ | 'function' | A function |
7006
+ | 'array' | An instance of Array |
7007
+ | 'class' | A Ember class (created using Ember.Object.extend()) |
7008
+ | 'instance' | A Ember object instance |
7009
+ | 'error' | An instance of the Error object |
7010
+ | 'object' | A JavaScript object not inheriting from Ember.Object |
7011
+
7012
+ Examples:
7013
+
7014
+ Ember.typeOf(); => 'undefined'
7015
+ Ember.typeOf(null); => 'null'
7016
+ Ember.typeOf(undefined); => 'undefined'
7017
+ Ember.typeOf('michael'); => 'string'
7018
+ Ember.typeOf(101); => 'number'
7019
+ Ember.typeOf(true); => 'boolean'
7020
+ Ember.typeOf(Ember.makeArray); => 'function'
7021
+ Ember.typeOf([1,2,90]); => 'array'
7022
+ Ember.typeOf(Ember.Object.extend()); => 'class'
7023
+ Ember.typeOf(Ember.Object.create()); => 'instance'
7024
+ Ember.typeOf(new Error('teamocil')); => 'error'
7025
+
7026
+ // "normal" JavaScript object
7027
+ Ember.typeOf({a: 'b'}); => 'object'
6854
7028
 
6855
7029
  @param item {Object} the item to check
6856
7030
  @returns {String} the type
@@ -6876,6 +7050,13 @@ Ember.typeOf = function(item) {
6876
7050
  from JSLint complaining about use of ==, which can be technically
6877
7051
  confusing.
6878
7052
 
7053
+ Ember.none(); => true
7054
+ Ember.none(null); => true
7055
+ Ember.none(undefined); => true
7056
+ Ember.none(''); => false
7057
+ Ember.none([]); => false
7058
+ Ember.none(function(){}); => false
7059
+
6879
7060
  @param {Object} obj Value to test
6880
7061
  @returns {Boolean}
6881
7062
  */
@@ -6886,6 +7067,17 @@ Ember.none = function(obj) {
6886
7067
  /**
6887
7068
  Verifies that a value is null or an empty string | array | function.
6888
7069
 
7070
+ Constrains the rules on `Ember.none` by returning false for empty
7071
+ string and empty arrays.
7072
+
7073
+ Ember.empty(); => true
7074
+ Ember.empty(null); => true
7075
+ Ember.empty(undefined); => true
7076
+ Ember.empty(''); => true
7077
+ Ember.empty([]); => true
7078
+ Ember.empty('tobias fünke'); => false
7079
+ Ember.empty([0,1,2]); => false
7080
+
6889
7081
  @param {Object} obj Value to test
6890
7082
  @returns {Boolean}
6891
7083
  */
@@ -6893,10 +7085,6 @@ Ember.empty = function(obj) {
6893
7085
  return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function');
6894
7086
  };
6895
7087
 
6896
- /**
6897
- Ember.isArray defined in ember-metal/lib/utils
6898
- **/
6899
-
6900
7088
  /**
6901
7089
  This will compare two javascript values of possibly different types.
6902
7090
  It will tell you which one is greater than the other by returning:
@@ -6908,6 +7096,10 @@ Ember.empty = function(obj) {
6908
7096
  The order is calculated based on Ember.ORDER_DEFINITION, if types are different.
6909
7097
  In case they have the same type an appropriate comparison for this type is made.
6910
7098
 
7099
+ Ember.compare('hello', 'hello'); => 0
7100
+ Ember.compare('abc', 'dfg'); => -1
7101
+ Ember.compare(2, 1); => 1
7102
+
6911
7103
  @param {Object} v First value to compare
6912
7104
  @param {Object} w Second value to compare
6913
7105
  @returns {Number} -1 if v < w, 0 if v = w and 1 if v > w.
@@ -7077,6 +7269,10 @@ Ember.inspect = function(obj) {
7077
7269
  internal objects. For any other object that implements `isEqual()` it will
7078
7270
  respect that method.
7079
7271
 
7272
+ Ember.isEqual('hello', 'hello'); => true
7273
+ Ember.isEqual(1, 2); => false
7274
+ Ember.isEqual([4,2], [4,2]); => false
7275
+
7080
7276
  @param {Object} a first object to compare
7081
7277
  @param {Object} b second object to compare
7082
7278
  @returns {Boolean}
@@ -7144,9 +7340,11 @@ Ember.Error = function() {
7144
7340
 
7145
7341
  Ember.Error.prototype = Ember.create(Error.prototype);
7146
7342
 
7147
- })({});
7343
+ })();
7344
+
7148
7345
 
7149
- (function(exports) {
7346
+
7347
+ (function() {
7150
7348
  // ==========================================================================
7151
7349
  // Project: Ember Runtime
7152
7350
  // Copyright: ©2011 Strobe Inc.
@@ -7339,9 +7537,11 @@ Ember.String = {
7339
7537
  replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase();
7340
7538
  }
7341
7539
  };
7342
- })({});
7540
+ })();
7541
+
7343
7542
 
7344
- (function(exports) {
7543
+
7544
+ (function() {
7345
7545
  // ==========================================================================
7346
7546
  // Project: Ember Runtime
7347
7547
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -7410,9 +7610,11 @@ if (Ember.EXTEND_PROTOTYPES) {
7410
7610
  }
7411
7611
 
7412
7612
 
7413
- })({});
7613
+ })();
7614
+
7414
7615
 
7415
- (function(exports) {
7616
+
7617
+ (function() {
7416
7618
  // ==========================================================================
7417
7619
  // Project: Ember Runtime
7418
7620
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -7520,9 +7722,11 @@ if (Ember.EXTEND_PROTOTYPES) {
7520
7722
  }
7521
7723
 
7522
7724
 
7523
- })({});
7725
+ })();
7726
+
7524
7727
 
7525
- (function(exports) {
7728
+
7729
+ (function() {
7526
7730
  // ==========================================================================
7527
7731
  // Project: Ember Runtime
7528
7732
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -7556,18 +7760,22 @@ Ember._mixinBindings = function(obj, key, value, m) {
7556
7760
  return value;
7557
7761
  };
7558
7762
 
7559
- })({});
7763
+ })();
7764
+
7560
7765
 
7561
- (function(exports) {
7766
+
7767
+ (function() {
7562
7768
  // ==========================================================================
7563
7769
  // Project: Ember Runtime
7564
7770
  // Copyright: ©2011 Strobe Inc. and contributors.
7565
7771
  // License: Licensed under MIT license (see license.js)
7566
7772
  // ==========================================================================
7567
7773
 
7568
- })({});
7774
+ })();
7775
+
7569
7776
 
7570
- (function(exports) {
7777
+
7778
+ (function() {
7571
7779
  // ==========================================================================
7572
7780
  // Project: Ember Runtime
7573
7781
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -7679,7 +7887,7 @@ Ember.Enumerable = Ember.Mixin.create( /** @lends Ember.Enumerable */ {
7679
7887
  reaches the your current length-1. If you run out of data before this
7680
7888
  time for some reason, you should simply return undefined.
7681
7889
 
7682
- The default impementation of this method simply looks up the index.
7890
+ The default implementation of this method simply looks up the index.
7683
7891
  This works great on any Array-like objects.
7684
7892
 
7685
7893
  @param index {Number} the current index of the iteration
@@ -8304,7 +8512,7 @@ Ember.Enumerable = Ember.Mixin.create( /** @lends Ember.Enumerable */ {
8304
8512
 
8305
8513
  @param {Enumerable} removes
8306
8514
  optional enumerable containing items that were removed from the set.
8307
- For ordered enumerables, this hsould be an ordered array of items. If
8515
+ For ordered enumerables, this should be an ordered array of items. If
8308
8516
  no items were removed you can pass null.
8309
8517
 
8310
8518
  @returns {Object} receiver
@@ -8336,9 +8544,11 @@ Ember.Enumerable = Ember.Mixin.create( /** @lends Ember.Enumerable */ {
8336
8544
 
8337
8545
 
8338
8546
 
8339
- })({});
8547
+ })();
8548
+
8340
8549
 
8341
- (function(exports) {
8550
+
8551
+ (function() {
8342
8552
  // ==========================================================================
8343
8553
  // Project: Ember Runtime
8344
8554
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -8346,9 +8556,9 @@ Ember.Enumerable = Ember.Mixin.create( /** @lends Ember.Enumerable */ {
8346
8556
  // ==========================================================================
8347
8557
  // ..........................................................
8348
8558
  // HELPERS
8349
- //
8559
+ //
8350
8560
 
8351
- var get = Ember.get, set = Ember.set, meta = Ember.meta;
8561
+ var get = Ember.get, set = Ember.set, meta = Ember.meta, map = Ember.ArrayUtils.map;
8352
8562
 
8353
8563
  /** @private */
8354
8564
  function none(obj) { return obj===null || obj===undefined; }
@@ -8360,7 +8570,7 @@ function xform(target, method, params) {
8360
8570
 
8361
8571
  // ..........................................................
8362
8572
  // ARRAY
8363
- //
8573
+ //
8364
8574
  /**
8365
8575
  @namespace
8366
8576
 
@@ -8397,7 +8607,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8397
8607
 
8398
8608
  /** @private - compatibility */
8399
8609
  isSCArray: true,
8400
-
8610
+
8401
8611
  /**
8402
8612
  @field {Number} length
8403
8613
 
@@ -8421,11 +8631,22 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8421
8631
  return get(this, idx);
8422
8632
  },
8423
8633
 
8634
+ /**
8635
+ This returns the objects at the specified indexes, using objectAt.
8636
+
8637
+ @param {Array} indexes
8638
+ An array of indexes of items to return.
8639
+ */
8640
+ objectsAt: function(indexes) {
8641
+ var self = this;
8642
+ return map(indexes, function(idx){ return self.objectAt(idx); });
8643
+ },
8644
+
8424
8645
  /** @private (nodoc) - overrides Ember.Enumerable version */
8425
8646
  nextObject: function(idx) {
8426
8647
  return this.objectAt(idx);
8427
8648
  },
8428
-
8649
+
8429
8650
  /**
8430
8651
  @field []
8431
8652
 
@@ -8474,21 +8695,20 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8474
8695
  /**
8475
8696
  Returns the index of the given object's first occurrence.
8476
8697
  If no startAt argument is given, the starting location to
8477
- search is 0. If it's negative, will count backward from
8698
+ search is 0. If it's negative, will count backward from
8478
8699
  the end of the array. Returns -1 if no match is found.
8479
8700
 
8701
+ var arr = ["a", "b", "c", "d", "a"];
8702
+ arr.indexOf("a"); => 0
8703
+ arr.indexOf("z"); => -1
8704
+ arr.indexOf("a", 2); => 4
8705
+ arr.indexOf("a", -1); => 4
8706
+ arr.indexOf("b", 3); => -1
8707
+ arr.indexOf("a", 100); => -1
8708
+
8480
8709
  @param {Object} object the item to search for
8481
8710
  @param {Number} startAt optional starting location to search, default 0
8482
8711
  @returns {Number} index or -1 if not found
8483
-
8484
- @example
8485
- var arr = ["a", "b", "c", "d", "a"];
8486
- arr.indexOf("a"); => 0
8487
- arr.indexOf("z"); => -1
8488
- arr.indexOf("a", 2); => 4
8489
- arr.indexOf("a", -1); => 4
8490
- arr.indexOf("b", 3); => -1
8491
- arr.indexOf("a", 100); => -1
8492
8712
  */
8493
8713
  indexOf: function(object, startAt) {
8494
8714
  var idx, len = get(this, 'length');
@@ -8505,21 +8725,20 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8505
8725
  /**
8506
8726
  Returns the index of the given object's last occurrence.
8507
8727
  If no startAt argument is given, the search starts from
8508
- the last position. If it's negative, will count backward
8728
+ the last position. If it's negative, will count backward
8509
8729
  from the end of the array. Returns -1 if no match is found.
8510
8730
 
8731
+ var arr = ["a", "b", "c", "d", "a"];
8732
+ arr.lastIndexOf("a"); => 4
8733
+ arr.lastIndexOf("z"); => -1
8734
+ arr.lastIndexOf("a", 2); => 0
8735
+ arr.lastIndexOf("a", -1); => 4
8736
+ arr.lastIndexOf("b", 3); => 1
8737
+ arr.lastIndexOf("a", 100); => 4
8738
+
8511
8739
  @param {Object} object the item to search for
8512
8740
  @param {Number} startAt optional starting location to search, default 0
8513
8741
  @returns {Number} index or -1 if not found
8514
-
8515
- @example
8516
- var arr = ["a", "b", "c", "d", "a"];
8517
- arr.lastIndexOf("a"); => 4
8518
- arr.lastIndexOf("z"); => -1
8519
- arr.lastIndexOf("a", 2); => 0
8520
- arr.lastIndexOf("a", -1); => 4
8521
- arr.lastIndexOf("b", 3); => 1
8522
- arr.lastIndexOf("a", 100); => 4
8523
8742
  */
8524
8743
  lastIndexOf: function(object, startAt) {
8525
8744
  var idx, len = get(this, 'length');
@@ -8532,36 +8751,36 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8532
8751
  }
8533
8752
  return -1;
8534
8753
  },
8535
-
8754
+
8536
8755
  // ..........................................................
8537
8756
  // ARRAY OBSERVERS
8538
- //
8539
-
8757
+ //
8758
+
8540
8759
  /**
8541
8760
  Adds an array observer to the receiving array. The array observer object
8542
8761
  normally must implement two methods:
8543
-
8762
+
8544
8763
  * `arrayWillChange(start, removeCount, addCount)` - This method will be
8545
8764
  called just before the array is modified.
8546
8765
  * `arrayDidChange(start, removeCount, addCount)` - This method will be
8547
8766
  called just after the array is modified.
8548
-
8549
- Both callbacks will be passed the starting index of the change as well a
8767
+
8768
+ Both callbacks will be passed the starting index of the change as well a
8550
8769
  a count of the items to be removed and added. You can use these callbacks
8551
- to optionally inspect the array during the change, clear caches, or do
8770
+ to optionally inspect the array during the change, clear caches, or do
8552
8771
  any other bookkeeping necessary.
8553
-
8554
- In addition to passing a target, you can also include an options hash
8772
+
8773
+ In addition to passing a target, you can also include an options hash
8555
8774
  which you can use to override the method names that will be invoked on the
8556
8775
  target.
8557
-
8776
+
8558
8777
  @param {Object} target
8559
8778
  The observer object.
8560
-
8779
+
8561
8780
  @param {Hash} opts
8562
8781
  Optional hash of configuration options including willChange, didChange,
8563
8782
  and a context option.
8564
-
8783
+
8565
8784
  @returns {Ember.Array} receiver
8566
8785
  */
8567
8786
  addArrayObserver: function(target, opts) {
@@ -8575,15 +8794,15 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8575
8794
  if (!hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
8576
8795
  return this;
8577
8796
  },
8578
-
8797
+
8579
8798
  /**
8580
- Removes an array observer from the object if the observer is current
8799
+ Removes an array observer from the object if the observer is current
8581
8800
  registered. Calling this method multiple times with the same object will
8582
8801
  have no effect.
8583
-
8802
+
8584
8803
  @param {Object} target
8585
8804
  The object observing the array.
8586
-
8805
+
8587
8806
  @returns {Ember.Array} receiver
8588
8807
  */
8589
8808
  removeArrayObserver: function(target, opts) {
@@ -8597,32 +8816,32 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8597
8816
  if (hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers');
8598
8817
  return this;
8599
8818
  },
8600
-
8819
+
8601
8820
  /**
8602
8821
  Becomes true whenever the array currently has observers watching changes
8603
8822
  on the array.
8604
-
8823
+
8605
8824
  @property {Boolean}
8606
8825
  */
8607
8826
  hasArrayObservers: Ember.computed(function() {
8608
8827
  return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before');
8609
8828
  }).property().cacheable(),
8610
-
8829
+
8611
8830
  /**
8612
- If you are implementing an object that supports Ember.Array, call this
8831
+ If you are implementing an object that supports Ember.Array, call this
8613
8832
  method just before the array content changes to notify any observers and
8614
8833
  invalidate any related properties. Pass the starting index of the change
8615
8834
  as well as a delta of the amounts to change.
8616
-
8835
+
8617
8836
  @param {Number} startIdx
8618
8837
  The starting index in the array that will change.
8619
-
8838
+
8620
8839
  @param {Number} removeAmt
8621
8840
  The number of items that will be removed. If you pass null assumes 0
8622
-
8841
+
8623
8842
  @param {Number} addAmt
8624
8843
  The number of items that will be added. If you pass null assumes 0.
8625
-
8844
+
8626
8845
  @returns {Ember.Array} receiver
8627
8846
  */
8628
8847
  arrayContentWillChange: function(startIdx, removeAmt, addAmt) {
@@ -8646,14 +8865,14 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8646
8865
  } else {
8647
8866
  removing = removeAmt;
8648
8867
  }
8649
-
8868
+
8650
8869
  this.enumerableContentWillChange(removing, addAmt);
8651
8870
 
8652
8871
  // Make sure the @each proxy is set up if anyone is observing @each
8653
8872
  if (Ember.isWatching(this, '@each')) { get(this, '@each'); }
8654
8873
  return this;
8655
8874
  },
8656
-
8875
+
8657
8876
  arrayContentDidChange: function(startIdx, removeAmt, addAmt) {
8658
8877
 
8659
8878
  // if no args are passed assume everything changes
@@ -8664,7 +8883,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8664
8883
  if (!removeAmt) removeAmt=0;
8665
8884
  if (!addAmt) addAmt=0;
8666
8885
  }
8667
-
8886
+
8668
8887
  var adding, lim;
8669
8888
  if (startIdx>=0 && addAmt>=0 && get(this, 'hasEnumerableObservers')) {
8670
8889
  adding = [];
@@ -8678,15 +8897,15 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8678
8897
  Ember.sendEvent(this, '@array:change', startIdx, removeAmt, addAmt);
8679
8898
  return this;
8680
8899
  },
8681
-
8900
+
8682
8901
  // ..........................................................
8683
8902
  // ENUMERATED PROPERTIES
8684
- //
8685
-
8903
+ //
8904
+
8686
8905
  /**
8687
8906
  Returns a special object that can be used to observe individual properties
8688
8907
  on the array. Just get an equivalent property on this object and it will
8689
- return an enumerable that maps automatically to the named key on the
8908
+ return an enumerable that maps automatically to the named key on the
8690
8909
  member objects.
8691
8910
  */
8692
8911
  '@each': Ember.computed(function() {
@@ -8701,9 +8920,11 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8701
8920
 
8702
8921
 
8703
8922
 
8704
- })({});
8923
+ })();
8924
+
8705
8925
 
8706
- (function(exports) {
8926
+
8927
+ (function() {
8707
8928
  // ==========================================================================
8708
8929
  // Project: Ember Runtime
8709
8930
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -8750,9 +8971,11 @@ Ember.Comparable = Ember.Mixin.create( /** @scope Ember.Comparable.prototype */{
8750
8971
  });
8751
8972
 
8752
8973
 
8753
- })({});
8974
+ })();
8975
+
8754
8976
 
8755
- (function(exports) {
8977
+
8978
+ (function() {
8756
8979
  // ==========================================================================
8757
8980
  // Project: Ember Runtime
8758
8981
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -8812,9 +9035,11 @@ Ember.Copyable = Ember.Mixin.create(
8812
9035
 
8813
9036
 
8814
9037
 
8815
- })({});
9038
+ })();
9039
+
8816
9040
 
8817
- (function(exports) {
9041
+
9042
+ (function() {
8818
9043
  // ==========================================================================
8819
9044
  // Project: Ember Runtime
8820
9045
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -8899,7 +9124,7 @@ Ember.Freezable = Ember.Mixin.create(
8899
9124
  Freezes the object. Once this method has been called the object should
8900
9125
  no longer allow any properties to be edited.
8901
9126
 
8902
- @returns {Object} reciever
9127
+ @returns {Object} receiver
8903
9128
  */
8904
9129
  freeze: function() {
8905
9130
  if (get(this, 'isFrozen')) return this;
@@ -8914,9 +9139,11 @@ Ember.FROZEN_ERROR = "Frozen object cannot be modified.";
8914
9139
 
8915
9140
 
8916
9141
 
8917
- })({});
9142
+ })();
9143
+
9144
+
8918
9145
 
8919
- (function(exports) {
9146
+ (function() {
8920
9147
  // ==========================================================================
8921
9148
  // Project: Ember Runtime
8922
9149
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -8941,7 +9168,6 @@ var forEach = Ember.ArrayUtils.forEach;
8941
9168
  method will only add the object to the enumerable if the object is not
8942
9169
  already present and the object if of a type supported by the enumerable.
8943
9170
 
8944
- javascript:
8945
9171
  set.addObject(contact);
8946
9172
 
8947
9173
  ## Removing Objects
@@ -8950,7 +9176,6 @@ var forEach = Ember.ArrayUtils.forEach;
8950
9176
  will only remove the object if it is already in the enumerable, otherwise
8951
9177
  this method has no effect.
8952
9178
 
8953
- javascript:
8954
9179
  set.removeObject(contact);
8955
9180
 
8956
9181
  ## Implementing In Your Own Code
@@ -9028,9 +9253,11 @@ Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable,
9028
9253
 
9029
9254
  });
9030
9255
 
9031
- })({});
9256
+ })();
9257
+
9258
+
9032
9259
 
9033
- (function(exports) {
9260
+ (function() {
9034
9261
  // ==========================================================================
9035
9262
  // Project: Ember Runtime
9036
9263
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -9056,8 +9283,8 @@ var get = Ember.get, set = Ember.set, forEach = Ember.ArrayUtils.forEach;
9056
9283
  can be applied only to a collection that keeps its items in an ordered set.
9057
9284
 
9058
9285
  Note that an Array can change even if it does not implement this mixin.
9059
- For example, a SparyArray may not be directly modified but if its
9060
- underlying enumerable changes, it will change also.
9286
+ For example, one might implement a SparseArray that cannot be directly
9287
+ modified, but if its underlying enumerable changes, it will change also.
9061
9288
 
9062
9289
  @extends Ember.Mixin
9063
9290
  @extends Ember.Array
@@ -9069,7 +9296,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
9069
9296
  /**
9070
9297
  __Required.__ You must implement this method to apply this mixin.
9071
9298
 
9072
- This is one of the primitves you must implement to support Ember.Array. You
9299
+ This is one of the primitives you must implement to support Ember.Array. You
9073
9300
  should replace amt objects started at idx with the objects in the passed
9074
9301
  array. You should also call this.enumerableContentDidChange() ;
9075
9302
 
@@ -9087,6 +9314,24 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
9087
9314
  */
9088
9315
  replace: Ember.required(),
9089
9316
 
9317
+ /**
9318
+ Remove all elements from self. This is useful if you
9319
+ want to reuse an existing array without having to recreate it.
9320
+
9321
+ var colors = ["red", "green", "blue"];
9322
+ color.length(); => 3
9323
+ colors.clear(); => []
9324
+ colors.length(); => 0
9325
+
9326
+ @returns {Ember.Array} An empty Array.
9327
+ */
9328
+ clear: function () {
9329
+ var len = get(this, 'length');
9330
+ if (len === 0) return this;
9331
+ this.replace(0, len, EMPTY);
9332
+ return this;
9333
+ },
9334
+
9090
9335
  /**
9091
9336
  This will use the primitive replace() method to insert an object at the
9092
9337
  specified index.
@@ -9257,9 +9502,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
9257
9502
  });
9258
9503
 
9259
9504
 
9260
- })({});
9505
+ })();
9506
+
9507
+
9261
9508
 
9262
- (function(exports) {
9509
+ (function() {
9263
9510
  // ==========================================================================
9264
9511
  // Project: Ember Runtime
9265
9512
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -9371,17 +9618,25 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9371
9618
 
9372
9619
  /**
9373
9620
  To get multiple properties at once, call getProperties
9374
- with a list of strings:
9621
+ with a list of strings or an array:
9375
9622
 
9376
9623
  record.getProperties('firstName', 'lastName', 'zipCode'); // => { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
9377
9624
 
9378
- @param {String...} list of keys to get
9379
- @returns {Hash}
9625
+ is equivalent to:
9626
+
9627
+ record.getProperties(['firstName', 'lastName', 'zipCode']); // => { firstName: 'John', lastName: 'Doe', zipCode: '10011' }
9628
+
9629
+ @param {String...|Array} list of keys to get
9630
+ @returns {Hash}
9380
9631
  */
9381
9632
  getProperties: function() {
9382
9633
  var ret = {};
9383
- for(var i = 0; i < arguments.length; i++) {
9384
- ret[arguments[i]] = get(this, arguments[i]);
9634
+ var propertyNames = arguments;
9635
+ if (arguments.length === 1 && Ember.typeOf(arguments[0]) === 'array') {
9636
+ propertyNames = arguments[0];
9637
+ }
9638
+ for(var i = 0; i < propertyNames.length; i++) {
9639
+ ret[propertyNames[i]] = get(this, propertyNames[i]);
9385
9640
  }
9386
9641
  return ret;
9387
9642
  },
@@ -9407,7 +9662,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9407
9662
  If you try to set a value on a key that is undefined in the target
9408
9663
  object, then the unknownProperty() handler will be called instead. This
9409
9664
  gives you an opportunity to implement complex "virtual" properties that
9410
- are not predefined on the obejct. If unknownProperty() returns
9665
+ are not predefined on the object. If unknownProperty() returns
9411
9666
  undefined, then set() will simply set the value on the object.
9412
9667
 
9413
9668
  ### Property Observers
@@ -9418,7 +9673,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9418
9673
  observers (i.e. observer methods declared on the same object), will be
9419
9674
  called immediately. Any "remote" observers (i.e. observer methods
9420
9675
  declared on another object) will be placed in a queue and called at a
9421
- later time in a coelesced manner.
9676
+ later time in a coalesced manner.
9422
9677
 
9423
9678
  ### Chaining
9424
9679
 
@@ -9593,7 +9848,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9593
9848
  @param {String} key The key to observer
9594
9849
  @param {Object} target The target object to invoke
9595
9850
  @param {String|Function} method The method to invoke.
9596
- @returns {Ember.Observable} reciever
9851
+ @returns {Ember.Observable} receiver
9597
9852
  */
9598
9853
  removeObserver: function(key, target, method) {
9599
9854
  Ember.removeObserver(this, key, target, method);
@@ -9730,19 +9985,33 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9730
9985
  return get(this, keyName);
9731
9986
  },
9732
9987
 
9988
+ /**
9989
+ Returns the cached value of a computed property, if it exists.
9990
+ This allows you to inspect the value of a computed property
9991
+ without accidentally invoking it if it is intended to be
9992
+ generated lazily.
9993
+
9994
+ @param {String} keyName
9995
+ @returns {Object} The cached value of the computed property, if any
9996
+ */
9997
+ cacheFor: function(keyName) {
9998
+ return Ember.cacheFor(this, keyName);
9999
+ },
10000
+
9733
10001
  /** @private - intended for debugging purposes */
9734
10002
  observersForKey: function(keyName) {
9735
10003
  return Ember.observersFor(this, keyName);
9736
10004
  }
9737
-
9738
10005
  });
9739
10006
 
9740
10007
 
9741
10008
 
9742
10009
 
9743
- })({});
10010
+ })();
10011
+
10012
+
9744
10013
 
9745
- (function(exports) {
10014
+ (function() {
9746
10015
  var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
9747
10016
 
9748
10017
  Ember.TargetActionSupport = Ember.Mixin.create({
@@ -9786,9 +10055,11 @@ Ember.TargetActionSupport = Ember.Mixin.create({
9786
10055
  }
9787
10056
  });
9788
10057
 
9789
- })({});
10058
+ })();
10059
+
9790
10060
 
9791
- (function(exports) {
10061
+
10062
+ (function() {
9792
10063
  var get = Ember.get, set = Ember.set, a_slice = Array.prototype.slice;
9793
10064
 
9794
10065
  /** @private */
@@ -9816,18 +10087,22 @@ Ember.Evented = Ember.Mixin.create({
9816
10087
  }
9817
10088
  });
9818
10089
 
9819
- })({});
10090
+ })();
10091
+
9820
10092
 
9821
- (function(exports) {
10093
+
10094
+ (function() {
9822
10095
  // ==========================================================================
9823
10096
  // Project: Ember Runtime
9824
10097
  // Copyright: ©2011 Strobe Inc. and contributors.
9825
10098
  // License: Licensed under MIT license (see license.js)
9826
10099
  // ==========================================================================
9827
10100
 
9828
- })({});
10101
+ })();
10102
+
9829
10103
 
9830
- (function(exports) {
10104
+
10105
+ (function() {
9831
10106
  // ==========================================================================
9832
10107
  // Project: Ember Runtime
9833
10108
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -9856,18 +10131,9 @@ function makeCtor() {
9856
10131
  // method a lot faster. This is glue code so we want it to be as fast as
9857
10132
  // possible.
9858
10133
 
9859
- var wasApplied = false, initMixins, defaults, init = false, hasChains = false;
10134
+ var wasApplied = false, initMixins, init = false, hasChains = false;
9860
10135
 
9861
10136
  var Class = function() {
9862
- if (defaults) {
9863
- for (var prop in defaults) {
9864
- if (!defaults.hasOwnProperty(prop)) { continue; }
9865
- Ember.defineProperty(this, prop, undefined, defaults[prop]);
9866
- }
9867
-
9868
- defaults = null;
9869
- }
9870
-
9871
10137
  if (!wasApplied) { Class.proto(); } // prepare prototype...
9872
10138
  if (initMixins) {
9873
10139
  this.reopen.apply(this, initMixins);
@@ -9897,7 +10163,6 @@ function makeCtor() {
9897
10163
  wasApplied = false;
9898
10164
  };
9899
10165
  Class._initMixins = function(args) { initMixins = args; };
9900
- Class._setDefaults = function(arg) { defaults = arg; };
9901
10166
 
9902
10167
  Class.proto = function() {
9903
10168
  var superclass = Class.superclass;
@@ -9929,9 +10194,13 @@ CoreObject.PrototypeMixin = Ember.Mixin.create(
9929
10194
 
9930
10195
  isInstance: true,
9931
10196
 
10197
+ /** @private */
9932
10198
  init: function() {},
9933
10199
 
10200
+ /** @field */
9934
10201
  isDestroyed: false,
10202
+
10203
+ /** @field */
9935
10204
  isDestroying: false,
9936
10205
 
9937
10206
  /**
@@ -10025,30 +10294,6 @@ var ClassMixin = Ember.Mixin.create({
10025
10294
  return new C();
10026
10295
  },
10027
10296
 
10028
- /**
10029
- @private
10030
-
10031
- Right now, when a key is passed in `create` that is not already
10032
- present in the superclass, we need to create a mixin object and
10033
- apply the mixin to the object we're creating. This is
10034
- unnecessarily expensive. Because Ember views are created a lot,
10035
- this is a temporary convenience that will allow us to create
10036
- a new object and set properties before `init` time.
10037
-
10038
- The correct solution is for the default init code to detect
10039
- properties that do not need special handling and call
10040
- `setProperties` on them when `create` occurs. This will
10041
- massively speed up `create` calls that do not need any special
10042
- Ember features (like bindings, observers or computed properties)
10043
- and are not overriding a computed property with a regular value.
10044
- */
10045
- createWith: function(defaults) {
10046
- var C = this;
10047
- if (arguments.length>0) { this._initMixins(a_slice.call(arguments, 1)); }
10048
- if (defaults) { this._setDefaults(defaults); }
10049
- return new C();
10050
- },
10051
-
10052
10297
  reopen: function() {
10053
10298
  this.willReopen();
10054
10299
  var PrototypeMixin = this.PrototypeMixin;
@@ -10135,9 +10380,11 @@ Ember.CoreObject = CoreObject;
10135
10380
 
10136
10381
 
10137
10382
 
10138
- })({});
10383
+ })();
10384
+
10385
+
10139
10386
 
10140
- (function(exports) {
10387
+ (function() {
10141
10388
  // ==========================================================================
10142
10389
  // Project: Ember Runtime
10143
10390
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -10274,7 +10521,13 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
10274
10521
  clear: function() {
10275
10522
  if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
10276
10523
  var len = get(this, 'length');
10524
+ var guid;
10277
10525
  this.enumerableContentWillChange(len, 0);
10526
+ for (var i=0; i < len; i++){
10527
+ guid = guidFor(this[i]);
10528
+ delete this[guid];
10529
+ delete this[i];
10530
+ }
10278
10531
  set(this, 'length', 0);
10279
10532
  this.enumerableContentDidChange(len, 0);
10280
10533
  return this;
@@ -10574,9 +10827,11 @@ Ember.Set.create = function(items) {
10574
10827
  }
10575
10828
  };
10576
10829
 
10577
- })({});
10830
+ })();
10831
+
10832
+
10578
10833
 
10579
- (function(exports) {
10834
+ (function() {
10580
10835
  // ==========================================================================
10581
10836
  // Project: Ember Runtime
10582
10837
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -10594,9 +10849,11 @@ Ember.Object = Ember.CoreObject.extend(Ember.Observable);
10594
10849
 
10595
10850
 
10596
10851
 
10597
- })({});
10852
+ })();
10853
+
10854
+
10598
10855
 
10599
- (function(exports) {
10856
+ (function() {
10600
10857
  // ==========================================================================
10601
10858
  // Project: Ember Runtime
10602
10859
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -10641,9 +10898,11 @@ Ember.Namespace = Ember.Object.extend({
10641
10898
  Ember.Namespace.NAMESPACES = [Ember];
10642
10899
  Ember.Namespace.PROCESSED = false;
10643
10900
 
10644
- })({});
10901
+ })();
10902
+
10903
+
10645
10904
 
10646
- (function(exports) {
10905
+ (function() {
10647
10906
  // ==========================================================================
10648
10907
  // Project: Ember Runtime
10649
10908
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -10675,9 +10934,11 @@ Ember.Namespace.PROCESSED = false;
10675
10934
  Ember.Application = Ember.Namespace.extend();
10676
10935
 
10677
10936
 
10678
- })({});
10937
+ })();
10938
+
10939
+
10679
10940
 
10680
- (function(exports) {
10941
+ (function() {
10681
10942
  // ==========================================================================
10682
10943
  // Project: Ember Runtime
10683
10944
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -10738,7 +10999,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
10738
10999
  This method will only be called if content is non-null.
10739
11000
 
10740
11001
  @param {Number} idx
10741
- The index to retreive.
11002
+ The index to retrieve.
10742
11003
 
10743
11004
  @returns {Object} the value or undefined if none found
10744
11005
  */
@@ -10828,9 +11089,11 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
10828
11089
 
10829
11090
 
10830
11091
 
10831
- })({});
11092
+ })();
11093
+
11094
+
10832
11095
 
10833
- (function(exports) {
11096
+ (function() {
10834
11097
  // ==========================================================================
10835
11098
  // Project: Ember Runtime
10836
11099
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -11031,9 +11294,11 @@ Ember.EachProxy = Ember.Object.extend({
11031
11294
 
11032
11295
 
11033
11296
 
11034
- })({});
11297
+ })();
11298
+
11299
+
11035
11300
 
11036
- (function(exports) {
11301
+ (function() {
11037
11302
  // ==========================================================================
11038
11303
  // Project: Ember Runtime
11039
11304
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -11177,9 +11442,11 @@ if (Ember.EXTEND_PROTOTYPES) Ember.NativeArray.activate();
11177
11442
 
11178
11443
 
11179
11444
 
11180
- })({});
11445
+ })();
11446
+
11447
+
11181
11448
 
11182
- (function(exports) {
11449
+ (function() {
11183
11450
  /**
11184
11451
  JavaScript (before ES6) does not have a Map implementation. Objects,
11185
11452
  which are often used as dictionaries, may only have Strings as keys.
@@ -11378,20 +11645,24 @@ Map.prototype = {
11378
11645
  }
11379
11646
  };
11380
11647
 
11381
- })({});
11648
+ })();
11649
+
11650
+
11382
11651
 
11383
- (function(exports) {
11652
+ (function() {
11384
11653
  // ==========================================================================
11385
11654
  // Project: Ember Runtime
11386
11655
  // Copyright: ©2011 Strobe Inc. and contributors.
11387
11656
  // License: Licensed under MIT license (see license.js)
11388
11657
  // ==========================================================================
11389
11658
 
11390
- })({});
11659
+ })();
11660
+
11661
+
11391
11662
 
11392
- (function(exports) {
11663
+ (function() {
11393
11664
  // ==========================================================================
11394
- // Project: Ember Metal
11665
+ // Project: Ember Runtime
11395
11666
  // Copyright: ©2011 Strobe Inc. and contributors.
11396
11667
  // License: Licensed under MIT license (see license.js)
11397
11668
  // ==========================================================================
@@ -11436,22 +11707,26 @@ Map.prototype = {
11436
11707
 
11437
11708
  Ember.ArrayController = Ember.ArrayProxy.extend();
11438
11709
 
11439
- })({});
11710
+ })();
11711
+
11712
+
11713
+
11714
+ (function() {
11715
+
11716
+ })();
11440
11717
 
11441
- (function(exports) {
11442
11718
 
11443
- })({});
11444
11719
 
11445
- (function(exports) {
11720
+ (function() {
11446
11721
  // ==========================================================================
11447
11722
  // Project: Ember Runtime
11448
11723
  // Copyright: ©2011 Strobe Inc. and contributors.
11449
11724
  // License: Licensed under MIT license (see license.js)
11450
11725
  // ==========================================================================
11451
11726
 
11452
- })({});
11727
+ })();
11453
11728
 
11454
- (function(exports) {
11729
+ (function() {
11455
11730
  // ==========================================================================
11456
11731
  // Project: Ember - JavaScript Application Framework
11457
11732
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -11459,12 +11734,14 @@ Ember.ArrayController = Ember.ArrayProxy.extend();
11459
11734
  // License: Licensed under MIT license (see license.js)
11460
11735
  // ==========================================================================
11461
11736
 
11462
- ember_assert("Ember requires jQuery 1.6 or 1.7", window.jQuery && window.jQuery().jquery.match(/^1\.[67](.\d+)?$/));
11737
+ ember_assert("Ember requires jQuery 1.6 or 1.7", window.jQuery && window.jQuery().jquery.match(/^1\.[67](\.\d+)?(pre|rc\d?)?/));
11463
11738
  Ember.$ = window.jQuery;
11464
11739
 
11465
- })({});
11740
+ })();
11741
+
11742
+
11466
11743
 
11467
- (function(exports) {
11744
+ (function() {
11468
11745
  // ==========================================================================
11469
11746
  // Project: Ember - JavaScript Application Framework
11470
11747
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -11476,6 +11753,7 @@ var get = Ember.get, set = Ember.set;
11476
11753
  var forEach = Ember.ArrayUtils.forEach;
11477
11754
  var indexOf = Ember.ArrayUtils.indexOf;
11478
11755
 
11756
+ /** @private */
11479
11757
  var ClassSet = function() {
11480
11758
  this.seen = {};
11481
11759
  this.list = [];
@@ -11813,13 +12091,13 @@ Ember._RenderBuffer.prototype =
11813
12091
 
11814
12092
  openTag = ["<" + tag];
11815
12093
 
11816
- if (id) { openTag.push('id="' + id + '"'); }
11817
- if (classes) { openTag.push('class="' + classes.toDOM() + '"'); }
12094
+ if (id) { openTag.push('id="' + this._escapeAttribute(id) + '"'); }
12095
+ if (classes) { openTag.push('class="' + this._escapeAttribute(classes.toDOM()) + '"'); }
11818
12096
 
11819
12097
  if (style) {
11820
12098
  for (prop in style) {
11821
12099
  if (style.hasOwnProperty(prop)) {
11822
- styleBuffer += (prop + ':' + style[prop] + ';');
12100
+ styleBuffer += (prop + ':' + this._escapeAttribute(style[prop]) + ';');
11823
12101
  }
11824
12102
  }
11825
12103
 
@@ -11829,7 +12107,7 @@ Ember._RenderBuffer.prototype =
11829
12107
  if (attrs) {
11830
12108
  for (prop in attrs) {
11831
12109
  if (attrs.hasOwnProperty(prop)) {
11832
- openTag.push(prop + '="' + attrs[prop] + '"');
12110
+ openTag.push(prop + '="' + this._escapeAttribute(attrs[prop]) + '"');
11833
12111
  }
11834
12112
  }
11835
12113
  }
@@ -11849,13 +12127,24 @@ Ember._RenderBuffer.prototype =
11849
12127
  } else {
11850
12128
  return content;
11851
12129
  }
12130
+ },
12131
+
12132
+ _escapeAttribute: function(string) {
12133
+ // Escaping only double quotes is probably sufficient, but it can't hurt to do a few more
12134
+ return string.replace(/&/g, '&amp;')
12135
+ .replace(/</g, '&lt;')
12136
+ .replace(/>/g, '&gt;')
12137
+ .replace(/'/g, '&#x27;')
12138
+ .replace(/"/g, '&quot;');
11852
12139
  }
11853
12140
 
11854
12141
  };
11855
12142
 
11856
- })({});
12143
+ })();
12144
+
11857
12145
 
11858
- (function(exports) {
12146
+
12147
+ (function() {
11859
12148
  // ==========================================================================
11860
12149
  // Project: Ember - JavaScript Application Framework
11861
12150
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -12046,9 +12335,11 @@ Ember.EventDispatcher = Ember.Object.extend(
12046
12335
  }
12047
12336
  });
12048
12337
 
12049
- })({});
12338
+ })();
12339
+
12050
12340
 
12051
- (function(exports) {
12341
+
12342
+ (function() {
12052
12343
  // ==========================================================================
12053
12344
  // Project: Ember - JavaScript Application Framework
12054
12345
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -12081,7 +12372,6 @@ var get = Ember.get, set = Ember.set;
12081
12372
  You only need to specify the root if your page contains multiple instances
12082
12373
  of Ember.Application.
12083
12374
 
12084
- @since Ember 2.0
12085
12375
  @extends Ember.Object
12086
12376
  */
12087
12377
  Ember.Application = Ember.Namespace.extend(
@@ -12157,9 +12447,11 @@ Ember.Application = Ember.Namespace.extend(
12157
12447
 
12158
12448
 
12159
12449
 
12160
- })({});
12450
+ })();
12451
+
12161
12452
 
12162
- (function(exports) {
12453
+
12454
+ (function() {
12163
12455
  // ==========================================================================
12164
12456
  // Project: Ember - JavaScript Application Framework
12165
12457
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -12172,9 +12464,11 @@ Ember.Application = Ember.Namespace.extend(
12172
12464
  var queues = Ember.run.queues;
12173
12465
  queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render');
12174
12466
 
12175
- })({});
12467
+ })();
12468
+
12176
12469
 
12177
- (function(exports) {
12470
+
12471
+ (function() {
12178
12472
  // ==========================================================================
12179
12473
  // Project: Ember - JavaScript Application Framework
12180
12474
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -12182,9 +12476,11 @@ queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render');
12182
12476
  // License: Licensed under MIT license (see license.js)
12183
12477
  // ==========================================================================
12184
12478
 
12185
- })({});
12479
+ })();
12480
+
12186
12481
 
12187
- (function(exports) {
12482
+
12483
+ (function() {
12188
12484
  // ==========================================================================
12189
12485
  // Project: Ember - JavaScript Application Framework
12190
12486
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -12306,9 +12602,17 @@ Ember.View = Ember.Object.extend(Ember.Evented,
12306
12602
  return template || get(this, 'defaultTemplate');
12307
12603
  }).property('templateName').cacheable(),
12308
12604
 
12605
+ /**
12606
+ The controller managing this view. If this property is set, it will be made
12607
+ made available for use by the template.
12608
+
12609
+ @type Object
12610
+ */
12611
+ controller: null,
12612
+
12309
12613
  /**
12310
12614
  A view may contain a layout. A layout is a regular template but
12311
- supercedes the `template` property during rendering. It is the
12615
+ supersedes the `template` property during rendering. It is the
12312
12616
  responsibility of the layout template to retrieve the `template`
12313
12617
  property from the view and render it in the correct location.
12314
12618
 
@@ -12353,9 +12657,39 @@ Ember.View = Ember.Object.extend(Ember.Evented,
12353
12657
  @type Object
12354
12658
  */
12355
12659
  templateContext: Ember.computed(function(key, value) {
12356
- return value !== undefined ? value : this;
12660
+ if (arguments.length === 2) {
12661
+ set(this, '_templateContext', value);
12662
+ return value;
12663
+ } else {
12664
+ return get(this, '_templateContext');
12665
+ }
12357
12666
  }).cacheable(),
12358
12667
 
12668
+ /**
12669
+ @private
12670
+
12671
+ Private copy of the view's template context. This can be set directly
12672
+ by Handlebars without triggering the observer that causes the view
12673
+ to be re-rendered.
12674
+ */
12675
+ _templateContext: Ember.computed(function(key, value) {
12676
+ if (arguments.length === 2) {
12677
+ return value;
12678
+ } else {
12679
+ return this;
12680
+ }
12681
+ }).cacheable(),
12682
+
12683
+ /**
12684
+ If a value that affects template rendering changes, the view should be
12685
+ re-rendered to reflect the new value.
12686
+
12687
+ @private
12688
+ */
12689
+ _displayPropertyDidChange: Ember.observer(function() {
12690
+ this.rerender();
12691
+ }, 'templateContext', 'controller'),
12692
+
12359
12693
  /**
12360
12694
  If the view is currently inserted into the DOM of a parent view, this
12361
12695
  property will point to the parent of the view.
@@ -12511,8 +12845,23 @@ Ember.View = Ember.Object.extend(Ember.Evented,
12511
12845
  var template = get(this, 'layout') || get(this, 'template');
12512
12846
 
12513
12847
  if (template) {
12514
- var context = get(this, 'templateContext'),
12515
- data = { view: this, buffer: buffer, isRenderData: true };
12848
+ var context = get(this, '_templateContext'),
12849
+ templateData = this.get('templateData'),
12850
+ controller = this.get('controller');
12851
+
12852
+ var data = {
12853
+ view: this,
12854
+ buffer: buffer,
12855
+ isRenderData: true,
12856
+ keywords: {
12857
+ view: get(this, 'concreteView')
12858
+ }
12859
+ };
12860
+
12861
+ // If the view has a controller specified, make it available to the
12862
+ // template. If not, pass along the parent template's controller,
12863
+ // if it exists.
12864
+ data.keywords.controller = controller || (templateData && templateData.keywords.controller);
12516
12865
 
12517
12866
  // Invoke the template with the provided template context, which
12518
12867
  // is the view by default. A hash of data is also passed that provides
@@ -13479,11 +13828,14 @@ Ember.View = Ember.Object.extend(Ember.Evented,
13479
13828
  @test in createChildViews
13480
13829
  */
13481
13830
  createChildView: function(view, attrs) {
13831
+ var coreAttrs;
13832
+
13482
13833
  if (Ember.View.detect(view)) {
13834
+ coreAttrs = { _parentView: this };
13483
13835
  if (attrs) {
13484
- view = view.createWith({ _parentView: this }, attrs);
13836
+ view = view.create(coreAttrs, attrs);
13485
13837
  } else {
13486
- view = view.createWith({ _parentView: this });
13838
+ view = view.create(coreAttrs);
13487
13839
  }
13488
13840
 
13489
13841
  var viewName = view.viewName;
@@ -13495,6 +13847,7 @@ Ember.View = Ember.Object.extend(Ember.Evented,
13495
13847
  ember_assert('must pass instance of View', view instanceof Ember.View);
13496
13848
  set(view, '_parentView', this);
13497
13849
  }
13850
+
13498
13851
  return view;
13499
13852
  },
13500
13853
 
@@ -13579,7 +13932,9 @@ Ember.View = Ember.Object.extend(Ember.Evented,
13579
13932
  also call methods with the given name.
13580
13933
  */
13581
13934
  fire: function(name) {
13582
- this[name].apply(this, [].slice.call(arguments, 1));
13935
+ if (this[name]) {
13936
+ this[name].apply(this, [].slice.call(arguments, 1));
13937
+ }
13583
13938
  this._super.apply(this, arguments);
13584
13939
  },
13585
13940
 
@@ -13691,9 +14046,11 @@ Ember.View.applyAttributeBindings = function(elem, name, value) {
13691
14046
  }
13692
14047
  };
13693
14048
 
13694
- })({});
14049
+ })();
14050
+
14051
+
13695
14052
 
13696
- (function(exports) {
14053
+ (function() {
13697
14054
  // ==========================================================================
13698
14055
  // Project: Ember - JavaScript Application Framework
13699
14056
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13728,9 +14085,11 @@ Ember.View.reopen({
13728
14085
  states: Ember.View.states
13729
14086
  });
13730
14087
 
13731
- })({});
14088
+ })();
14089
+
14090
+
13732
14091
 
13733
- (function(exports) {
14092
+ (function() {
13734
14093
  // ==========================================================================
13735
14094
  // Project: Ember - JavaScript Application Framework
13736
14095
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13783,9 +14142,11 @@ Ember.View.states.preRender = {
13783
14142
  }
13784
14143
  };
13785
14144
 
13786
- })({});
14145
+ })();
14146
+
14147
+
13787
14148
 
13788
- (function(exports) {
14149
+ (function() {
13789
14150
  // ==========================================================================
13790
14151
  // Project: Ember - JavaScript Application Framework
13791
14152
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13869,9 +14230,11 @@ Ember.View.states.inBuffer = {
13869
14230
  };
13870
14231
 
13871
14232
 
13872
- })({});
14233
+ })();
14234
+
14235
+
13873
14236
 
13874
- (function(exports) {
14237
+ (function() {
13875
14238
  // ==========================================================================
13876
14239
  // Project: Ember - JavaScript Application Framework
13877
14240
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13928,6 +14291,13 @@ Ember.View.states.hasElement = {
13928
14291
  },
13929
14292
 
13930
14293
  empty: function(view) {
14294
+ var _childViews = get(view, '_childViews'), len, idx;
14295
+ if (_childViews) {
14296
+ len = get(_childViews, 'length');
14297
+ for (idx = 0; idx < len; idx++) {
14298
+ _childViews[idx]._notifyWillDestroyElement();
14299
+ }
14300
+ }
13931
14301
  view.domManager.empty(view);
13932
14302
  },
13933
14303
 
@@ -13950,9 +14320,11 @@ Ember.View.states.inDOM = {
13950
14320
  }
13951
14321
  };
13952
14322
 
13953
- })({});
14323
+ })();
14324
+
14325
+
13954
14326
 
13955
- (function(exports) {
14327
+ (function() {
13956
14328
  // ==========================================================================
13957
14329
  // Project: Ember - JavaScript Application Framework
13958
14330
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13987,9 +14359,11 @@ Ember.View.states.destroyed = {
13987
14359
  };
13988
14360
 
13989
14361
 
13990
- })({});
14362
+ })();
14363
+
14364
+
13991
14365
 
13992
- (function(exports) {
14366
+ (function() {
13993
14367
  // ==========================================================================
13994
14368
  // Project: Ember - JavaScript Application Framework
13995
14369
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -13997,9 +14371,11 @@ Ember.View.states.destroyed = {
13997
14371
  // License: Licensed under MIT license (see license.js)
13998
14372
  // ==========================================================================
13999
14373
 
14000
- })({});
14374
+ })();
14375
+
14376
+
14001
14377
 
14002
- (function(exports) {
14378
+ (function() {
14003
14379
  // ==========================================================================
14004
14380
  // Project: Ember - JavaScript Application Framework
14005
14381
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -14013,6 +14389,177 @@ var childViewsProperty = Ember.computed(function() {
14013
14389
  return get(this, '_childViews');
14014
14390
  }).property('_childViews').cacheable();
14015
14391
 
14392
+ /**
14393
+ @class
14394
+ @extends Ember.View
14395
+
14396
+ A `ContainerView` is an `Ember.View` subclass that allows for manual or programatic
14397
+ management of a view's `childViews` array that will correctly update the `ContainerView`
14398
+ instance's rendered DOM representation.
14399
+
14400
+ ## Setting Initial Child Views
14401
+ The initial array of child views can be set in one of two ways. You can provide
14402
+ a `childViews` property at creation time that contains instance of `Ember.View`:
14403
+
14404
+
14405
+ aContainer = Ember.ContainerView.create({
14406
+ childViews: [Ember.View.create(), Ember.View.create()]
14407
+ })
14408
+
14409
+ You can also provide a list of property names whose values are instances of `Ember.View`:
14410
+
14411
+ aContainer = Ember.ContainerView.create({
14412
+ childViews: ['aView', 'bView', 'cView'],
14413
+ aView: Ember.View.create(),
14414
+ bView: Ember.View.create()
14415
+ cView: Ember.View.create()
14416
+ })
14417
+
14418
+ The two strategies can be combined:
14419
+
14420
+ aContainer = Ember.ContainerView.create({
14421
+ childViews: ['aView', Ember.View.create()],
14422
+ aView: Ember.View.create()
14423
+ })
14424
+
14425
+ Each child view's rendering will be inserted into the container's rendered HTML in the same
14426
+ order as its position in the `childViews` property.
14427
+
14428
+ ## Adding and Removing Child Views
14429
+ The views in a container's `childViews` array should be added and removed by manipulating
14430
+ the `childViews` property directly.
14431
+
14432
+ To remove a view pass that view into a `removeObject` call on the container's `childViews` property.
14433
+
14434
+ Given an empty `<body>` the following code
14435
+
14436
+ aContainer = Ember.ContainerView.create({
14437
+ classNames: ['the-container'],
14438
+ childViews: ['aView', 'bView'],
14439
+ aView: Ember.View.create({
14440
+ template: Ember.Handlebars.compile("A")
14441
+ }),
14442
+ bView: Ember.View.create({
14443
+ template: Ember.Handlebars.compile("B")
14444
+ })
14445
+ })
14446
+
14447
+ aContainer.appendTo('body')
14448
+
14449
+ Results in the HTML
14450
+
14451
+ <div class="ember-view the-container">
14452
+ <div class="ember-view">A</div>
14453
+ <div class="ember-view">B</div>
14454
+ </div>
14455
+
14456
+ Removing a view
14457
+
14458
+ aContainer.get('childViews') // [aContainer.aView, aContainer.bView]
14459
+ aContainer.get('childViews').removeObject(aContainer.get('bView'))
14460
+ aContainer.get('childViews') // [aContainer.aView]
14461
+
14462
+ Will result in the following HTML
14463
+
14464
+ <div class="ember-view the-container">
14465
+ <div class="ember-view">A</div>
14466
+ </div>
14467
+
14468
+
14469
+ Similarly, adding a child view is accomplished by adding `Ember.View` instances to the
14470
+ container's `childViews` property.
14471
+
14472
+ Given an empty `<body>` the following code
14473
+
14474
+ aContainer = Ember.ContainerView.create({
14475
+ classNames: ['the-container'],
14476
+ childViews: ['aView', 'bView'],
14477
+ aView: Ember.View.create({
14478
+ template: Ember.Handlebars.compile("A")
14479
+ }),
14480
+ bView: Ember.View.create({
14481
+ template: Ember.Handlebars.compile("B")
14482
+ })
14483
+ })
14484
+
14485
+ aContainer.appendTo('body')
14486
+
14487
+ Results in the HTML
14488
+
14489
+ <div class="ember-view the-container">
14490
+ <div class="ember-view">A</div>
14491
+ <div class="ember-view">B</div>
14492
+ </div>
14493
+
14494
+ Adding a view
14495
+
14496
+ AnotherViewClass = Ember.View.extend({
14497
+ template: Ember.Handlebars.compile("Another view")
14498
+ })
14499
+
14500
+ aContainer.get('childViews') // [aContainer.aView, aContainer.bView]
14501
+ aContainer.get('childViews').pushObject(AnotherViewClass.create())
14502
+ aContainer.get('childViews') // [aContainer.aView, <AnotherViewClass instance>]
14503
+
14504
+ Will result in the following HTML
14505
+
14506
+ <div class="ember-view the-container">
14507
+ <div class="ember-view">A</div>
14508
+ <div class="ember-view">Another view</div>
14509
+ </div>
14510
+
14511
+
14512
+ Direct manipulation of childViews presence or absence in the DOM via calls to
14513
+ `remove` or `removeFromParent` or calls to a container's `removeChild` may not behave
14514
+ correctly.
14515
+
14516
+ Calling `remove()` on a child view will remove the view's HTML, but it will remain as part of its
14517
+ container's `childView`s property.
14518
+
14519
+ Calling `removeChild()` on the container will remove the passed view instance from the container's
14520
+ `childView`s but keep its HTML within the container's rendered view.
14521
+
14522
+ Calling `removeFromParent()` behaves as expected but should be avoided in favor of direct
14523
+ manipulation of a container's `childViews` property.
14524
+
14525
+ aContainer = Ember.ContainerView.create({
14526
+ classNames: ['the-container'],
14527
+ childViews: ['aView', 'bView'],
14528
+ aView: Ember.View.create({
14529
+ template: Ember.Handlebars.compile("A")
14530
+ }),
14531
+ bView: Ember.View.create({
14532
+ template: Ember.Handlebars.compile("B")
14533
+ })
14534
+ })
14535
+
14536
+ aContainer.appendTo('body')
14537
+
14538
+ Results in the HTML
14539
+
14540
+ <div class="ember-view the-container">
14541
+ <div class="ember-view">A</div>
14542
+ <div class="ember-view">B</div>
14543
+ </div>
14544
+
14545
+ Calling `aContainer.get('aView').removeFromParent()` will result in the following HTML
14546
+
14547
+ <div class="ember-view the-container">
14548
+ <div class="ember-view">A</div>
14549
+ <div class="ember-view">B</div>
14550
+ </div>
14551
+
14552
+ And the `Ember.View` instance stored in `aContainer.aView` will be removed from `aContainer`'s
14553
+ `childViews` array.
14554
+
14555
+
14556
+ ## Templates and Layout
14557
+ A `template`, `templateName`, `defaultTempalte`, `layout`, `layoutName` or `defaultLayout`
14558
+ property on a container view will not result in the template or layout being rendered.
14559
+ The HTML contents of a `Ember.ContainerView`'s DOM representation will only be the rendered HTML
14560
+ of its child views.
14561
+ */
14562
+
14016
14563
  Ember.ContainerView = Ember.View.extend({
14017
14564
 
14018
14565
  init: function() {
@@ -14092,7 +14639,7 @@ Ember.ContainerView = Ember.View.extend({
14092
14639
  if (removed === 0) { return; }
14093
14640
 
14094
14641
  var changedViews = views.slice(start, start+removed);
14095
- this.setParentView(changedViews, null);
14642
+ this.initializeViews(changedViews, null, null);
14096
14643
 
14097
14644
  this.invokeForState('childViewsWillChange', views, start, removed);
14098
14645
  },
@@ -14119,15 +14666,16 @@ Ember.ContainerView = Ember.View.extend({
14119
14666
  if (added === 0) return;
14120
14667
 
14121
14668
  var changedViews = views.slice(start, start+added);
14122
- this.setParentView(changedViews, this);
14669
+ this.initializeViews(changedViews, this, get(this, 'templateData'));
14123
14670
 
14124
14671
  // Let the current state handle the changes
14125
14672
  this.invokeForState('childViewsDidChange', views, start, added);
14126
14673
  },
14127
14674
 
14128
- setParentView: function(views, parentView) {
14675
+ initializeViews: function(views, parentView, templateData) {
14129
14676
  forEach(views, function(view) {
14130
14677
  set(view, '_parentView', parentView);
14678
+ set(view, 'templateData', templateData);
14131
14679
  });
14132
14680
  },
14133
14681
 
@@ -14214,9 +14762,11 @@ Ember.ContainerView.reopen({
14214
14762
  states: Ember.ContainerView.states
14215
14763
  });
14216
14764
 
14217
- })({});
14765
+ })();
14766
+
14767
+
14218
14768
 
14219
- (function(exports) {
14769
+ (function() {
14220
14770
  // ==========================================================================
14221
14771
  // Project: Ember - JavaScript Application Framework
14222
14772
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -14228,24 +14778,132 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
14228
14778
  /**
14229
14779
  @class
14230
14780
  @since Ember 0.9
14231
- @extends Ember.View
14232
- */
14233
- Ember.CollectionView = Ember.ContainerView.extend(
14234
- /** @scope Ember.CollectionView.prototype */ {
14781
+ @extends Ember.ContainerView
14782
+
14783
+ `Ember.CollectionView` is an `Ember.View` descendent responsible for managing a
14784
+ collection (an array or array-like object) by maintaing a child view object and
14785
+ associated DOM representation for each item in the array and ensuring that child
14786
+ views and their associated rendered HTML are updated when items in the array
14787
+ are added, removed, or replaced.
14235
14788
 
14236
- /**
14237
- A list of items to be displayed by the Ember.CollectionView.
14789
+ ## Setting content
14790
+ The managed collection of objects is referenced as the `Ember.CollectionView` instance's
14791
+ `content` property.
14238
14792
 
14239
- @type Ember.Array
14240
- @default null
14241
- */
14242
- content: null,
14793
+ someItemsView = Ember.CollectionView.create({
14794
+ content: ['A', 'B','C']
14795
+ })
14243
14796
 
14244
- /**
14245
- An optional view to display if content is set to an empty array.
14797
+ The view for each item in the collection will have its `content` property set
14798
+ to the item.
14246
14799
 
14247
- @type Ember.View
14248
- @default null
14800
+ ## Specifying itemViewClass
14801
+ By default the view class for each item in the managed collection will be an instance
14802
+ of `Ember.View`. You can supply a different class by setting the `CollectionView`'s
14803
+ `itemViewClass` property.
14804
+
14805
+ Given an empty `<body>` and the following code:
14806
+
14807
+
14808
+ someItemsView = Ember.CollectionView.create({
14809
+ classNames: ['a-collection'],
14810
+ content: ['A','B','C'],
14811
+ itemViewClass: Ember.View.extend({
14812
+ template: Ember.Handlebars.compile("the letter: {{content}}")
14813
+ })
14814
+ })
14815
+
14816
+ someItemsView.appendTo('body')
14817
+
14818
+ Will result in the following HTML structure
14819
+
14820
+ <div class="ember-view a-collection">
14821
+ <div class="ember-view">the letter: A</div>
14822
+ <div class="ember-view">the letter: B</div>
14823
+ <div class="ember-view">the letter: C</div>
14824
+ </div>
14825
+
14826
+
14827
+ ## Automatic matching of parent/child tagNames
14828
+ Setting the `tagName` property of a `CollectionView` to any of
14829
+ "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
14830
+ in the item views receiving an appropriately matched `tagName` property.
14831
+
14832
+
14833
+ Given an empty `<body>` and the following code:
14834
+
14835
+ anUndorderedListView = Ember.CollectionView.create({
14836
+ tagName: 'ul',
14837
+ content: ['A','B','C'],
14838
+ itemViewClass: Ember.View.extend({
14839
+ template: Ember.Handlebars.compile("the letter: {{content}}")
14840
+ })
14841
+ })
14842
+
14843
+ anUndorderedListView.appendTo('body')
14844
+
14845
+ Will result in the following HTML structure
14846
+
14847
+ <ul class="ember-view a-collection">
14848
+ <li class="ember-view">the letter: A</li>
14849
+ <li class="ember-view">the letter: B</li>
14850
+ <li class="ember-view">the letter: C</li>
14851
+ </ul>
14852
+
14853
+ Additional tagName pairs can be provided by adding to `Ember.CollectionView.CONTAINER_MAP `
14854
+
14855
+ Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
14856
+
14857
+
14858
+ ## Empty View
14859
+ You can provide an `Ember.View` subclass to the `Ember.CollectionView` instance as its
14860
+ `emptyView` property. If the `content` property of a `CollectionView` is set to `null`
14861
+ or an empty array, an instance of this view will be the `CollectionView`s only child.
14862
+
14863
+ aListWithNothing = Ember.CollectionView.create({
14864
+ classNames: ['nothing']
14865
+ content: null,
14866
+ emptyView: Ember.View.extend({
14867
+ template: Ember.Handlebars.compile("The collection is empty")
14868
+ })
14869
+ })
14870
+
14871
+ aListWithNothing.appendTo('body')
14872
+
14873
+ Will result in the following HTML structure
14874
+
14875
+ <div class="ember-view nothing">
14876
+ <div class="ember-view">
14877
+ The collection is empty
14878
+ </div>
14879
+ </div>
14880
+
14881
+ ## Adding and Removing items
14882
+ The `childViews` property of a `CollectionView` should not be directly manipulated. Instead,
14883
+ add, remove, replace items from its `content` property. This will trigger
14884
+ appropriate changes to its rendered HTML.
14885
+
14886
+ ## Use in templates via the `{{collection}}` Ember.Handlebars helper
14887
+ Ember.Handlebars provides a helper specifically for adding `CollectionView`s to templates.
14888
+ See `Ember.Handlebars.collection` for more details
14889
+
14890
+ */
14891
+ Ember.CollectionView = Ember.ContainerView.extend(
14892
+ /** @scope Ember.CollectionView.prototype */ {
14893
+
14894
+ /**
14895
+ A list of items to be displayed by the Ember.CollectionView.
14896
+
14897
+ @type Ember.Array
14898
+ @default null
14899
+ */
14900
+ content: null,
14901
+
14902
+ /**
14903
+ An optional view to display if content is set to an empty array.
14904
+
14905
+ @type Ember.View
14906
+ @default null
14249
14907
  */
14250
14908
  emptyView: null,
14251
14909
 
@@ -14255,6 +14913,7 @@ Ember.CollectionView = Ember.ContainerView.extend(
14255
14913
  */
14256
14914
  itemViewClass: Ember.View,
14257
14915
 
14916
+ /** @private */
14258
14917
  init: function() {
14259
14918
  var ret = this._super();
14260
14919
  this._contentDidChange();
@@ -14409,9 +15068,11 @@ Ember.CollectionView.CONTAINER_MAP = {
14409
15068
  select: 'option'
14410
15069
  };
14411
15070
 
14412
- })({});
15071
+ })();
15072
+
15073
+
14413
15074
 
14414
- (function(exports) {
15075
+ (function() {
14415
15076
  // ==========================================================================
14416
15077
  // Project: Ember - JavaScript Application Framework
14417
15078
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -14419,9 +15080,11 @@ Ember.CollectionView.CONTAINER_MAP = {
14419
15080
  // License: Licensed under MIT license (see license.js)
14420
15081
  // ==========================================================================
14421
15082
 
14422
- })({});
15083
+ })();
15084
+
15085
+
14423
15086
 
14424
- (function(exports) {
15087
+ (function() {
14425
15088
  // ==========================================================================
14426
15089
  // Project: Ember - JavaScript Application Framework
14427
15090
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
@@ -14431,9 +15094,9 @@ Ember.CollectionView.CONTAINER_MAP = {
14431
15094
 
14432
15095
  /*globals jQuery*/
14433
15096
 
14434
- })({});
15097
+ })();
14435
15098
 
14436
- (function(exports) {
15099
+ (function() {
14437
15100
  var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
14438
15101
 
14439
15102
  Ember.State = Ember.Object.extend({
@@ -14501,13 +15164,598 @@ Ember.State = Ember.Object.extend({
14501
15164
  exit: Ember.K
14502
15165
  });
14503
15166
 
14504
- })({});
15167
+ })();
15168
+
14505
15169
 
14506
- (function(exports) {
15170
+
15171
+ (function() {
14507
15172
  var get = Ember.get, set = Ember.set, getPath = Ember.getPath, fmt = Ember.String.fmt;
14508
15173
  /**
14509
15174
  @class
14510
- */
15175
+
15176
+ StateManager is part of Ember's implementation of a finite state machine. A StateManager
15177
+ instance manages a number of properties that are instances of `Ember.State`,
15178
+ tracks the current active state, and triggers callbacks when states have changed.
15179
+
15180
+ ## Defining States
15181
+
15182
+ The states of StateManager can be declared in one of two ways. First, you can define
15183
+ a `states` property that contains all the states:
15184
+
15185
+ managerA = Ember.StateManager.create({
15186
+ states: {
15187
+ stateOne: Ember.State.create(),
15188
+ stateTwo: Ember.State.create()
15189
+ }
15190
+ })
15191
+
15192
+ managerA.get('states')
15193
+ // {
15194
+ // stateOne: Ember.State.create(),
15195
+ // stateTwo: Ember.State.create()
15196
+ // }
15197
+
15198
+ You can also add instances of `Ember.State` (or an `Ember.State` subclass) directly as properties
15199
+ of a StateManager. These states will be collected into the `states` property for you.
15200
+
15201
+ managerA = Ember.StateManager.create({
15202
+ stateOne: Ember.State.create(),
15203
+ stateTwo: Ember.State.create()
15204
+ })
15205
+
15206
+ managerA.get('states')
15207
+ // {
15208
+ // stateOne: Ember.State.create(),
15209
+ // stateTwo: Ember.State.create()
15210
+ // }
15211
+
15212
+ ## The Initial State
15213
+ When created a StateManager instance will immediately enter into the state
15214
+ defined as its `start` property or the state referenced by name in its
15215
+ `initialState` property:
15216
+
15217
+ managerA = Ember.StateManager.create({
15218
+ start: Ember.State.create({})
15219
+ })
15220
+
15221
+ managerA.getPath('currentState.name') // 'start'
15222
+
15223
+ managerB = Ember.StateManager.create({
15224
+ initialState: 'beginHere',
15225
+ beginHere: Ember.State.create({})
15226
+ })
15227
+
15228
+ managerB.getPath('currentState.name') // 'beginHere'
15229
+
15230
+ Because it is a property you may also provided a computed function if you wish to derive
15231
+ an `initialState` programmatically:
15232
+
15233
+ managerC = Ember.StateManager.create({
15234
+ initialState: function(){
15235
+ if (someLogic) {
15236
+ return 'active';
15237
+ } else {
15238
+ return 'passive';
15239
+ }
15240
+ }.property(),
15241
+ active: Ember.State.create({})
15242
+ passive: Ember.State.create({})
15243
+ })
15244
+
15245
+ ## Moving Between States
15246
+ A StateManager can have any number of Ember.State objects as properties
15247
+ and can have a single one of these states as its current state.
15248
+
15249
+ Calling `goToState` transitions between states:
15250
+
15251
+ robotManager = Ember.StateManager.create({
15252
+ initialState: 'poweredDown',
15253
+ poweredDown: Ember.State.create({}),
15254
+ poweredUp: Ember.State.create({})
15255
+ })
15256
+
15257
+ robotManager.getPath('currentState.name') // 'poweredDown'
15258
+ robotManager.goToState('poweredUp')
15259
+ robotManager.getPath('currentState.name') // 'poweredUp'
15260
+
15261
+ Before transitioning into a new state the existing `currentState` will have its
15262
+ `exit` method called with with the StateManager instance as its first argument and
15263
+ an object representing the the transition as its second argument.
15264
+
15265
+ After transitioning into a new state the new `currentState` will have its
15266
+ `enter` method called with with the StateManager instance as its first argument and
15267
+ an object representing the the transition as its second argument.
15268
+
15269
+ robotManager = Ember.StateManager.create({
15270
+ initialState: 'poweredDown',
15271
+ poweredDown: Ember.State.create({
15272
+ exit: function(stateManager, transition){
15273
+ console.log("exiting the poweredDown state")
15274
+ }
15275
+ }),
15276
+ poweredUp: Ember.State.create({
15277
+ enter: function(stateManager, transition){
15278
+ console.log("entering the poweredUp state. Destroy all humans.")
15279
+ }
15280
+ })
15281
+ })
15282
+
15283
+ robotManager.getPath('currentState.name') // 'poweredDown'
15284
+ robotManager.goToState('poweredUp')
15285
+ // will log
15286
+ // 'exiting the poweredDown state'
15287
+ // 'entering the poweredUp state. Destroy all humans.'
15288
+
15289
+
15290
+ Once a StateManager is already in a state, subsequent attempts to enter that state will
15291
+ not trigger enter or exit method calls. Attempts to transition into a state that the
15292
+ manager does not have will result in no changes in the StateManager's current state:
15293
+
15294
+ robotManager = Ember.StateManager.create({
15295
+ initialState: 'poweredDown',
15296
+ poweredDown: Ember.State.create({
15297
+ exit: function(stateManager, transition){
15298
+ console.log("exiting the poweredDown state")
15299
+ }
15300
+ }),
15301
+ poweredUp: Ember.State.create({
15302
+ enter: function(stateManager, transition){
15303
+ console.log("entering the poweredUp state. Destroy all humans.")
15304
+ }
15305
+ })
15306
+ })
15307
+
15308
+ robotManager.getPath('currentState.name') // 'poweredDown'
15309
+ robotManager.goToState('poweredUp')
15310
+ // will log
15311
+ // 'exiting the poweredDown state'
15312
+ // 'entering the poweredUp state. Destroy all humans.'
15313
+ robotManager.goToState('poweredUp') // no logging, no state change
15314
+
15315
+ robotManager.goToState('someUnknownState') // silently fails
15316
+ robotManager.getPath('currentState.name') // 'poweredUp'
15317
+
15318
+
15319
+ Each state property may itself contain properties that are instances of Ember.State.
15320
+ The StateManager can transition to specific sub-states in a series of goToState method calls or
15321
+ via a single goToState with the full path to the specific state. The StateManager will also
15322
+ keep track of the full path to its currentState
15323
+
15324
+
15325
+ robotManager = Ember.StateManager.create({
15326
+ initialState: 'poweredDown',
15327
+ poweredDown: Ember.State.create({
15328
+ charging: Ember.State.create(),
15329
+ charged: Ember.State.create()
15330
+ }),
15331
+ poweredUp: Ember.State.create({
15332
+ mobile: Ember.State.create(),
15333
+ stationary: Ember.State.create()
15334
+ })
15335
+ })
15336
+
15337
+ robotManager.getPath('currentState.name') // 'poweredDown'
15338
+
15339
+ robotManager.goToState('poweredUp')
15340
+ robotManager.getPath('currentState.name') // 'poweredUp'
15341
+
15342
+ robotManager.goToState('mobile')
15343
+ robotManager.getPath('currentState.name') // 'mobile'
15344
+
15345
+ // transition via a state path
15346
+ robotManager.goToState('poweredDown.charging')
15347
+ robotManager.getPath('currentState.name') // 'charging'
15348
+
15349
+ robotManager.getPath('currentState.get.path') // 'poweredDown.charging'
15350
+
15351
+ Enter transition methods will be called for each state and nested child state in their
15352
+ hierarchical order. Exit methods will be called for each state and its nested states in
15353
+ reverse hierarchical order.
15354
+
15355
+ Exit transitions for a parent state are not called when entering into one of its child states,
15356
+ only when transitioning to a new section of possible states in the hierarchy.
15357
+
15358
+ robotManager = Ember.StateManager.create({
15359
+ initialState: 'poweredDown',
15360
+ poweredDown: Ember.State.create({
15361
+ enter: function(){},
15362
+ exit: function(){
15363
+ console.log("exited poweredDown state")
15364
+ },
15365
+ charging: Ember.State.create({
15366
+ enter: function(){},
15367
+ exit: function(){}
15368
+ }),
15369
+ charged: Ember.State.create({
15370
+ enter: function(){
15371
+ console.log("entered charged state")
15372
+ },
15373
+ exit: function(){
15374
+ console.log("exited charged state")
15375
+ }
15376
+ })
15377
+ }),
15378
+ poweredUp: Ember.State.create({
15379
+ enter: function(){
15380
+ console.log("entered poweredUp state")
15381
+ },
15382
+ exit: function(){},
15383
+ mobile: Ember.State.create({
15384
+ enter: function(){
15385
+ console.log("entered mobile state")
15386
+ },
15387
+ exit: function(){}
15388
+ }),
15389
+ stationary: Ember.State.create({
15390
+ enter: function(){},
15391
+ exit: function(){}
15392
+ })
15393
+ })
15394
+ })
15395
+
15396
+
15397
+ robotManager.get('currentState.get.path') // 'poweredDown'
15398
+ robotManager.goToState('charged')
15399
+ // logs 'entered charged state'
15400
+ // but does *not* log 'exited poweredDown state'
15401
+ robotManager.getPath('currentState.name') // 'charged
15402
+
15403
+ robotManager.goToState('poweredUp.mobile')
15404
+ // logs
15405
+ // 'exited charged state'
15406
+ // 'exited poweredDown state'
15407
+ // 'entered poweredUp state'
15408
+ // 'entered mobile state'
15409
+
15410
+ During development you can set a StateManager's `enableLogging` property to `true` to
15411
+ receive console messages of state transitions.
15412
+
15413
+ robotManager = Ember.StateManager.create({
15414
+ enableLogging: true
15415
+ })
15416
+
15417
+ ## Managing currentState with Actions
15418
+ To control which transitions between states are possible for a given state, StateManager
15419
+ can receive and route action messages to its states via the `send` method. Calling to `send` with
15420
+ an action name will begin searching for a method with the same name starting at the current state
15421
+ and moving up through the parent states in a state hierarchy until an appropriate method is found
15422
+ or the StateManager instance itself is reached.
15423
+
15424
+ If an appropriately named method is found it will be called with the state manager as the first
15425
+ argument and an optional `context` object as the second argument.
15426
+
15427
+ managerA = Ember.StateManager.create({
15428
+ initialState: 'stateOne.substateOne.subsubstateOne',
15429
+ stateOne: Ember.State.create({
15430
+ substateOne: Ember.State.create({
15431
+ anAction: function(manager, context){
15432
+ console.log("an action was called")
15433
+ },
15434
+ subsubstateOne: Ember.State.create({})
15435
+ })
15436
+ })
15437
+ })
15438
+
15439
+ managerA.getPath('currentState.name') // 'subsubstateOne'
15440
+ managerA.send('anAction')
15441
+ // 'stateOne.substateOne.subsubstateOne' has no anAction method
15442
+ // so the 'anAction' method of 'stateOne.substateOne' is called
15443
+ // and logs "an action was called"
15444
+ // with managerA as the first argument
15445
+ // and no second argument
15446
+
15447
+ someObject = {}
15448
+ managerA.send('anAction', someObject)
15449
+ // the 'anAction' method of 'stateOne.substateOne' is called again
15450
+ // with managerA as the first argument and
15451
+ // someObject as the second argument.
15452
+
15453
+
15454
+ If the StateManager attempts to send an action but does not find an appropriately named
15455
+ method in the current state or while moving upwards through the state hierarchy
15456
+ it will throw a new Ember.Error. Action detection only moves upwards through the state hierarchy
15457
+ from the current state. It does not search in other portions of the hierarchy.
15458
+
15459
+ managerB = Ember.StateManager.create({
15460
+ initialState: 'stateOne.substateOne.subsubstateOne',
15461
+ stateOne: Ember.State.create({
15462
+ substateOne: Ember.State.create({
15463
+ subsubstateOne: Ember.State.create({})
15464
+ })
15465
+ }),
15466
+ stateTwo: Ember.State.create({
15467
+ anAction: function(manager, context){
15468
+ // will not be called below because it is
15469
+ // not a parent of the current state
15470
+ }
15471
+ })
15472
+ })
15473
+
15474
+ managerB.getPath('currentState.name') // 'subsubstateOne'
15475
+ managerB.send('anAction')
15476
+ // Error: <Ember.StateManager:ember132> could not
15477
+ // respond to event anAction in state stateOne.substateOne.subsubstateOne.
15478
+
15479
+ Inside of an action method the given state should delegate `goToState` calls on its
15480
+ StateManager.
15481
+
15482
+ robotManager = Ember.StateManager.create({
15483
+ initialState: 'poweredDown.charging',
15484
+ poweredDown: Ember.State.create({
15485
+ charging: Ember.State.create({
15486
+ chargeComplete: function(manager, context){
15487
+ manager.goToState('charged')
15488
+ }
15489
+ }),
15490
+ charged: Ember.State.create({
15491
+ boot: function(manager, context){
15492
+ manager.goToState('poweredUp')
15493
+ }
15494
+ })
15495
+ }),
15496
+ poweredUp: Ember.State.create({
15497
+ beginExtermination: function(manager, context){
15498
+ manager.goToState('rampaging')
15499
+ },
15500
+ rampaging: Ember.State.create()
15501
+ })
15502
+ })
15503
+
15504
+ robotManager.getPath('currentState.name') // 'charging'
15505
+ robotManager.send('boot') // throws error, no boot action
15506
+ // in current hierarchy
15507
+ robotManager.getPath('currentState.name') // remains 'charging'
15508
+
15509
+ robotManager.send('beginExtermination') // throws error, no beginExtermination
15510
+ // action in current hierarchy
15511
+ robotManager.getPath('currentState.name') // remains 'charging'
15512
+
15513
+ robotManager.send('chargeComplete')
15514
+ robotManager.getPath('currentState.name') // 'charged'
15515
+
15516
+ robotManager.send('boot')
15517
+ robotManager.getPath('currentState.name') // 'poweredUp'
15518
+
15519
+ robotManager.send('beginExtermination', allHumans)
15520
+ robotManager.getPath('currentState.name') // 'rampaging'
15521
+
15522
+
15523
+ ## Interactions with Ember's View System.
15524
+ When combined with instances of `Ember.ViewState`, StateManager is designed to
15525
+ interact with Ember's view system to control which views are added to
15526
+ and removed from the DOM based on the manager's current state.
15527
+
15528
+ By default, a StateManager will manage views inside the 'body' element. This can be
15529
+ customized by setting the `rootElement` property to a CSS selector of an existing
15530
+ HTML element you would prefer to receive view rendering.
15531
+
15532
+
15533
+ viewStates = Ember.StateManager.create({
15534
+ rootElement: '#some-other-element'
15535
+ })
15536
+
15537
+ You can also specify a particular instance of `Ember.ContainerView` you would like to receive
15538
+ view rendering by setting the `rootView` property. You will be responsible for placing
15539
+ this element into the DOM yourself.
15540
+
15541
+ aLayoutView = Ember.ContainerView.create()
15542
+
15543
+ // make sure this view instance is added to the browser
15544
+ aLayoutView.appendTo('body')
15545
+
15546
+ App.viewStates = Ember.StateManager.create({
15547
+ rootView: aLayoutView
15548
+ })
15549
+
15550
+
15551
+ Once you have an instance of StateManager controlling a view, you can provide states
15552
+ that are instances of `Ember.ViewState`. When the StateManager enters a state
15553
+ that is an instance of `Ember.ViewState` that `ViewState`'s `view` property will be
15554
+ instantiated and inserted into the StateManager's `rootView` or `rootElement`.
15555
+ When a state is exited, the `ViewState`'s view will be removed from the StateManager's
15556
+ view.
15557
+
15558
+ ContactListView = Ember.View.extend({
15559
+ classNames: ['my-contacts-css-class'],
15560
+ defaultTemplate: Ember.Handlebars.compile('<h2>People</h2>')
15561
+ })
15562
+
15563
+ PhotoListView = Ember.View.extend({
15564
+ classNames: ['my-photos-css-class'],
15565
+ defaultTemplate: Ember.Handlebars.compile('<h2>Photos</h2>')
15566
+ })
15567
+
15568
+ viewStates = Ember.StateManager.create({
15569
+ showingPeople: Ember.ViewState.create({
15570
+ view: ContactListView
15571
+ }),
15572
+ showingPhotos: Ember.ViewState.create({
15573
+ view: PhotoListView
15574
+ })
15575
+ })
15576
+
15577
+ viewStates.goToState('showingPeople')
15578
+
15579
+ The above code will change the rendered HTML from
15580
+
15581
+ <body></body>
15582
+
15583
+ to
15584
+
15585
+ <body>
15586
+ <div id="ember1" class="ember-view my-contacts-css-class">
15587
+ <h2>People</h2>
15588
+ </div>
15589
+ </body>
15590
+
15591
+ Changing the current state via `goToState` from `showingPeople` to
15592
+ `showingPhotos` will remove the `showingPeople` view and add the `showingPhotos` view:
15593
+
15594
+ viewStates.goToState('showingPhotos')
15595
+
15596
+ will change the rendered HTML to
15597
+
15598
+ <body>
15599
+ <div id="ember2" class="ember-view my-photos-css-class">
15600
+ <h2>Photos</h2>
15601
+ </div>
15602
+ </body>
15603
+
15604
+
15605
+ When entering nested `ViewState`s, each state's view will be draw into the the StateManager's
15606
+ `rootView` or `rootElement` as siblings.
15607
+
15608
+
15609
+ ContactListView = Ember.View.extend({
15610
+ classNames: ['my-contacts-css-class'],
15611
+ defaultTemplate: Ember.Handlebars.compile('<h2>People</h2>')
15612
+ })
15613
+
15614
+ EditAContactView = Ember.View.extend({
15615
+ classNames: ['editing-a-contact-css-class'],
15616
+ defaultTemplate: Ember.Handlebars.compile('Editing...')
15617
+ })
15618
+
15619
+ viewStates = Ember.StateManager.create({
15620
+ showingPeople: Ember.ViewState.create({
15621
+ view: ContactListView,
15622
+
15623
+ withEditingPanel: Ember.ViewState.create({
15624
+ view: EditAContactView
15625
+ })
15626
+ })
15627
+ })
15628
+
15629
+
15630
+ viewStates.goToState('showingPeople.withEditingPanel')
15631
+
15632
+
15633
+ Will result in the following rendered HTML:
15634
+
15635
+ <body>
15636
+ <div id="ember2" class="ember-view my-contacts-css-class">
15637
+ <h2>People</h2>
15638
+ </div>
15639
+
15640
+ <div id="ember2" class="ember-view editing-a-contact-css-class">
15641
+ Editing...
15642
+ </div>
15643
+ </body>
15644
+
15645
+
15646
+ ViewState views are added and removed from their StateManager's view via their
15647
+ `enter` and `exit` methods. If you need to override these methods, be sure to call
15648
+ `_super` to maintain the adding and removing behavior:
15649
+
15650
+ viewStates = Ember.StateManager.create({
15651
+ aState: Ember.ViewState.create({
15652
+ view: Ember.View.extend({}),
15653
+ enter: function(manager, transition){
15654
+ // calling _super ensures this view will be
15655
+ // properly inserted
15656
+ this._super();
15657
+
15658
+ // now you can do other things
15659
+ }
15660
+ })
15661
+ })
15662
+
15663
+ ## Managing Multiple Sections of A Page With States
15664
+ Multiple StateManagers can be combined to control multiple areas of an application's rendered views.
15665
+ Given the following HTML body:
15666
+
15667
+ <body>
15668
+ <div id='sidebar-nav'>
15669
+ </div>
15670
+ <div id='content-area'>
15671
+ </div>
15672
+ </body>
15673
+
15674
+ You could separately manage view state for each section with two StateManagers
15675
+
15676
+ navigationStates = Ember.StateManager.create({
15677
+ rootElement: '#sidebar-nav',
15678
+ userAuthenticated: Em.ViewState.create({
15679
+ view: Ember.View.extend({})
15680
+ }),
15681
+ userNotAuthenticated: Em.ViewState.create({
15682
+ view: Ember.View.extend({})
15683
+ })
15684
+ })
15685
+
15686
+ contentStates = Ember.StateManager.create({
15687
+ rootElement: '#content-area',
15688
+ books: Em.ViewState.create({
15689
+ view: Ember.View.extend({})
15690
+ }),
15691
+ music: Em.ViewState.create({
15692
+ view: Ember.View.extend({})
15693
+ })
15694
+ })
15695
+
15696
+
15697
+ If you prefer to start with an empty body and manage state programmatically you
15698
+ can also take advantage of StateManager's `rootView` property and the ability of
15699
+ `Ember.ContainerView`s to manually manage their child views.
15700
+
15701
+
15702
+ dashboard = Ember.ContainerView.create({
15703
+ childViews: ['navigationAreaView', 'contentAreaView'],
15704
+ navigationAreaView: Ember.ContainerView.create({}),
15705
+ contentAreaView: Ember.ContainerView.create({})
15706
+ })
15707
+
15708
+ navigationStates = Ember.StateManager.create({
15709
+ rootView: dashboard.get('navigationAreaView'),
15710
+ userAuthenticated: Em.ViewState.create({
15711
+ view: Ember.View.extend({})
15712
+ }),
15713
+ userNotAuthenticated: Em.ViewState.create({
15714
+ view: Ember.View.extend({})
15715
+ })
15716
+ })
15717
+
15718
+ contentStates = Ember.StateManager.create({
15719
+ rootView: dashboard.get('contentAreaView'),
15720
+ books: Em.ViewState.create({
15721
+ view: Ember.View.extend({})
15722
+ }),
15723
+ music: Em.ViewState.create({
15724
+ view: Ember.View.extend({})
15725
+ })
15726
+ })
15727
+
15728
+ dashboard.appendTo('body')
15729
+
15730
+ ## User Manipulation of State via `{{action}}` Helpers
15731
+ The Handlebars `{{action}}` helper is StateManager-aware and will use StateManager action sending
15732
+ to connect user interaction to action-based state transitions.
15733
+
15734
+ Given the following body and handlebars template
15735
+
15736
+ <body>
15737
+ <script type='text/x-handlebars'>
15738
+ <a href="#" {{action "anAction" target="App.appStates"}}> Go </a>
15739
+ </script>
15740
+ </body>
15741
+
15742
+ And application code
15743
+
15744
+ App = Ember.Application.create()
15745
+ App.appStates = Ember.StateManager.create({
15746
+ initialState: 'aState',
15747
+ aState: Ember.State.create({
15748
+ anAction: function(manager, context){}
15749
+ }),
15750
+ bState: Ember.State.create({})
15751
+ })
15752
+
15753
+ A user initiated click or touch event on "Go" will trigger the 'anAction' method of
15754
+ `App.appStates.aState` with `App.appStates` as the first argument and a
15755
+ `jQuery.Event` object as the second object. The `jQuery.Event` will include a property
15756
+ `view` that references the `Ember.View` object that was interacted with.
15757
+
15758
+ **/
14511
15759
  Ember.StateManager = Ember.State.extend(
14512
15760
  /** @scope Ember.State.prototype */ {
14513
15761
 
@@ -14730,9 +15978,11 @@ Ember.StateManager = Ember.State.extend(
14730
15978
  }
14731
15979
  });
14732
15980
 
14733
- })({});
15981
+ })();
15982
+
14734
15983
 
14735
- (function(exports) {
15984
+
15985
+ (function() {
14736
15986
  var get = Ember.get, set = Ember.set;
14737
15987
 
14738
15988
  Ember.ViewState = Ember.State.extend({
@@ -14780,18 +16030,20 @@ Ember.ViewState = Ember.State.extend({
14780
16030
  }
14781
16031
  });
14782
16032
 
14783
- })({});
16033
+ })();
16034
+
14784
16035
 
14785
- (function(exports) {
16036
+
16037
+ (function() {
14786
16038
  // ==========================================================================
14787
16039
  // Project: Ember Statecharts
14788
16040
  // Copyright: ©2011 Living Social Inc. and contributors.
14789
16041
  // License: Licensed under MIT license (see license.js)
14790
16042
  // ==========================================================================
14791
16043
 
14792
- })({});
16044
+ })();
14793
16045
 
14794
- (function(exports) {
16046
+ (function() {
14795
16047
  // ==========================================================================
14796
16048
  // Project: metamorph
14797
16049
  // Copyright: ©2011 My Company Inc. All rights reserved.
@@ -15192,9 +16444,9 @@ Ember.ViewState = Ember.State.extend({
15192
16444
  })(this);
15193
16445
 
15194
16446
 
15195
- })({});
16447
+ })();
15196
16448
 
15197
- (function(exports) {
16449
+ (function() {
15198
16450
  // ==========================================================================
15199
16451
  // Project: Ember Handlebar Views
15200
16452
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -15323,14 +16575,64 @@ Ember.Handlebars.compile = function(string) {
15323
16575
  };
15324
16576
 
15325
16577
  /**
15326
- Lookup both on root and on window
16578
+ If a path starts with a reserved keyword, returns the root
16579
+ that should be used.
16580
+
16581
+ @private
16582
+ */
16583
+ var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data) {
16584
+ var keywords = (data && data.keywords) || {},
16585
+ keyword, isKeyword;
16586
+
16587
+ // Get the first segment of the path. For example, if the
16588
+ // path is "foo.bar.baz", returns "foo".
16589
+ keyword = path.split('.', 1)[0];
16590
+
16591
+ // Test to see if the first path is a keyword that has been
16592
+ // passed along in the view's data hash. If so, we will treat
16593
+ // that object as the new root.
16594
+ if (keywords.hasOwnProperty(keyword)) {
16595
+ // Look up the value in the template's data hash.
16596
+ root = keywords[keyword];
16597
+ isKeyword = true;
16598
+
16599
+ // Handle cases where the entire path is the reserved
16600
+ // word. In that case, return the object itself.
16601
+ if (path === keyword) {
16602
+ path = '';
16603
+ } else {
16604
+ // Strip the keyword from the path and look up
16605
+ // the remainder from the newly found root.
16606
+ path = path.substr(keyword.length);
16607
+ }
16608
+ }
16609
+
16610
+ return { root: root, path: path, isKeyword: isKeyword };
16611
+ };
16612
+ /**
16613
+ Lookup both on root and on window. If the path starts with
16614
+ a keyword, the corresponding object will be looked up in the
16615
+ template's data hash and used to resolve the path.
15327
16616
 
15328
16617
  @param {Object} root The object to look up the property on
15329
16618
  @param {String} path The path to be lookedup
16619
+ @param {Object} options The template's option hash
15330
16620
  */
15331
- Ember.Handlebars.getPath = function(root, path) {
16621
+
16622
+ Ember.Handlebars.getPath = function(root, path, options) {
16623
+ var data = options.data,
16624
+ normalizedPath = normalizePath(root, path, data),
16625
+ value;
16626
+
16627
+ // In cases where the path begins with a keyword, change the
16628
+ // root to the value represented by that keyword, and ensure
16629
+ // the path is relative to it.
16630
+ root = normalizedPath.root;
16631
+ path = normalizedPath.path;
16632
+
15332
16633
  // TODO: Remove this `false` when the `getPath` globals support is removed
15333
- var value = Ember.getPath(root, path, false);
16634
+ value = Ember.getPath(root, path, false);
16635
+
15334
16636
  if (value === undefined && root !== window && Ember.isGlobalPath(path)) {
15335
16637
  value = Ember.getPath(window, path);
15336
16638
  }
@@ -15360,9 +16662,11 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
15360
16662
  });
15361
16663
 
15362
16664
 
15363
- })({});
16665
+ })();
16666
+
15364
16667
 
15365
- (function(exports) {
16668
+
16669
+ (function() {
15366
16670
  /*jshint newcap:false*/
15367
16671
  var set = Ember.set, get = Ember.get, getPath = Ember.getPath;
15368
16672
 
@@ -15441,9 +16745,11 @@ Ember.Metamorph = Ember.Mixin.create({
15441
16745
  });
15442
16746
 
15443
16747
 
15444
- })({});
16748
+ })();
16749
+
16750
+
15445
16751
 
15446
- (function(exports) {
16752
+ (function() {
15447
16753
  // ==========================================================================
15448
16754
  // Project: Ember Handlebar Views
15449
16755
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -15526,14 +16832,15 @@ Ember._BindableSpanView = Ember.View.extend(Ember.Metamorph,
15526
16832
  var property = get(this, 'property'),
15527
16833
  context = get(this, 'previousContext'),
15528
16834
  valueNormalizer = get(this, 'valueNormalizerFunc'),
15529
- result;
16835
+ result, templateData;
15530
16836
 
15531
16837
  // Use the current context as the result if no
15532
16838
  // property is provided.
15533
16839
  if (property === '') {
15534
16840
  result = context;
15535
16841
  } else {
15536
- result = getPath(context, property);
16842
+ templateData = get(this, 'templateData');
16843
+ result = getPath(context, property, { data: templateData });
15537
16844
  }
15538
16845
 
15539
16846
  return valueNormalizer ? valueNormalizer(result) : result;
@@ -15584,12 +16891,12 @@ Ember._BindableSpanView = Ember.View.extend(Ember.Metamorph,
15584
16891
  // If we are preserving the context (for example, if this
15585
16892
  // is an #if block, call the template with the same object.
15586
16893
  if (preserveContext) {
15587
- set(this, 'templateContext', context);
16894
+ set(this, '_templateContext', context);
15588
16895
  } else {
15589
16896
  // Otherwise, determine if this is a block bind or not.
15590
16897
  // If so, pass the specified object to the template
15591
16898
  if (displayTemplate) {
15592
- set(this, 'templateContext', result);
16899
+ set(this, '_templateContext', result);
15593
16900
  } else {
15594
16901
  // This is not a bind block, just push the result of the
15595
16902
  // expression to the render context and return.
@@ -15608,9 +16915,9 @@ Ember._BindableSpanView = Ember.View.extend(Ember.Metamorph,
15608
16915
  set(this, 'template', inverseTemplate);
15609
16916
 
15610
16917
  if (preserveContext) {
15611
- set(this, 'templateContext', context);
16918
+ set(this, '_templateContext', context);
15612
16919
  } else {
15613
- set(this, 'templateContext', result);
16920
+ set(this, '_templateContext', result);
15614
16921
  }
15615
16922
  } else {
15616
16923
  set(this, 'template', function() { return ''; });
@@ -15620,9 +16927,11 @@ Ember._BindableSpanView = Ember.View.extend(Ember.Metamorph,
15620
16927
  }
15621
16928
  });
15622
16929
 
15623
- })({});
16930
+ })();
15624
16931
 
15625
- (function(exports) {
16932
+
16933
+
16934
+ (function() {
15626
16935
  // ==========================================================================
15627
16936
  // Project: Ember Handlebar Views
15628
16937
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -15641,7 +16950,13 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
15641
16950
  fn = options.fn,
15642
16951
  inverse = options.inverse,
15643
16952
  view = data.view,
15644
- ctx = this;
16953
+ ctx = this,
16954
+ normalized;
16955
+
16956
+ normalized = Ember.Handlebars.normalizePath(ctx, property, data);
16957
+
16958
+ ctx = normalized.root;
16959
+ property = normalized.path;
15645
16960
 
15646
16961
  // Set up observers for observable objects
15647
16962
  if ('object' === typeof this) {
@@ -15656,7 +16971,8 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
15656
16971
  inverseTemplate: inverse,
15657
16972
  property: property,
15658
16973
  previousContext: ctx,
15659
- isEscaped: options.hash.escaped
16974
+ isEscaped: options.hash.escaped,
16975
+ templateData: options.data
15660
16976
  });
15661
16977
 
15662
16978
  view.appendChild(bindView);
@@ -15676,7 +16992,7 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
15676
16992
  } else {
15677
16993
  // The object is not observable, so just render it out and
15678
16994
  // be done with it.
15679
- data.buffer.push(getPath(this, property));
16995
+ data.buffer.push(getPath(this, property, options));
15680
16996
  }
15681
16997
  };
15682
16998
 
@@ -15835,7 +17151,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
15835
17151
  // Handle classes differently, as we can bind multiple classes
15836
17152
  var classBindings = attrs['class'];
15837
17153
  if (classBindings !== null && classBindings !== undefined) {
15838
- var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId);
17154
+ var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options);
15839
17155
  ret.push('class="' + classResults.join(' ') + '"');
15840
17156
  delete attrs['class'];
15841
17157
  }
@@ -15849,7 +17165,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
15849
17165
 
15850
17166
  ember_assert(fmt("You must provide a String for a bound attribute, not %@", [property]), typeof property === 'string');
15851
17167
 
15852
- var value = (property === 'this') ? ctx : getPath(ctx, property),
17168
+ var value = (property === 'this') ? ctx : getPath(ctx, property, options),
15853
17169
  type = Ember.typeOf(value);
15854
17170
 
15855
17171
  ember_assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');
@@ -15858,7 +17174,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
15858
17174
 
15859
17175
  /** @private */
15860
17176
  observer = function observer() {
15861
- var result = getPath(ctx, property);
17177
+ var result = getPath(ctx, property, options);
15862
17178
 
15863
17179
  ember_assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), result === null || result === undefined || typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean');
15864
17180
 
@@ -15928,7 +17244,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
15928
17244
 
15929
17245
  @returns {Array} An array of class names to add
15930
17246
  */
15931
- EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId) {
17247
+ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId, options) {
15932
17248
  var ret = [], newClass, value, elem;
15933
17249
 
15934
17250
  // Helper method to retrieve the property from the context and
@@ -15940,7 +17256,7 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId)
15940
17256
 
15941
17257
  property = split[0];
15942
17258
 
15943
- var val = property !== '' ? getPath(context, property) : true;
17259
+ var val = property !== '' ? getPath(context, property, options) : true;
15944
17260
 
15945
17261
  // If value is a Boolean and true, return the dasherized property
15946
17262
  // name.
@@ -16032,9 +17348,11 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId)
16032
17348
  };
16033
17349
 
16034
17350
 
16035
- })({});
17351
+ })();
17352
+
16036
17353
 
16037
- (function(exports) {
17354
+
17355
+ (function() {
16038
17356
  // ==========================================================================
16039
17357
  // Project: Ember Handlebar Views
16040
17358
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16046,17 +17364,19 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId)
16046
17364
  var get = Ember.get, set = Ember.set;
16047
17365
  var indexOf = Ember.ArrayUtils.indexOf;
16048
17366
  var PARENT_VIEW_PATH = /^parentView\./;
17367
+ var EmberHandlebars = Ember.Handlebars;
16049
17368
 
16050
17369
  /** @private */
16051
- Ember.Handlebars.ViewHelper = Ember.Object.create({
17370
+ EmberHandlebars.ViewHelper = Ember.Object.create({
16052
17371
 
16053
17372
  viewClassFromHTMLOptions: function(viewClass, options, thisContext) {
17373
+ var hash = options.hash, data = options.data;
16054
17374
  var extensions = {},
16055
- classes = options['class'],
17375
+ classes = hash['class'],
16056
17376
  dup = false;
16057
17377
 
16058
- if (options.id) {
16059
- extensions.elementId = options.id;
17378
+ if (hash.id) {
17379
+ extensions.elementId = hash.id;
16060
17380
  dup = true;
16061
17381
  }
16062
17382
 
@@ -16066,45 +17386,49 @@ Ember.Handlebars.ViewHelper = Ember.Object.create({
16066
17386
  dup = true;
16067
17387
  }
16068
17388
 
16069
- if (options.classBinding) {
16070
- extensions.classNameBindings = options.classBinding.split(' ');
17389
+ if (hash.classBinding) {
17390
+ extensions.classNameBindings = hash.classBinding.split(' ');
16071
17391
  dup = true;
16072
17392
  }
16073
17393
 
16074
- if (options.classNameBindings) {
16075
- extensions.classNameBindings = options.classNameBindings.split(' ');
17394
+ if (hash.classNameBindings) {
17395
+ extensions.classNameBindings = hash.classNameBindings.split(' ');
16076
17396
  dup = true;
16077
17397
  }
16078
17398
 
16079
- if (options.attributeBindings) {
17399
+ if (hash.attributeBindings) {
16080
17400
  ember_assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead.");
16081
17401
  extensions.attributeBindings = null;
16082
17402
  dup = true;
16083
17403
  }
16084
17404
 
16085
17405
  if (dup) {
16086
- options = Ember.$.extend({}, options);
16087
- delete options.id;
16088
- delete options['class'];
16089
- delete options.classBinding;
17406
+ hash = Ember.$.extend({}, hash);
17407
+ delete hash.id;
17408
+ delete hash['class'];
17409
+ delete hash.classBinding;
16090
17410
  }
16091
17411
 
16092
17412
  // Look for bindings passed to the helper and, if they are
16093
17413
  // local, make them relative to the current context instead of the
16094
17414
  // view.
16095
- var path;
17415
+ var path, normalized;
16096
17416
 
16097
- for (var prop in options) {
16098
- if (!options.hasOwnProperty(prop)) { continue; }
17417
+ for (var prop in hash) {
17418
+ if (!hash.hasOwnProperty(prop)) { continue; }
16099
17419
 
16100
17420
  // Test if the property ends in "Binding"
16101
17421
  if (Ember.IS_BINDING.test(prop)) {
16102
- path = options[prop];
16103
- if (!Ember.isGlobalPath(path)) {
17422
+ path = hash[prop];
17423
+
17424
+ normalized = Ember.Handlebars.normalizePath(null, path, data);
17425
+ if (normalized.isKeyword) {
17426
+ hash[prop] = 'templateData.keywords.'+path;
17427
+ } else if (!Ember.isGlobalPath(path)) {
16104
17428
  if (path === 'this') {
16105
- options[prop] = 'bindingContext';
17429
+ hash[prop] = 'bindingContext';
16106
17430
  } else {
16107
- options[prop] = 'bindingContext.'+path;
17431
+ hash[prop] = 'bindingContext.'+path;
16108
17432
  }
16109
17433
  }
16110
17434
  }
@@ -16114,7 +17438,7 @@ Ember.Handlebars.ViewHelper = Ember.Object.create({
16114
17438
  // for the bindings set up above.
16115
17439
  extensions.bindingContext = thisContext;
16116
17440
 
16117
- return viewClass.extend(options, extensions);
17441
+ return viewClass.extend(hash, extensions);
16118
17442
  },
16119
17443
 
16120
17444
  helper: function(thisContext, path, options) {
@@ -16126,7 +17450,7 @@ Ember.Handlebars.ViewHelper = Ember.Object.create({
16126
17450
  newView;
16127
17451
 
16128
17452
  if ('string' === typeof path) {
16129
- newView = Ember.Handlebars.getPath(thisContext, path);
17453
+ newView = EmberHandlebars.getPath(thisContext, path, options);
16130
17454
  ember_assert("Unable to find view at path '" + path + "'", !!newView);
16131
17455
  } else {
16132
17456
  newView = path;
@@ -16134,12 +17458,14 @@ Ember.Handlebars.ViewHelper = Ember.Object.create({
16134
17458
 
16135
17459
  ember_assert(Ember.String.fmt('You must pass a view class to the #view helper, not %@ (%@)', [path, newView]), Ember.View.detect(newView));
16136
17460
 
16137
- newView = this.viewClassFromHTMLOptions(newView, hash, thisContext);
17461
+ newView = this.viewClassFromHTMLOptions(newView, options, thisContext);
16138
17462
  var currentView = data.view;
16139
- var viewOptions = {};
17463
+ var viewOptions = {
17464
+ templateData: options.data
17465
+ };
16140
17466
 
16141
17467
  if (fn) {
16142
- ember_assert("You cannot provide a template block if you also specified a templateName", !(get(viewOptions, 'templateName')) && (indexOf(newView.PrototypeMixin.keys(), 'templateName') >= 0));
17468
+ ember_assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newView.proto(), 'templateName'));
16143
17469
  viewOptions.template = fn;
16144
17470
  }
16145
17471
 
@@ -16153,7 +17479,7 @@ Ember.Handlebars.ViewHelper = Ember.Object.create({
16153
17479
  @param {Hash} options
16154
17480
  @returns {String} HTML string
16155
17481
  */
16156
- Ember.Handlebars.registerHelper('view', function(path, options) {
17482
+ EmberHandlebars.registerHelper('view', function(path, options) {
16157
17483
  ember_assert("The view helper only takes a single argument", arguments.length <= 2);
16158
17484
 
16159
17485
  // If no path is provided, treat path param as options.
@@ -16162,13 +17488,15 @@ Ember.Handlebars.registerHelper('view', function(path, options) {
16162
17488
  path = "Ember.View";
16163
17489
  }
16164
17490
 
16165
- return Ember.Handlebars.ViewHelper.helper(this, path, options);
17491
+ return EmberHandlebars.ViewHelper.helper(this, path, options);
16166
17492
  });
16167
17493
 
16168
17494
 
16169
- })({});
17495
+ })();
17496
+
17497
+
16170
17498
 
16171
- (function(exports) {
17499
+ (function() {
16172
17500
  // ==========================================================================
16173
17501
  // Project: Ember Handlebar Views
16174
17502
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16184,6 +17512,108 @@ var get = Ember.get, getPath = Ember.Handlebars.getPath, fmt = Ember.String.fmt;
16184
17512
  @param {String} path
16185
17513
  @param {Hash} options
16186
17514
  @returns {String} HTML string
17515
+
17516
+ `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
17517
+ `Ember.CollectionView` to a template. See `Ember.CollectionView` for additional
17518
+ information on how a `CollectionView` functions.
17519
+
17520
+ `{{collection}}`'s primary use is as a block helper with a `contentBinding` option
17521
+ pointing towards an `Ember.Array`-compatible object. An `Ember.View` instance will
17522
+ be created for each item in its `content` property. Each view will have its own
17523
+ `content` property set to the appropriate item in the collection.
17524
+
17525
+ The provided block will be applied as the template for each item's view.
17526
+
17527
+ Given an empty `<body>` the following template:
17528
+
17529
+ <script type="text/x-handlebars">
17530
+ {{#collection contentBinding="App.items"}}
17531
+ Hi {{content.name}}
17532
+ {{/collection}}
17533
+ </script>
17534
+
17535
+ And the following application code
17536
+
17537
+ App = Ember.Application.create()
17538
+ App.items = [
17539
+ Ember.Object.create({name: 'Dave'}),
17540
+ Ember.Object.create({name: 'Mary'}),
17541
+ Ember.Object.create({name: 'Sara'})
17542
+ ]
17543
+
17544
+ Will result in the HTML structure below
17545
+
17546
+ <div class="ember-view">
17547
+ <div class="ember-view">Hi Dave</div>
17548
+ <div class="ember-view">Hi Mary</div>
17549
+ <div class="ember-view">Hi Sara</div>
17550
+ </div>
17551
+
17552
+ ### Blockless Use
17553
+ If you provide an `itemViewClass` option that has its own `template` you can omit
17554
+ the block.
17555
+
17556
+ The following template:
17557
+
17558
+ <script type="text/x-handlebars">
17559
+ {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
17560
+ </script>
17561
+
17562
+ And application code
17563
+
17564
+ App = Ember.Application.create()
17565
+ App.items = [
17566
+ Ember.Object.create({name: 'Dave'}),
17567
+ Ember.Object.create({name: 'Mary'}),
17568
+ Ember.Object.create({name: 'Sara'})
17569
+ ]
17570
+
17571
+ App.AnItemView = Ember.View.extend({
17572
+ template: Ember.Handlebars.compile("Greetings {{content.name}}")
17573
+ })
17574
+
17575
+ Will result in the HTML structure below
17576
+
17577
+ <div class="ember-view">
17578
+ <div class="ember-view">Greetings Dave</div>
17579
+ <div class="ember-view">Greetings Mary</div>
17580
+ <div class="ember-view">Greetings Sara</div>
17581
+ </div>
17582
+
17583
+ ### Specifying a CollectionView subclass
17584
+ By default the `{{collection}}` helper will create an instance of `Ember.CollectionView`.
17585
+ You can supply a `Ember.CollectionView` subclass to the helper by passing it
17586
+ as the first argument:
17587
+
17588
+ <script type="text/x-handlebars">
17589
+ {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
17590
+ Hi {{content.name}}
17591
+ {{/collection}}
17592
+ </script>
17593
+
17594
+
17595
+ ### Forwarded `item.*`-named Options
17596
+ As with the `{{view}}`, helper options passed to the `{{collection}}` will be set on
17597
+ the resulting `Ember.CollectionView` as properties. Additionally, options prefixed with
17598
+ `item` will be applied to the views rendered for each item (note the camelcasing):
17599
+
17600
+ <script type="text/x-handlebars">
17601
+ {{#collection contentBinding="App.items"
17602
+ itemTagName="p"
17603
+ itemClassNames="greeting"}}
17604
+ Howdy {{content.name}}
17605
+ {{/collection}}
17606
+ </script>
17607
+
17608
+ Will result in the following HTML structure:
17609
+
17610
+ <div class="ember-view">
17611
+ <p class="ember-view greeting">Howdy Dave</p>
17612
+ <p class="ember-view greeting">Howdy Mary</p>
17613
+ <p class="ember-view greeting">Howdy Sara</p>
17614
+ </div>
17615
+
17616
+
16187
17617
  */
16188
17618
  Ember.Handlebars.registerHelper('collection', function(path, options) {
16189
17619
  // If no path is provided, treat path param as options.
@@ -16202,7 +17632,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
16202
17632
  // If passed a path string, convert that into an object.
16203
17633
  // Otherwise, just default to the standard class.
16204
17634
  var collectionClass;
16205
- collectionClass = path ? getPath(this, path) : Ember.CollectionView;
17635
+ collectionClass = path ? getPath(this, path, options) : Ember.CollectionView;
16206
17636
  ember_assert(fmt("%@ #collection: Could not find %@", data.view, path), !!collectionClass);
16207
17637
 
16208
17638
  var hash = options.hash, itemHash = {}, match;
@@ -16211,7 +17641,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
16211
17641
  var itemViewClass, itemViewPath = hash.itemViewClass;
16212
17642
  var collectionPrototype = collectionClass.proto();
16213
17643
  delete hash.itemViewClass;
16214
- itemViewClass = itemViewPath ? getPath(collectionPrototype, itemViewPath) : collectionPrototype.itemViewClass;
17644
+ itemViewClass = itemViewPath ? getPath(collectionPrototype, itemViewPath, options) : collectionPrototype.itemViewClass;
16215
17645
  ember_assert(fmt("%@ #collection: Could not find %@", data.view, itemViewPath), !!itemViewClass);
16216
17646
 
16217
17647
  // Go through options passed to the {{collection}} helper and extract options
@@ -16242,7 +17672,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
16242
17672
 
16243
17673
  if (hash.emptyViewClass) {
16244
17674
  emptyViewClass = Ember.View.detect(hash.emptyViewClass) ?
16245
- hash.emptyViewClass : getPath(this, hash.emptyViewClass);
17675
+ hash.emptyViewClass : getPath(this, hash.emptyViewClass, options);
16246
17676
  }
16247
17677
 
16248
17678
  hash.emptyView = emptyViewClass.extend({
@@ -16252,13 +17682,13 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
16252
17682
  }
16253
17683
 
16254
17684
  if (hash.preserveContext) {
16255
- itemHash.templateContext = Ember.computed(function() {
17685
+ itemHash._templateContext = Ember.computed(function() {
16256
17686
  return get(this, 'content');
16257
17687
  }).property('content');
16258
17688
  delete hash.preserveContext;
16259
17689
  }
16260
17690
 
16261
- hash.itemViewClass = Ember.Handlebars.ViewHelper.viewClassFromHTMLOptions(itemViewClass, itemHash, this);
17691
+ hash.itemViewClass = Ember.Handlebars.ViewHelper.viewClassFromHTMLOptions(itemViewClass, { data: data, hash: itemHash }, this);
16262
17692
 
16263
17693
  return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
16264
17694
  });
@@ -16266,9 +17696,11 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
16266
17696
 
16267
17697
 
16268
17698
 
16269
- })({});
17699
+ })();
16270
17700
 
16271
- (function(exports) {
17701
+
17702
+
17703
+ (function() {
16272
17704
  // ==========================================================================
16273
17705
  // Project: Ember Handlebar Views
16274
17706
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16289,12 +17721,14 @@ var getPath = Ember.Handlebars.getPath;
16289
17721
  */
16290
17722
  Ember.Handlebars.registerHelper('unbound', function(property, fn) {
16291
17723
  var context = (fn.contexts && fn.contexts[0]) || this;
16292
- return getPath(context, property);
17724
+ return getPath(context, property, fn);
16293
17725
  });
16294
17726
 
16295
- })({});
17727
+ })();
17728
+
16296
17729
 
16297
- (function(exports) {
17730
+
17731
+ (function() {
16298
17732
  // ==========================================================================
16299
17733
  // Project: Ember Handlebar Views
16300
17734
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16331,9 +17765,11 @@ Ember.Handlebars.registerHelper('debugger', function() {
16331
17765
  debugger;
16332
17766
  });
16333
17767
 
16334
- })({});
17768
+ })();
17769
+
17770
+
16335
17771
 
16336
- (function(exports) {
17772
+ (function() {
16337
17773
  Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember.Metamorph, {
16338
17774
  itemViewClass: Ember.View.extend(Ember.Metamorph)
16339
17775
  });
@@ -16349,9 +17785,11 @@ Ember.Handlebars.registerHelper('each', function(path, options) {
16349
17785
  return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
16350
17786
  });
16351
17787
 
16352
- })({});
17788
+ })();
17789
+
17790
+
16353
17791
 
16354
- (function(exports) {
17792
+ (function() {
16355
17793
  /**
16356
17794
  `template` allows you to render a template from inside another template.
16357
17795
  This allows you to re-use the same template in multiple places. For example:
@@ -16388,15 +17826,128 @@ Ember.Handlebars.registerHelper('template', function(name, options) {
16388
17826
  Ember.TEMPLATES[name](this, { data: options.data });
16389
17827
  });
16390
17828
 
16391
- })({});
17829
+ })();
17830
+
16392
17831
 
16393
- (function(exports) {
16394
- var EmberHandlebars = Ember.Handlebars, getPath = Ember.Handlebars.getPath;
17832
+
17833
+ (function() {
17834
+ var EmberHandlebars = Ember.Handlebars, getPath = EmberHandlebars.getPath;
16395
17835
 
16396
17836
  var ActionHelper = EmberHandlebars.ActionHelper = {
16397
17837
  registeredActions: {}
16398
17838
  };
17839
+ /**
17840
+ @name Handlebars.helpers.action
17841
+
17842
+ The `{{action}}` helper registers an HTML element within a template for
17843
+ DOM event handling. User interaction with that element will call the method
17844
+ on the template's associated `Ember.View` instance that has the same name
17845
+ as the first provided argument to `{{action}}`:
17846
+
17847
+ Given the following Handlebars template on the page
17848
+
17849
+ <script type="text/x-handlebars" data-template-name='a-template'>
17850
+ <div {{action "anActionName"}}>
17851
+ click me
17852
+ </div>
17853
+ </script>
17854
+
17855
+ And application code
17856
+
17857
+ AView = Ember.View.extend({
17858
+ templateName; 'a-template',
17859
+ anActionName: function(event){}
17860
+ })
17861
+
17862
+ aView = AView.create()
17863
+ aView.appendTo('body')
17864
+
17865
+ Will results in the following rendered HTML
17866
+
17867
+ <div class="ember-view">
17868
+ <div data-ember-action="1">
17869
+ click me
17870
+ </div>
17871
+ </div>
17872
+
17873
+ Clicking "click me" will trigger the `anActionName` method of the `aView` object with a
17874
+ `jQuery.Event` object as its argument. The `jQuery.Event` object will be extended to include
17875
+ a `view` property that is set to the original view interacted with (in this case the `aView` object).
17876
+
17877
+
17878
+ ### Specifying an Action Target
17879
+ A `target` option can be provided to change which object will receive the method call. This option must be
17880
+ a string representing a path to an object:
17881
+
17882
+ <script type="text/x-handlebars" data-template-name='a-template'>
17883
+ <div {{action "anActionName" target="MyApplication.someObject"}}>
17884
+ click me
17885
+ </div>
17886
+ </script>
17887
+
17888
+ Clicking "click me" in the rendered HTML of the above template will trigger the
17889
+ `anActionName` method of the object at `MyApplication.someObject`. The first argument
17890
+ to this method will be a `jQuery.Event` extended to include a `view` property that is
17891
+ set to the original view interacted with.
17892
+
17893
+ A path relative to the template's `Ember.View` instance can also be used as a target:
17894
+
17895
+ <script type="text/x-handlebars" data-template-name='a-template'>
17896
+ <div {{action "anActionName" target="parentView"}}>
17897
+ click me
17898
+ </div>
17899
+ </script>
17900
+
17901
+ Clicking "click me" in the rendered HTML of the above template will trigger the
17902
+ `anActionName` method of the view's parent view.
17903
+
17904
+ The `{{action}}` helper is `Ember.StateManager` aware. If the target of
17905
+ the action is an `Ember.StateManager` instance `{{action}}` will use the `send`
17906
+ functionality of StateManagers. The documentation for `Ember.StateManager` has additional
17907
+ information about this use.
17908
+
17909
+ If an action's target does not implement a method that matches the supplied action name
17910
+ an error will be thrown.
17911
+
17912
+
17913
+ <script type="text/x-handlebars" data-template-name='a-template'>
17914
+ <div {{action "aMethodNameThatIsMissing"}}>
17915
+ click me
17916
+ </div>
17917
+ </script>
17918
+
17919
+ With the following application code
17920
+
17921
+ AView = Ember.View.extend({
17922
+ templateName; 'a-template',
17923
+ // note: no method 'aMethodNameThatIsMissing'
17924
+ anActionName: function(event){}
17925
+ })
16399
17926
 
17927
+ aView = AView.create()
17928
+ aView.appendTo('body')
17929
+
17930
+ Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when "click me" is clicked.
17931
+
17932
+
17933
+ ### Specifying DOM event type
17934
+ By default the `{{action}}` helper registers for DOM `click` events. You can supply an
17935
+ `on` option to the helper to specify a different DOM event name:
17936
+
17937
+ <script type="text/x-handlebars" data-template-name='a-template'>
17938
+ <div {{action "aMethodNameThatIsMissing" on="doubleClick"}}>
17939
+ click me
17940
+ </div>
17941
+ </script>
17942
+
17943
+ See `Ember.EventDispatcher` for a list of acceptable DOM event names.
17944
+
17945
+ Because `{{action}}` depends on Ember's event dispatch system it will only function if
17946
+ an `Ember.EventDispatcher` instance is available. An `Ember.EventDispatcher` instance
17947
+ will be created when a new `Ember.Application` is created. Having an instance of
17948
+ `Ember.Application` will satisfy this requirement.
17949
+
17950
+ */
16400
17951
  ActionHelper.registerAction = function(actionName, eventName, target, view, context) {
16401
17952
  var actionId = (++Ember.$.uuid).toString();
16402
17953
 
@@ -16406,7 +17957,8 @@ ActionHelper.registerAction = function(actionName, eventName, target, view, cont
16406
17957
  event.view = view;
16407
17958
  event.context = context;
16408
17959
 
16409
- if ('function' === typeof target.send) {
17960
+ // Check for StateManager (or compatible object)
17961
+ if (target.isState && typeof target.send === 'function') {
16410
17962
  return target.send(actionName, event);
16411
17963
  } else {
16412
17964
  return target[actionName].call(target, event);
@@ -16423,23 +17975,68 @@ ActionHelper.registerAction = function(actionName, eventName, target, view, cont
16423
17975
 
16424
17976
  EmberHandlebars.registerHelper('action', function(actionName, options) {
16425
17977
  var hash = options.hash || {},
16426
- eventName = options.hash.on || "click",
17978
+ eventName = hash.on || "click",
16427
17979
  view = options.data.view,
16428
17980
  target, context;
16429
17981
 
16430
17982
  if (view.isVirtual) { view = view.get('parentView'); }
16431
- target = options.hash.target ? getPath(this, options.hash.target) : view;
17983
+ target = hash.target ? getPath(this, hash.target, options) : view;
16432
17984
  context = options.contexts[0];
16433
17985
 
16434
17986
  var actionId = ActionHelper.registerAction(actionName, eventName, target, view, context);
16435
17987
  return new EmberHandlebars.SafeString('data-ember-action="' + actionId + '"');
16436
17988
  });
16437
17989
 
16438
- })({});
17990
+ })();
17991
+
16439
17992
 
16440
- (function(exports) {
17993
+
17994
+ (function() {
16441
17995
  var get = Ember.get, set = Ember.set;
16442
17996
 
17997
+ /**
17998
+ @name Handlebars.helpers.yield
17999
+
18000
+ When used in a Handlebars template that is assigned to an `Ember.View` instance's
18001
+ `layout` property Ember will render the layout template first, inserting the view's
18002
+ own rendered output at the `{{ yield }}` location.
18003
+
18004
+ An empty `<body>` and the following application code:
18005
+
18006
+ AView = Ember.View.extend({
18007
+ classNames: ['a-view-with-layout'],
18008
+ layout: Ember.Handlebars.compile('<div class="wrapper">{{ yield }}</div>'),
18009
+ template: Ember.Handlebars.compile('<span>I am wrapped</span>')
18010
+ })
18011
+
18012
+ aView = AView.create()
18013
+ aView.appendTo('body')
18014
+
18015
+ Will result in the following HTML output:
18016
+
18017
+ <body>
18018
+ <div class='ember-view a-view-with-layout'>
18019
+ <div class="wrapper">
18020
+ <span>I am wrapped</span>
18021
+ </div>
18022
+ </div>
18023
+ </body>
18024
+
18025
+
18026
+ The yield helper cannot be used outside of a template assigned to an `Ember.View`'s `layout` property
18027
+ and will throw an error if attempted.
18028
+
18029
+ BView = Ember.View.extend({
18030
+ classNames: ['a-view-with-layout'],
18031
+ template: Ember.Handlebars.compile('{{yield}}')
18032
+ })
18033
+
18034
+ bView = BView.create()
18035
+ bView.appendTo('body')
18036
+
18037
+ // throws
18038
+ // Uncaught Error: assertion failed: You called yield in a template that was not a layout
18039
+ */
16443
18040
  Ember.Handlebars.registerHelper('yield', function(options) {
16444
18041
  var view = options.data.view, template;
16445
18042
 
@@ -16451,31 +18048,36 @@ Ember.Handlebars.registerHelper('yield', function(options) {
16451
18048
 
16452
18049
  template = get(view, 'template');
16453
18050
 
16454
- ember_assert("You called yield on " + view.toString() + " without supplying a template", !!template);
16455
- template(this, options);
18051
+ if (template) { template(this, options); }
16456
18052
  });
16457
18053
 
16458
- })({});
18054
+ })();
18055
+
16459
18056
 
16460
- (function(exports) {
18057
+
18058
+ (function() {
16461
18059
  // ==========================================================================
16462
18060
  // Project: Ember Handlebar Views
16463
18061
  // Copyright: ©2011 Strobe Inc. and contributors.
16464
18062
  // License: Licensed under MIT license (see license.js)
16465
18063
  // ==========================================================================
16466
18064
 
16467
- })({});
18065
+ })();
18066
+
16468
18067
 
16469
- (function(exports) {
18068
+
18069
+ (function() {
16470
18070
  // ==========================================================================
16471
18071
  // Project: Ember Handlebar Views
16472
18072
  // Copyright: ©2011 Strobe Inc. and contributors.
16473
18073
  // License: Licensed under MIT license (see license.js)
16474
18074
  // ==========================================================================
16475
18075
 
16476
- })({});
18076
+ })();
18077
+
18078
+
16477
18079
 
16478
- (function(exports) {
18080
+ (function() {
16479
18081
  // ==========================================================================
16480
18082
  // Project: Ember Handlebar Views
16481
18083
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16483,35 +18085,100 @@ Ember.Handlebars.registerHelper('yield', function(options) {
16483
18085
  // ==========================================================================
16484
18086
  var set = Ember.set, get = Ember.get;
16485
18087
 
16486
- // TODO: Be explicit in the class documentation that you
16487
- // *MUST* set the value of a checkbox through Ember.
16488
- // Updating the value of a checkbox directly via jQuery objects
16489
- // will not work.
18088
+ /**
18089
+ @class
18090
+
18091
+ Creates an HTML input view in one of two formats.
18092
+
18093
+ If a `title` property or binding is provided the input will be wrapped in
18094
+ a `div` and `label` tag. View properties like `classNames` will be applied to
18095
+ the outermost `div`. This behavior is deprecated and will issue a warning in development.
18096
+
18097
+
18098
+ {{view Ember.Checkbox classNames="applicaton-specific-checkbox" title="Some title"}}
18099
+
18100
+
18101
+ <div id="ember1" class="ember-view ember-checkbox applicaton-specific-checkbox">
18102
+ <label><input type="checkbox" />Some title</label>
18103
+ </div>
18104
+
18105
+ If `title` isn't provided the view will render as an input element of the 'checkbox' type and HTML
18106
+ related properties will be applied directly to the input.
18107
+
18108
+ {{view Ember.Checkbox classNames="applicaton-specific-checkbox"}}
18109
+
18110
+ <input id="ember1" class="ember-view ember-checkbox applicaton-specific-checkbox" type="checkbox">
18111
+
18112
+ You can add a `label` tag yourself in the template where the Ember.Checkbox is being used.
18113
+
18114
+ <label>
18115
+ Some Title
18116
+ {{view Ember.Checkbox classNames="applicaton-specific-checkbox"}}
18117
+ </label>
18118
+
18119
+
18120
+ The `checked` attribute of an Ember.Checkbox object should always be set
18121
+ through the Ember object or by interacting with its rendered element representation
18122
+ via the mouse, keyboard, or touch. Updating the value of the checkbox via jQuery will
18123
+ result in the checked value of the object and its element losing synchronization.
16490
18124
 
18125
+ */
16491
18126
  Ember.Checkbox = Ember.View.extend({
16492
- title: null,
16493
- value: false,
18127
+ classNames: ['ember-checkbox'],
18128
+
18129
+ tagName: Ember.computed(function(){
18130
+ return get(this, 'title') ? undefined : 'input';
18131
+ }).property(),
18132
+
18133
+ attributeBindings: Ember.computed(function(){
18134
+ return get(this, 'title') ? [] : ['type', 'checked', 'disabled'];
18135
+ }).property(),
18136
+
18137
+ type: "checkbox",
18138
+ checked: false,
16494
18139
  disabled: false,
16495
18140
 
16496
- classNames: ['ember-checkbox'],
18141
+ title: Ember.computed(function(propName, value){
18142
+ ember_deprecate("Automatically surrounding Ember.Checkbox inputs with a label by providing a 'title' property is deprecated", value === undefined);
18143
+ return value;
18144
+ }).property().cacheable(),
16497
18145
 
16498
- defaultTemplate: Ember.Handlebars.compile('<label><input type="checkbox" {{bindAttr checked="value" disabled="disabled"}}>{{title}}</label>'),
18146
+ defaultTemplate: Ember.computed(function(){
18147
+ if (get(this, 'title')) {
18148
+ return Ember.Handlebars.compile('<label><input type="checkbox" {{bindAttr checked="checked" disabled="disabled"}}>{{title}}</label>');
18149
+ } else {
18150
+ return undefined;
18151
+ }
18152
+ }).property().cacheable(),
18153
+
18154
+ value: Ember.computed(function(propName, value){
18155
+ ember_deprecate("Ember.Checkbox's 'value' property has been renamed to 'checked' to match the html element attribute name");
18156
+ if (value !== undefined) {
18157
+ return set(this, 'checked', value);
18158
+ } else {
18159
+ return get(this, 'checked');
18160
+ }
18161
+ }).property('checked'),
16499
18162
 
16500
18163
  change: function() {
16501
18164
  Ember.run.once(this, this._updateElementValue);
16502
18165
  // returning false will cause IE to not change checkbox state
16503
18166
  },
16504
-
18167
+
18168
+ /**
18169
+ @private
18170
+ */
16505
18171
  _updateElementValue: function() {
16506
- var input = this.$('input:checkbox');
16507
- set(this, 'value', input.prop('checked'));
18172
+ var input = get(this, 'title') ? this.$('input:checkbox') : this.$();
18173
+ set(this, 'checked', input.prop('checked'));
16508
18174
  }
16509
18175
  });
16510
18176
 
18177
+ })();
18178
+
16511
18179
 
16512
- })({});
16513
18180
 
16514
- (function(exports) {
18181
+ (function() {
16515
18182
  // ==========================================================================
16516
18183
  // Project: Ember Handlebar Views
16517
18184
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16567,9 +18234,11 @@ Ember.TextSupport.KEY_EVENTS = {
16567
18234
  27: 'cancel'
16568
18235
  };
16569
18236
 
16570
- })({});
18237
+ })();
18238
+
16571
18239
 
16572
- (function(exports) {
18240
+
18241
+ (function() {
16573
18242
  // ==========================================================================
16574
18243
  // Project: Ember Handlebar Views
16575
18244
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16592,9 +18261,11 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
16592
18261
  size: null
16593
18262
  });
16594
18263
 
16595
- })({});
18264
+ })();
18265
+
18266
+
16596
18267
 
16597
- (function(exports) {
18268
+ (function() {
16598
18269
  // ==========================================================================
16599
18270
  // Project: Ember Handlebar Views
16600
18271
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16612,6 +18283,20 @@ Ember.Button = Ember.View.extend(Ember.TargetActionSupport, {
16612
18283
 
16613
18284
  attributeBindings: ['type', 'disabled', 'href'],
16614
18285
 
18286
+ /** @private
18287
+ Overrides TargetActionSupport's targetObject computed
18288
+ property to use Handlebars-specific path resolution.
18289
+ */
18290
+ targetObject: Ember.computed(function() {
18291
+ var target = get(this, 'target'),
18292
+ root = get(this, 'templateContext'),
18293
+ data = get(this, 'templateData');
18294
+
18295
+ if (typeof target !== 'string') { return target; }
18296
+
18297
+ return Ember.Handlebars.getPath(root, target, { data: data });
18298
+ }).property('target').cacheable(),
18299
+
16615
18300
  // Defaults to 'button' if tagName is 'input' or 'button'
16616
18301
  type: Ember.computed(function(key, value) {
16617
18302
  var tagName = this.get('tagName');
@@ -16690,9 +18375,11 @@ Ember.Button = Ember.View.extend(Ember.TargetActionSupport, {
16690
18375
  }
16691
18376
  });
16692
18377
 
16693
- })({});
18378
+ })();
18379
+
16694
18380
 
16695
- (function(exports) {
18381
+
18382
+ (function() {
16696
18383
  // ==========================================================================
16697
18384
  // Project: Ember Handlebar Views
16698
18385
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16727,14 +18414,18 @@ Ember.TextArea = Ember.View.extend(Ember.TextSupport,
16727
18414
 
16728
18415
  });
16729
18416
 
16730
- })({});
18417
+ })();
18418
+
18419
+
16731
18420
 
16732
- (function(exports) {
18421
+ (function() {
16733
18422
  Ember.TabContainerView = Ember.View.extend();
16734
18423
 
16735
- })({});
18424
+ })();
16736
18425
 
16737
- (function(exports) {
18426
+
18427
+
18428
+ (function() {
16738
18429
  var get = Ember.get, getPath = Ember.getPath;
16739
18430
 
16740
18431
  Ember.TabPaneView = Ember.View.extend({
@@ -16747,9 +18438,11 @@ Ember.TabPaneView = Ember.View.extend({
16747
18438
  }).property('tabsContainer.currentView')
16748
18439
  });
16749
18440
 
16750
- })({});
18441
+ })();
18442
+
16751
18443
 
16752
- (function(exports) {
18444
+
18445
+ (function() {
16753
18446
  var get = Ember.get, setPath = Ember.setPath;
16754
18447
 
16755
18448
  Ember.TabView = Ember.View.extend({
@@ -16762,17 +18455,21 @@ Ember.TabView = Ember.View.extend({
16762
18455
  }
16763
18456
  });
16764
18457
 
16765
- })({});
18458
+ })();
18459
+
16766
18460
 
16767
- (function(exports) {
16768
18461
 
16769
- })({});
18462
+ (function() {
16770
18463
 
16771
- (function(exports) {
18464
+ })();
18465
+
18466
+
18467
+
18468
+ (function() {
16772
18469
  /*jshint eqeqeq:false */
16773
18470
 
16774
18471
  var set = Ember.set, get = Ember.get, getPath = Ember.getPath;
16775
- var indexOf = Ember.ArrayUtils.indexOf;
18472
+ var indexOf = Ember.ArrayUtils.indexOf, indexesOf = Ember.ArrayUtils.indexesOf;
16776
18473
 
16777
18474
  Ember.Select = Ember.View.extend({
16778
18475
  tagName: 'select',
@@ -16780,7 +18477,9 @@ Ember.Select = Ember.View.extend({
16780
18477
  '{{#if prompt}}<option>{{prompt}}</option>{{/if}}' +
16781
18478
  '{{#each content}}{{view Ember.SelectOption contentBinding="this"}}{{/each}}'
16782
18479
  ),
18480
+ attributeBindings: ['multiple'],
16783
18481
 
18482
+ multiple: false,
16784
18483
  content: null,
16785
18484
  selection: null,
16786
18485
  prompt: null,
@@ -16797,6 +18496,29 @@ Ember.Select = Ember.View.extend({
16797
18496
  },
16798
18497
 
16799
18498
  change: function() {
18499
+ if (get(this, 'multiple')) {
18500
+ this._changeMultiple();
18501
+ } else {
18502
+ this._changeSingle();
18503
+ }
18504
+ },
18505
+
18506
+ selectionDidChange: Ember.observer(function() {
18507
+ var selection = get(this, 'selection'),
18508
+ isArray = Ember.isArray(selection);
18509
+ if (get(this, 'multiple')) {
18510
+ if (!isArray) {
18511
+ set(this, 'selection', Ember.A([selection]));
18512
+ return;
18513
+ }
18514
+ this._selectionDidChangeMultiple();
18515
+ } else {
18516
+ this._selectionDidChangeSingle();
18517
+ }
18518
+ }, 'selection'),
18519
+
18520
+
18521
+ _changeSingle: function() {
16800
18522
  var selectedIndex = this.$()[0].selectedIndex,
16801
18523
  content = get(this, 'content'),
16802
18524
  prompt = get(this, 'prompt');
@@ -16808,7 +18530,22 @@ Ember.Select = Ember.View.extend({
16808
18530
  set(this, 'selection', content.objectAt(selectedIndex));
16809
18531
  },
16810
18532
 
16811
- selectionDidChange: Ember.observer(function() {
18533
+ _changeMultiple: function() {
18534
+ var options = this.$('option:selected'),
18535
+ prompt = get(this, 'prompt'),
18536
+ offset = prompt ? 1 : 0,
18537
+ content = get(this, 'content');
18538
+
18539
+ if (!content){ return; }
18540
+ if (options) {
18541
+ var selectedIndexes = options.map(function(){
18542
+ return this.index - offset;
18543
+ }).toArray();
18544
+ set(this, 'selection', content.objectsAt(selectedIndexes));
18545
+ }
18546
+ },
18547
+
18548
+ _selectionDidChangeSingle: function() {
16812
18549
  var el = this.$()[0],
16813
18550
  content = get(this, 'content'),
16814
18551
  selection = get(this, 'selection'),
@@ -16817,7 +18554,23 @@ Ember.Select = Ember.View.extend({
16817
18554
 
16818
18555
  if (prompt) { selectionIndex += 1; }
16819
18556
  if (el) { el.selectedIndex = selectionIndex; }
16820
- }, 'selection')
18557
+ },
18558
+
18559
+ _selectionDidChangeMultiple: function() {
18560
+ var content = get(this, 'content'),
18561
+ selection = get(this, 'selection'),
18562
+ selectedIndexes = indexesOf(content, selection),
18563
+ prompt = get(this, 'prompt'),
18564
+ offset = prompt ? 1 : 0,
18565
+ options = this.$('option');
18566
+
18567
+ if (options) {
18568
+ options.each(function() {
18569
+ this.selected = indexOf(selectedIndexes, this.index + offset) > -1;
18570
+ });
18571
+ }
18572
+ }
18573
+
16821
18574
  });
16822
18575
 
16823
18576
  Ember.SelectOption = Ember.View.extend({
@@ -16833,8 +18586,15 @@ Ember.SelectOption = Ember.View.extend({
16833
18586
  },
16834
18587
 
16835
18588
  selected: Ember.computed(function() {
16836
- // Primitives get passed through bindings as objects... since `new Number(4) !== 4`, we use `==` below
16837
- return get(this, 'content') == getPath(this, 'parentView.selection');
18589
+ var content = get(this, 'content'),
18590
+ selection = getPath(this, 'parentView.selection');
18591
+ if (getPath(this, 'parentView.multiple')) {
18592
+ return selection && indexOf(selection, content) > -1;
18593
+ } else {
18594
+ // Primitives get passed through bindings as objects... since
18595
+ // `new Number(4) !== 4`, we use `==` below
18596
+ return content == selection;
18597
+ }
16838
18598
  }).property('content', 'parentView.selection'),
16839
18599
 
16840
18600
  labelPathDidChange: Ember.observer(function() {
@@ -16859,18 +18619,22 @@ Ember.SelectOption = Ember.View.extend({
16859
18619
  });
16860
18620
 
16861
18621
 
16862
- })({});
18622
+ })();
18623
+
18624
+
16863
18625
 
16864
- (function(exports) {
18626
+ (function() {
16865
18627
  // ==========================================================================
16866
18628
  // Project: Ember Handlebar Views
16867
18629
  // Copyright: ©2011 Strobe Inc. and contributors.
16868
18630
  // License: Licensed under MIT license (see license.js)
16869
18631
  // ==========================================================================
16870
18632
 
16871
- })({});
18633
+ })();
18634
+
16872
18635
 
16873
- (function(exports) {
18636
+
18637
+ (function() {
16874
18638
  // ==========================================================================
16875
18639
  // Project: Ember Handlebar Views
16876
18640
  // Copyright: ©2011 Strobe Inc. and contributors.
@@ -16903,15 +18667,12 @@ Ember.Handlebars.bootstrap = function(ctx) {
16903
18667
  var compile = (script.attr('type') === 'text/x-raw-handlebars') ?
16904
18668
  Ember.$.proxy(Handlebars.compile, Handlebars) :
16905
18669
  Ember.$.proxy(Ember.Handlebars.compile, Ember.Handlebars),
16906
- // Get the id of the script, used by Ember.View's elementId property,
16907
- // Look for data-element-id attribute.
16908
- elementId = script.attr('data-element-id'),
16909
18670
  // Get the name of the script, used by Ember.View's templateName property.
16910
18671
  // First look for data-template-name attribute, then fall back to its
16911
18672
  // id if no name is found.
16912
18673
  templateName = script.attr('data-template-name') || script.attr('id'),
16913
18674
  template = compile(script.html()),
16914
- view, viewPath, tagName;
18675
+ view, viewPath, elementId, tagName, options;
16915
18676
 
16916
18677
  if (templateName) {
16917
18678
  // For templates which have a name, we save them and then remove them from the DOM
@@ -16936,15 +18697,19 @@ Ember.Handlebars.bootstrap = function(ctx) {
16936
18697
  viewPath = script.attr('data-view');
16937
18698
  view = viewPath ? Ember.getPath(viewPath) : Ember.View;
16938
18699
 
18700
+ // Get the id of the script, used by Ember.View's elementId property,
18701
+ // Look for data-element-id attribute.
18702
+ elementId = script.attr('data-element-id');
18703
+
16939
18704
  // Users can optionally specify a custom tag name to use by setting the
16940
18705
  // data-tag-name attribute on the script tag.
16941
18706
  tagName = script.attr('data-tag-name');
16942
18707
 
16943
- view = view.create({
16944
- elementId: elementId,
16945
- template: template,
16946
- tagName: (tagName) ? tagName : undefined
16947
- });
18708
+ options = { template: template };
18709
+ if (elementId) { options.elementId = elementId; }
18710
+ if (tagName) { options.tagName = tagName; }
18711
+
18712
+ view = view.create(options);
16948
18713
 
16949
18714
  view._insertElementLater(function() {
16950
18715
  script.replaceWith(this.$());
@@ -16962,23 +18727,25 @@ Ember.$(document).ready(
16962
18727
  }
16963
18728
  );
16964
18729
 
16965
- })({});
18730
+ })();
16966
18731
 
16967
- (function(exports) {
18732
+
18733
+
18734
+ (function() {
16968
18735
  // ==========================================================================
16969
18736
  // Project: Ember Handlebar Views
16970
18737
  // Copyright: ©2011 Strobe Inc. and contributors.
16971
18738
  // License: Licensed under MIT license (see license.js)
16972
18739
  // ==========================================================================
16973
18740
 
16974
- })({});
18741
+ })();
16975
18742
 
16976
- (function(exports) {
18743
+ (function() {
16977
18744
  // ==========================================================================
16978
18745
  // Project: Ember
16979
18746
  // Copyright: ©2011 Strobe Inc. and contributors.
16980
18747
  // License: Licensed under MIT license (see license.js)
16981
18748
  // ==========================================================================
16982
18749
 
16983
- })({});
18750
+ })();
16984
18751