+ Ember.View.extend({
+ attributeBindings: ['type'],
+ type: 'button'
+ });
+ ```
+
+ If the value of the property is a Boolean, the name of that property is
+ added as an attribute.
+
+ ```javascript
+ // Renders something like
+ Ember.View.extend({
+ attributeBindings: ['enabled'],
+ enabled: true
+ });
+ ```
+
+ @property attributeBindings
+ */
+ attributeBindings: EMPTY_ARRAY,
+
+ // .......................................................
+ // CORE DISPLAY METHODS
+ //
+
+ /**
+ Setup a view, but do not finish waking it up.
+
+ * configure `childViews`
+ * register the view with the global views hash, which is used for event
+ dispatch
+
+ @method init
+ @private
+ */
+ init: function() {
+ this.elementId = this.elementId || guidFor(this);
+
+ this._super();
+
+ // setup child views. be sure to clone the child views array first
+ this._childViews = this._childViews.slice();
+
+ Ember.assert("Only arrays are allowed for 'classNameBindings'", typeOf(this.classNameBindings) === 'array');
+ this.classNameBindings = A(this.classNameBindings.slice());
+
+ Ember.assert("Only arrays are allowed for 'classNames'", typeOf(this.classNames) === 'array');
+ this.classNames = A(this.classNames.slice());
+ },
+
+ appendChild: function(view, options) {
+ return this.currentState.appendChild(this, view, options);
+ },
+
+ /**
+ Removes the child view from the parent view.
+
+ @method removeChild
+ @param {Ember.View} view
+ @return {Ember.View} receiver
+ */
+ removeChild: function(view) {
+ // If we're destroying, the entire subtree will be
+ // freed, and the DOM will be handled separately,
+ // so no need to mess with childViews.
+ if (this.isDestroying) { return; }
+
+ // update parent node
+ set(view, '_parentView', null);
+
+ // remove view from childViews array.
+ var childViews = this._childViews;
+
+ a_removeObject(childViews, view);
+
+ this.propertyDidChange('childViews'); // HUH?! what happened to will change?
+
+ return this;
+ },
+
+ /**
+ Removes all children from the `parentView`.
+
+ @method removeAllChildren
+ @return {Ember.View} receiver
+ */
+ removeAllChildren: function() {
+ return this.mutateChildViews(function(parentView, view) {
+ parentView.removeChild(view);
+ });
+ },
+
+ destroyAllChildren: function() {
+ return this.mutateChildViews(function(parentView, view) {
+ view.destroy();
+ });
+ },
+
+ /**
+ Removes the view from its `parentView`, if one is found. Otherwise
+ does nothing.
+
+ @method removeFromParent
+ @return {Ember.View} receiver
+ */
+ removeFromParent: function() {
+ var parent = this._parentView;
+
+ // Remove DOM element from parent
+ this.remove();
+
+ if (parent) { parent.removeChild(this); }
+ return this;
+ },
+
+ /**
+ You must call `destroy` on a view to destroy the view (and all of its
+ child views). This will remove the view from any parent node, then make
+ sure that the DOM element managed by the view can be released by the
+ memory manager.
+
+ @method destroy
+ */
+ destroy: function() {
+ var childViews = this._childViews,
+ // get parentView before calling super because it'll be destroyed
+ nonVirtualParentView = get(this, 'parentView'),
+ viewName = this.viewName,
+ childLen, i;
+
+ if (!this._super()) { return; }
+
+ childLen = childViews.length;
+ for (i=childLen-1; i>=0; i--) {
+ childViews[i].removedFromDOM = true;
+ }
+
+ // remove from non-virtual parent view if viewName was specified
+ if (viewName && nonVirtualParentView) {
+ nonVirtualParentView.set(viewName, null);
+ }
+
+ childLen = childViews.length;
+ for (i=childLen-1; i>=0; i--) {
+ childViews[i].destroy();
+ }
+
+ return this;
+ },
+
+ /**
+ Instantiates a view to be added to the childViews array during view
+ initialization. You generally will not call this method directly unless
+ you are overriding `createChildViews()`. Note that this method will
+ automatically configure the correct settings on the new view instance to
+ act as a child of the parent.
+
+ @method createChildView
+ @param {Class|String} viewClass
+ @param {Hash} [attrs] Attributes to add
+ @return {Ember.View} new instance
+ */
+ createChildView: function(view, attrs) {
+ if (!view) {
+ throw new TypeError("createChildViews first argument must exist");
+ }
+
+ if (view.isView && view._parentView === this && view.container === this.container) {
+ return view;
+ }
+
+ attrs = attrs || {};
+ attrs._parentView = this;
+
+ if (CoreView.detect(view)) {
+ attrs.templateData = attrs.templateData || get(this, 'templateData');
+
+ attrs.container = this.container;
+ view = view.create(attrs);
+
+ // don't set the property on a virtual view, as they are invisible to
+ // consumers of the view API
+ if (view.viewName) {
+ set(get(this, 'concreteView'), view.viewName, view);
+ }
+ } else if ('string' === typeof view) {
+ var fullName = 'view:' + view;
+ var ViewKlass = this.container.lookupFactory(fullName);
+
+ Ember.assert("Could not find view: '" + fullName + "'", !!ViewKlass);
+
+ attrs.templateData = get(this, 'templateData');
+ view = ViewKlass.create(attrs);
} else {
- this.triggerAction('stop');
+ Ember.assert('You must pass instance or subclass of View', view.isView);
+ attrs.container = this.container;
+
+ if (!get(view, 'templateData')) {
+ attrs.templateData = get(this, 'templateData');
+ }
+
+ setProperties(view, attrs);
+
}
- }
- });
- ```
- When used inside a template these component actions are configured to
- trigger actions in the outer application context:
+ return view;
+ },
- ```handlebars
- {{! application.hbs }}
- {{play-button play="musicStarted" stop="musicStopped"}}
- ```
+ becameVisible: Ember.K,
+ becameHidden: Ember.K,
- When the component receives a browser `click` event it translate this
- interaction into application-specific semantics ("play" or "stop") and
- triggers the specified action name on the controller for the template
- where the component is used:
+ /**
+ When the view's `isVisible` property changes, toggle the visibility
+ element of the actual DOM element.
+ @method _isVisibleDidChange
+ @private
+ */
+ _isVisibleDidChange: observer('isVisible', function() {
+ if (this._isVisible === get(this, 'isVisible')) { return ; }
+ run.scheduleOnce('render', this, this._toggleVisibility);
+ }),
- ```javascript
- App.ApplicationController = Ember.Controller.extend({
- actions: {
- musicStarted: function(){
- // called when the play button is clicked
- // and the music started playing
- },
- musicStopped: function(){
- // called when the play button is clicked
- // and the music stopped playing
+ _toggleVisibility: function() {
+ var $el = this.$();
+ if (!$el) { return; }
+
+ var isVisible = get(this, 'isVisible');
+
+ if (this._isVisible === isVisible) { return ; }
+
+ $el.toggle(isVisible);
+
+ this._isVisible = isVisible;
+
+ if (this._isAncestorHidden()) { return; }
+
+ if (isVisible) {
+ this._notifyBecameVisible();
+ } else {
+ this._notifyBecameHidden();
}
- }
- });
- ```
+ },
- If no action name is passed to `sendAction` a default name of "action"
- is assumed.
+ _notifyBecameVisible: function() {
+ this.trigger('becameVisible');
- ```javascript
- App.NextButtonComponent = Ember.Component.extend({
- click: function(){
- this.sendAction();
- }
- });
- ```
+ this.forEachChildView(function(view) {
+ var isVisible = get(view, 'isVisible');
- ```handlebars
- {{! application.hbs }}
- {{next-button action="playNextSongInAlbum"}}
- ```
+ if (isVisible || isVisible === null) {
+ view._notifyBecameVisible();
+ }
+ });
+ },
- ```javascript
- App.ApplicationController = Ember.Controller.extend({
- actions: {
- playNextSongInAlbum: function(){
- ...
+ _notifyBecameHidden: function() {
+ this.trigger('becameHidden');
+ this.forEachChildView(function(view) {
+ var isVisible = get(view, 'isVisible');
+
+ if (isVisible || isVisible === null) {
+ view._notifyBecameHidden();
+ }
+ });
+ },
+
+ _isAncestorHidden: function() {
+ var parent = get(this, 'parentView');
+
+ while (parent) {
+ if (get(parent, 'isVisible') === false) { return true; }
+
+ parent = get(parent, 'parentView');
}
+
+ return false;
+ },
+
+ clearBuffer: function() {
+ this.invokeRecursively(nullViewsBuffer);
+ },
+
+ transitionTo: function(state, children) {
+ var priorState = this.currentState,
+ currentState = this.currentState = this.states[state];
+ this.state = state;
+
+ if (priorState && priorState.exit) { priorState.exit(this); }
+ if (currentState.enter) { currentState.enter(this); }
+ if (state === 'inDOM') { meta(this).cache.element = undefined; }
+
+ if (children !== false) {
+ this.forEachChildView(function(view) {
+ view.transitionTo(state);
+ });
+ }
+ },
+
+ // .......................................................
+ // EVENT HANDLING
+ //
+
+ /**
+ Handle events from `Ember.EventDispatcher`
+
+ @method handleEvent
+ @param eventName {String}
+ @param evt {Event}
+ @private
+ */
+ handleEvent: function(eventName, evt) {
+ return this.currentState.handleEvent(this, eventName, evt);
+ },
+
+ registerObserver: function(root, path, target, observer) {
+ if (!observer && 'function' === typeof target) {
+ observer = target;
+ target = null;
+ }
+
+ if (!root || typeof root !== 'object') {
+ return;
+ }
+
+ var view = this,
+ stateCheckedObserver = function() {
+ view.currentState.invokeObserver(this, observer);
+ },
+ scheduledObserver = function() {
+ run.scheduleOnce('render', this, stateCheckedObserver);
+ };
+
+ addObserver(root, path, target, scheduledObserver);
+
+ this.one('willClearRender', function() {
+ removeObserver(root, path, target, scheduledObserver);
+ });
}
+
});
- ```
- @method sendAction
- @param [action] {String} the action to trigger
- @param [context] {*} a context to send with the action
- */
- sendAction: function(action) {
- var actionName,
- contexts = a_slice.call(arguments, 1);
+ /*
+ Describe how the specified actions should behave in the various
+ states that a view can exist in. Possible states:
- // Send the default action
- if (action === undefined) {
- actionName = get(this, 'action');
- Ember.assert("The default action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string');
- } else {
- actionName = get(this, action);
- Ember.assert("The " + action + " action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string');
+ * preRender: when a view is first instantiated, and after its
+ element was destroyed, it is in the preRender state
+ * inBuffer: once a view has been rendered, but before it has
+ been inserted into the DOM, it is in the inBuffer state
+ * hasElement: the DOM representation of the view is created,
+ and is ready to be inserted
+ * inDOM: once a view has been inserted into the DOM it is in
+ the inDOM state. A view spends the vast majority of its
+ existence in this state.
+ * destroyed: once a view has been destroyed (using the destroy
+ method), it is in this state. No further actions can be invoked
+ on a destroyed view.
+ */
+
+ // in the destroyed state, everything is illegal
+
+ // before rendering has begun, all legal manipulations are noops.
+
+ // inside the buffer, legal manipulations are done on the buffer
+
+ // once the view has been inserted into the DOM, legal manipulations
+ // are done on the DOM element.
+
+ function notifyMutationListeners() {
+ run.once(View, 'notifyMutationListeners');
}
- // If no action name for that action could be found, just abort.
- if (actionName === undefined) { return; }
+ var DOMManager = {
+ prepend: function(view, html) {
+ view.$().prepend(html);
+ notifyMutationListeners();
+ },
- this.triggerAction({
- action: actionName,
- actionContext: contexts
+ after: function(view, html) {
+ view.$().after(html);
+ notifyMutationListeners();
+ },
+
+ html: function(view, html) {
+ view.$().html(html);
+ notifyMutationListeners();
+ },
+
+ replace: function(view) {
+ var element = get(view, 'element');
+
+ set(view, 'element', null);
+
+ view._insertElementLater(function() {
+ jQuery(element).replaceWith(get(view, 'element'));
+ notifyMutationListeners();
+ });
+ },
+
+ remove: function(view) {
+ view.$().remove();
+ notifyMutationListeners();
+ },
+
+ empty: function(view) {
+ view.$().empty();
+ notifyMutationListeners();
+ }
+ };
+
+ View.reopen({
+ domManager: DOMManager
});
- }
-});
-})();
+ View.reopenClass({
+ /**
+ Parse a path and return an object which holds the parsed properties.
+ For example a path like "content.isEnabled:enabled:disabled" will return the
+ following object:
-(function() {
+ ```javascript
+ {
+ path: "content.isEnabled",
+ className: "enabled",
+ falsyClassName: "disabled",
+ classNames: ":enabled:disabled"
+ }
+ ```
-})();
+ @method _parsePropertyPath
+ @static
+ @private
+ */
+ _parsePropertyPath: function(path) {
+ var split = path.split(':'),
+ propertyPath = split[0],
+ classNames = "",
+ className,
+ falsyClassName;
+ // check if the property is defined as prop:class or prop:trueClass:falseClass
+ if (split.length > 1) {
+ className = split[1];
+ if (split.length === 3) { falsyClassName = split[2]; }
+ classNames = ':' + className;
+ if (falsyClassName) { classNames += ":" + falsyClassName; }
+ }
-(function() {
-/**
-`Ember.ViewTargetActionSupport` is a mixin that can be included in a
-view class to add a `triggerAction` method with semantics similar to
-the Handlebars `{{action}}` helper. It provides intelligent defaults
-for the action's target: the view's controller; and the context that is
-sent with the action: the view's context.
+ return {
+ path: propertyPath,
+ classNames: classNames,
+ className: (className === '') ? undefined : className,
+ falsyClassName: falsyClassName
+ };
+ },
-Note: In normal Ember usage, the `{{action}}` helper is usually the best
-choice. This mixin is most often useful when you are doing more complex
-event handling in custom View subclasses.
+ /**
+ Get the class name for a given value, based on the path, optional
+ `className` and optional `falsyClassName`.
-For example:
+ - if a `className` or `falsyClassName` has been specified:
+ - if the value is truthy and `className` has been specified,
+ `className` is returned
+ - if the value is falsy and `falsyClassName` has been specified,
+ `falsyClassName` is returned
+ - otherwise `null` is returned
+ - if the value is `true`, the dasherized last part of the supplied path
+ is returned
+ - if the value is not `false`, `undefined` or `null`, the `value`
+ is returned
+ - if none of the above rules apply, `null` is returned
-```javascript
-App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, {
- action: 'save',
- click: function() {
- this.triggerAction(); // Sends the `save` action, along with the current context
- // to the current controller
- }
-});
-```
+ @method _classStringForValue
+ @param path
+ @param val
+ @param className
+ @param falsyClassName
+ @static
+ @private
+ */
+ _classStringForValue: function(path, val, className, falsyClassName) {
+ // When using the colon syntax, evaluate the truthiness or falsiness
+ // of the value to determine which className to return
+ if (className || falsyClassName) {
+ if (className && !!val) {
+ return className;
-The `action` can be provided as properties of an optional object argument
-to `triggerAction` as well.
+ } else if (falsyClassName && !val) {
+ return falsyClassName;
-```javascript
-App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, {
- click: function() {
- this.triggerAction({
- action: 'save'
- }); // Sends the `save` action, along with the current context
- // to the current controller
- }
-});
-```
+ } else {
+ return null;
+ }
-@class ViewTargetActionSupport
-@namespace Ember
-@extends Ember.TargetActionSupport
-*/
-Ember.ViewTargetActionSupport = Ember.Mixin.create(Ember.TargetActionSupport, {
- /**
- @property target
- */
- target: Ember.computed.alias('controller'),
- /**
- @property actionContext
- */
- actionContext: Ember.computed.alias('context')
-});
+ // If value is a Boolean and true, return the dasherized property
+ // name.
+ } else if (val === true) {
+ // Normalize property path to be suitable for use
+ // as a class name. For exaple, content.foo.barBaz
+ // becomes bar-baz.
+ var parts = path.split('.');
+ return dasherize(parts[parts.length-1]);
-})();
+ // If the value is not false, undefined, or null, return the current
+ // value of the property.
+ } else if (val !== false && val != null) {
+ return val;
+ // Nothing to display. Return null so that the old class is removed
+ // but no new class is added.
+ } else {
+ return null;
+ }
+ }
+ });
+ var mutation = EmberObject.extend(Evented).create();
-(function() {
+ View.addMutationListener = function(callback) {
+ mutation.on('change', callback);
+ };
-})();
+ View.removeMutationListener = function(callback) {
+ mutation.off('change', callback);
+ };
+ View.notifyMutationListeners = function() {
+ mutation.trigger('change');
+ };
+ /**
+ Global views hash
-(function() {
-/**
-Ember Views
+ @property views
+ @static
+ @type Hash
+ */
+ View.views = {};
-@module ember
-@submodule ember-views
-@requires ember-runtime
-@main ember-views
-*/
+ // If someone overrides the child views computed property when
+ // defining their class, we want to be able to process the user's
+ // supplied childViews and then restore the original computed property
+ // at view initialization time. This happens in Ember.ContainerView's init
+ // method.
+ View.childViewsProperty = childViewsProperty;
+ View.applyAttributeBindings = function(elem, name, value) {
+ var type = typeOf(value);
+
+ // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js
+ if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) {
+ if (value !== elem.attr(name)) {
+ elem.attr(name, value);
+ }
+ } else if (name === 'value' || type === 'boolean') {
+ if (isNone(value) || value === false) {
+ // `null`, `undefined` or `false` should remove attribute
+ elem.removeAttr(name);
+ elem.prop(name, '');
+ } else if (value !== elem.prop(name)) {
+ // value should always be properties
+ elem.prop(name, value);
+ }
+ } else if (!value) {
+ elem.removeAttr(name);
+ }
+ };
+
+ __exports__.CoreView = CoreView;
+ __exports__.View = View;
+ __exports__.ViewCollection = ViewCollection;
+ });
})();
(function() {
@@ -23682,21 +27594,28 @@ define("metamorph",
"use strict";
// ==========================================================================
// Project: metamorph
- // Copyright: ©2011 My Company Inc. All rights reserved.
+ // Copyright: ©2014 Tilde, Inc. All rights reserved.
// ==========================================================================
var K = function() {},
guid = 0,
- document = this.document,
- disableRange = ('undefined' === typeof ENV ? {} : ENV).DISABLE_RANGE_API,
+ disableRange = (function(){
+ if ('undefined' !== typeof MetamorphENV) {
+ return MetamorphENV.DISABLE_RANGE_API;
+ } else if ('undefined' !== ENV) {
+ return ENV.DISABLE_RANGE_API;
+ } else {
+ return false;
+ }
+ })(),
// Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
- supportsRange = (!disableRange) && document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
+ supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use
- needsShy = document && (function() {
+ needsShy = typeof document !== 'undefined' && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "
";
testEl.firstChild.innerHTML = "";
@@ -23800,7 +27719,7 @@ define("metamorph",
/**
* @public
- *
+ *
* Remove this object (including starting and ending
* placeholders).
*
@@ -24036,6 +27955,10 @@ define("metamorph",
// swallow some of the content.
node = firstNodeFor(start.parentNode, html);
+ if (outerToo) {
+ start.parentNode.removeChild(start);
+ }
+
// copy the nodes for the HTML between the starting and ending
// placeholder.
while (node) {
@@ -24148,5093 +28071,11529 @@ define("metamorph",
})();
(function() {
-/**
-@module ember
-@submodule ember-handlebars-compiler
-*/
-
-// Eliminate dependency on any Ember to simplify precompilation workflow
-var objectCreate = Object.create || function(parent) {
- function F() {}
- F.prototype = parent;
- return new F();
-};
-
-var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
-if (!Handlebars && typeof require === 'function') {
- Handlebars = require('handlebars');
-}
-
-Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include a SCRIPT tag in the HTML HEAD linking to the Handlebars file before you link to Ember.", Handlebars);
-Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + " - Please note: Builds of master may have other COMPILER_REVISION values.", Handlebars.COMPILER_REVISION === 4);
-
-/**
- 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);
-
-/**
- Register a bound helper or custom view helper.
-
- ## Simple bound helper example
-
- ```javascript
- Ember.Handlebars.helper('capitalize', function(value) {
- return value.toUpperCase();
- });
- ```
-
- The above bound helper can be used inside of templates as follows:
-
- ```handlebars
- {{capitalize name}}
- ```
-
- In this case, when the `name` property of the template's context changes,
- the rendered value of the helper will update to reflect this change.
-
- For more examples of bound helpers, see documentation for
- `Ember.Handlebars.registerBoundHelper`.
-
- ## Custom view helper example
-
- Assuming a view subclass named `App.CalendarView` were defined, a helper
- for rendering instances of this view could be registered as follows:
-
- ```javascript
- Ember.Handlebars.helper('calendar', App.CalendarView):
- ```
-
- The above bound helper can be used inside of templates as follows:
-
- ```handlebars
- {{calendar}}
- ```
-
- Which is functionally equivalent to:
-
- ```handlebars
- {{view App.CalendarView}}
- ```
-
- Options in the helper will be passed to the view in exactly the same
- manner as with the `view` helper.
-
- @method helper
- @for Ember.Handlebars
- @param {String} name
- @param {Function|Ember.View} function or view class constructor
- @param {String} dependentKeys*
-*/
-Ember.Handlebars.helper = function(name, value) {
- Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Ember.Component.detect(value) || name.match(/-/));
-
- if (Ember.View.detect(value)) {
- Ember.Handlebars.registerHelper(name, Ember.Handlebars.makeViewHelper(value));
- } else {
- Ember.Handlebars.registerBoundHelper.apply(null, arguments);
- }
-};
-
-/**
- @private
-
- Returns a helper function that renders the provided ViewClass.
-
- Used internally by Ember.Handlebars.helper and other methods
- involving helper/component registration.
-
- @method helper
- @for Ember.Handlebars
- @param {Function} ViewClass view class constructor
-*/
-Ember.Handlebars.makeViewHelper = function(ViewClass) {
- return function(options) {
- Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View", arguments.length < 2);
- return Ember.Handlebars.helpers.view.call(this, ViewClass, options);
- };
-};
-
-/**
-@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+");";
-};
-
-// Hacks ahead:
-// Handlebars presently has a bug where the `blockHelperMissing` hook
-// doesn't get passed the name of the missing helper name, but rather
-// gets passed the value of that missing helper evaluated on the current
-// context, which is most likely `undefined` and totally useless.
-//
-// So we alter the compiled template function to pass the name of the helper
-// instead, as expected.
-//
-// This can go away once the following is closed:
-// https://github.com/wycats/handlebars.js/issues/617
-
-var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/,
- BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/,
- INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/;
-
-Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) {
- var helperInvocation = source[source.length - 1],
- helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1],
- matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation);
-
- source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3];
-}
-var stringifyBlockHelperMissing = Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation;
-
-var originalBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.blockValue;
-Ember.Handlebars.JavaScriptCompiler.prototype.blockValue = function() {
- originalBlockValue.apply(this, arguments);
- stringifyBlockHelperMissing(this.source);
-};
-
-var originalAmbiguousBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue;
-Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() {
- originalAmbiguousBlockValue.apply(this, arguments);
- stringifyBlockHelperMissing(this.source);
-};
-
-var prefix = "ember" + (+new Date()), incr = 1;
-
-/**
- @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.isHelper && mustache.id.string === 'control') {
- mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
- mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
- } else if (mustache.params.length || mustache.hash) {
- // no changes required
- } else {
- var id = new Handlebars.AST.IdNode([{ part: '_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);
-
- var template = Ember.Handlebars.template(templateSpec);
- template.isMethod = false; //Make sure we don't wrap templates with ._super
-
- return template;
- };
-}
-
-
-})();
-
-(function() {
-var slice = Array.prototype.slice,
- originalTemplate = Ember.Handlebars.template;
-
-/**
- @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 get
- @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
-*/
-var handlebarsGet = Ember.Handlebars.get = 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 the path starts with a capital letter, look it up on Ember.lookup,
- // which defaults to the `window` object in browsers.
- if (value === undefined && root !== Ember.lookup && Ember.isGlobalPath(path)) {
- value = Ember.get(Ember.lookup, path);
- }
- return value;
-};
-
-Ember.Handlebars.resolveParams = function(context, params, options) {
- var resolvedParams = [], types = options.types, param, type;
-
- for (var i=0, l=params.length; i
someString')
- ```
-
- @method htmlSafe
- @for Ember.String
- @static
- @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars
-*/
-Ember.String.htmlSafe = function(str) {
- return new Handlebars.SafeString(str);
-};
-
-var htmlSafe = Ember.String.htmlSafe;
-
-if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
-
- /**
- Mark a string as being safe for unescaped output with Handlebars.
-
- ```javascript
- '
'.htmlSafe()
- ```
-
- See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe).
-
- @method htmlSafe
- @for String
- @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars
- */
- String.prototype.htmlSafe = function() {
- return htmlSafe(this);
- };
-}
-
-})();
-
-
-
-(function() {
-Ember.Handlebars.resolvePaths = function(options) {
- var ret = [],
- contexts = options.contexts,
- roots = options.roots,
- data = options.data;
-
- for (var i=0, l=contexts.length; i