diff --git a/assets/javascripts/app/app.coffee b/assets/javascripts/app/app.coffee
index 5636edfe..e9896f25 100644
--- a/assets/javascripts/app/app.coffee
+++ b/assets/javascripts/app/app.coffee
@@ -21,6 +21,7 @@ require 'data/sponsors'
Travis.reopen
App: Em.Application.extend
+ autoinit: false
currentUserBinding: 'auth.user'
accessTokenBinding: 'auth.user.accessToken'
authStateBinding: 'auth.state'
diff --git a/assets/javascripts/app/routes.coffee b/assets/javascripts/app/routes.coffee
index fdab0984..59370c57 100644
--- a/assets/javascripts/app/routes.coffee
+++ b/assets/javascripts/app/routes.coffee
@@ -68,6 +68,7 @@ Travis.Router = Ember.Router.extend
router.get('statsLayoutController').connectOutlet 'main', 'stats'
profile: Ember.Route.extend
+ initialState: 'index'
route: '/profile'
connectOutlets: (router) ->
router.get('applicationController').connectOutlet 'profileLayout'
@@ -82,6 +83,7 @@ Travis.Router = Ember.Router.extend
router.get('profileController').activate 'hooks'
account: Ember.Route.extend
+ initialState: 'index'
route: '/:login'
connectOutlets: (router, account) ->
@@ -112,6 +114,7 @@ Travis.Router = Ember.Router.extend
router.get('profileController').activate 'user'
home: Ember.Route.extend
+ initialState: 'show'
route: '/'
connectOutlets: (router) ->
router.get('applicationController').connectOutlet 'home'
@@ -127,6 +130,7 @@ Travis.Router = Ember.Router.extend
router.get('repositoryController').activate('index')
repository: Ember.Route.extend
+ initialState: 'show'
route: '/:owner/:name'
connectOutlets: (router, repository) ->
@@ -164,6 +168,7 @@ Travis.Router = Ember.Router.extend
builds: Ember.Route.extend
route: '/builds'
+ initialState: 'index'
index: Ember.Route.extend
route: '/'
diff --git a/assets/javascripts/vendor/ember.js b/assets/javascripts/vendor/ember.js
index 5fd30d45..45c2e6b3 100644
--- a/assets/javascripts/vendor/ember.js
+++ b/assets/javascripts/vendor/ember.js
@@ -3790,7 +3790,7 @@ Ember.RunLoop = RunLoop;
call.
Ember.run(function(){
- // code to be execute within a RunLoop
+ // code to be execute within a RunLoop
});
@class run
@@ -3824,7 +3824,7 @@ var run = Ember.run;
an lower-level way to use a RunLoop instead of using Ember.run().
Ember.run.begin();
- // code to be execute within a RunLoop
+ // code to be execute within a RunLoop
Ember.run.end();
@method begin
@@ -3840,7 +3840,7 @@ Ember.run.begin = function() {
instead of using Ember.run().
Ember.run.begin();
- // code to be execute within a RunLoop
+ // code to be execute within a RunLoop
Ember.run.end();
@method end
@@ -5645,7 +5645,7 @@ Ember.inspect = function(obj) {
/**
Compares two objects, returning true if they are logically equal. This is
a deeper comparison than a simple triple equal. For sets it will compare the
- internal objects. For any other object that implements `isEqual()` it will
+ internal objects. For any other object that implements `isEqual()` it will
respect that method.
Ember.isEqual('hello', 'hello'); => true
@@ -5841,7 +5841,7 @@ Ember.String = {
/**
Converts a camelized string into all lower case separated by underscores.
-
+
'innerHTML'.decamelize() => 'inner_html'
'action_name'.decamelize() => 'action_name'
'css-class-name'.decamelize() => 'css-class-name'
@@ -5857,7 +5857,7 @@ Ember.String = {
/**
Replaces underscores or spaces with dashes.
-
+
'innerHTML'.dasherize() => 'inner-html'
'action_name'.dasherize() => 'action-name'
'css-class-name'.dasherize() => 'css-class-name'
@@ -7737,7 +7737,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
colors.length(); => 0
@method clear
- @return {Ember.Array} An empty Array.
+ @return {Ember.Array} An empty Array.
*/
clear: function () {
var len = get(this, 'length');
@@ -9518,7 +9518,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
The array that the proxy pretends to be. In the default `ArrayProxy`
implementation, this and `content` are the same. Subclasses of `ArrayProxy`
can override this property to provide things like sorting and filtering.
-
+
@property arrangedContent
*/
arrangedContent: Ember.computed('content', function() {
@@ -12186,9 +12186,9 @@ Ember.ControllerMixin.reopen({
}
outletName = outletName || 'view';
-
+
Ember.assert("The viewClass is either missing or the one provided did not resolve to a view", !!name || (!name && !!viewClass));
-
+
Ember.assert("You must supply a name or a viewClass to connectOutlet, but not both", (!!name && !viewClass && !controller) || (!name && !!viewClass));
if (name) {
@@ -12325,7 +12325,7 @@ var invokeForState = {
`Ember.View` is the class in Ember responsible for encapsulating templates of HTML
content, combining templates with data to render as sections of a page's DOM, and
registering and responding to user-initiated events.
-
+
## HTML Tag
The default HTML tag name used for a view's DOM representation is `div`. This can be
customized by setting the `tagName` property. The following view class:
@@ -12359,7 +12359,7 @@ var invokeForState = {
```
`class` attribute values can also be set by providing a `classNameBindings` property
- set to an array of properties names for the view. The return value of these properties
+ set to an array of properties names for the view. The return value of these properties
will be added as part of the value for the view's `class` attribute. These properties
can be computed properties:
@@ -12396,7 +12396,7 @@ var invokeForState = {
```
- When using boolean class name bindings you can supply a string value other than the
+ When using boolean class name bindings you can supply a string value other than the
property name for use as the `class` HTML attribute by appending the preferred value after
a ":" character when defining the binding:
@@ -12466,7 +12466,7 @@ var invokeForState = {
``` html
- ```
+ ```
When isEnabled is `false`, the resulting HTML reprensentation looks like this:
@@ -12497,11 +12497,11 @@ var invokeForState = {
```
- Updates to the the value of a class name binding will result in automatic update
+ Updates to the the value of a class name binding will result in automatic update
of the HTML `class` attribute in the view's rendered HTML representation.
If the value becomes `false` or `undefined` the class name will be removed.
- Both `classNames` and `classNameBindings` are concatenated properties.
+ Both `classNames` and `classNameBindings` are concatenated properties.
See `Ember.Object` documentation for more information about concatenated properties.
## HTML Attributes
@@ -12558,7 +12558,7 @@ var invokeForState = {
});
```
- Updates to the the property of an attribute binding will result in automatic update
+ Updates to the the property of an attribute binding will result in automatic update
of the HTML attribute in the view's rendered HTML representation.
`attributeBindings` is a concatenated property. See `Ember.Object` documentation
@@ -12580,7 +12580,7 @@ var invokeForState = {
``` html
I am the template
- ```
+ ```
The default context of the compiled template will be the view instance itself:
@@ -12670,7 +12670,7 @@ var invokeForState = {
primary templates, layouts can be any function that accepts an optional context
parameter and returns a string of HTML that will be inserted inside view's tag. Views whose HTML
element is self closing (e.g. ``) cannot have a layout and this property will be ignored.
-
+
Most typically in Ember a layout will be a compiled Ember.Handlebars template.
A view's layout can be set directly with the `layout` property or reference an
@@ -12700,7 +12700,7 @@ var invokeForState = {
## Responding to Browser Events
- Views can respond to user-initiated events in one of three ways: method implementation,
+ Views can respond to user-initiated events in one of three ways: method implementation,
through an event manager, and through `{{action}}` helper use in their template or layout.
### Method Implementation
@@ -12721,8 +12721,8 @@ var invokeForState = {
Views can define an object as their `eventManager` property. This object can then
implement methods that match the desired event names. Matching events that occur
- on the view's rendered HTML or the rendered HTML of any of its DOM descendants
- will trigger this method. A `jQuery.Event` object will be passed as the first
+ on the view's rendered HTML or the rendered HTML of any of its DOM descendants
+ will trigger this method. A `jQuery.Event` object will be passed as the first
argument to the method and an `Ember.View` object as the second. The `Ember.View`
will be the view whose rendered HTML was interacted with. This may be the view with
the `eventManager` property or one of its descendent views.
@@ -12759,7 +12759,7 @@ var invokeForState = {
Similarly a view's event manager will take precedence for events of any views
rendered as a descendent. A method name that matches an event name will not be called
- if the view instance was rendered inside the HTML representation of a view that has
+ if the view instance was rendered inside the HTML representation of a view that has
an `eventManager` property defined that handles events of the name. Events not handled
by the event manager will still trigger method calls on the descendent.
@@ -12782,7 +12782,7 @@ var invokeForState = {
// eventManager doesn't handle click events
},
mouseEnter: function(event){
- // will never be called if rendered inside
+ // will never be called if rendered inside
// an OuterView.
}
});
@@ -12806,9 +12806,9 @@ var invokeForState = {
Form events: 'submit', 'change', 'focusIn', 'focusOut', 'input'
HTML5 drag and drop events: 'dragStart', 'drag', 'dragEnter', 'dragLeave', 'drop', 'dragEnd'
-
+
## Handlebars `{{view}}` Helper
-
+
Other `Ember.View` instances can be included as part of a view's template by using the `{{view}}`
Handlebars helper. See `Handlebars.helpers.view` for additional information.
@@ -14985,7 +14985,7 @@ var childViewsProperty = Ember.computed(function() {
});
aContainer.appendTo('body');
- ```
+ ```
Results in the HTML
@@ -15398,7 +15398,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
/**
`Ember.CollectionView` is an `Ember.View` descendent responsible for managing a
- collection (an array or array-like object) by maintaing a child view object and
+ collection (an array or array-like object) by maintaing a child view object and
associated DOM representation for each item in the array and ensuring that child
views and their associated rendered HTML are updated when items in the array
are added, removed, or replaced.
@@ -15423,7 +15423,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
Given an empty `` and the following code:
- ``` javascript
+ ``` javascript
someItemsView = Ember.CollectionView.create({
classNames: ['a-collection'],
content: ['A','B','C'],
@@ -15447,7 +15447,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
## Automatic matching of parent/child tagNames
- Setting the `tagName` property of a `CollectionView` to any of
+ Setting the `tagName` property of a `CollectionView` to any of
"ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
in the item views receiving an appropriately matched `tagName` property.
@@ -18926,6 +18926,3432 @@ Ember Routing
})(this);
+})();
+
+(function() {
+/*globals Handlebars */
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var objectCreate = Ember.create;
+
+
+Ember.assert("Ember Handlebars requires Handlebars 1.0.beta.5 or greater", window.Handlebars && window.Handlebars.VERSION.match(/^1\.0\.beta\.[56789]$|^1\.0\.rc\.[123456789]+/));
+
+/**
+ Prepares the Handlebars templating library for use inside Ember's view
+ system.
+
+ The Ember.Handlebars object is the standard Handlebars library, extended to use
+ Ember's get() method instead of direct property access, which allows
+ computed properties to be used inside templates.
+
+ To create an Ember.Handlebars template, call Ember.Handlebars.compile(). This will
+ return a function that can be used by Ember.View for rendering.
+
+ @class Handlebars
+ @namespace Ember
+*/
+Ember.Handlebars = objectCreate(Handlebars);
+
+/**
+@class helpers
+@namespace Ember.Handlebars
+*/
+Ember.Handlebars.helpers = objectCreate(Handlebars.helpers);
+
+/**
+ Override the the opcode compiler and JavaScript compiler for Handlebars.
+
+ @class Compiler
+ @namespace Ember.Handlebars
+ @private
+ @constructor
+*/
+Ember.Handlebars.Compiler = function() {};
+
+// Handlebars.Compiler doesn't exist in runtime-only
+if (Handlebars.Compiler) {
+ Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
+}
+
+Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler;
+
+/**
+ @class JavaScriptCompiler
+ @namespace Ember.Handlebars
+ @private
+ @constructor
+*/
+Ember.Handlebars.JavaScriptCompiler = function() {};
+
+// Handlebars.JavaScriptCompiler doesn't exist in runtime-only
+if (Handlebars.JavaScriptCompiler) {
+ Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
+ Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler;
+}
+
+
+Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";
+
+
+Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() {
+ return "''";
+};
+
+/**
+ @private
+
+ Override the default buffer for Ember Handlebars. By default, Handlebars creates
+ an empty String at the beginning of each invocation and appends to it. Ember's
+ Handlebars overrides this to append to a single shared buffer.
+
+ @method appendToBuffer
+ @param string {String}
+*/
+Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
+ return "data.buffer.push("+string+");";
+};
+
+/**
+ @private
+
+ Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that all simple
+ mustaches in Ember's Handlebars will also set up an observer to keep the DOM
+ up to date when the underlying property changes.
+
+ @method mustache
+ @for Ember.Handlebars.Compiler
+ @param mustache
+*/
+Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
+ if (mustache.params.length || mustache.hash) {
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
+ } else {
+ var id = new Handlebars.AST.IdNode(['_triageMustache']);
+
+ // Update the mustache node to include a hash value indicating whether the original node
+ // was escaped. This will allow us to properly escape values when the underlying value
+ // changes and we need to re-render the value.
+ if(!mustache.escaped) {
+ mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
+ mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
+ }
+ mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
+ }
+};
+
+/**
+ Used for precompilation of Ember Handlebars templates. This will not be used during normal
+ app execution.
+
+ @method precompile
+ @for Ember.Handlebars
+ @static
+ @param {String} string The template to precompile
+*/
+Ember.Handlebars.precompile = function(string) {
+ var ast = Handlebars.parse(string);
+
+ var options = {
+ knownHelpers: {
+ action: true,
+ unbound: true,
+ bindAttr: true,
+ template: true,
+ view: true,
+ _triageMustache: true
+ },
+ data: true,
+ stringParams: true
+ };
+
+ var environment = new Ember.Handlebars.Compiler().compile(ast, options);
+ return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
+};
+
+// We don't support this for Handlebars runtime-only
+if (Handlebars.compile) {
+ /**
+ The entry point for Ember Handlebars. This replaces the default Handlebars.compile and turns on
+ template-local data and String parameters.
+
+ @method compile
+ @for Ember.Handlebars
+ @static
+ @param {String} string The template to compile
+ @return {Function}
+ */
+ Ember.Handlebars.compile = function(string) {
+ var ast = Handlebars.parse(string);
+ var options = { data: true, stringParams: true };
+ var environment = new Ember.Handlebars.Compiler().compile(ast, options);
+ var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
+
+ return Handlebars.template(templateSpec);
+ };
+}
+
+/**
+ @private
+
+ If a path starts with a reserved keyword, returns the root
+ that should be used.
+
+ @method normalizePath
+ @for Ember
+ @param root {Object}
+ @param path {String}
+ @param data {Hash}
+*/
+var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data) {
+ var keywords = (data && data.keywords) || {},
+ keyword, isKeyword;
+
+ // Get the first segment of the path. For example, if the
+ // path is "foo.bar.baz", returns "foo".
+ keyword = path.split('.', 1)[0];
+
+ // Test to see if the first path is a keyword that has been
+ // passed along in the view's data hash. If so, we will treat
+ // that object as the new root.
+ if (keywords.hasOwnProperty(keyword)) {
+ // Look up the value in the template's data hash.
+ root = keywords[keyword];
+ isKeyword = true;
+
+ // Handle cases where the entire path is the reserved
+ // word. In that case, return the object itself.
+ if (path === keyword) {
+ path = '';
+ } else {
+ // Strip the keyword from the path and look up
+ // the remainder from the newly found root.
+ path = path.substr(keyword.length+1);
+ }
+ }
+
+ return { root: root, path: path, isKeyword: isKeyword };
+};
+
+
+/**
+ Lookup both on root and on window. If the path starts with
+ a keyword, the corresponding object will be looked up in the
+ template's data hash and used to resolve the path.
+
+ @method getPath
+ @for Ember.Handlebars
+ @param {Object} root The object to look up the property on
+ @param {String} path The path to be lookedup
+ @param {Object} options The template's option hash
+*/
+Ember.Handlebars.getPath = function(root, path, options) {
+ var data = options && options.data,
+ normalizedPath = normalizePath(root, path, data),
+ value;
+
+ // In cases where the path begins with a keyword, change the
+ // root to the value represented by that keyword, and ensure
+ // the path is relative to it.
+ root = normalizedPath.root;
+ path = normalizedPath.path;
+
+ value = Ember.get(root, path);
+
+ if (value === undefined && root !== window && Ember.isGlobalPath(path)) {
+ value = Ember.get(window, path);
+ }
+ return value;
+};
+
+/**
+ @private
+
+ Registers a helper in Handlebars that will be called if no property with the
+ given name can be found on the current context object, and no helper with
+ that name is registered.
+
+ This throws an exception with a more helpful error message so the user can
+ track down where the problem is happening.
+
+ @method helperMissing
+ @for Ember.Handlebars.helpers
+ @param {String} path
+ @param {Hash} options
+*/
+Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
+ var error, view = "";
+
+ error = "%@ Handlebars error: Could not find property '%@' on object %@.";
+ if (options.data){
+ view = options.data.view;
+ }
+ throw new Ember.Error(Ember.String.fmt(error, [view, path, this]));
+});
+
+
+})();
+
+
+
+(function() {
+/**
+ @method htmlSafe
+ @for Ember.String
+ @static
+*/
+Ember.String.htmlSafe = function(str) {
+ return new Handlebars.SafeString(str);
+};
+
+var htmlSafe = Ember.String.htmlSafe;
+
+if (Ember.EXTEND_PROTOTYPES) {
+
+ /**
+ See {{#crossLink "Ember.String/htmlSafe"}}{{/crossLink}}
+
+ @method htmlSafe
+ @for String
+ */
+ String.prototype.htmlSafe = function() {
+ return htmlSafe(this);
+ };
+
+}
+
+})();
+
+
+
+(function() {
+/*jshint newcap:false*/
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var set = Ember.set, get = Ember.get;
+
+// DOMManager should just abstract dom manipulation between jquery and metamorph
+var DOMManager = {
+ remove: function(view) {
+ view.morph.remove();
+ },
+
+ prepend: function(view, html) {
+ view.morph.prepend(html);
+ },
+
+ after: function(view, html) {
+ view.morph.after(html);
+ },
+
+ html: function(view, html) {
+ view.morph.html(html);
+ },
+
+ // This is messed up.
+ replace: function(view) {
+ var morph = view.morph;
+
+ view.transitionTo('preRender');
+ view.clearRenderedChildren();
+ var buffer = view.renderToBuffer();
+
+ Ember.run.schedule('render', this, function() {
+ if (get(view, 'isDestroyed')) { return; }
+ view.invalidateRecursively('element');
+ view._notifyWillInsertElement();
+ morph.replaceWith(buffer.string());
+ view.transitionTo('inDOM');
+ view._notifyDidInsertElement();
+ });
+ },
+
+ empty: function(view) {
+ view.morph.html("");
+ }
+};
+
+// The `morph` and `outerHTML` properties are internal only
+// and not observable.
+
+/**
+ @class _Metamorph
+ @namespace Ember
+ @extends Ember.Mixin
+ @private
+*/
+Ember._Metamorph = Ember.Mixin.create({
+ isVirtual: true,
+ tagName: '',
+
+ init: function() {
+ this._super();
+ this.morph = Metamorph();
+ },
+
+ beforeRender: function(buffer) {
+ buffer.push(this.morph.startTag());
+ },
+
+ afterRender: function(buffer) {
+ buffer.push(this.morph.endTag());
+ },
+
+ createElement: function() {
+ var buffer = this.renderToBuffer();
+ this.outerHTML = buffer.string();
+ this.clearBuffer();
+ },
+
+ domManager: DOMManager
+});
+
+/**
+ @class _MetamorphView
+ @namespace Ember
+ @extends Ember.View
+ @uses Ember._Metamorph
+ @private
+*/
+Ember._MetamorphView = Ember.View.extend(Ember._Metamorph);
+
+
+})();
+
+
+
+(function() {
+/*globals Handlebars */
+
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set, getPath = Ember.Handlebars.getPath;
+/**
+ Ember._HandlebarsBoundView is a private view created by the Handlebars `{{bind}}`
+ helpers that is used to keep track of bound properties.
+
+ Every time a property is bound using a `{{mustache}}`, an anonymous subclass
+ of Ember._HandlebarsBoundView is created with the appropriate sub-template and
+ context set up. When the associated property changes, just the template for
+ this view will re-render.
+
+ @class _HandlebarsBoundView
+ @namespace Ember
+ @extends Ember._MetamorphView
+ @private
+*/
+Ember._HandlebarsBoundView = Ember._MetamorphView.extend({
+
+ /**
+ The function used to determine if the `displayTemplate` or
+ `inverseTemplate` should be rendered. This should be a function that takes
+ a value and returns a Boolean.
+
+ @property shouldDisplayFunc
+ @type Function
+ @default null
+ */
+ shouldDisplayFunc: null,
+
+ /**
+ Whether the template rendered by this view gets passed the context object
+ of its parent template, or gets passed the value of retrieving `path`
+ from the `pathRoot`.
+
+ For example, this is true when using the `{{#if}}` helper, because the
+ template inside the helper should look up properties relative to the same
+ object as outside the block. This would be false when used with `{{#with
+ foo}}` because the template should receive the object found by evaluating
+ `foo`.
+
+ @property preserveContext
+ @type Boolean
+ @default false
+ */
+ preserveContext: false,
+
+ /**
+ If `preserveContext` is true, this is the object that will be used
+ to render the template.
+
+ @property previousContext
+ @type Object
+ */
+ previousContext: null,
+
+ /**
+ The template to render when `shouldDisplayFunc` evaluates to true.
+
+ @property displayTemplate
+ @type Function
+ @default null
+ */
+ displayTemplate: null,
+
+ /**
+ The template to render when `shouldDisplayFunc` evaluates to false.
+
+ @property inverseTemplate
+ @type Function
+ @default null
+ */
+ inverseTemplate: null,
+
+
+ /**
+ The path to look up on `pathRoot` that is passed to
+ `shouldDisplayFunc` to determine which template to render.
+
+ In addition, if `preserveContext` is false, the object at this path will
+ be passed to the template when rendering.
+
+ @property path
+ @type String
+ @default null
+ */
+ path: null,
+
+ /**
+ The object from which the `path` will be looked up. Sometimes this is the
+ same as the `previousContext`, but in cases where this view has been generated
+ for paths that start with a keyword such as `view` or `controller`, the
+ path root will be that resolved object.
+
+ @property pathRoot
+ @type Object
+ */
+ pathRoot: null,
+
+ normalizedValue: Ember.computed(function() {
+ var path = get(this, 'path'),
+ pathRoot = get(this, 'pathRoot'),
+ valueNormalizer = get(this, 'valueNormalizerFunc'),
+ result, templateData;
+
+ // Use the pathRoot as the result if no path is provided. This
+ // happens if the path is `this`, which gets normalized into
+ // a `pathRoot` of the current Handlebars context and a path
+ // of `''`.
+ if (path === '') {
+ result = pathRoot;
+ } else {
+ templateData = get(this, 'templateData');
+ result = getPath(pathRoot, path, { data: templateData });
+ }
+
+ return valueNormalizer ? valueNormalizer(result) : result;
+ }).property('path', 'pathRoot', 'valueNormalizerFunc').volatile(),
+
+ rerenderIfNeeded: function() {
+ if (!get(this, 'isDestroyed') && get(this, 'normalizedValue') !== this._lastNormalizedValue) {
+ this.rerender();
+ }
+ },
+
+ /**
+ Determines which template to invoke, sets up the correct state based on
+ that logic, then invokes the default Ember.View `render` implementation.
+
+ This method will first look up the `path` key on `pathRoot`,
+ then pass that value to the `shouldDisplayFunc` function. If that returns
+ true, the `displayTemplate` function will be rendered to DOM. Otherwise,
+ `inverseTemplate`, if specified, will be rendered.
+
+ For example, if this Ember._HandlebarsBoundView represented the `{{#with foo}}`
+ helper, it would look up the `foo` property of its context, and
+ `shouldDisplayFunc` would always return true. The object found by looking
+ up `foo` would be passed to `displayTemplate`.
+
+ @method render
+ @param {Ember.RenderBuffer} buffer
+ */
+ render: function(buffer) {
+ // If not invoked via a triple-mustache ({{{foo}}}), escape
+ // the content of the template.
+ var escape = get(this, 'isEscaped');
+
+ var shouldDisplay = get(this, 'shouldDisplayFunc'),
+ preserveContext = get(this, 'preserveContext'),
+ context = get(this, 'previousContext');
+
+ var inverseTemplate = get(this, 'inverseTemplate'),
+ displayTemplate = get(this, 'displayTemplate');
+
+ var result = get(this, 'normalizedValue');
+ this._lastNormalizedValue = result;
+
+ // First, test the conditional to see if we should
+ // render the template or not.
+ if (shouldDisplay(result)) {
+ set(this, 'template', displayTemplate);
+
+ // If we are preserving the context (for example, if this
+ // is an #if block, call the template with the same object.
+ if (preserveContext) {
+ set(this, '_context', context);
+ } else {
+ // Otherwise, determine if this is a block bind or not.
+ // If so, pass the specified object to the template
+ if (displayTemplate) {
+ set(this, '_context', result);
+ } else {
+ // This is not a bind block, just push the result of the
+ // expression to the render context and return.
+ if (result === null || result === undefined) {
+ result = "";
+ } else if (!(result instanceof Handlebars.SafeString)) {
+ result = String(result);
+ }
+
+ if (escape) { result = Handlebars.Utils.escapeExpression(result); }
+ buffer.push(result);
+ return;
+ }
+ }
+ } else if (inverseTemplate) {
+ set(this, 'template', inverseTemplate);
+
+ if (preserveContext) {
+ set(this, '_context', context);
+ } else {
+ set(this, '_context', result);
+ }
+ } else {
+ set(this, 'template', function() { return ''; });
+ }
+
+ return this._super(buffer);
+ }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
+var getPath = Ember.Handlebars.getPath, normalizePath = Ember.Handlebars.normalizePath;
+var forEach = Ember.ArrayPolyfills.forEach;
+
+var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
+
+// Binds a property into the DOM. This will create a hook in DOM that the
+// KVO system will look for and update if the property changes.
+function bind(property, options, preserveContext, shouldDisplay, valueNormalizer) {
+ var data = options.data,
+ fn = options.fn,
+ inverse = options.inverse,
+ view = data.view,
+ currentContext = this,
+ pathRoot, path, normalized;
+
+ normalized = normalizePath(currentContext, property, data);
+
+ pathRoot = normalized.root;
+ path = normalized.path;
+
+ // Set up observers for observable objects
+ if ('object' === typeof this) {
+ // Create the view that will wrap the output of this template/property
+ // and add it to the nearest view's childViews array.
+ // See the documentation of Ember._HandlebarsBoundView for more.
+ var bindView = view.createChildView(Ember._HandlebarsBoundView, {
+ preserveContext: preserveContext,
+ shouldDisplayFunc: shouldDisplay,
+ valueNormalizerFunc: valueNormalizer,
+ displayTemplate: fn,
+ inverseTemplate: inverse,
+ path: path,
+ pathRoot: pathRoot,
+ previousContext: currentContext,
+ isEscaped: !options.hash.unescaped,
+ templateData: options.data
+ });
+
+ view.appendChild(bindView);
+
+ var observer = function() {
+ Ember.run.scheduleOnce('render', bindView, 'rerenderIfNeeded');
+ };
+
+ // Observes the given property on the context and
+ // tells the Ember._HandlebarsBoundView to re-render. If property
+ // is an empty string, we are printing the current context
+ // object ({{this}}) so updating it is not our responsibility.
+ if (path !== '') {
+ Ember.addObserver(pathRoot, path, observer);
+ }
+ } else {
+ // The object is not observable, so just render it out and
+ // be done with it.
+ data.buffer.push(getPath(pathRoot, path, options));
+ }
+}
+
+/**
+ @private
+
+ '_triageMustache' is used internally select between a binding and helper for
+ the given context. Until this point, it would be hard to determine if the
+ mustache is a property reference or a regular helper reference. This triage
+ helper resolves that.
+
+ This would not be typically invoked by directly.
+
+ @method _triageMustache
+ @for Ember.Handlebars.helpers
+ @param {String} property Property/helperID to triage
+ @param {Function} fn Context to provide for rendering
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('_triageMustache', function(property, fn) {
+ Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2);
+ if (helpers[property]) {
+ return helpers[property].call(this, fn);
+ }
+ else {
+ return helpers.bind.apply(this, arguments);
+ }
+});
+
+/**
+ @private
+
+ `bind` can be used to display a value, then update that value if it
+ changes. For example, if you wanted to print the `title` property of
+ `content`:
+
+ ``` handlebars
+ {{bind "content.title"}}
+ ```
+
+ This will return the `title` property as a string, then create a new
+ observer at the specified path. If it changes, it will update the value in
+ DOM. Note that if you need to support IE7 and IE8 you must modify the
+ model objects properties using Ember.get() and Ember.set() for this to work as
+ it relies on Ember's KVO system. For all other browsers this will be handled
+ for you automatically.
+
+ @method bind
+ @for Ember.Handlebars.helpers
+ @param {String} property Property to bind
+ @param {Function} fn Context to provide for rendering
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('bind', function(property, fn) {
+ Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2);
+
+ var context = (fn.contexts && fn.contexts[0]) || this;
+
+ return bind.call(context, property, fn, false, function(result) {
+ return !Ember.none(result);
+ });
+});
+
+/**
+ @private
+
+ Use the `boundIf` helper to create a conditional that re-evaluates
+ whenever the bound value changes.
+
+ ``` handlebars
+ {{#boundIf "content.shouldDisplayTitle"}}
+ {{content.title}}
+ {{/boundIf}}
+ ```
+
+ @method boundIf
+ @for Ember.Handlebars.helpers
+ @param {String} property Property to bind
+ @param {Function} fn Context to provide for rendering
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('boundIf', function(property, fn) {
+ var context = (fn.contexts && fn.contexts[0]) || this;
+ var func = function(result) {
+ if (Ember.typeOf(result) === 'array') {
+ return get(result, 'length') !== 0;
+ } else {
+ return !!result;
+ }
+ };
+
+ return bind.call(context, property, fn, true, func, func);
+});
+
+/**
+ @method with
+ @for Ember.Handlebars.helpers
+ @param {Function} context
+ @param {Hash} options
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('with', function(context, options) {
+ if (arguments.length === 4) {
+ var keywordName, path, rootPath, normalized;
+
+ Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as");
+ options = arguments[3];
+ keywordName = arguments[2];
+ path = arguments[0];
+
+ Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
+
+ if (Ember.isGlobalPath(path)) {
+ Ember.bind(options.data.keywords, keywordName, path);
+ } else {
+ normalized = normalizePath(this, path, options.data);
+ path = normalized.path;
+ rootPath = normalized.root;
+
+ // This is a workaround for the fact that you cannot bind separate objects
+ // together. When we implement that functionality, we should use it here.
+ var contextKey = Ember.$.expando + Ember.guidFor(rootPath);
+ options.data.keywords[contextKey] = rootPath;
+
+ // if the path is '' ("this"), just bind directly to the current context
+ var contextPath = path ? contextKey + '.' + path : contextKey;
+ Ember.bind(options.data.keywords, keywordName, contextPath);
+ }
+
+ return bind.call(this, path, options, true, function(result) {
+ return !Ember.none(result);
+ });
+ } else {
+ Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2);
+ Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop);
+ return helpers.bind.call(options.contexts[0], context, options);
+ }
+});
+
+
+/**
+ @method if
+ @for Ember.Handlebars.helpers
+ @param {Function} context
+ @param {Hash} options
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('if', function(context, options) {
+ Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2);
+ Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop);
+
+ return helpers.boundIf.call(options.contexts[0], context, options);
+});
+
+/**
+ @method unless
+ @for Ember.Handlebars.helpers
+ @param {Function} context
+ @param {Hash} options
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('unless', function(context, options) {
+ Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2);
+ Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop);
+
+ var fn = options.fn, inverse = options.inverse;
+
+ options.fn = inverse;
+ options.inverse = fn;
+
+ return helpers.boundIf.call(options.contexts[0], context, options);
+});
+
+/**
+ `bindAttr` allows you to create a binding between DOM element attributes and
+ Ember objects. For example:
+
+ ``` handlebars
+
+ ```
+
+ @method bindAttr
+ @for Ember.Handlebars.helpers
+ @param {Hash} options
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('bindAttr', function(options) {
+
+ var attrs = options.hash;
+
+ Ember.assert("You must specify at least one hash argument to bindAttr", !!Ember.keys(attrs).length);
+
+ var view = options.data.view;
+ var ret = [];
+ var ctx = this;
+
+ // Generate a unique id for this element. This will be added as a
+ // data attribute to the element so it can be looked up when
+ // the bound property changes.
+ var dataId = ++Ember.$.uuid;
+
+ // Handle classes differently, as we can bind multiple classes
+ var classBindings = attrs['class'];
+ if (classBindings !== null && classBindings !== undefined) {
+ var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options);
+ ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"');
+ delete attrs['class'];
+ }
+
+ var attrKeys = Ember.keys(attrs);
+
+ // For each attribute passed, create an observer and emit the
+ // current value of the property as an attribute.
+ forEach.call(attrKeys, function(attr) {
+ var path = attrs[attr],
+ pathRoot, normalized;
+
+ Ember.assert(fmt("You must provide a String for a bound attribute, not %@", [path]), typeof path === 'string');
+
+ normalized = normalizePath(ctx, path, options.data);
+
+ pathRoot = normalized.root;
+ path = normalized.path;
+
+ var value = (path === 'this') ? pathRoot : getPath(pathRoot, path, options),
+ type = Ember.typeOf(value);
+
+ Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');
+
+ var observer, invoker;
+
+ observer = function observer() {
+ var result = getPath(pathRoot, path, options);
+
+ 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');
+
+ var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");
+
+ // If we aren't able to find the element, it means the element
+ // to which we were bound has been removed from the view.
+ // In that case, we can assume the template has been re-rendered
+ // and we need to clean up the observer.
+ if (!elem || elem.length === 0) {
+ Ember.removeObserver(pathRoot, path, invoker);
+ return;
+ }
+
+ Ember.View.applyAttributeBindings(elem, attr, result);
+ };
+
+ invoker = function() {
+ Ember.run.scheduleOnce('render', observer);
+ };
+
+ // Add an observer to the view for when the property changes.
+ // When the observer fires, find the element using the
+ // unique data id and update the attribute to the new value.
+ if (path !== 'this') {
+ Ember.addObserver(pathRoot, path, invoker);
+ }
+
+ // if this changes, also change the logic in ember-views/lib/views/view.js
+ if ((type === 'string' || (type === 'number' && !isNaN(value)))) {
+ ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"');
+ } else if (value && type === 'boolean') {
+ // The developer controls the attr name, so it should always be safe
+ ret.push(attr + '="' + attr + '"');
+ }
+ }, this);
+
+ // Add the unique identifier
+ // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG
+ ret.push('data-bindattr-' + dataId + '="' + dataId + '"');
+ return new EmberHandlebars.SafeString(ret.join(' '));
+});
+
+/**
+ @private
+
+ Helper that, given a space-separated string of property paths and a context,
+ returns an array of class names. Calling this method also has the side
+ effect of setting up observers at those property paths, such that if they
+ change, the correct class name will be reapplied to the DOM element.
+
+ For example, if you pass the string "fooBar", it will first look up the
+ "fooBar" value of the context. If that value is true, it will add the
+ "foo-bar" class to the current element (i.e., the dasherized form of
+ "fooBar"). If the value is a string, it will add that string as the class.
+ Otherwise, it will not add any new class name.
+
+ @method bindClasses
+ @for Ember.Handlebars
+ @param {Ember.Object} context The context from which to lookup properties
+ @param {String} classBindings A string, space-separated, of class bindings to use
+ @param {Ember.View} view The view in which observers should look for the element to update
+ @param {Srting} bindAttrId Optional bindAttr id used to lookup elements
+ @return {Array} An array of class names to add
+*/
+EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId, options) {
+ var ret = [], newClass, value, elem;
+
+ // Helper method to retrieve the property from the context and
+ // determine which class string to return, based on whether it is
+ // a Boolean or not.
+ var classStringForPath = function(root, parsedPath, options) {
+ var val,
+ path = parsedPath.path;
+
+ if (path === 'this') {
+ val = root;
+ } else if (path === '') {
+ val = true;
+ } else {
+ val = getPath(root, path, options);
+ }
+
+ return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
+ };
+
+ // For each property passed, loop through and setup
+ // an observer.
+ forEach.call(classBindings.split(' '), function(binding) {
+
+ // Variable in which the old class value is saved. The observer function
+ // closes over this variable, so it knows which string to remove when
+ // the property changes.
+ var oldClass;
+
+ var observer, invoker;
+
+ var parsedPath = Ember.View._parsePropertyPath(binding),
+ path = parsedPath.path,
+ pathRoot = context,
+ normalized;
+
+ if (path !== '' && path !== 'this') {
+ normalized = normalizePath(context, path, options.data);
+
+ pathRoot = normalized.root;
+ path = normalized.path;
+ }
+
+ // Set up an observer on the context. If the property changes, toggle the
+ // class name.
+ observer = function() {
+ // Get the current value of the property
+ newClass = classStringForPath(pathRoot, parsedPath, options);
+ elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$();
+
+ // If we can't find the element anymore, a parent template has been
+ // re-rendered and we've been nuked. Remove the observer.
+ if (!elem || elem.length === 0) {
+ Ember.removeObserver(pathRoot, path, invoker);
+ } else {
+ // If we had previously added a class to the element, remove it.
+ if (oldClass) {
+ elem.removeClass(oldClass);
+ }
+
+ // If necessary, add a new class. Make sure we keep track of it so
+ // it can be removed in the future.
+ if (newClass) {
+ elem.addClass(newClass);
+ oldClass = newClass;
+ } else {
+ oldClass = null;
+ }
+ }
+ };
+
+ invoker = function() {
+ Ember.run.scheduleOnce('render', observer);
+ };
+
+ if (path !== '' && path !== 'this') {
+ Ember.addObserver(pathRoot, path, invoker);
+ }
+
+ // We've already setup the observer; now we just need to figure out the
+ // correct behavior right now on the first pass through.
+ value = classStringForPath(pathRoot, parsedPath, options);
+
+ if (value) {
+ ret.push(value);
+
+ // Make sure we save the current value so that it can be removed if the
+ // observer fires.
+ oldClass = value;
+ }
+ });
+
+ return ret;
+};
+
+
+})();
+
+
+
+(function() {
+/*globals Handlebars */
+
+// TODO: Don't require the entire module
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+var PARENT_VIEW_PATH = /^parentView\./;
+var EmberHandlebars = Ember.Handlebars;
+var VIEW_PRESERVES_CONTEXT = Ember.VIEW_PRESERVES_CONTEXT;
+
+EmberHandlebars.ViewHelper = Ember.Object.create({
+
+ propertiesFromHTMLOptions: function(options, thisContext) {
+ var hash = options.hash, data = options.data;
+ var extensions = {},
+ classes = hash['class'],
+ dup = false;
+
+ if (hash.id) {
+ extensions.elementId = hash.id;
+ dup = true;
+ }
+
+ if (classes) {
+ classes = classes.split(' ');
+ extensions.classNames = classes;
+ dup = true;
+ }
+
+ if (hash.classBinding) {
+ extensions.classNameBindings = hash.classBinding.split(' ');
+ dup = true;
+ }
+
+ if (hash.classNameBindings) {
+ if (extensions.classNameBindings === undefined) extensions.classNameBindings = [];
+ extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' '));
+ dup = true;
+ }
+
+ if (hash.attributeBindings) {
+ Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead.");
+ extensions.attributeBindings = null;
+ dup = true;
+ }
+
+ if (dup) {
+ hash = Ember.$.extend({}, hash);
+ delete hash.id;
+ delete hash['class'];
+ delete hash.classBinding;
+ }
+
+ // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings
+ // as well as class name bindings. If the bindings are local, make them relative to the current context
+ // instead of the view.
+ var path;
+
+ // Evaluate the context of regular attribute bindings:
+ for (var prop in hash) {
+ if (!hash.hasOwnProperty(prop)) { continue; }
+
+ // Test if the property ends in "Binding"
+ if (Ember.IS_BINDING.test(prop) && typeof hash[prop] === 'string') {
+ path = this.contextualizeBindingPath(hash[prop], data);
+ if (path) { hash[prop] = path; }
+ }
+ }
+
+ // Evaluate the context of class name bindings:
+ if (extensions.classNameBindings) {
+ for (var b in extensions.classNameBindings) {
+ var full = extensions.classNameBindings[b];
+ if (typeof full === 'string') {
+ // Contextualize the path of classNameBinding so this:
+ //
+ // classNameBinding="isGreen:green"
+ //
+ // is converted to this:
+ //
+ // classNameBinding="bindingContext.isGreen:green"
+ var parsedPath = Ember.View._parsePropertyPath(full);
+ path = this.contextualizeBindingPath(parsedPath.path, data);
+ if (path) { extensions.classNameBindings[b] = path + parsedPath.classNames; }
+ }
+ }
+ }
+
+ // Make the current template context available to the view
+ // for the bindings set up above.
+ extensions.bindingContext = thisContext;
+
+ return Ember.$.extend(hash, extensions);
+ },
+
+ // Transform bindings from the current context to a context that can be evaluated within the view.
+ // Returns null if the path shouldn't be changed.
+ //
+ // TODO: consider the addition of a prefix that would allow this method to return `path`.
+ contextualizeBindingPath: function(path, data) {
+ var normalized = Ember.Handlebars.normalizePath(null, path, data);
+ if (normalized.isKeyword) {
+ return 'templateData.keywords.' + path;
+ } else if (Ember.isGlobalPath(path)) {
+ return null;
+ } else if (path === 'this') {
+ return 'bindingContext';
+ } else {
+ return 'bindingContext.' + path;
+ }
+ },
+
+ helper: function(thisContext, path, options) {
+ var inverse = options.inverse,
+ data = options.data,
+ view = data.view,
+ fn = options.fn,
+ hash = options.hash,
+ newView;
+
+ if ('string' === typeof path) {
+ newView = EmberHandlebars.getPath(thisContext, path, options);
+ Ember.assert("Unable to find view at path '" + path + "'", !!newView);
+ } else {
+ newView = path;
+ }
+
+ Ember.assert(Ember.String.fmt('You must pass a view class to the #view helper, not %@ (%@)', [path, newView]), Ember.View.detect(newView));
+
+ var viewOptions = this.propertiesFromHTMLOptions(options, thisContext);
+ var currentView = data.view;
+ viewOptions.templateData = options.data;
+
+ if (fn) {
+ Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newView.proto(), 'templateName'));
+ viewOptions.template = fn;
+ }
+
+ // We only want to override the `_context` computed property if there is
+ // no specified controller. See View#_context for more information.
+ if (VIEW_PRESERVES_CONTEXT && !newView.proto().controller && !newView.proto().controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) {
+ viewOptions._context = thisContext;
+ }
+
+ currentView.appendChild(newView, viewOptions);
+ }
+});
+
+/**
+ `{{view}}` inserts a new instance of `Ember.View` into a template passing its options
+ to the `Ember.View`'s `create` method and using the supplied block as the view's own template.
+
+ An empty `` and the following template:
+
+ ``` handlebars
+
+ ```
+
+ Will result in HTML structure:
+
+ ``` html
+
+
+
+
+ A span:
+
+ Hello.
+
+
+
+ ```
+
+ ### parentView setting
+
+ The `parentView` property of the new `Ember.View` instance created through `{{view}}`
+ will be set to the `Ember.View` instance of the template where `{{view}}` was called.
+
+ ``` javascript
+ aView = Ember.View.create({
+ template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}")
+ });
+
+ aView.appendTo('body');
+ ```
+
+ Will result in HTML structure:
+
+ ``` html
+
+
+ my parent: ember1
+
+
+ ```
+
+ ### Setting CSS id and class attributes
+
+ The HTML `id` attribute can be set on the `{{view}}`'s resulting element with the `id` option.
+ This option will _not_ be passed to `Ember.View.create`.
+
+ ``` handlebars
+
+ ```
+
+ Results in the following HTML structure:
+
+ ``` html
+
+
+ hello.
+
+
+ ```
+
+ The HTML `class` attribute can be set on the `{{view}}`'s resulting element with
+ the `class` or `classNameBindings` options. The `class` option
+ will directly set the CSS `class` attribute and will not be passed to
+ `Ember.View.create`. `classNameBindings` will be passed to `create` and use
+ `Ember.View`'s class name binding functionality:
+
+ ``` handlebars
+
+ ```
+
+ Results in the following HTML structure:
+
+ ``` html
+
+
+ hello.
+
+
+ ```
+
+ ### Supplying a different view class
+
+ `{{view}}` can take an optional first argument before its supplied options to specify a
+ path to a custom view class.
+
+ ``` handlebars
+
+ ```
+
+ The first argument can also be a relative path. Ember will search for the view class
+ starting at the `Ember.View` of the template where `{{view}}` was used as the root object:
+
+ ``` javascript
+ MyApp = Ember.Application.create({});
+ MyApp.OuterView = Ember.View.extend({
+ innerViewClass: Ember.View.extend({
+ classNames: ['a-custom-view-class-as-property']
+ }),
+ template: Ember.Handlebars.compile('{{#view "innerViewClass"}} hi {{/view}}')
+ });
+
+ MyApp.OuterView.create().appendTo('body');
+ ```
+
+ Will result in the following HTML:
+
+ ``` html
+
+
+ hi
+
+
+ ```
+
+ ### Blockless use
+
+ If you supply a custom `Ember.View` subclass that specifies its own template
+ or provide a `templateName` option to `{{view}}` it can be used without supplying a block.
+ Attempts to use both a `templateName` option and supply a block will throw an error.
+
+ ``` handlebars
+
+ ```
+
+ ### viewName property
+
+ You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance will
+ be referenced as a property of its parent view by this name.
+
+ ``` javascript
+ aView = Ember.View.create({
+ template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}')
+ });
+
+ aView.appendTo('body');
+ aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper
+ ```
+
+ @method view
+ @for Ember.Handlebars.helpers
+ @param {String} path
+ @param {Hash} options
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('view', function(path, options) {
+ Ember.assert("The view helper only takes a single argument", arguments.length <= 2);
+
+ // If no path is provided, treat path param as options.
+ if (path && path.data && path.data.isRenderData) {
+ options = path;
+ path = "Ember.View";
+ }
+
+ return EmberHandlebars.ViewHelper.helper(this, path, options);
+});
+
+
+})();
+
+
+
+(function() {
+/*globals Handlebars */
+
+// TODO: Don't require all of this module
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, getPath = Ember.Handlebars.getPath, fmt = Ember.String.fmt;
+
+/**
+ `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
+ `Ember.CollectionView` to a template. See `Ember.CollectionView` for additional
+ information on how a `CollectionView` functions.
+
+ `{{collection}}`'s primary use is as a block helper with a `contentBinding` option
+ pointing towards an `Ember.Array`-compatible object. An `Ember.View` instance will
+ be created for each item in its `content` property. Each view will have its own
+ `content` property set to the appropriate item in the collection.
+
+ The provided block will be applied as the template for each item's view.
+
+ Given an empty `` the following template:
+
+ ``` handlebars
+
+ ```
+
+ And the following application code
+
+ ``` javascript
+ App = Ember.Application.create()
+ App.items = [
+ Ember.Object.create({name: 'Dave'}),
+ Ember.Object.create({name: 'Mary'}),
+ Ember.Object.create({name: 'Sara'})
+ ]
+ ```
+
+ Will result in the HTML structure below
+
+ ``` html
+
+
Hi Dave
+
Hi Mary
+
Hi Sara
+
+ ```
+
+ ### Blockless Use
+ If you provide an `itemViewClass` option that has its own `template` you can omit
+ the block.
+
+ The following template:
+
+ ``` handlebars
+
+ ```
+
+ And application code
+
+ ``` javascript
+ App = Ember.Application.create();
+ App.items = [
+ Ember.Object.create({name: 'Dave'}),
+ Ember.Object.create({name: 'Mary'}),
+ Ember.Object.create({name: 'Sara'})
+ ];
+
+ App.AnItemView = Ember.View.extend({
+ template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
+ });
+ ```
+
+ Will result in the HTML structure below
+
+ ``` html
+
+
Greetings Dave
+
Greetings Mary
+
Greetings Sara
+
+ ```
+
+ ### Specifying a CollectionView subclass
+
+ By default the `{{collection}}` helper will create an instance of `Ember.CollectionView`.
+ You can supply a `Ember.CollectionView` subclass to the helper by passing it
+ as the first argument:
+
+ ``` handlebars
+
+ ```
+
+
+ ### Forwarded `item.*`-named Options
+
+ As with the `{{view}}`, helper options passed to the `{{collection}}` will be set on
+ the resulting `Ember.CollectionView` as properties. Additionally, options prefixed with
+ `item` will be applied to the views rendered for each item (note the camelcasing):
+
+ ``` handlebars
+
+ ```
+
+ Will result in the following HTML structure:
+
+ ``` html
+
+
Howdy Dave
+
Howdy Mary
+
Howdy Sara
+
+ ```
+
+ @method collection
+ @for Ember.Handlebars.helpers
+ @param {String} path
+ @param {Hash} options
+ @return {String} HTML string
+*/
+Ember.Handlebars.registerHelper('collection', function(path, options) {
+ // If no path is provided, treat path param as options.
+ if (path && path.data && path.data.isRenderData) {
+ options = path;
+ path = undefined;
+ Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
+ } else {
+ Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
+ }
+
+ var fn = options.fn;
+ var data = options.data;
+ var inverse = options.inverse;
+
+ // If passed a path string, convert that into an object.
+ // Otherwise, just default to the standard class.
+ var collectionClass;
+ collectionClass = path ? getPath(this, path, options) : Ember.CollectionView;
+ Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);
+
+ var hash = options.hash, itemHash = {}, match;
+
+ // Extract item view class if provided else default to the standard class
+ var itemViewClass, itemViewPath = hash.itemViewClass;
+ var collectionPrototype = collectionClass.proto();
+ delete hash.itemViewClass;
+ itemViewClass = itemViewPath ? getPath(collectionPrototype, itemViewPath, options) : collectionPrototype.itemViewClass;
+ Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewPath]), !!itemViewClass);
+
+ // Go through options passed to the {{collection}} helper and extract options
+ // that configure item views instead of the collection itself.
+ for (var prop in hash) {
+ if (hash.hasOwnProperty(prop)) {
+ match = prop.match(/^item(.)(.*)$/);
+
+ if(match) {
+ // Convert itemShouldFoo -> shouldFoo
+ itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
+ // Delete from hash as this will end up getting passed to the
+ // {{view}} helper method.
+ delete hash[prop];
+ }
+ }
+ }
+
+ var tagName = hash.tagName || collectionPrototype.tagName;
+
+ if (fn) {
+ itemHash.template = fn;
+ delete options.fn;
+ }
+
+ var emptyViewClass;
+ if (inverse && inverse !== Handlebars.VM.noop) {
+ emptyViewClass = get(collectionPrototype, 'emptyViewClass');
+ emptyViewClass = emptyViewClass.extend({
+ template: inverse,
+ tagName: itemHash.tagName
+ });
+ } else if (hash.emptyViewClass) {
+ emptyViewClass = getPath(this, hash.emptyViewClass, options);
+ }
+ hash.emptyView = emptyViewClass;
+
+ if (hash.eachHelper === 'each') {
+ itemHash._context = Ember.computed(function() {
+ return get(this, 'content');
+ }).property('content');
+ delete hash.eachHelper;
+ }
+
+ var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
+ hash.itemViewClass = itemViewClass.extend(viewOptions);
+
+ return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
+});
+
+
+})();
+
+
+
+(function() {
+/*globals Handlebars */
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var getPath = Ember.Handlebars.getPath;
+
+/**
+ `unbound` allows you to output a property without binding. *Important:* The
+ output will not be updated if the property changes. Use with caution.
+
+ ``` handlebars
+
{{unbound somePropertyThatDoesntChange}}
+ ```
+
+ @method unbound
+ @for Ember.Handlebars.helpers
+ @param {String} property
+ @return {String} HTML string
+*/
+Ember.Handlebars.registerHelper('unbound', function(property, fn) {
+ var context = (fn.contexts && fn.contexts[0]) || this;
+ return getPath(context, property, fn);
+});
+
+})();
+
+
+
+(function() {
+/*jshint debug:true*/
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var getPath = Ember.Handlebars.getPath, normalizePath = Ember.Handlebars.normalizePath;
+
+/**
+ `log` allows you to output the value of a value in the current rendering
+ context.
+
+ ``` handlebars
+ {{log myVariable}}
+ ```
+
+ @method log
+ @for Ember.Handlebars.helpers
+ @param {String} property
+*/
+Ember.Handlebars.registerHelper('log', function(property, options) {
+ var context = (options.contexts && options.contexts[0]) || this,
+ normalized = normalizePath(context, property, options.data),
+ pathRoot = normalized.root,
+ path = normalized.path,
+ value = (path === 'this') ? pathRoot : getPath(pathRoot, path, options);
+ Ember.Logger.log(value);
+});
+
+/**
+ The `debugger` helper executes the `debugger` statement in the current
+ context.
+
+ ``` handlebars
+ {{debugger}}
+ ```
+
+ @method debugger
+ @for Ember.Handlebars.helpers
+ @param {String} property
+*/
+Ember.Handlebars.registerHelper('debugger', function() {
+ debugger;
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
+ itemViewClass: Ember._MetamorphView,
+ emptyViewClass: Ember._MetamorphView,
+
+ createChildView: function(view, attrs) {
+ view = this._super(view, attrs);
+
+ // At the moment, if a container view subclass wants
+ // to insert keywords, it is responsible for cloning
+ // the keywords hash. This will be fixed momentarily.
+ var keyword = get(this, 'keyword');
+
+ if (keyword) {
+ var data = get(view, 'templateData');
+
+ data = Ember.copy(data);
+ data.keywords = view.cloneKeywords();
+ set(view, 'templateData', data);
+
+ var content = get(view, 'content');
+
+ // In this case, we do not bind, because the `content` of
+ // a #each item cannot change.
+ data.keywords[keyword] = content;
+ }
+
+ return view;
+ }
+});
+
+/**
+ The `{{#each}}` helper loops over elements in a collection, rendering its block once for each item:
+
+ ``` javascript
+ Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
+ ```
+
+ ``` handlebars
+ {{#each Developers}}
+ {{name}}
+ {{/each}}
+ ```
+
+ `{{each}}` supports an alternative syntax with element naming:
+
+ ``` handlebars
+ {{#each person in Developers}}
+ {{person.name}}
+ {{/each}}
+ ```
+
+ When looping over objects that do not have properties, `{{this}}` can be used to render the object:
+
+ ``` javascript
+ DeveloperNames = ['Yehuda', 'Tom', 'Paul']
+ ```
+
+ ``` handlebars
+ {{#each DeveloperNames}}
+ {{this}}
+ {{/each}}
+ ```
+
+ ### Blockless Use
+
+ If you provide an `itemViewClass` option that has its own `template` you can omit
+ the block in a similar way to how it can be done with the collection helper.
+
+ The following template:
+
+ ``` handlebars
+
+ ```
+
+ And application code
+
+ ``` javascript
+ App = Ember.Application.create({
+ MyView: Ember.View.extend({
+ items: [
+ Ember.Object.create({name: 'Dave'}),
+ Ember.Object.create({name: 'Mary'}),
+ Ember.Object.create({name: 'Sara'})
+ ]
+ })
+ });
+
+ App.AnItemView = Ember.View.extend({
+ template: Ember.Handlebars.compile("Greetings {{name}}")
+ });
+
+ App.initialize();
+ ```
+
+ Will result in the HTML structure below
+
+ ``` html
+
+
Greetings Dave
+
Greetings Mary
+
Greetings Sara
+
+ ```
+
+
+ @method each
+ @for Ember.Handlebars.helpers
+ @param [name] {String} name for item (used with `in`)
+ @param path {String} path
+*/
+Ember.Handlebars.registerHelper('each', function(path, options) {
+ if (arguments.length === 4) {
+ Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in");
+
+ var keywordName = arguments[0];
+
+ options = arguments[3];
+ path = arguments[2];
+ if (path === '') { path = "this"; }
+
+ options.hash.keyword = keywordName;
+ } else {
+ options.hash.eachHelper = 'each';
+ }
+
+ options.hash.contentBinding = path;
+ // Set up emptyView as a metamorph with no tag
+ //options.hash.emptyViewClass = Ember._MetamorphView;
+
+ return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options);
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+/**
+ `template` allows you to render a template from inside another template.
+ This allows you to re-use the same template in multiple places. For example:
+
+ ``` handlebars
+
+
+
+ ```
+
+ This helper looks for templates in the global Ember.TEMPLATES hash. If you
+ add <script> tags to your page with the `data-template-name` attribute set,
+ they will be compiled and placed in this hash automatically.
+
+ You can also manually register templates by adding them to the hash:
+
+ ``` javascript
+ Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('{{user}}');
+ ```
+
+ @method template
+ @for Ember.Handlebars.helpers
+ @param {String} templateName the template to render
+*/
+
+Ember.Handlebars.registerHelper('template', function(name, options) {
+ var template = Ember.TEMPLATES[name];
+
+ Ember.assert("Unable to find template with name '"+name+"'.", !!template);
+
+ Ember.TEMPLATES[name](this, { data: options.data });
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var EmberHandlebars = Ember.Handlebars,
+ getPath = EmberHandlebars.getPath,
+ get = Ember.get,
+ a_slice = Array.prototype.slice;
+
+var ActionHelper = EmberHandlebars.ActionHelper = {
+ registeredActions: {}
+};
+
+ActionHelper.registerAction = function(actionName, options) {
+ var actionId = (++Ember.$.uuid).toString();
+
+ ActionHelper.registeredActions[actionId] = {
+ eventName: options.eventName,
+ handler: function(event) {
+ var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
+ secondaryClick = event.which > 1, // IE9 may return undefined
+ nonStandard = modifier || secondaryClick;
+
+ if (options.link && nonStandard) {
+ // Allow the browser to handle special link clicks normally
+ return;
+ }
+
+ event.preventDefault();
+
+ event.view = options.view;
+
+ if (options.hasOwnProperty('context')) {
+ event.context = options.context;
+ }
+
+ if (options.hasOwnProperty('contexts')) {
+ event.contexts = options.contexts;
+ }
+
+ var target = options.target;
+
+ // Check for StateManager (or compatible object)
+ if (target.isState && typeof target.send === 'function') {
+ return target.send(actionName, event);
+ } else {
+ Ember.assert(Ember.String.fmt('Target %@ does not have action %@', [target, actionName]), target[actionName]);
+ return target[actionName].call(target, event);
+ }
+ }
+ };
+
+ options.view.on('willRerender', function() {
+ delete ActionHelper.registeredActions[actionId];
+ });
+
+ return actionId;
+};
+
+/**
+ The `{{action}}` helper registers an HTML element within a template for
+ DOM event handling and forwards that interaction to the Application's router,
+ the template's `Ember.View` instance, or supplied `target` option (see 'Specifying a Target').
+
+ User interaction with that element will invoke the supplied action name on
+ the appropriate target.
+
+ Given the following Handlebars template on the page
+
+ ``` handlebars
+
+ ```
+
+ And application code
+
+ ``` javascript
+ AView = Ember.View.extend({
+ templateName; 'a-template',
+ anActionName: function(event){}
+ });
+
+ aView = AView.create();
+ aView.appendTo('body');
+ ```
+
+ Will results in the following rendered HTML
+
+ ``` html
+
+
+ click me
+
+
+ ```
+
+ Clicking "click me" will trigger the `anActionName` method of the `aView`
+ object with a `jQuery.Event` object as its argument. The `jQuery.Event`
+ object will be extended to include a `view` property that is set to the
+ original view interacted with (in this case the `aView` object).
+
+ ### Event Propagation
+
+ Events triggered through the action helper will automatically have
+ `.preventDefault()` called on them. You do not need to do so in your event
+ handlers. To stop propagation of the event, simply return `false` from your
+ handler.
+
+ If you need the default handler to trigger you should either register your
+ own event handler, or use event methods on your view class. See Ember.View
+ 'Responding to Browser Events' for more information.
+
+ ### Specifying DOM event type
+
+ By default the `{{action}}` helper registers for DOM `click` events. You can
+ supply an `on` option to the helper to specify a different DOM event name:
+
+ ``` handlebars
+
+ ```
+
+ See Ember.View 'Responding to Browser Events' for a list of
+ acceptable DOM event names.
+
+ Because `{{action}}` depends on Ember's event dispatch system it will only
+ function if an `Ember.EventDispatcher` instance is available. An
+ `Ember.EventDispatcher` instance will be created when a new
+ `Ember.Application` is created. Having an instance of `Ember.Application`
+ will satisfy this requirement.
+
+
+ ### Specifying a Target
+ There are several possible target objects for `{{action}}` helpers:
+
+ In a typical `Ember.Router`-backed Application where views are managed
+ through use of the `{{outlet}}` helper, actions will be forwarded to the
+ current state of the Applications's Router. See Ember.Router 'Responding
+ to User-initiated Events' for more information.
+
+ If you manually set the `target` property on the controller of a template's
+ `Ember.View` instance, the specifed `controller.target` will become the target
+ for any actions. Likely custom values for a controller's `target` are the
+ controller itself or a StateManager other than the Application's Router.
+
+ If the templates's view lacks a controller property the view itself is the target.
+
+ Finally, a `target` option can be provided to the helper to change which object
+ will receive the method call. This option must be a string representing a
+ path to an object:
+
+ ``` handlebars
+
+ ```
+
+ Clicking "click me" in the rendered HTML of the above template will trigger
+ the `anActionName` method of the object at `MyApplication.someObject`.
+ The first argument to this method will be a `jQuery.Event` extended to
+ include a `view` property that is set to the original view interacted with.
+
+ A path relative to the template's `Ember.View` instance can also be used as
+ a target:
+
+ ``` handlebars
+
+ ```
+
+ Clicking "click me" in the rendered HTML of the above template will trigger
+ the `anActionName` method of the view's parent view.
+
+ The `{{action}}` helper is `Ember.StateManager` aware. If the target of the
+ action is an `Ember.StateManager` instance `{{action}}` will use the `send`
+ functionality of StateManagers. The documentation for `Ember.StateManager`
+ has additional information about this use.
+
+ If an action's target does not implement a method that matches the supplied
+ action name an error will be thrown.
+
+ ``` handlebars
+
+ ```
+
+ With the following application code
+
+ ``` javascript
+ AView = Ember.View.extend({
+ templateName; 'a-template',
+ // note: no method 'aMethodNameThatIsMissing'
+ anActionName: function(event){}
+ });
+
+ aView = AView.create();
+ aView.appendTo('body');
+ ```
+
+ Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
+ "click me" is clicked.
+
+ ### Specifying a context
+
+ By default the `{{action}}` helper passes the current Handlebars context
+ along in the `jQuery.Event` object. You may specify an alternate object to
+ pass as the context by providing a property path:
+
+ ``` handlebars
+
+ ```
+
+ @method action
+ @for Ember.Handlebars.helpers
+ @param {String} actionName
+ @param {Object...} contexts
+ @param {Hash} options
+*/
+EmberHandlebars.registerHelper('action', function(actionName) {
+ var options = arguments[arguments.length - 1],
+ contexts = a_slice.call(arguments, 1, -1);
+
+ var hash = options.hash,
+ view = options.data.view,
+ target, controller, link;
+
+ // create a hash to pass along to registerAction
+ var action = {
+ eventName: hash.on || "click"
+ };
+
+ action.view = view = get(view, 'concreteView');
+
+ if (hash.target) {
+ target = getPath(this, hash.target, options);
+ } else if (controller = options.data.keywords.controller) {
+ target = get(controller, 'target');
+ }
+
+ action.target = target = target || view;
+
+ if (contexts.length) {
+ action.contexts = contexts = Ember.EnumerableUtils.map(contexts, function(context) {
+ return getPath(this, context, options);
+ }, this);
+ action.context = contexts[0];
+ }
+
+ var output = [], url;
+
+ if (hash.href && target.urlForEvent) {
+ url = target.urlForEvent.apply(target, [actionName].concat(contexts));
+ output.push('href="' + url + '"');
+ action.link = true;
+ }
+
+ var actionId = ActionHelper.registerAction(actionName, action);
+ output.push('data-ember-action="' + actionId + '"');
+
+ return new EmberHandlebars.SafeString(output.join(" "));
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+/**
+
+ When used in a Handlebars template that is assigned to an `Ember.View` instance's
+ `layout` property Ember will render the layout template first, inserting the view's
+ own rendered output at the `{{ yield }}` location.
+
+ An empty `` and the following application code:
+
+ ``` javascript
+ AView = Ember.View.extend({
+ classNames: ['a-view-with-layout'],
+ layout: Ember.Handlebars.compile('
{{ yield }}
'),
+ template: Ember.Handlebars.compile('I am wrapped')
+ });
+
+ aView = AView.create();
+ aView.appendTo('body');
+ ```
+
+ Will result in the following HTML output:
+
+ ``` html
+
+
+
+ I am wrapped
+
+
+
+ ```
+
+ The yield helper cannot be used outside of a template assigned to an `Ember.View`'s `layout` property
+ and will throw an error if attempted.
+
+ ``` javascript
+ BView = Ember.View.extend({
+ classNames: ['a-view-with-layout'],
+ template: Ember.Handlebars.compile('{{yield}}')
+ });
+
+ bView = BView.create();
+ bView.appendTo('body');
+
+ // throws
+ // Uncaught Error: assertion failed: You called yield in a template that was not a layout
+ ```
+
+ @method yield
+ @for Ember.Handlebars.helpers
+ @param {Hash} options
+ @return {String} HTML string
+*/
+Ember.Handlebars.registerHelper('yield', function(options) {
+ var view = options.data.view, template;
+
+ while (view && !get(view, 'layout')) {
+ view = get(view, 'parentView');
+ }
+
+ Ember.assert("You called yield in a template that was not a layout", !!view);
+
+ template = get(view, 'template');
+
+ if (template) { template(this, options); }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+Ember.Handlebars.OutletView = Ember.ContainerView.extend(Ember._Metamorph);
+
+/**
+ The `outlet` helper allows you to specify that the current
+ view's controller will fill in the view for a given area.
+
+ ``` handlebars
+ {{outlet}}
+ ```
+
+ By default, when the the current controller's `view`
+ property changes, the outlet will replace its current
+ view with the new view.
+
+ ``` javascript
+ controller.set('view', someView);
+ ```
+
+ You can also specify a particular name, other than view:
+
+ ``` handlebars
+ {{outlet masterView}}
+ {{outlet detailView}}
+ ```
+
+ Then, you can control several outlets from a single
+ controller:
+
+ ``` javascript
+ controller.set('masterView', postsView);
+ controller.set('detailView', postView);
+ ```
+
+ @method outlet
+ @for Ember.Handlebars.helpers
+ @param {String} property the property on the controller
+ that holds the view for this outlet
+*/
+Ember.Handlebars.registerHelper('outlet', function(property, options) {
+ if (property && property.data && property.data.isRenderData) {
+ options = property;
+ property = 'view';
+ }
+
+ options.hash.currentViewBinding = "controller." + property;
+
+ return Ember.Handlebars.helpers.view.call(this, Ember.Handlebars.OutletView, options);
+});
+
+})();
+
+
+
+(function() {
+
+})();
+
+
+
+(function() {
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var set = Ember.set, get = Ember.get;
+
+/**
+ The `Ember.Checkbox` view class renders a checkbox [input](https://developer.mozilla.org/en/HTML/Element/Input)
+ element. It allows for binding an Ember property (`checked`) to the status of the checkbox.
+
+ Example:
+
+ ``` handlebars
+ {{view Ember.Checkbox checkedBinding="receiveEmail"}}
+ ```
+
+ You can add a `label` tag yourself in the template where the Ember.Checkbox is being used.
+
+ ``` html
+
+ ```
+
+
+ The `checked` attribute of an Ember.Checkbox object should always be set
+ through the Ember object or by interacting with its rendered element representation
+ via the mouse, keyboard, or touch. Updating the value of the checkbox via jQuery will
+ result in the checked value of the object and its element losing synchronization.
+
+ ## Layout and LayoutName properties
+ Because HTML `input` elements are self closing `layout` and `layoutName` properties will
+ not be applied. See `Ember.View`'s layout section for more information.
+
+ @class Checkbox
+ @namespace Ember
+ @extends Ember.View
+*/
+Ember.Checkbox = Ember.View.extend({
+ classNames: ['ember-checkbox'],
+
+ tagName: 'input',
+
+ attributeBindings: ['type', 'checked', 'disabled', 'tabindex'],
+
+ type: "checkbox",
+ checked: false,
+ disabled: false,
+
+ init: function() {
+ this._super();
+ this.on("change", this, this._updateElementValue);
+ },
+
+ _updateElementValue: function() {
+ set(this, 'checked', this.$().prop('checked'));
+ }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+/**
+ Shared mixin used by Ember.TextField and Ember.TextArea.
+
+ @class TextSupport
+ @namespace Ember
+ @extends Ember.Mixin
+ @private
+*/
+Ember.TextSupport = Ember.Mixin.create({
+ value: "",
+
+ attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex'],
+ placeholder: null,
+ disabled: false,
+ maxlength: null,
+
+ insertNewline: Ember.K,
+ cancel: Ember.K,
+
+ init: function() {
+ this._super();
+ this.on("focusOut", this, this._elementValueDidChange);
+ this.on("change", this, this._elementValueDidChange);
+ this.on("keyUp", this, this.interpretKeyEvents);
+ },
+
+ interpretKeyEvents: function(event) {
+ var map = Ember.TextSupport.KEY_EVENTS;
+ var method = map[event.keyCode];
+
+ this._elementValueDidChange();
+ if (method) { return this[method](event); }
+ },
+
+ _elementValueDidChange: function() {
+ set(this, 'value', this.$().val());
+ }
+
+});
+
+Ember.TextSupport.KEY_EVENTS = {
+ 13: 'insertNewline',
+ 27: 'cancel'
+};
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+/**
+ The `Ember.TextField` view class renders a text
+ [input](https://developer.mozilla.org/en/HTML/Element/Input) element. It
+ allows for binding Ember properties to the text field contents (`value`),
+ live-updating as the user inputs text.
+
+ Example:
+
+ ``` handlebars
+ {{view Ember.TextField valueBinding="firstName"}}
+ ```
+
+ ## Layout and LayoutName properties
+ Because HTML `input` elements are self closing `layout` and `layoutName` properties will
+ not be applied. See `Ember.View`'s layout section for more information.
+
+ @class TextField
+ @namespace Ember
+ @extends Ember.View
+ @uses Ember.TextSupport
+*/
+Ember.TextField = Ember.View.extend(Ember.TextSupport,
+ /** @scope Ember.TextField.prototype */ {
+
+ classNames: ['ember-text-field'],
+ tagName: "input",
+ attributeBindings: ['type', 'value', 'size'],
+
+ /**
+ The value attribute of the input element. As the user inputs text, this
+ property is updated live.
+
+ @property value
+ @type String
+ @default ""
+ */
+ value: "",
+
+ /**
+ The type attribute of the input element.
+
+ @property type
+ @type String
+ @default "text"
+ */
+ type: "text",
+
+ /**
+ The size of the text field in characters.
+
+ @property size
+ @type String
+ @default null
+ */
+ size: null
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+/**
+ @class Button
+ @namespace Ember
+ @extends Ember.View
+ @uses Ember.TargetActionSupport
+ @deprecated
+*/
+Ember.Button = Ember.View.extend(Ember.TargetActionSupport, {
+ classNames: ['ember-button'],
+ classNameBindings: ['isActive'],
+
+ tagName: 'button',
+
+ propagateEvents: false,
+
+ attributeBindings: ['type', 'disabled', 'href', 'tabindex'],
+
+ /**
+ @private
+
+ Overrides TargetActionSupport's targetObject computed
+ property to use Handlebars-specific path resolution.
+
+ @property targetObject
+ */
+ targetObject: Ember.computed(function() {
+ var target = get(this, 'target'),
+ root = get(this, 'context'),
+ data = get(this, 'templateData');
+
+ if (typeof target !== 'string') { return target; }
+
+ return Ember.Handlebars.getPath(root, target, { data: data });
+ }).property('target').cacheable(),
+
+ // Defaults to 'button' if tagName is 'input' or 'button'
+ type: Ember.computed(function(key, value) {
+ var tagName = this.get('tagName');
+ if (value !== undefined) { this._type = value; }
+ if (this._type !== undefined) { return this._type; }
+ if (tagName === 'input' || tagName === 'button') { return 'button'; }
+ }).property('tagName').cacheable(),
+
+ disabled: false,
+
+ // Allow 'a' tags to act like buttons
+ href: Ember.computed(function() {
+ return this.get('tagName') === 'a' ? '#' : null;
+ }).property('tagName').cacheable(),
+
+ mouseDown: function() {
+ if (!get(this, 'disabled')) {
+ set(this, 'isActive', true);
+ this._mouseDown = true;
+ this._mouseEntered = true;
+ }
+ return get(this, 'propagateEvents');
+ },
+
+ mouseLeave: function() {
+ if (this._mouseDown) {
+ set(this, 'isActive', false);
+ this._mouseEntered = false;
+ }
+ },
+
+ mouseEnter: function() {
+ if (this._mouseDown) {
+ set(this, 'isActive', true);
+ this._mouseEntered = true;
+ }
+ },
+
+ mouseUp: function(event) {
+ if (get(this, 'isActive')) {
+ // Actually invoke the button's target and action.
+ // This method comes from the Ember.TargetActionSupport mixin.
+ this.triggerAction();
+ set(this, 'isActive', false);
+ }
+
+ this._mouseDown = false;
+ this._mouseEntered = false;
+ return get(this, 'propagateEvents');
+ },
+
+ keyDown: function(event) {
+ // Handle space or enter
+ if (event.keyCode === 13 || event.keyCode === 32) {
+ this.mouseDown();
+ }
+ },
+
+ keyUp: function(event) {
+ // Handle space or enter
+ if (event.keyCode === 13 || event.keyCode === 32) {
+ this.mouseUp();
+ }
+ },
+
+ // TODO: Handle proper touch behavior. Including should make inactive when
+ // finger moves more than 20x outside of the edge of the button (vs mouse
+ // which goes inactive as soon as mouse goes out of edges.)
+
+ touchStart: function(touch) {
+ return this.mouseDown(touch);
+ },
+
+ touchEnd: function(touch) {
+ return this.mouseUp(touch);
+ },
+
+ init: function() {
+ Ember.deprecate("Ember.Button is deprecated and will be removed from future releases. Consider using the `{{action}}` helper.");
+ this._super();
+ }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, set = Ember.set;
+
+/**
+ The `Ember.TextArea` view class renders a
+ [textarea](https://developer.mozilla.org/en/HTML/Element/textarea) element.
+ It allows for binding Ember properties to the text area contents (`value`),
+ live-updating as the user inputs text.
+
+ ## Layout and LayoutName properties
+
+ Because HTML `textarea` elements do not contain inner HTML the `layout` and `layoutName`
+ properties will not be applied. See `Ember.View`'s layout section for more information.
+
+ @class TextArea
+ @namespace Ember
+ @extends Ember.View
+ @uses Ember.TextSupport
+*/
+Ember.TextArea = Ember.View.extend(Ember.TextSupport, {
+ classNames: ['ember-text-area'],
+
+ tagName: "textarea",
+ attributeBindings: ['rows', 'cols'],
+ rows: null,
+ cols: null,
+
+ _updateElementValue: Ember.observer(function() {
+ // We do this check so cursor position doesn't get affected in IE
+ var value = get(this, 'value'),
+ $el = this.$();
+ if ($el && value !== $el.val()) {
+ $el.val(value);
+ }
+ }, 'value'),
+
+ init: function() {
+ this._super();
+ this.on("didInsertElement", this, this._updateElementValue);
+ }
+
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+/**
+@class TabContainerView
+@namespace Ember
+@deprecated
+@extends Ember.View
+*/
+Ember.TabContainerView = Ember.View.extend({
+ init: function() {
+ Ember.deprecate("Ember.TabContainerView is deprecated and will be removed from future releases.");
+ this._super();
+ }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get;
+
+/**
+ @class TabPaneView
+ @namespace Ember
+ @extends Ember.View
+ @deprecated
+*/
+Ember.TabPaneView = Ember.View.extend({
+ tabsContainer: Ember.computed(function() {
+ return this.nearestInstanceOf(Ember.TabContainerView);
+ }).property().volatile(),
+
+ isVisible: Ember.computed(function() {
+ return get(this, 'viewName') === get(this, 'tabsContainer.currentView');
+ }).property('tabsContainer.currentView').volatile(),
+
+ init: function() {
+ Ember.deprecate("Ember.TabPaneView is deprecated and will be removed from future releases.");
+ this._super();
+ }
+});
+
+})();
+
+
+
+(function() {
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var get = Ember.get, setPath = Ember.setPath;
+
+/**
+@class TabView
+@namespace Ember
+@extends Ember.View
+@deprecated
+*/
+Ember.TabView = Ember.View.extend({
+ tabsContainer: Ember.computed(function() {
+ return this.nearestInstanceOf(Ember.TabContainerView);
+ }).property().volatile(),
+
+ mouseUp: function() {
+ setPath(this, 'tabsContainer.currentView', get(this, 'value'));
+ },
+
+ init: function() {
+ Ember.deprecate("Ember.TabView is deprecated and will be removed from future releases.");
+ this._super();
+ }
+});
+
+})();
+
+
+
+(function() {
+
+})();
+
+
+
+(function() {
+/*jshint eqeqeq:false */
+
+/**
+@module ember
+@submodule ember-handlebars
+*/
+
+var set = Ember.set, get = Ember.get;
+var indexOf = Ember.EnumerableUtils.indexOf, indexesOf = Ember.EnumerableUtils.indexesOf;
+
+/**
+ The Ember.Select view class renders a
+ [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element,
+ allowing the user to choose from a list of options.
+
+ The text and `value` property of each `