@@ -39944,8 +38270,18 @@ enifed("ember-views/views/collection_view",
// Loop through child views that correspond with the removed items.
// Note that we loop from the end of the array to the beginning because
// we are mutating it as we go.
- var childViews = this._childViews;
- var childView, idx;
+ var childViews = this._childViews, childView, idx, len;
+
+ len = this._childViews.length;
+
+ var removingAll = removedCount === len;
+
+ if (removingAll) {
+ this.currentState.empty(this);
+ this.invokeRecursively(function(view) {
+ view.removedFromDOM = true;
+ }, false);
+ }
for (idx = start + removedCount - 1; idx >= start; idx--) {
childView = childViews[idx];
@@ -39968,14 +38304,21 @@ enifed("ember-views/views/collection_view",
@param {Number} added number of object added to content
*/
arrayDidChange: function(content, start, removed, added) {
- var addedViews = [];
- var view, item, idx, len, itemViewClass, emptyView;
+ var addedViews = [], view, item, idx, len, itemViewClass,
+ emptyView;
len = content ? get(content, 'length') : 0;
if (len) {
itemViewClass = get(this, 'itemViewClass');
- itemViewClass = handlebarsGetView(content, itemViewClass, this.container);
+
+ if ('string' === typeof itemViewClass && isGlobalPath(itemViewClass)) {
+ itemViewClass = get(itemViewClass) || itemViewClass;
+ }
+
+ Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@",
+ [itemViewClass]),
+ 'string' === typeof itemViewClass || View.detect(itemViewClass));
for (idx = start; idx < start+added; idx++) {
item = content.objectAt(idx);
@@ -40060,7 +38403,7 @@ enifed("ember-views/views/collection_view",
__exports__["default"] = CollectionView;
});
-enifed("ember-views/views/component",
+define("ember-views/views/component",
["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -40210,8 +38553,8 @@ enifed("ember-views/views/component",
template: computed(function(key, value) {
if (value !== undefined) { return value; }
- var templateName = get(this, 'templateName');
- var template = this.templateForName(templateName, 'template');
+ var templateName = get(this, 'templateName'),
+ template = this.templateForName(templateName, 'template');
Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
@@ -40236,9 +38579,9 @@ enifed("ember-views/views/component",
},
_yield: function(context, options) {
- var view = options.data.view;
- var parentView = this._parentView;
- var template = get(this, 'template');
+ var view = options.data.view,
+ parentView = this._parentView,
+ template = get(this, 'template');
if (template) {
Ember.assert("A Component must have a parent view in order to yield.", parentView);
@@ -40349,8 +38692,8 @@ enifed("ember-views/views/component",
@param [context] {*} a context to send with the action
*/
sendAction: function(action) {
- var actionName;
- var contexts = a_slice.call(arguments, 1);
+ var actionName,
+ contexts = a_slice.call(arguments, 1);
// Send the default action
if (action === undefined) {
@@ -40378,9 +38721,9 @@ enifed("ember-views/views/component",
__exports__["default"] = Component;
});
-enifed("ember-views/views/container_view",
- ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) {
+define("ember-views/views/container_view",
+ ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/view_collection","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) {
"use strict";
var Ember = __dependency1__["default"];
// Ember.assert, Ember.K
@@ -40391,21 +38734,22 @@ enifed("ember-views/views/container_view",
var set = __dependency5__.set;
var View = __dependency6__["default"];
+ var ViewCollection = __dependency7__["default"];
- var cloneStates = __dependency7__.cloneStates;
- var EmberViewStates = __dependency7__.states;
+ var cloneStates = __dependency8__.cloneStates;
+ var EmberViewStates = __dependency8__.states;
- var EmberError = __dependency8__["default"];
+ var EmberError = __dependency9__["default"];
- var forEach = __dependency9__.forEach;
+ var forEach = __dependency10__.forEach;
- var computed = __dependency10__.computed;
- var run = __dependency11__["default"];
- var defineProperty = __dependency12__.defineProperty;
- var renderBuffer = __dependency13__["default"];
- var observer = __dependency14__.observer;
- var beforeObserver = __dependency14__.beforeObserver;
- var emberA = __dependency15__.A;
+ var computed = __dependency11__.computed;
+ var run = __dependency12__["default"];
+ var defineProperty = __dependency13__.defineProperty;
+ var renderBuffer = __dependency14__["default"];
+ var observer = __dependency15__.observer;
+ var beforeObserver = __dependency15__.beforeObserver;
+ var emberA = __dependency16__.A;
/**
@module ember
@@ -40565,7 +38909,6 @@ enifed("ember-views/views/container_view",
@extends Ember.View
*/
var ContainerView = View.extend(MutableArray, {
- isContainer: true,
_states: states,
willWatchProperty: function(prop){
@@ -40644,6 +38987,9 @@ enifed("ember-views/views/container_view",
@param {Ember.RenderBuffer} buffer the buffer to render to
*/
render: function(buffer) {
+ this.forEachChildView(function(view) {
+ view.renderToBuffer(buffer);
+ });
},
instrumentName: 'container',
@@ -40762,40 +39108,69 @@ enifed("ember-views/views/container_view",
},
ensureChildrenAreInDOM: function(view) {
- var childViews = view._childViews;
- var renderer = view._renderer;
+ var childViews = view._childViews, i, len, childView, previous, buffer, viewCollection = new ViewCollection();
- var i, len, childView;
for (i = 0, len = childViews.length; i < len; i++) {
childView = childViews[i];
- if (!childView._elementCreated) {
- renderer.renderTree(childView, view, i);
+
+ if (!buffer) { buffer = renderBuffer(); buffer._hasElement = false; }
+
+ if (childView.renderToBufferIfNeeded(buffer)) {
+ viewCollection.push(childView);
+ } else if (viewCollection.length) {
+ insertViewCollection(view, viewCollection, previous, buffer);
+ buffer = null;
+ previous = childView;
+ viewCollection.clear();
+ } else {
+ previous = childView;
}
}
+
+ if (viewCollection.length) {
+ insertViewCollection(view, viewCollection, previous, buffer);
+ }
}
});
+ function insertViewCollection(view, viewCollection, previous, buffer) {
+ viewCollection.triggerRecursively('willInsertElement');
+
+ if (previous) {
+ previous.domManager.after(previous, buffer.string());
+ } else {
+ view.domManager.prepend(view, buffer.string());
+ }
+
+ viewCollection.forEach(function(v) {
+ v._transitionTo('inDOM');
+ v.propertyDidChange('element');
+ v.triggerRecursively('didInsertElement');
+ });
+ }
+
+
__exports__["default"] = ContainerView;
});
-enifed("ember-views/views/core_view",
- ["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) {
+define("ember-views/views/core_view",
+ ["ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","ember-views/system/render_buffer","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) {
"use strict";
- var Rerender = __dependency1__["default"];
+ var cloneStates = __dependency1__.cloneStates;
+ var states = __dependency1__.states;
+ var EmberObject = __dependency2__["default"];
+ var Evented = __dependency3__["default"];
+ var ActionHandler = __dependency4__["default"];
- var cloneStates = __dependency2__.cloneStates;
- var states = __dependency2__.states;
- var EmberObject = __dependency3__["default"];
- var Evented = __dependency4__["default"];
- var ActionHandler = __dependency5__["default"];
+ var get = __dependency5__.get;
+ var computed = __dependency6__.computed;
- var get = __dependency6__.get;
- var set = __dependency7__.set;
- var computed = __dependency8__.computed;
+ var typeOf = __dependency7__.typeOf;
- var typeOf = __dependency9__.typeOf;
+ var instrument = __dependency8__.instrument;
- var instrument = __dependency10__.instrument;
+
+ var renderBuffer = __dependency9__["default"];
/**
`Ember.CoreView` is an abstract class that exists to give view-like behavior
@@ -40814,8 +39189,6 @@ enifed("ember-views/views/core_view",
*/
var CoreView = EmberObject.extend(Evented, ActionHandler, {
isView: true,
- isVirtual: false,
- isContainer: false,
_states: cloneStates(states),
@@ -40861,6 +39234,55 @@ enifed("ember-views/views/core_view",
hash.view = this;
},
+ /**
+ Invoked by the view system when this view needs to produce an HTML
+ representation. This method will create a new render buffer, if needed,
+ then apply any default attributes, such as class names and visibility.
+ Finally, the `render()` method is invoked, which is responsible for
+ doing the bulk of the rendering.
+
+ You should not need to override this method; instead, implement the
+ `template` property, or if you need more control, override the `render`
+ method.
+
+ @method renderToBuffer
+ @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is
+ passed, a default buffer, using the current view's `tagName`, will
+ be used.
+ @private
+ */
+ renderToBuffer: function(buffer) {
+ var name = 'render.' + this.instrumentName,
+ details = {};
+
+ this.instrumentDetails(details);
+
+ return instrument(name, details, function instrumentRenderToBuffer() {
+ return this._renderToBuffer(buffer);
+ }, this);
+ },
+
+ _renderToBuffer: function(_buffer) {
+ // If this is the top-most view, start a new buffer. Otherwise,
+ // create a new buffer relative to the original using the
+ // provided buffer operation (for example, `insertAfter` will
+ // insert a new buffer after the "parent buffer").
+ var tagName = this.tagName;
+
+ if (tagName === null || tagName === undefined) {
+ tagName = 'div';
+ }
+
+ var buffer = this.buffer = _buffer && _buffer.begin(tagName) || renderBuffer(tagName);
+ this._transitionTo('inBuffer', false);
+
+ this.beforeRender(buffer);
+ this.render(buffer);
+ this.afterRender(buffer);
+
+ return buffer;
+ },
+
/**
Override the default event firing from `Ember.Evented` to
also call methods with the given name.
@@ -40883,6 +39305,18 @@ enifed("ember-views/views/core_view",
}
},
+ deprecatedSendHandles: function(actionName) {
+ return !!this[actionName];
+ },
+
+ deprecatedSend: function(actionName) {
+ var args = [].slice.call(arguments, 1);
+ Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function');
+ Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object ( action: `' + actionName + '` on ' + this + ')', false);
+ this[actionName].apply(this, args);
+ return;
+ },
+
has: function(name) {
return typeOf(this[name]) === 'function' || this._super(name);
},
@@ -40892,12 +39326,9 @@ enifed("ember-views/views/core_view",
if (!this._super()) { return; }
-
// destroy the element -- this will avoid each child view destroying
// the element over and over again...
- if (!this.removedFromDOM && this._renderer) {
- this._renderer.remove(this, true);
- }
+ if (!this.removedFromDOM) { this.destroyElement(); }
// remove from parent if found. Don't call removeFromParent,
// as removeFromParent will try to remove the element from
@@ -40910,17 +39341,15 @@ enifed("ember-views/views/core_view",
},
clearRenderedChildren: Ember.K,
+ triggerRecursively: Ember.K,
+ invokeRecursively: Ember.K,
_transitionTo: Ember.K,
destroyElement: Ember.K
});
- CoreView.reopenClass({
- renderer: new Rerender()
- });
-
__exports__["default"] = CoreView;
});
-enifed("ember-views/views/states",
+define("ember-views/views/states",
["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -40961,7 +39390,7 @@ enifed("ember-views/views/states",
};
__exports__.states = states;
});
-enifed("ember-views/views/states/default",
+define("ember-views/views/states/default",
["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -40996,16 +39425,23 @@ enifed("ember-views/views/states/default",
},
destroyElement: function(view) {
- if (view._renderer)
- view._renderer.remove(view, false);
+ set(view, 'element', null);
+ if (view._scheduledInsert) {
+ run.cancel(view._scheduledInsert);
+ view._scheduledInsert = null;
+ }
return view;
},
+ renderToBufferIfNeeded: function () {
+ return false;
+ },
+
rerender: Ember.K,
invokeObserver: Ember.K
};
});
-enifed("ember-views/views/states/destroying",
+define("ember-views/views/states/destroying",
["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -41032,12 +39468,27 @@ enifed("ember-views/views/states/destroying",
},
destroyElement: function() {
throw new EmberError(fmt(destroyingError, ['destroyElement']));
- }
+ },
+ empty: function() {
+ throw new EmberError(fmt(destroyingError, ['empty']));
+ },
+
+ setElement: function() {
+ throw new EmberError(fmt(destroyingError, ["set('element', ...)"]));
+ },
+
+ renderToBufferIfNeeded: function() {
+ return false;
+ },
+
+ // Since element insertion is scheduled, don't do anything if
+ // the view has been destroyed between scheduling and execution
+ insertElement: Ember.K
});
__exports__["default"] = destroying;
});
-enifed("ember-views/views/states/has_element",
+define("ember-views/views/states/has_element",
["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -41060,7 +39511,7 @@ enifed("ember-views/views/states/has_element",
merge(hasElement, {
$: function(view, sel) {
- var elem = view.get('concreteView').element;
+ var elem = get(view, 'element');
return sel ? jQuery(sel, elem) : jQuery(elem);
},
@@ -41071,17 +39522,25 @@ enifed("ember-views/views/states/has_element",
return jQuery("#" + get(view, 'elementId'))[0];
},
+ setElement: function(view, value) {
+ if (value === null) {
+ view._transitionTo('preRender');
+ } else {
+ throw new EmberError("You cannot set an element to a non-null value when the element is already in the DOM.");
+ }
+
+ return value;
+ },
+
// once the view has been inserted into the DOM, rerendering is
// deferred to allow bindings to synchronize.
rerender: function(view) {
- if (view._root._morph && !view._elementInserted) {
- throw new EmberError("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");
- }
- // TODO: should be scheduled with renderer
- run.scheduleOnce('render', function () {
- if (view.isDestroying) return;
- view._renderer.renderTree(view, view._parentView);
- });
+ view.triggerRecursively('willClearRender');
+
+ view.clearRenderedChildren();
+
+ view.domManager.replace(view);
+ return view;
},
// once the view is already in the DOM, destroying it removes it
@@ -41089,10 +39548,27 @@ enifed("ember-views/views/states/has_element",
// preRender state if inDOM.
destroyElement: function(view) {
- view._renderer.remove(view, false);
+ view._notifyWillDestroyElement();
+ view.domManager.remove(view);
+ set(view, 'element', null);
+ if (view._scheduledInsert) {
+ run.cancel(view._scheduledInsert);
+ view._scheduledInsert = null;
+ }
return view;
},
+ empty: function(view) {
+ var _childViews = view._childViews, len, idx;
+ if (_childViews) {
+ len = _childViews.length;
+ for (idx = 0; idx < len; idx++) {
+ _childViews[idx]._notifyWillDestroyElement();
+ }
+ }
+ view.domManager.empty(view);
+ },
+
// Handle events from `Ember.EventDispatcher`
handleEvent: function(view, eventName, evt) {
if (view.has(eventName)) {
@@ -41111,7 +39587,7 @@ enifed("ember-views/views/states/has_element",
__exports__["default"] = hasElement;
});
-enifed("ember-views/views/states/in_buffer",
+define("ember-views/views/states/in_buffer",
["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -41150,22 +39626,58 @@ enifed("ember-views/views/states/in_buffer",
// view will render that view and append the resulting
// buffer into its buffer.
appendChild: function(view, childView, options) {
- var buffer = view.buffer;
- var _childViews = view._childViews;
+ var buffer = view.buffer, _childViews = view._childViews;
childView = view.createChildView(childView, options);
if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); }
_childViews.push(childView);
- if (!childView._morph) {
- buffer.pushChildView(childView);
- }
+ childView.renderToBuffer(buffer);
view.propertyDidChange('childViews');
return childView;
},
+ // when a view is rendered in a buffer, destroying the
+ // element will simply destroy the buffer and put the
+ // state back into the preRender state.
+ destroyElement: function(view) {
+ view.clearBuffer();
+ var viewCollection = view._notifyWillDestroyElement();
+ viewCollection.transitionTo('preRender', false);
+
+ return view;
+ },
+
+ empty: function() {
+ Ember.assert("Emptying a view in the inBuffer state is not allowed and " +
+ "should not happen under normal circumstances. Most likely " +
+ "there is a bug in your application. This may be due to " +
+ "excessive property change notifications.");
+ },
+
+ renderToBufferIfNeeded: function (view, buffer) {
+ return false;
+ },
+
+ // It should be impossible for a rendered view to be scheduled for
+ // insertion.
+ insertElement: function() {
+ throw new EmberError("You can't insert an element that has already been rendered");
+ },
+
+ setElement: function(view, value) {
+ if (value === null) {
+ view._transitionTo('preRender');
+ } else {
+ view.clearBuffer();
+ view._transitionTo('hasElement');
+ }
+
+ return value;
+ },
+
invokeObserver: function(target, observer) {
observer.call(target);
}
@@ -41173,7 +39685,7 @@ enifed("ember-views/views/states/in_buffer",
__exports__["default"] = inBuffer;
});
-enifed("ember-views/views/states/in_dom",
+define("ember-views/views/states/in_dom",
["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -41213,15 +39725,21 @@ enifed("ember-views/views/states/in_dom",
if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles...
if (!this.isVirtual) delete View.views[view.elementId];
+ },
+
+ insertElement: function(view, fn) {
+ throw new EmberError("You can't insert an element into the DOM that has already been inserted");
}
});
__exports__["default"] = inDOM;
});
-enifed("ember-views/views/states/pre_render",
+define("ember-views/views/states/pre_render",
["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
"use strict";
+ /* global Node */
+
var _default = __dependency1__["default"];
var create = __dependency2__.create;
var merge = __dependency3__["default"];
@@ -41233,10 +39751,44 @@ enifed("ember-views/views/states/pre_render",
*/
var preRender = create(_default);
+ merge(preRender, {
+ // a view leaves the preRender state once its element has been
+ // created (createElement).
+ insertElement: function(view, fn) {
+ view.createElement();
+ var viewCollection = view.viewHierarchyCollection();
+
+ viewCollection.trigger('willInsertElement');
+
+ fn.call(view);
+
+ // We transition to `inDOM` if the element exists in the DOM
+ var element = view.get('element');
+ if (jQuery.contains(document.body, element)) {
+ viewCollection.transitionTo('inDOM', false);
+ viewCollection.trigger('didInsertElement');
+ }
+ },
+
+ renderToBufferIfNeeded: function(view, buffer) {
+ view.renderToBuffer(buffer);
+ return true;
+ },
+
+ empty: Ember.K,
+
+ setElement: function(view, value) {
+ if (value !== null) {
+ view._transitionTo('hasElement');
+ }
+ return value;
+ }
+ });
+
__exports__["default"] = preRender;
});
-enifed("ember-views/views/view",
- ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"],
+define("ember-views/views/view",
+ ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","ember-views/views/view_collection","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __exports__) {
"use strict";
// Ember.assert, Ember.deprecate, Ember.warn, Ember.TEMPLATES,
@@ -41266,36 +39818,47 @@ enifed("ember-views/views/view",
var isArray = __dependency11__.isArray;
var isNone = __dependency14__.isNone;
var Mixin = __dependency13__.Mixin;
- var deprecateProperty = __dependency15__.deprecateProperty;
- var emberA = __dependency16__.A;
+ var deprecateProperty = __dependency10__.deprecateProperty;
+ var emberA = __dependency15__.A;
- var dasherize = __dependency17__.dasherize;
+ var dasherize = __dependency16__.dasherize;
// ES6TODO: functions on EnumerableUtils should get their own export
- var forEach = __dependency18__.forEach;
- var addObject = __dependency18__.addObject;
- var removeObject = __dependency18__.removeObject;
+ var forEach = __dependency17__.forEach;
+ var addObject = __dependency17__.addObject;
+ var removeObject = __dependency17__.removeObject;
var beforeObserver = __dependency13__.beforeObserver;
- var copy = __dependency19__["default"];
- var isGlobalPath = __dependency20__.isGlobalPath;
+ var copy = __dependency18__["default"];
+ var isGlobalPath = __dependency19__.isGlobalPath;
- var propertyWillChange = __dependency21__.propertyWillChange;
- var propertyDidChange = __dependency21__.propertyDidChange;
+ var propertyWillChange = __dependency20__.propertyWillChange;
+ var propertyDidChange = __dependency20__.propertyDidChange;
- var jQuery = __dependency22__["default"];
+ var jQuery = __dependency21__["default"];
// for the side effect of extending Ember.run.queues
- var CoreView = __dependency24__["default"];
+ var CoreView = __dependency23__["default"];
+ var ViewCollection = __dependency24__["default"];
/**
@module ember
@submodule ember-views
*/
+
+ var ContainerView;
+
+ function nullViewsBuffer(view) {
+ view.buffer = null;
+
+ }
+
+ function clearCachedElement(view) {
+ meta(view).cache.element = undefined;
+ }
+
var childViewsProperty = computed(function() {
- var childViews = this._childViews;
- var ret = emberA();
- var view = this;
+ var childViews = this._childViews, ret = emberA(), view = this;
forEach(childViews, function(view) {
var currentChildViews;
@@ -41309,6 +39872,12 @@ enifed("ember-views/views/view",
});
ret.replace = function (idx, removedCount, addedViews) {
+ if (!ContainerView) { ContainerView = requireModule('ember-views/views/container_view')['default']; } // ES6TODO: stupid circular dep
+
+ if (view instanceof ContainerView) {
+ Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
+ return view.replace(idx, removedCount, addedViews);
+ }
throw new EmberError("childViews is immutable");
};
@@ -41827,9 +40396,8 @@ enifed("ember-views/views/view",
on the descendent.
```javascript
- var App = Ember.Application.create();
- App.OuterView = Ember.View.extend({
- template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"),
+ OuterView = Ember.View.extend({
+ template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"),
eventManager: Ember.Object.create({
mouseEnter: function(event, view) {
// view might be instance of either
@@ -41839,7 +40407,7 @@ enifed("ember-views/views/view",
})
});
- App.InnerView = Ember.View.extend({
+ InnerView = Ember.View.extend({
click: function(event) {
// will be called if rendered inside
// an OuterView because OuterView's
@@ -41983,8 +40551,8 @@ enifed("ember-views/views/view",
template: computed('templateName', function(key, value) {
if (value !== undefined) { return value; }
- var templateName = get(this, 'templateName');
- var template = this.templateForName(templateName, 'template');
+ var templateName = get(this, 'templateName'),
+ template = this.templateForName(templateName, 'template');
Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
@@ -42018,8 +40586,8 @@ enifed("ember-views/views/view",
@type Function
*/
layout: computed(function(key) {
- var layoutName = get(this, 'layoutName');
- var layout = this.templateForName(layoutName, 'layout');
+ var layoutName = get(this, 'layoutName'),
+ layout = this.templateForName(layoutName, 'layout');
Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout);
@@ -42178,8 +40746,8 @@ enifed("ember-views/views/view",
@return Ember.View
*/
nearestOfType: function(klass) {
- var view = get(this, 'parentView');
- var isOfType = klass instanceof Mixin ?
+ var view = get(this, 'parentView'),
+ isOfType = klass instanceof Mixin ?
function(view) { return klass.detect(view); } :
function(view) { return klass.detect(view.constructor); };
@@ -42325,6 +40893,21 @@ enifed("ember-views/views/view",
return this.currentState.rerender(this);
},
+ clearRenderedChildren: function() {
+ var lengthBefore = this.lengthBeforeRender,
+ lengthAfter = this.lengthAfterRender;
+
+ // If there were child views created during the last call to render(),
+ // remove them under the assumption that they will be re-created when
+ // we re-render.
+
+ // VIEW-TODO: Unit test this path.
+ var childViews = this._childViews;
+ for (var i=lengthAfter-1; i>=lengthBefore; i--) {
+ if (childViews[i]) { childViews[i].destroy(); }
+ }
+ },
+
/**
Iterates over the view's `classNameBindings` array, inserts the value
of the specified property into the `classNames` array, then creates an
@@ -42335,8 +40918,8 @@ enifed("ember-views/views/view",
@private
*/
_applyClassNameBindings: function(classBindings) {
- var classNames = this.classNames;
- var elem, newClass, dasherizedClass;
+ var classNames = this.classNames,
+ elem, newClass, dasherizedClass;
// Loop through all of the configured bindings. These will be either
// property names ('isUrgent') or property paths relative to the view
@@ -42415,15 +40998,13 @@ enifed("ember-views/views/view",
@private
*/
_applyAttributeBindings: function(buffer, attributeBindings) {
- var attributeValue;
- var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {};
+ var attributeValue,
+ unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {};
forEach(attributeBindings, function(binding) {
- var split = binding.split(':');
- var property = split[0];
- var attributeName = split[1] || property;
-
- Ember.assert('You cannot use class as an attributeBinding, use classNameBindings instead.', attributeName !== 'class');
+ var split = binding.split(':'),
+ property = split[0],
+ attributeName = split[1] || property;
if (property in this) {
this._setupAttributeBindingObservation(property, attributeName);
@@ -42513,7 +41094,13 @@ enifed("ember-views/views/view",
@property element
@type DOMElement
*/
- element: null,
+ element: computed('_parentView', function(key, value) {
+ if (value !== undefined) {
+ return this.currentState.setElement(this, value);
+ } else {
+ return this.currentState.getElement(this);
+ }
+ }),
/**
Returns a jQuery object for this view's element. If you pass in a selector
@@ -42532,9 +41119,9 @@ enifed("ember-views/views/view",
},
mutateChildViews: function(callback) {
- var childViews = this._childViews;
- var idx = childViews.length;
- var view;
+ var childViews = this._childViews,
+ idx = childViews.length,
+ view;
while(--idx >= 0) {
view = childViews[idx];
@@ -42549,8 +41136,8 @@ enifed("ember-views/views/view",
if (!childViews) { return this; }
- var len = childViews.length;
- var view, idx;
+ var len = childViews.length,
+ view, idx;
for (idx = 0; idx < len; idx++) {
view = childViews[idx];
@@ -42580,13 +41167,14 @@ enifed("ember-views/views/view",
@param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object
@return {Ember.View} receiver
*/
- appendTo: function(selector) {
- var target = jQuery(selector);
-
- Ember.assert("You tried to append to (" + selector + ") but that isn't in the DOM", target.length > 0);
- Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view'));
-
- this.constructor.renderer.appendTo(this, target[0]);
+ appendTo: function(target) {
+ // Schedule the DOM element to be created and appended to the given
+ // element after bindings have synchronized.
+ this._insertElementLater(function() {
+ Ember.assert("You tried to append to (" + target + ") but that isn't in the DOM", jQuery(target).length > 0);
+ Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view'));
+ this.$().appendTo(target);
+ });
return this;
},
@@ -42604,17 +41192,49 @@ enifed("ember-views/views/view",
@param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object
@return {Ember.View} received
*/
- replaceIn: function(selector) {
- var target = jQuery(selector);
+ replaceIn: function(target) {
+ Ember.assert("You tried to replace in (" + target + ") but that isn't in the DOM", jQuery(target).length > 0);
+ Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view'));
- Ember.assert("You tried to replace in (" + selector + ") but that isn't in the DOM", target.length > 0);
- Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view'));
-
- this.constructor.renderer.replaceIn(this, target[0]);
+ this._insertElementLater(function() {
+ jQuery(target).empty();
+ this.$().appendTo(target);
+ });
return this;
},
+ /**
+ Schedules a DOM operation to occur during the next render phase. This
+ ensures that all bindings have finished synchronizing before the view is
+ rendered.
+
+ To use, pass a function that performs a DOM operation.
+
+ Before your function is called, this view and all child views will receive
+ the `willInsertElement` event. After your function is invoked, this view
+ and all of its child views will receive the `didInsertElement` event.
+
+ ```javascript
+ view._insertElementLater(function() {
+ this.createElement();
+ this.$().appendTo('body');
+ });
+ ```
+
+ @method _insertElementLater
+ @param {Function} fn the function that inserts the element into the DOM
+ @private
+ */
+ _insertElementLater: function(fn) {
+ this._scheduledInsert = run.scheduleOnce('render', this, '_insertElement', fn);
+ },
+
+ _insertElement: function (fn) {
+ this._scheduledInsert = null;
+ this.currentState.insertElement(this, fn);
+ },
+
/**
Appends the view's element to the document body. If the view does
not have an HTML representation yet, `createElement()` will be called
@@ -42648,6 +41268,9 @@ enifed("ember-views/views/view",
// In the interim, we will just re-render if that happens. It is more
// important than elements get garbage collected.
if (!this.removedFromDOM) { this.destroyElement(); }
+ this.invokeRecursively(function(view) {
+ if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
+ });
},
elementId: null,
@@ -42669,20 +41292,20 @@ enifed("ember-views/views/view",
},
/**
- Creates a DOM representation of the view and all of its child views by
- recursively calling the `render()` method.
+ Creates a DOM representation of the view and all of its
+ child views by recursively calling the `render()` method.
- After the element has been inserted into the DOM, `didInsertElement` will
+ After the element has been created, `didInsertElement` will
be called on this view and all of its child views.
@method createElement
@return {Ember.View} receiver
*/
createElement: function() {
- if (this.element) { return this; }
+ if (get(this, 'element')) { return this; }
- this._didCreateElementWithoutMorph = true;
- this.constructor.renderer.renderTree(this);
+ var buffer = this.renderToBuffer();
+ set(this, 'element', buffer.element());
return this;
},
@@ -42699,9 +41322,6 @@ enifed("ember-views/views/view",
or after the view was re-rendered. Override this function to do any
set up that requires an element in the document body.
- When a view has children, didInsertElement will be called on the
- child view(s) first, bubbling upwards through the hierarchy.
-
@event didInsertElement
*/
didInsertElement: Ember.K,
@@ -42715,6 +41335,65 @@ enifed("ember-views/views/view",
*/
willClearRender: Ember.K,
+ /**
+ Run this callback on the current view (unless includeSelf is false) and recursively on child views.
+
+ @method invokeRecursively
+ @param fn {Function}
+ @param includeSelf {Boolean} Includes itself if true.
+ @private
+ */
+ invokeRecursively: function(fn, includeSelf) {
+ var childViews = (includeSelf === false) ? this._childViews : [this];
+ var currentViews, view, currentChildViews;
+
+ while (childViews.length) {
+ currentViews = childViews.slice();
+ childViews = [];
+
+ for (var i=0, l=currentViews.length; 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;
},
@@ -43109,18 +41840,16 @@ enifed("ember-views/views/view",
_toggleVisibility: function() {
var $el = this.$();
+ if (!$el) { return; }
+
var isVisible = get(this, 'isVisible');
if (this._isVisible === isVisible) { return ; }
- // It's important to keep these in sync, even if we don't yet have
- // an element in the DOM to manipulate:
- this._isVisible = isVisible;
-
- if (!$el) { return; }
-
$el.toggle(isVisible);
+ this._isVisible = isVisible;
+
if (this._isAncestorHidden()) { return; }
if (isVisible) {
@@ -43164,6 +41893,10 @@ enifed("ember-views/views/view",
return false;
},
+
+ clearBuffer: function() {
+ this.invokeRecursively(nullViewsBuffer);
+ },
transitionTo: function(state, children) {
Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only");
this._transitionTo(state, children);
@@ -43171,10 +41904,18 @@ enifed("ember-views/views/view",
_transitionTo: function(state, children) {
var priorState = this.currentState;
var 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);
+ });
+ }
},
// .......................................................
@@ -43203,13 +41944,13 @@ enifed("ember-views/views/view",
return;
}
- var view = this;
- var stateCheckedObserver = function() {
- view.currentState.invokeObserver(this, observer);
- };
- var scheduledObserver = function() {
- run.scheduleOnce('render', this, stateCheckedObserver);
- };
+ var view = this,
+ stateCheckedObserver = function() {
+ view.currentState.invokeObserver(this, observer);
+ },
+ scheduledObserver = function() {
+ run.scheduleOnce('render', this, stateCheckedObserver);
+ };
addObserver(root, path, target, scheduledObserver);
@@ -43253,6 +41994,48 @@ enifed("ember-views/views/view",
run.once(View, 'notifyMutationListeners');
}
+ var DOMManager = {
+ prepend: function(view, html) {
+ view.$().prepend(html);
+ notifyMutationListeners();
+ },
+
+ 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({
/**
@@ -43275,10 +42058,11 @@ enifed("ember-views/views/view",
@private
*/
_parsePropertyPath: function(path) {
- var split = path.split(':');
- var propertyPath = split[0];
- var classNames = "";
- var className, falsyClassName;
+ 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) {
@@ -43362,7 +42146,7 @@ enifed("ember-views/views/view",
});
var mutation = EmberObject.extend(Evented).create();
- // TODO MOVE TO RENDERER HOOKS
+
View.addMutationListener = function(callback) {
mutation.on('change', callback);
};
@@ -43420,11 +42204,82 @@ enifed("ember-views/views/view",
__exports__["default"] = View;
});
-enifed("ember",
+define("ember-views/views/view_collection",
+ ["ember-metal/enumerable_utils","exports"],
+ function(__dependency1__, __exports__) {
+ "use strict";
+ var forEach = __dependency1__.forEach;
+
+ function ViewCollection(initialViews) {
+ var views = this.views = initialViews || [];
+ this.length = views.length;
+ }
+
+ ViewCollection.prototype = {
+ length: 0,
+
+ trigger: function(eventName) {
+ var views = this.views, view;
+ for (var i = 0, l = views.length; i < l; i++) {
+ view = views[i];
+ if (view.trigger) { view.trigger(eventName); }
+ }
+ },
+
+ triggerRecursively: function(eventName) {
+ var views = this.views;
+ for (var i = 0, l = views.length; i < l; i++) {
+ views[i].triggerRecursively(eventName);
+ }
+ },
+
+ invokeRecursively: function(fn) {
+ var views = this.views, view;
+
+ for (var i = 0, l = views.length; i < l; i++) {
+ view = views[i];
+ fn(view);
+ }
+ },
+
+ transitionTo: function(state, children) {
+ var views = this.views;
+ for (var i = 0, l = views.length; i < l; i++) {
+ views[i]._transitionTo(state, children);
+ }
+ },
+
+ push: function() {
+ this.length += arguments.length;
+ var views = this.views;
+ return views.push.apply(views, arguments);
+ },
+
+ objectAt: function(idx) {
+ return this.views[idx];
+ },
+
+ forEach: function(callback) {
+ var views = this.views;
+ return forEach(views, callback);
+ },
+
+ clear: function() {
+ this.length = 0;
+ this.views.length = 0;
+ }
+ };
+
+ __exports__["default"] = ViewCollection;
+ });
+define("ember",
["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) {
- "use strict";
- /* global navigator */
+ // Remove "use strict"; from transpiled module until
+ // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed
+ //
+ // REMOVE_USE_STRICT: true
+
// require the main entry points for each of these packages
// this is so that the global exports occur properly
@@ -43440,831 +42295,521 @@ enifed("ember",
@module ember
*/
- Ember.deprecate('Usage of Ember is deprecated for Internet Explorer 6 and 7, support will be removed in the next major version.', !navigator.userAgent.match(/MSIE [67]/));
+ function throwWithMessage(msg) {
+ return function() {
+ throw new Ember.Error(msg);
+ };
+ }
+
+ function generateRemovedClass(className) {
+ var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states";
+
+ return {
+ extend: throwWithMessage(className + msg),
+ create: throwWithMessage(className + msg)
+ };
+ }
+
+ Ember.StateManager = generateRemovedClass("Ember.StateManager");
+
+ /**
+ This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
+
+ @class StateManager
+ @namespace Ember
+ */
+
+ Ember.State = generateRemovedClass("Ember.State");
+
+ /**
+ This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
+
+ @class State
+ @namespace Ember
+ */
});
-enifed("morph",
- ["./morph/morph","./morph/dom-helper","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
+define("metamorph",
+ [],
+ function() {
"use strict";
- var Morph = __dependency1__["default"];
- var Morph;
- __exports__.Morph = Morph;
- var DOMHelper = __dependency2__["default"];
- var DOMHelper;
- __exports__.DOMHelper = DOMHelper;
- });
-enifed("morph/dom-helper",
- ["../morph/morph","./dom-helper/build-html-dom","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
- "use strict";
- var Morph = __dependency1__["default"];
- var buildHTMLDOM = __dependency2__.buildHTMLDOM;
- var svgNamespace = __dependency2__.svgNamespace;
- var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints;
+ // ==========================================================================
+ // Project: metamorph
+ // Copyright: ©2014 Tilde, Inc. All rights reserved.
+ // ==========================================================================
- var deletesBlankTextNodes = (function(){
- var element = document.createElement('div');
- element.appendChild( document.createTextNode('') );
- var clonedElement = element.cloneNode(true);
- return clonedElement.childNodes.length === 0;
- })();
-
- var ignoresCheckedAttribute = (function(){
- var element = document.createElement('input');
- element.setAttribute('checked', 'checked');
- var clonedElement = element.cloneNode(false);
- return !clonedElement.checked;
- })();
-
- function isSVG(ns){
- return ns === svgNamespace;
- }
-
- // This is not the namespace of the element, but of
- // the elements inside that elements.
- function interiorNamespace(element){
- if (
- element &&
- element.namespaceURI === svgNamespace &&
- !svgHTMLIntegrationPoints[element.tagName]
- ) {
- return svgNamespace;
- } else {
- return null;
- }
- }
-
- // The HTML spec allows for "omitted start tags". These tags are optional
- // when their intended child is the first thing in the parent tag. For
- // example, this is a tbody start tag:
- //
- //
- //
- //
- //
- // The tbody may be omitted, and the browser will accept and render:
- //
- //
- //
- //
- // However, the omitted start tag will still be added to the DOM. Here
- // we test the string and context to see if the browser is about to
- // perform this cleanup.
- //
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags
- // describes which tags are omittable. The spec for tbody and colgroup
- // explains this behavior:
- //
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element
- //
-
- var omittedStartTagChildTest = /<([\w:]+)/;
- function detectOmittedStartTag(string, contextualElement){
- // Omitted start tags are only inside table tags.
- if (contextualElement.tagName === 'TABLE') {
- var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string);
- if (omittedStartTagChildMatch) {
- var omittedStartTagChild = omittedStartTagChildMatch[1];
- // It is already asserted that the contextual element is a table
- // and not the proper start tag. Just see if a tag was omitted.
- return omittedStartTagChild === 'tr' ||
- omittedStartTagChild === 'col';
- }
- }
- }
-
- function buildSVGDOM(html, dom){
- var div = dom.document.createElement('div');
- div.innerHTML = '';
- return div.firstChild.childNodes;
- }
-
- /*
- * A class wrapping DOM functions to address environment compatibility,
- * namespaces, contextual elements for morph un-escaped content
- * insertion.
- *
- * When entering a template, a DOMHelper should be passed:
- *
- * template(context, { hooks: hooks, dom: new DOMHelper() });
- *
- * TODO: support foreignObject as a passed contextual element. It has
- * a namespace (svg) that does not match its internal namespace
- * (xhtml).
- *
- * @class DOMHelper
- * @constructor
- * @param {HTMLDocument} _document The document DOM methods are proxied to
- */
- function DOMHelper(_document){
- this.document = _document || window.document;
- this.namespace = null;
- }
-
- var prototype = DOMHelper.prototype;
- prototype.constructor = DOMHelper;
-
- prototype.insertBefore = function(element, childElement, referenceChild) {
- return element.insertBefore(childElement, referenceChild);
- };
-
- prototype.appendChild = function(element, childElement) {
- return element.appendChild(childElement);
- };
-
- prototype.appendText = function(element, text) {
- return element.appendChild(this.document.createTextNode(text));
- };
-
- prototype.setAttribute = function(element, name, value) {
- element.setAttribute(name, value);
- };
-
- if (document.createElementNS) {
- // Only opt into namespace detection if a contextualElement
- // is passed.
- prototype.createElement = function(tagName, contextualElement) {
- var namespace = this.namespace;
- if (contextualElement) {
- if (tagName === 'svg') {
- namespace = svgNamespace;
+ var K = function() {},
+ guid = 0,
+ disableRange = (function(){
+ if ('undefined' !== typeof MetamorphENV) {
+ return MetamorphENV.DISABLE_RANGE_API;
+ } else if ('undefined' !== ENV) {
+ return ENV.DISABLE_RANGE_API;
} else {
- namespace = interiorNamespace(contextualElement);
+ return false;
}
- }
- if (namespace) {
- return this.document.createElementNS(namespace, tagName);
+ })(),
+
+ // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
+ 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 = typeof document !== 'undefined' && (function() {
+ var testEl = document.createElement('div');
+ testEl.innerHTML = "";
+ testEl.firstChild.innerHTML = "";
+ return testEl.firstChild.innerHTML === '';
+ })(),
+
+
+ // IE 8 (and likely earlier) likes to move whitespace preceeding
+ // a script tag to appear after it. This means that we can
+ // accidentally remove whitespace when updating a morph.
+ movesWhitespace = document && (function() {
+ var testEl = document.createElement('div');
+ testEl.innerHTML = "Test: Value";
+ return testEl.childNodes[0].nodeValue === 'Test:' &&
+ testEl.childNodes[2].nodeValue === ' Value';
+ })();
+
+ // Constructor that supports either Metamorph('foo') or new
+ // Metamorph('foo');
+ //
+ // Takes a string of HTML as the argument.
+
+ var Metamorph = function(html) {
+ var self;
+
+ if (this instanceof Metamorph) {
+ self = this;
+ } else {
+ self = new K();
+ }
+
+ self.innerHTML = html;
+ var myGuid = 'metamorph-'+(guid++);
+ self.start = myGuid + '-start';
+ self.end = myGuid + '-end';
+
+ return self;
+ };
+
+ K.prototype = Metamorph.prototype;
+
+ var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc;
+
+ outerHTMLFunc = function() {
+ return this.startTag() + this.innerHTML + this.endTag();
+ };
+
+ startTagFunc = function() {
+ /*
+ * We replace chevron by its hex code in order to prevent escaping problems.
+ * Check this thread for more explaination:
+ * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
+ */
+ return "
hi |
";
+ * div.firstChild.firstChild.tagName //=> ""
+ *
+ * If our script markers are inside such a node, we need to find that
+ * node and use *it* as the marker.
+ */
+ var realNode = function(start) {
+ while (start.parentNode.tagName === "") {
+ start = start.parentNode;
+ }
+
+ return start;
+ };
+
+ /*
+ * When automatically adding a tbody, Internet Explorer inserts the
+ * tbody immediately before the first
. Other browsers create it
+ * before the first node, no matter what.
+ *
+ * This means the the following code:
+ *
+ * div = document.createElement("div");
+ * div.innerHTML = "
+ *
+ * Generates the following DOM in IE:
+ *
+ * + div
+ * + table
+ * - script id='first'
+ * + tbody
+ * + tr
+ * + td
+ * - "hi"
+ * - script id='last'
+ *
+ * Which means that the two script tags, even though they were
+ * inserted at the same point in the hierarchy in the original
+ * HTML, now have different parents.
+ *
+ * This code reparents the first script tag by making it the tbody's
+ * first child.
+ *
+ */
+ var fixParentage = function(start, end) {
+ if (start.parentNode !== end.parentNode) {
+ end.parentNode.insertBefore(start, end.parentNode.firstChild);
+ }
+ };
+
+ htmlFunc = function(html, outerToo) {
+ // get the real starting node. see realNode for details.
+ var start = realNode(document.getElementById(this.start));
+ var end = document.getElementById(this.end);
+ var parentNode = end.parentNode;
+ var node, nextSibling, last;
+
+ // make sure that the start and end nodes share the same
+ // parent. If not, fix it.
+ fixParentage(start, end);
+
+ // remove all of the nodes after the starting placeholder and
+ // before the ending placeholder.
+ node = start.nextSibling;
+ while (node) {
+ nextSibling = node.nextSibling;
+ last = node === end;
+
+ // if this is the last node, and we want to remove it as well,
+ // set the `end` node to the next sibling. This is because
+ // for the rest of the function, we insert the new nodes
+ // before the end (note that insertBefore(node, null) is
+ // the same as appendChild(node)).
+ //
+ // if we do not want to remove it, just break.
+ if (last) {
+ if (outerToo) { end = node.nextSibling; } else { break; }
+ }
+
+ node.parentNode.removeChild(node);
+
+ // if this is the last node and we didn't break before
+ // (because we wanted to remove the outer nodes), break
+ // now.
+ if (last) { break; }
+
+ node = nextSibling;
+ }
+
+ // get the first node for the HTML string, even in cases like
+ // tables and lists where a simple innerHTML on a div would
+ // 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) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, end);
+ node = nextSibling;
+ }
+ };
+
+ // remove the nodes in the DOM representing this metamorph.
+ //
+ // this includes the starting and ending placeholders.
+ removeFunc = function() {
+ var start = realNode(document.getElementById(this.start));
+ var end = document.getElementById(this.end);
+
+ this.html('');
+ start.parentNode.removeChild(start);
+ end.parentNode.removeChild(end);
+ };
+
+ appendToFunc = function(parentNode) {
+ var node = firstNodeFor(parentNode, this.outerHTML());
+ var nextSibling;
+
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.appendChild(node);
+ node = nextSibling;
+ }
+ };
+
+ afterFunc = function(html) {
+ // get the real starting node. see realNode for details.
+ var end = document.getElementById(this.end);
+ var insertBefore = end.nextSibling;
+ var parentNode = end.parentNode;
+ var nextSibling;
+ var node;
+
+ // get the first node for the HTML string, even in cases like
+ // tables and lists where a simple innerHTML on a div would
+ // swallow some of the content.
+ node = firstNodeFor(parentNode, html);
+
+ // copy the nodes for the HTML between the starting and ending
+ // placeholder.
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, insertBefore);
+ node = nextSibling;
+ }
+ };
+
+ prependFunc = function(html) {
+ var start = document.getElementById(this.start);
+ var parentNode = start.parentNode;
+ var nextSibling;
+ var node;
+
+ node = firstNodeFor(parentNode, html);
+ var insertBefore = start.nextSibling;
+
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, insertBefore);
+ node = nextSibling;
+ }
};
}
- prototype.setNamespace = function(ns) {
- this.namespace = ns;
+ Metamorph.prototype.html = function(html) {
+ this.checkRemoved();
+ if (html === undefined) { return this.innerHTML; }
+
+ htmlFunc.call(this, html);
+
+ this.innerHTML = html;
};
- prototype.detectNamespace = function(element) {
- this.namespace = interiorNamespace(element);
+ Metamorph.prototype.replaceWith = function(html) {
+ this.checkRemoved();
+ htmlFunc.call(this, html, true);
};
- prototype.createDocumentFragment = function(){
- return this.document.createDocumentFragment();
+ Metamorph.prototype.remove = removeFunc;
+ Metamorph.prototype.outerHTML = outerHTMLFunc;
+ Metamorph.prototype.appendTo = appendToFunc;
+ Metamorph.prototype.after = afterFunc;
+ Metamorph.prototype.prepend = prependFunc;
+ Metamorph.prototype.startTag = startTagFunc;
+ Metamorph.prototype.endTag = endTagFunc;
+
+ Metamorph.prototype.isRemoved = function() {
+ var before = document.getElementById(this.start);
+ var after = document.getElementById(this.end);
+
+ return !before || !after;
};
- prototype.createTextNode = function(text){
- return this.document.createTextNode(text);
- };
-
- prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){
- if (deletesBlankTextNodes && blankChildTextNodes.length > 0) {
- for (var i=0, len=blankChildTextNodes.length;i]*selected/;
- detectAutoSelectedOption = function detectAutoSelectedOption(select, option, html) { //jshint ignore:line
- return select.selectedIndex === 0 &&
- !detectAutoSelectedOptionRegex.test(html);
- };
- } else {
- detectAutoSelectedOption = function detectAutoSelectedOption(select, option, html) { //jshint ignore:line
- var selectedAttribute = option.getAttribute('selected');
- return select.selectedIndex === 0 && (
- selectedAttribute === null ||
- ( selectedAttribute !== '' && selectedAttribute.toLowerCase() !== 'selected' )
- );
- };
- }
-
- // IE 9 and earlier don't allow us to set innerHTML on col, colgroup, frameset,
- // html, style, table, tbody, tfoot, thead, title, tr. Detect this and add
- // them to an initial list of corrected tags.
- //
- // Here we are only dealing with the ones which can have child nodes.
- //
- var tagNamesRequiringInnerHTMLFix, tableNeedsInnerHTMLFix;
- var tableInnerHTMLTestElement = document.createElement('table');
- try {
- tableInnerHTMLTestElement.innerHTML = '';
- } catch (e) {
- } finally {
- tableNeedsInnerHTMLFix = (tableInnerHTMLTestElement.childNodes.length === 0);
- }
- if (tableNeedsInnerHTMLFix) {
- tagNamesRequiringInnerHTMLFix = {
- colgroup: ['table'],
- table: [],
- tbody: ['table'],
- tfoot: ['table'],
- thead: ['table'],
- tr: ['table', 'tbody']
- };
- }
-
- // IE 8 doesn't allow setting innerHTML on a select tag. Detect this and
- // add it to the list of corrected tags.
- //
- var selectInnerHTMLTestElement = document.createElement('select');
- selectInnerHTMLTestElement.innerHTML = '';
- if (selectInnerHTMLTestElement) {
- tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {};
- tagNamesRequiringInnerHTMLFix.select = [];
- }
-
- function scriptSafeInnerHTML(element, html) {
- // without a leading text node, IE will drop a leading script tag.
- html = ''+html;
-
- element.innerHTML = html;
-
- var nodes = element.childNodes;
-
- // Look for to remove it.
- var shyElement = nodes[0];
- while (shyElement.nodeType === 1 && !shyElement.nodeName) {
- shyElement = shyElement.firstChild;
- }
- // At this point it's the actual unicode character.
- if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
- var newValue = shyElement.nodeValue.slice(1);
- if (newValue.length) {
- shyElement.nodeValue = shyElement.nodeValue.slice(1);
- } else {
- shyElement.parentNode.removeChild(shyElement);
- }
- }
-
- return nodes;
- }
-
- function buildDOMWithFix(html, contextualElement){
- var tagName = contextualElement.tagName;
-
- // Firefox versions < 11 do not have support for element.outerHTML.
- var outerHTML = contextualElement.outerHTML || new XMLSerializer().serializeToString(contextualElement);
- if (!outerHTML) {
- throw "Can't set innerHTML on "+tagName+" in this browser";
- }
-
- var wrappingTags = tagNamesRequiringInnerHTMLFix[tagName.toLowerCase()];
- var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0];
- var endTag = ''+tagName+'>';
-
- var wrappedHTML = [startTag, html, endTag];
-
- var i = wrappingTags.length;
- var wrappedDepth = 1 + i;
- while(i--) {
- wrappedHTML.unshift('<'+wrappingTags[i]+'>');
- wrappedHTML.push(''+wrappingTags[i]+'>');
- }
-
- var wrapper = document.createElement('div');
- scriptSafeInnerHTML(wrapper, wrappedHTML.join(''));
- var element = wrapper;
- while (wrappedDepth--) {
- element = element.firstChild;
- while (element && element.nodeType !== 1) {
- element = element.nextSibling;
- }
- }
- while (element && element.tagName !== tagName) {
- element = element.nextSibling;
- }
- return element ? element.childNodes : [];
- }
-
- var buildDOM;
- if (needsShy) {
- buildDOM = function buildDOM(html, contextualElement, dom){
- contextualElement = dom.cloneNode(contextualElement, false);
- scriptSafeInnerHTML(contextualElement, html);
- return contextualElement.childNodes;
- };
- } else {
- buildDOM = function buildDOM(html, contextualElement, dom){
- contextualElement = dom.cloneNode(contextualElement, false);
- contextualElement.innerHTML = html;
- return contextualElement.childNodes;
- };
- }
-
- var buildIESafeDOM;
- if (tagNamesRequiringInnerHTMLFix || movesWhitespace) {
- buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) {
- // Make a list of the leading text on script nodes. Include
- // script tags without any whitespace for easier processing later.
- var spacesBefore = [];
- var spacesAfter = [];
- html = html.replace(/(\s*)(
```
- See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to
+ Take note that `"welcome"` is a string and not an object
+ reference.
+
+ See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to
set up localized string references.
@method loc
@@ -8949,9 +8662,11 @@ enifed("ember-handlebars/helpers/loc",
@param {String} str The string to format
@see {Ember.String#loc}
*/
- __exports__["default"] = loc;
+ __exports__["default"] = function locHelper(str) {
+ return loc(str);
+ }
});
-enifed("ember-handlebars/helpers/partial",
+define("ember-handlebars/helpers/partial",
["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
"use strict";
@@ -9061,17 +8776,17 @@ enifed("ember-handlebars/helpers/partial",
template(context, { data: options.data });
}
});
-enifed("ember-handlebars/helpers/shared",
+define("ember-handlebars/helpers/shared",
["ember-handlebars/ext","exports"],
function(__dependency1__, __exports__) {
"use strict";
var handlebarsGet = __dependency1__.handlebarsGet;
__exports__["default"] = function resolvePaths(options) {
- var ret = [];
- var contexts = options.contexts;
- var roots = options.roots;
- var data = options.data;
+ var ret = [],
+ contexts = options.contexts,
+ roots = options.roots,
+ data = options.data;
for (var i=0, l=contexts.length; i
+ {{#with loggedInUser}}
+ Last Login: {{lastLogin}}
+ User Info: {{template "user_info"}}
+ {{/with}}
+
+ ```
+
+ ```html
+
+ ```
+
+ ```handlebars
+ {{#if isUser}}
+ {{template "user_info"}}
+ {{else}}
+ {{template "unlogged_user_info"}}
+ {{/if}}
+ ```
+
+ This helper looks for templates in the global `Ember.TEMPLATES` hash. If you
+ add `";
+ return testEl.firstChild.innerHTML === '';
+ })();
+
+ // IE 8 (and likely earlier) likes to move whitespace preceeding
+ // a script tag to appear after it. This means that we can
+ // accidentally remove whitespace when updating a morph.
+ var movesWhitespace = typeof document !== 'undefined' && (function() {
+ var testEl = document.createElement('div');
+ testEl.innerHTML = "Test: Value";
+ return testEl.childNodes[0].nodeValue === 'Test:' &&
+ testEl.childNodes[2].nodeValue === ' Value';
+ })();
+
+ // Use this to find children by ID instead of using jQuery
+ var findChildById = function(element, id) {
+ if (element.getAttribute('id') === id) { return element; }
+
+ var len = element.childNodes.length, idx, node, found;
+ for (idx=0; idx 0) {
+ var len = matches.length, idx;
+ for (idx=0; idxTest');
+ canSet = el.options.length === 1;
+ }
+
+ innerHTMLTags[tagName] = canSet;
+
+ return canSet;
+ };
+
+ function setInnerHTML(element, html) {
+ var tagName = element.tagName;
+
+ if (canSetInnerHTML(tagName)) {
+ setInnerHTMLWithoutFix(element, html);
+ } else {
+ // Firefox versions < 11 do not have support for element.outerHTML.
+ var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element);
+
+ var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0],
+ endTag = ''+tagName+'>';
+
+ var wrapper = document.createElement('div');
+ setInnerHTMLWithoutFix(wrapper, startTag + html + endTag);
+ element = wrapper.firstChild;
+ while (element.tagName !== tagName) {
+ element = element.nextSibling;
+ }
+ }
+
+ return element;
+ }
+
+ __exports__.setInnerHTML = setInnerHTML;function isSimpleClick(event) {
+ var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
+ secondaryClick = event.which > 1; // IE9 may return undefined
return !modifier && !secondaryClick;
}
__exports__.isSimpleClick = isSimpleClick;
});
-enifed("ember-views/views/collection_view",
- ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-handlebars/ext","ember-runtime/mixins/array","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) {
+define("ember-views/views/collection_view",
+ ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-runtime/mixins/array","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) {
"use strict";
/**
@@ -37908,8 +36373,7 @@ enifed("ember-views/views/collection_view",
var View = __dependency10__["default"];
var observer = __dependency11__.observer;
var beforeObserver = __dependency11__.beforeObserver;
- var handlebarsGetView = __dependency12__.handlebarsGetView;
- var EmberArray = __dependency13__["default"];
+ var EmberArray = __dependency12__["default"];
/**
`Ember.CollectionView` is an `Ember.View` descendent responsible for managing
@@ -37932,32 +36396,27 @@ enifed("ember-views/views/collection_view",
The view for each item in the collection will have its `content` property set
to the item.
- ## Specifying `itemViewClass`
+ ## Specifying itemViewClass
By default the view class for each item in the managed collection will be an
instance of `Ember.View`. You can supply a different class by setting the
`CollectionView`'s `itemViewClass` property.
- Given the following application code:
+ Given an empty `` and the following code:
```javascript
- var App = Ember.Application.create();
- App.ItemListView = Ember.CollectionView.extend({
+ someItemsView = Ember.CollectionView.create({
classNames: ['a-collection'],
content: ['A','B','C'],
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile("the letter: {{view.content}}")
})
});
+
+ someItemsView.appendTo('body');
```
- And a simple application template:
-
- ```handlebars
- {{view 'item-list'}}
- ```
-
- The following HTML will result:
+ Will result in the following HTML structure
```html
@@ -37973,26 +36432,21 @@ enifed("ember-views/views/collection_view",
"ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
in the item views receiving an appropriately matched `tagName` property.
- Given the following application code:
+ Given an empty `` and the following code:
```javascript
- var App = Ember.Application.create();
- App.UnorderedListView = Ember.CollectionView.create({
+ anUnorderedListView = Ember.CollectionView.create({
tagName: 'ul',
content: ['A','B','C'],
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile("the letter: {{view.content}}")
})
});
+
+ anUnorderedListView.appendTo('body');
```
- And a simple application template:
-
- ```handlebars
- {{view 'unordered-list-view'}}
- ```
-
- The following HTML will result:
+ Will result in the following HTML structure
```html
@@ -38003,7 +36457,7 @@ enifed("ember-views/views/collection_view",
```
Additional `tagName` pairs can be provided by adding to
- `Ember.CollectionView.CONTAINER_MAP`. For example:
+ `Ember.CollectionView.CONTAINER_MAP `
```javascript
Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
@@ -38016,7 +36470,7 @@ enifed("ember-views/views/collection_view",
`createChildView` method can be overidden:
```javascript
- App.CustomCollectionView = Ember.CollectionView.extend({
+ CustomCollectionView = Ember.CollectionView.extend({
createChildView: function(viewClass, attrs) {
if (attrs.content.kind == 'album') {
viewClass = App.AlbumView;
@@ -38036,23 +36490,18 @@ enifed("ember-views/views/collection_view",
will be the `CollectionView`s only child.
```javascript
- var App = Ember.Application.create();
- App.ListWithNothing = Ember.CollectionView.create({
- classNames: ['nothing'],
+ aListWithNothing = Ember.CollectionView.create({
+ classNames: ['nothing']
content: null,
emptyView: Ember.View.extend({
template: Ember.Handlebars.compile("The collection is empty")
})
});
+
+ aListWithNothing.appendTo('body');
```
- And a simple application template:
-
- ```handlebars
- {{view 'list-with-nothing'}}
- ```
-
- The following HTML will result:
+ Will result in the following HTML structure
```html
@@ -38209,8 +36658,18 @@ enifed("ember-views/views/collection_view",
// Loop through child views that correspond with the removed items.
// Note that we loop from the end of the array to the beginning because
// we are mutating it as we go.
- var childViews = this._childViews;
- var childView, idx;
+ var childViews = this._childViews, childView, idx, len;
+
+ len = this._childViews.length;
+
+ var removingAll = removedCount === len;
+
+ if (removingAll) {
+ this.currentState.empty(this);
+ this.invokeRecursively(function(view) {
+ view.removedFromDOM = true;
+ }, false);
+ }
for (idx = start + removedCount - 1; idx >= start; idx--) {
childView = childViews[idx];
@@ -38233,15 +36692,19 @@ enifed("ember-views/views/collection_view",
@param {Number} added number of object added to content
*/
arrayDidChange: function(content, start, removed, added) {
- var addedViews = [];
- var view, item, idx, len, itemViewClass, emptyView;
+ var addedViews = [], view, item, idx, len, itemViewClass,
+ emptyView;
len = content ? get(content, 'length') : 0;
if (len) {
itemViewClass = get(this, 'itemViewClass');
- itemViewClass = handlebarsGetView(content, itemViewClass, this.container);
+ if ('string' === typeof itemViewClass && isGlobalPath(itemViewClass)) {
+ itemViewClass = get(itemViewClass) || itemViewClass;
+ }
+
+
for (idx = start; idx < start+added; idx++) {
item = content.objectAt(idx);
@@ -38325,7 +36788,7 @@ enifed("ember-views/views/collection_view",
__exports__["default"] = CollectionView;
});
-enifed("ember-views/views/component",
+define("ember-views/views/component",
["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -38475,8 +36938,8 @@ enifed("ember-views/views/component",
template: computed(function(key, value) {
if (value !== undefined) { return value; }
- var templateName = get(this, 'templateName');
- var template = this.templateForName(templateName, 'template');
+ var templateName = get(this, 'templateName'),
+ template = this.templateForName(templateName, 'template');
return template || get(this, 'defaultTemplate');
@@ -38500,9 +36963,9 @@ enifed("ember-views/views/component",
},
_yield: function(context, options) {
- var view = options.data.view;
- var parentView = this._parentView;
- var template = get(this, 'template');
+ var view = options.data.view,
+ parentView = this._parentView,
+ template = get(this, 'template');
if (template) {
@@ -38612,8 +37075,8 @@ enifed("ember-views/views/component",
@param [context] {*} a context to send with the action
*/
sendAction: function(action) {
- var actionName;
- var contexts = a_slice.call(arguments, 1);
+ var actionName,
+ contexts = a_slice.call(arguments, 1);
// Send the default action
if (action === undefined) {
@@ -38634,9 +37097,9 @@ enifed("ember-views/views/component",
__exports__["default"] = Component;
});
-enifed("ember-views/views/container_view",
- ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) {
+define("ember-views/views/container_view",
+ ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/view_collection","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) {
"use strict";
var Ember = __dependency1__["default"];
// Ember.assert, Ember.K
@@ -38647,21 +37110,22 @@ enifed("ember-views/views/container_view",
var set = __dependency5__.set;
var View = __dependency6__["default"];
+ var ViewCollection = __dependency7__["default"];
- var cloneStates = __dependency7__.cloneStates;
- var EmberViewStates = __dependency7__.states;
+ var cloneStates = __dependency8__.cloneStates;
+ var EmberViewStates = __dependency8__.states;
- var EmberError = __dependency8__["default"];
+ var EmberError = __dependency9__["default"];
- var forEach = __dependency9__.forEach;
+ var forEach = __dependency10__.forEach;
- var computed = __dependency10__.computed;
- var run = __dependency11__["default"];
- var defineProperty = __dependency12__.defineProperty;
- var renderBuffer = __dependency13__["default"];
- var observer = __dependency14__.observer;
- var beforeObserver = __dependency14__.beforeObserver;
- var emberA = __dependency15__.A;
+ var computed = __dependency11__.computed;
+ var run = __dependency12__["default"];
+ var defineProperty = __dependency13__.defineProperty;
+ var renderBuffer = __dependency14__["default"];
+ var observer = __dependency15__.observer;
+ var beforeObserver = __dependency15__.beforeObserver;
+ var emberA = __dependency16__.A;
/**
@module ember
@@ -38821,7 +37285,6 @@ enifed("ember-views/views/container_view",
@extends Ember.View
*/
var ContainerView = View.extend(MutableArray, {
- isContainer: true,
_states: states,
willWatchProperty: function(prop){
@@ -38895,6 +37358,9 @@ enifed("ember-views/views/container_view",
@param {Ember.RenderBuffer} buffer the buffer to render to
*/
render: function(buffer) {
+ this.forEachChildView(function(view) {
+ view.renderToBuffer(buffer);
+ });
},
instrumentName: 'container',
@@ -39012,40 +37478,69 @@ enifed("ember-views/views/container_view",
},
ensureChildrenAreInDOM: function(view) {
- var childViews = view._childViews;
- var renderer = view._renderer;
+ var childViews = view._childViews, i, len, childView, previous, buffer, viewCollection = new ViewCollection();
- var i, len, childView;
for (i = 0, len = childViews.length; i < len; i++) {
childView = childViews[i];
- if (!childView._elementCreated) {
- renderer.renderTree(childView, view, i);
+
+ if (!buffer) { buffer = renderBuffer(); buffer._hasElement = false; }
+
+ if (childView.renderToBufferIfNeeded(buffer)) {
+ viewCollection.push(childView);
+ } else if (viewCollection.length) {
+ insertViewCollection(view, viewCollection, previous, buffer);
+ buffer = null;
+ previous = childView;
+ viewCollection.clear();
+ } else {
+ previous = childView;
}
}
+
+ if (viewCollection.length) {
+ insertViewCollection(view, viewCollection, previous, buffer);
+ }
}
});
+ function insertViewCollection(view, viewCollection, previous, buffer) {
+ viewCollection.triggerRecursively('willInsertElement');
+
+ if (previous) {
+ previous.domManager.after(previous, buffer.string());
+ } else {
+ view.domManager.prepend(view, buffer.string());
+ }
+
+ viewCollection.forEach(function(v) {
+ v._transitionTo('inDOM');
+ v.propertyDidChange('element');
+ v.triggerRecursively('didInsertElement');
+ });
+ }
+
+
__exports__["default"] = ContainerView;
});
-enifed("ember-views/views/core_view",
- ["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) {
+define("ember-views/views/core_view",
+ ["ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","ember-views/system/render_buffer","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) {
"use strict";
- var Rerender = __dependency1__["default"];
+ var cloneStates = __dependency1__.cloneStates;
+ var states = __dependency1__.states;
+ var EmberObject = __dependency2__["default"];
+ var Evented = __dependency3__["default"];
+ var ActionHandler = __dependency4__["default"];
- var cloneStates = __dependency2__.cloneStates;
- var states = __dependency2__.states;
- var EmberObject = __dependency3__["default"];
- var Evented = __dependency4__["default"];
- var ActionHandler = __dependency5__["default"];
+ var get = __dependency5__.get;
+ var computed = __dependency6__.computed;
- var get = __dependency6__.get;
- var set = __dependency7__.set;
- var computed = __dependency8__.computed;
+ var typeOf = __dependency7__.typeOf;
- var typeOf = __dependency9__.typeOf;
+ var instrument = __dependency8__.instrument;
- var instrument = __dependency10__.instrument;
+
+ var renderBuffer = __dependency9__["default"];
/**
`Ember.CoreView` is an abstract class that exists to give view-like behavior
@@ -39064,8 +37559,6 @@ enifed("ember-views/views/core_view",
*/
var CoreView = EmberObject.extend(Evented, ActionHandler, {
isView: true,
- isVirtual: false,
- isContainer: false,
_states: cloneStates(states),
@@ -39111,6 +37604,55 @@ enifed("ember-views/views/core_view",
hash.view = this;
},
+ /**
+ Invoked by the view system when this view needs to produce an HTML
+ representation. This method will create a new render buffer, if needed,
+ then apply any default attributes, such as class names and visibility.
+ Finally, the `render()` method is invoked, which is responsible for
+ doing the bulk of the rendering.
+
+ You should not need to override this method; instead, implement the
+ `template` property, or if you need more control, override the `render`
+ method.
+
+ @method renderToBuffer
+ @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is
+ passed, a default buffer, using the current view's `tagName`, will
+ be used.
+ @private
+ */
+ renderToBuffer: function(buffer) {
+ var name = 'render.' + this.instrumentName,
+ details = {};
+
+ this.instrumentDetails(details);
+
+ return instrument(name, details, function instrumentRenderToBuffer() {
+ return this._renderToBuffer(buffer);
+ }, this);
+ },
+
+ _renderToBuffer: function(_buffer) {
+ // If this is the top-most view, start a new buffer. Otherwise,
+ // create a new buffer relative to the original using the
+ // provided buffer operation (for example, `insertAfter` will
+ // insert a new buffer after the "parent buffer").
+ var tagName = this.tagName;
+
+ if (tagName === null || tagName === undefined) {
+ tagName = 'div';
+ }
+
+ var buffer = this.buffer = _buffer && _buffer.begin(tagName) || renderBuffer(tagName);
+ this._transitionTo('inBuffer', false);
+
+ this.beforeRender(buffer);
+ this.render(buffer);
+ this.afterRender(buffer);
+
+ return buffer;
+ },
+
/**
Override the default event firing from `Ember.Evented` to
also call methods with the given name.
@@ -39133,6 +37675,16 @@ enifed("ember-views/views/core_view",
}
},
+ deprecatedSendHandles: function(actionName) {
+ return !!this[actionName];
+ },
+
+ deprecatedSend: function(actionName) {
+ var args = [].slice.call(arguments, 1);
+ this[actionName].apply(this, args);
+ return;
+ },
+
has: function(name) {
return typeOf(this[name]) === 'function' || this._super(name);
},
@@ -39142,12 +37694,9 @@ enifed("ember-views/views/core_view",
if (!this._super()) { return; }
-
// destroy the element -- this will avoid each child view destroying
// the element over and over again...
- if (!this.removedFromDOM && this._renderer) {
- this._renderer.remove(this, true);
- }
+ if (!this.removedFromDOM) { this.destroyElement(); }
// remove from parent if found. Don't call removeFromParent,
// as removeFromParent will try to remove the element from
@@ -39160,17 +37709,15 @@ enifed("ember-views/views/core_view",
},
clearRenderedChildren: Ember.K,
+ triggerRecursively: Ember.K,
+ invokeRecursively: Ember.K,
_transitionTo: Ember.K,
destroyElement: Ember.K
});
- CoreView.reopenClass({
- renderer: new Rerender()
- });
-
__exports__["default"] = CoreView;
});
-enifed("ember-views/views/states",
+define("ember-views/views/states",
["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -39211,7 +37758,7 @@ enifed("ember-views/views/states",
};
__exports__.states = states;
});
-enifed("ember-views/views/states/default",
+define("ember-views/views/states/default",
["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -39246,16 +37793,23 @@ enifed("ember-views/views/states/default",
},
destroyElement: function(view) {
- if (view._renderer)
- view._renderer.remove(view, false);
+ set(view, 'element', null);
+ if (view._scheduledInsert) {
+ run.cancel(view._scheduledInsert);
+ view._scheduledInsert = null;
+ }
return view;
},
+ renderToBufferIfNeeded: function () {
+ return false;
+ },
+
rerender: Ember.K,
invokeObserver: Ember.K
};
});
-enifed("ember-views/views/states/destroying",
+define("ember-views/views/states/destroying",
["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -39282,12 +37836,27 @@ enifed("ember-views/views/states/destroying",
},
destroyElement: function() {
throw new EmberError(fmt(destroyingError, ['destroyElement']));
- }
+ },
+ empty: function() {
+ throw new EmberError(fmt(destroyingError, ['empty']));
+ },
+
+ setElement: function() {
+ throw new EmberError(fmt(destroyingError, ["set('element', ...)"]));
+ },
+
+ renderToBufferIfNeeded: function() {
+ return false;
+ },
+
+ // Since element insertion is scheduled, don't do anything if
+ // the view has been destroyed between scheduling and execution
+ insertElement: Ember.K
});
__exports__["default"] = destroying;
});
-enifed("ember-views/views/states/has_element",
+define("ember-views/views/states/has_element",
["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) {
"use strict";
@@ -39310,7 +37879,7 @@ enifed("ember-views/views/states/has_element",
merge(hasElement, {
$: function(view, sel) {
- var elem = view.get('concreteView').element;
+ var elem = get(view, 'element');
return sel ? jQuery(sel, elem) : jQuery(elem);
},
@@ -39321,17 +37890,25 @@ enifed("ember-views/views/states/has_element",
return jQuery("#" + get(view, 'elementId'))[0];
},
+ setElement: function(view, value) {
+ if (value === null) {
+ view._transitionTo('preRender');
+ } else {
+ throw new EmberError("You cannot set an element to a non-null value when the element is already in the DOM.");
+ }
+
+ return value;
+ },
+
// once the view has been inserted into the DOM, rerendering is
// deferred to allow bindings to synchronize.
rerender: function(view) {
- if (view._root._morph && !view._elementInserted) {
- throw new EmberError("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");
- }
- // TODO: should be scheduled with renderer
- run.scheduleOnce('render', function () {
- if (view.isDestroying) return;
- view._renderer.renderTree(view, view._parentView);
- });
+ view.triggerRecursively('willClearRender');
+
+ view.clearRenderedChildren();
+
+ view.domManager.replace(view);
+ return view;
},
// once the view is already in the DOM, destroying it removes it
@@ -39339,10 +37916,27 @@ enifed("ember-views/views/states/has_element",
// preRender state if inDOM.
destroyElement: function(view) {
- view._renderer.remove(view, false);
+ view._notifyWillDestroyElement();
+ view.domManager.remove(view);
+ set(view, 'element', null);
+ if (view._scheduledInsert) {
+ run.cancel(view._scheduledInsert);
+ view._scheduledInsert = null;
+ }
return view;
},
+ empty: function(view) {
+ var _childViews = view._childViews, len, idx;
+ if (_childViews) {
+ len = _childViews.length;
+ for (idx = 0; idx < len; idx++) {
+ _childViews[idx]._notifyWillDestroyElement();
+ }
+ }
+ view.domManager.empty(view);
+ },
+
// Handle events from `Ember.EventDispatcher`
handleEvent: function(view, eventName, evt) {
if (view.has(eventName)) {
@@ -39361,7 +37955,7 @@ enifed("ember-views/views/states/has_element",
__exports__["default"] = hasElement;
});
-enifed("ember-views/views/states/in_buffer",
+define("ember-views/views/states/in_buffer",
["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -39400,22 +37994,54 @@ enifed("ember-views/views/states/in_buffer",
// view will render that view and append the resulting
// buffer into its buffer.
appendChild: function(view, childView, options) {
- var buffer = view.buffer;
- var _childViews = view._childViews;
+ var buffer = view.buffer, _childViews = view._childViews;
childView = view.createChildView(childView, options);
if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); }
_childViews.push(childView);
- if (!childView._morph) {
- buffer.pushChildView(childView);
- }
+ childView.renderToBuffer(buffer);
view.propertyDidChange('childViews');
return childView;
},
+ // when a view is rendered in a buffer, destroying the
+ // element will simply destroy the buffer and put the
+ // state back into the preRender state.
+ destroyElement: function(view) {
+ view.clearBuffer();
+ var viewCollection = view._notifyWillDestroyElement();
+ viewCollection.transitionTo('preRender', false);
+
+ return view;
+ },
+
+ empty: function() {
+ },
+
+ renderToBufferIfNeeded: function (view, buffer) {
+ return false;
+ },
+
+ // It should be impossible for a rendered view to be scheduled for
+ // insertion.
+ insertElement: function() {
+ throw new EmberError("You can't insert an element that has already been rendered");
+ },
+
+ setElement: function(view, value) {
+ if (value === null) {
+ view._transitionTo('preRender');
+ } else {
+ view.clearBuffer();
+ view._transitionTo('hasElement');
+ }
+
+ return value;
+ },
+
invokeObserver: function(target, observer) {
observer.call(target);
}
@@ -39423,7 +38049,7 @@ enifed("ember-views/views/states/in_buffer",
__exports__["default"] = inBuffer;
});
-enifed("ember-views/views/states/in_dom",
+define("ember-views/views/states/in_dom",
["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
@@ -39462,15 +38088,21 @@ enifed("ember-views/views/states/in_dom",
if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles...
if (!this.isVirtual) delete View.views[view.elementId];
+ },
+
+ insertElement: function(view, fn) {
+ throw new EmberError("You can't insert an element into the DOM that has already been inserted");
}
});
__exports__["default"] = inDOM;
});
-enifed("ember-views/views/states/pre_render",
+define("ember-views/views/states/pre_render",
["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
"use strict";
+ /* global Node */
+
var _default = __dependency1__["default"];
var create = __dependency2__.create;
var merge = __dependency3__["default"];
@@ -39482,10 +38114,44 @@ enifed("ember-views/views/states/pre_render",
*/
var preRender = create(_default);
+ merge(preRender, {
+ // a view leaves the preRender state once its element has been
+ // created (createElement).
+ insertElement: function(view, fn) {
+ view.createElement();
+ var viewCollection = view.viewHierarchyCollection();
+
+ viewCollection.trigger('willInsertElement');
+
+ fn.call(view);
+
+ // We transition to `inDOM` if the element exists in the DOM
+ var element = view.get('element');
+ if (jQuery.contains(document.body, element)) {
+ viewCollection.transitionTo('inDOM', false);
+ viewCollection.trigger('didInsertElement');
+ }
+ },
+
+ renderToBufferIfNeeded: function(view, buffer) {
+ view.renderToBuffer(buffer);
+ return true;
+ },
+
+ empty: Ember.K,
+
+ setElement: function(view, value) {
+ if (value !== null) {
+ view._transitionTo('hasElement');
+ }
+ return value;
+ }
+ });
+
__exports__["default"] = preRender;
});
-enifed("ember-views/views/view",
- ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"],
+define("ember-views/views/view",
+ ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","ember-views/views/view_collection","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __exports__) {
"use strict";
// Ember.assert, Ember.deprecate, Ember.warn, Ember.TEMPLATES,
@@ -39515,36 +38181,47 @@ enifed("ember-views/views/view",
var isArray = __dependency11__.isArray;
var isNone = __dependency14__.isNone;
var Mixin = __dependency13__.Mixin;
- var deprecateProperty = __dependency15__.deprecateProperty;
- var emberA = __dependency16__.A;
+ var deprecateProperty = __dependency10__.deprecateProperty;
+ var emberA = __dependency15__.A;
- var dasherize = __dependency17__.dasherize;
+ var dasherize = __dependency16__.dasherize;
// ES6TODO: functions on EnumerableUtils should get their own export
- var forEach = __dependency18__.forEach;
- var addObject = __dependency18__.addObject;
- var removeObject = __dependency18__.removeObject;
+ var forEach = __dependency17__.forEach;
+ var addObject = __dependency17__.addObject;
+ var removeObject = __dependency17__.removeObject;
var beforeObserver = __dependency13__.beforeObserver;
- var copy = __dependency19__["default"];
- var isGlobalPath = __dependency20__.isGlobalPath;
+ var copy = __dependency18__["default"];
+ var isGlobalPath = __dependency19__.isGlobalPath;
- var propertyWillChange = __dependency21__.propertyWillChange;
- var propertyDidChange = __dependency21__.propertyDidChange;
+ var propertyWillChange = __dependency20__.propertyWillChange;
+ var propertyDidChange = __dependency20__.propertyDidChange;
- var jQuery = __dependency22__["default"];
+ var jQuery = __dependency21__["default"];
// for the side effect of extending Ember.run.queues
- var CoreView = __dependency24__["default"];
+ var CoreView = __dependency23__["default"];
+ var ViewCollection = __dependency24__["default"];
/**
@module ember
@submodule ember-views
*/
+
+ var ContainerView;
+
+ function nullViewsBuffer(view) {
+ view.buffer = null;
+
+ }
+
+ function clearCachedElement(view) {
+ meta(view).cache.element = undefined;
+ }
+
var childViewsProperty = computed(function() {
- var childViews = this._childViews;
- var ret = emberA();
- var view = this;
+ var childViews = this._childViews, ret = emberA(), view = this;
forEach(childViews, function(view) {
var currentChildViews;
@@ -39558,6 +38235,11 @@ enifed("ember-views/views/view",
});
ret.replace = function (idx, removedCount, addedViews) {
+ if (!ContainerView) { ContainerView = requireModule('ember-views/views/container_view')['default']; } // ES6TODO: stupid circular dep
+
+ if (view instanceof ContainerView) {
+ return view.replace(idx, removedCount, addedViews);
+ }
throw new EmberError("childViews is immutable");
};
@@ -40075,9 +38757,8 @@ enifed("ember-views/views/view",
on the descendent.
```javascript
- var App = Ember.Application.create();
- App.OuterView = Ember.View.extend({
- template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"),
+ OuterView = Ember.View.extend({
+ template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"),
eventManager: Ember.Object.create({
mouseEnter: function(event, view) {
// view might be instance of either
@@ -40087,7 +38768,7 @@ enifed("ember-views/views/view",
})
});
- App.InnerView = Ember.View.extend({
+ InnerView = Ember.View.extend({
click: function(event) {
// will be called if rendered inside
// an OuterView because OuterView's
@@ -40231,8 +38912,8 @@ enifed("ember-views/views/view",
template: computed('templateName', function(key, value) {
if (value !== undefined) { return value; }
- var templateName = get(this, 'templateName');
- var template = this.templateForName(templateName, 'template');
+ var templateName = get(this, 'templateName'),
+ template = this.templateForName(templateName, 'template');
return template || get(this, 'defaultTemplate');
@@ -40265,8 +38946,8 @@ enifed("ember-views/views/view",
@type Function
*/
layout: computed(function(key) {
- var layoutName = get(this, 'layoutName');
- var layout = this.templateForName(layoutName, 'layout');
+ var layoutName = get(this, 'layoutName'),
+ layout = this.templateForName(layoutName, 'layout');
return layout || get(this, 'defaultLayout');
@@ -40422,8 +39103,8 @@ enifed("ember-views/views/view",
@return Ember.View
*/
nearestOfType: function(klass) {
- var view = get(this, 'parentView');
- var isOfType = klass instanceof Mixin ?
+ var view = get(this, 'parentView'),
+ isOfType = klass instanceof Mixin ?
function(view) { return klass.detect(view); } :
function(view) { return klass.detect(view.constructor); };
@@ -40568,6 +39249,21 @@ enifed("ember-views/views/view",
return this.currentState.rerender(this);
},
+ clearRenderedChildren: function() {
+ var lengthBefore = this.lengthBeforeRender,
+ lengthAfter = this.lengthAfterRender;
+
+ // If there were child views created during the last call to render(),
+ // remove them under the assumption that they will be re-created when
+ // we re-render.
+
+ // VIEW-TODO: Unit test this path.
+ var childViews = this._childViews;
+ for (var i=lengthAfter-1; i>=lengthBefore; i--) {
+ if (childViews[i]) { childViews[i].destroy(); }
+ }
+ },
+
/**
Iterates over the view's `classNameBindings` array, inserts the value
of the specified property into the `classNames` array, then creates an
@@ -40578,8 +39274,8 @@ enifed("ember-views/views/view",
@private
*/
_applyClassNameBindings: function(classBindings) {
- var classNames = this.classNames;
- var elem, newClass, dasherizedClass;
+ var classNames = this.classNames,
+ elem, newClass, dasherizedClass;
// Loop through all of the configured bindings. These will be either
// property names ('isUrgent') or property paths relative to the view
@@ -40657,15 +39353,14 @@ enifed("ember-views/views/view",
@private
*/
_applyAttributeBindings: function(buffer, attributeBindings) {
- var attributeValue;
- var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {};
+ var attributeValue,
+ unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {};
forEach(attributeBindings, function(binding) {
- var split = binding.split(':');
- var property = split[0];
- var attributeName = split[1] || property;
+ var split = binding.split(':'),
+ property = split[0],
+ attributeName = split[1] || property;
-
if (property in this) {
this._setupAttributeBindingObservation(property, attributeName);
@@ -40754,7 +39449,13 @@ enifed("ember-views/views/view",
@property element
@type DOMElement
*/
- element: null,
+ element: computed('_parentView', function(key, value) {
+ if (value !== undefined) {
+ return this.currentState.setElement(this, value);
+ } else {
+ return this.currentState.getElement(this);
+ }
+ }),
/**
Returns a jQuery object for this view's element. If you pass in a selector
@@ -40773,9 +39474,9 @@ enifed("ember-views/views/view",
},
mutateChildViews: function(callback) {
- var childViews = this._childViews;
- var idx = childViews.length;
- var view;
+ var childViews = this._childViews,
+ idx = childViews.length,
+ view;
while(--idx >= 0) {
view = childViews[idx];
@@ -40790,8 +39491,8 @@ enifed("ember-views/views/view",
if (!childViews) { return this; }
- var len = childViews.length;
- var view, idx;
+ var len = childViews.length,
+ view, idx;
for (idx = 0; idx < len; idx++) {
view = childViews[idx];
@@ -40821,11 +39522,12 @@ enifed("ember-views/views/view",
@param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object
@return {Ember.View} receiver
*/
- appendTo: function(selector) {
- var target = jQuery(selector);
-
-
- this.constructor.renderer.appendTo(this, target[0]);
+ appendTo: function(target) {
+ // Schedule the DOM element to be created and appended to the given
+ // element after bindings have synchronized.
+ this._insertElementLater(function() {
+ this.$().appendTo(target);
+ });
return this;
},
@@ -40843,15 +39545,47 @@ enifed("ember-views/views/view",
@param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object
@return {Ember.View} received
*/
- replaceIn: function(selector) {
- var target = jQuery(selector);
-
+ replaceIn: function(target) {
- this.constructor.renderer.replaceIn(this, target[0]);
+ this._insertElementLater(function() {
+ jQuery(target).empty();
+ this.$().appendTo(target);
+ });
return this;
},
+ /**
+ Schedules a DOM operation to occur during the next render phase. This
+ ensures that all bindings have finished synchronizing before the view is
+ rendered.
+
+ To use, pass a function that performs a DOM operation.
+
+ Before your function is called, this view and all child views will receive
+ the `willInsertElement` event. After your function is invoked, this view
+ and all of its child views will receive the `didInsertElement` event.
+
+ ```javascript
+ view._insertElementLater(function() {
+ this.createElement();
+ this.$().appendTo('body');
+ });
+ ```
+
+ @method _insertElementLater
+ @param {Function} fn the function that inserts the element into the DOM
+ @private
+ */
+ _insertElementLater: function(fn) {
+ this._scheduledInsert = run.scheduleOnce('render', this, '_insertElement', fn);
+ },
+
+ _insertElement: function (fn) {
+ this._scheduledInsert = null;
+ this.currentState.insertElement(this, fn);
+ },
+
/**
Appends the view's element to the document body. If the view does
not have an HTML representation yet, `createElement()` will be called
@@ -40885,6 +39619,9 @@ enifed("ember-views/views/view",
// In the interim, we will just re-render if that happens. It is more
// important than elements get garbage collected.
if (!this.removedFromDOM) { this.destroyElement(); }
+ this.invokeRecursively(function(view) {
+ if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
+ });
},
elementId: null,
@@ -40906,20 +39643,20 @@ enifed("ember-views/views/view",
},
/**
- Creates a DOM representation of the view and all of its child views by
- recursively calling the `render()` method.
+ Creates a DOM representation of the view and all of its
+ child views by recursively calling the `render()` method.
- After the element has been inserted into the DOM, `didInsertElement` will
+ After the element has been created, `didInsertElement` will
be called on this view and all of its child views.
@method createElement
@return {Ember.View} receiver
*/
createElement: function() {
- if (this.element) { return this; }
+ if (get(this, 'element')) { return this; }
- this._didCreateElementWithoutMorph = true;
- this.constructor.renderer.renderTree(this);
+ var buffer = this.renderToBuffer();
+ set(this, 'element', buffer.element());
return this;
},
@@ -40936,9 +39673,6 @@ enifed("ember-views/views/view",
or after the view was re-rendered. Override this function to do any
set up that requires an element in the document body.
- When a view has children, didInsertElement will be called on the
- child view(s) first, bubbling upwards through the hierarchy.
-
@event didInsertElement
*/
didInsertElement: Ember.K,
@@ -40952,6 +39686,65 @@ enifed("ember-views/views/view",
*/
willClearRender: Ember.K,
+ /**
+ Run this callback on the current view (unless includeSelf is false) and recursively on child views.
+
+ @method invokeRecursively
+ @param fn {Function}
+ @param includeSelf {Boolean} Includes itself if true.
+ @private
+ */
+ invokeRecursively: function(fn, includeSelf) {
+ var childViews = (includeSelf === false) ? this._childViews : [this];
+ var currentViews, view, currentChildViews;
+
+ while (childViews.length) {
+ currentViews = childViews.slice();
+ childViews = [];
+
+ for (var i=0, l=currentViews.length; 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;
},
@@ -41342,18 +40187,16 @@ enifed("ember-views/views/view",
_toggleVisibility: function() {
var $el = this.$();
+ if (!$el) { return; }
+
var isVisible = get(this, 'isVisible');
if (this._isVisible === isVisible) { return ; }
- // It's important to keep these in sync, even if we don't yet have
- // an element in the DOM to manipulate:
- this._isVisible = isVisible;
-
- if (!$el) { return; }
-
$el.toggle(isVisible);
+ this._isVisible = isVisible;
+
if (this._isAncestorHidden()) { return; }
if (isVisible) {
@@ -41397,16 +40240,28 @@ enifed("ember-views/views/view",
return false;
},
+
+ clearBuffer: function() {
+ this.invokeRecursively(nullViewsBuffer);
+ },
transitionTo: function(state, children) {
this._transitionTo(state, children);
},
_transitionTo: function(state, children) {
var priorState = this.currentState;
var 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);
+ });
+ }
},
// .......................................................
@@ -41435,13 +40290,13 @@ enifed("ember-views/views/view",
return;
}
- var view = this;
- var stateCheckedObserver = function() {
- view.currentState.invokeObserver(this, observer);
- };
- var scheduledObserver = function() {
- run.scheduleOnce('render', this, stateCheckedObserver);
- };
+ var view = this,
+ stateCheckedObserver = function() {
+ view.currentState.invokeObserver(this, observer);
+ },
+ scheduledObserver = function() {
+ run.scheduleOnce('render', this, stateCheckedObserver);
+ };
addObserver(root, path, target, scheduledObserver);
@@ -41485,6 +40340,48 @@ enifed("ember-views/views/view",
run.once(View, 'notifyMutationListeners');
}
+ var DOMManager = {
+ prepend: function(view, html) {
+ view.$().prepend(html);
+ notifyMutationListeners();
+ },
+
+ 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({
/**
@@ -41507,10 +40404,11 @@ enifed("ember-views/views/view",
@private
*/
_parsePropertyPath: function(path) {
- var split = path.split(':');
- var propertyPath = split[0];
- var classNames = "";
- var className, falsyClassName;
+ 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) {
@@ -41594,7 +40492,7 @@ enifed("ember-views/views/view",
});
var mutation = EmberObject.extend(Evented).create();
- // TODO MOVE TO RENDERER HOOKS
+
View.addMutationListener = function(callback) {
mutation.on('change', callback);
};
@@ -41652,11 +40550,82 @@ enifed("ember-views/views/view",
__exports__["default"] = View;
});
-enifed("ember",
+define("ember-views/views/view_collection",
+ ["ember-metal/enumerable_utils","exports"],
+ function(__dependency1__, __exports__) {
+ "use strict";
+ var forEach = __dependency1__.forEach;
+
+ function ViewCollection(initialViews) {
+ var views = this.views = initialViews || [];
+ this.length = views.length;
+ }
+
+ ViewCollection.prototype = {
+ length: 0,
+
+ trigger: function(eventName) {
+ var views = this.views, view;
+ for (var i = 0, l = views.length; i < l; i++) {
+ view = views[i];
+ if (view.trigger) { view.trigger(eventName); }
+ }
+ },
+
+ triggerRecursively: function(eventName) {
+ var views = this.views;
+ for (var i = 0, l = views.length; i < l; i++) {
+ views[i].triggerRecursively(eventName);
+ }
+ },
+
+ invokeRecursively: function(fn) {
+ var views = this.views, view;
+
+ for (var i = 0, l = views.length; i < l; i++) {
+ view = views[i];
+ fn(view);
+ }
+ },
+
+ transitionTo: function(state, children) {
+ var views = this.views;
+ for (var i = 0, l = views.length; i < l; i++) {
+ views[i]._transitionTo(state, children);
+ }
+ },
+
+ push: function() {
+ this.length += arguments.length;
+ var views = this.views;
+ return views.push.apply(views, arguments);
+ },
+
+ objectAt: function(idx) {
+ return this.views[idx];
+ },
+
+ forEach: function(callback) {
+ var views = this.views;
+ return forEach(views, callback);
+ },
+
+ clear: function() {
+ this.length = 0;
+ this.views.length = 0;
+ }
+ };
+
+ __exports__["default"] = ViewCollection;
+ });
+define("ember",
["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) {
- "use strict";
- /* global navigator */
+ // Remove "use strict"; from transpiled module until
+ // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed
+ //
+ // REMOVE_USE_STRICT: true
+
// require the main entry points for each of these packages
// this is so that the global exports occur properly
@@ -41672,830 +40641,521 @@ enifed("ember",
@module ember
*/
- });
-enifed("morph",
- ["./morph/morph","./morph/dom-helper","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
- "use strict";
- var Morph = __dependency1__["default"];
- var Morph;
- __exports__.Morph = Morph;
- var DOMHelper = __dependency2__["default"];
- var DOMHelper;
- __exports__.DOMHelper = DOMHelper;
+ function throwWithMessage(msg) {
+ return function() {
+ throw new Ember.Error(msg);
+ };
+ }
+
+ function generateRemovedClass(className) {
+ var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states";
+
+ return {
+ extend: throwWithMessage(className + msg),
+ create: throwWithMessage(className + msg)
+ };
+ }
+
+ Ember.StateManager = generateRemovedClass("Ember.StateManager");
+
+ /**
+ This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
+
+ @class StateManager
+ @namespace Ember
+ */
+
+ Ember.State = generateRemovedClass("Ember.State");
+
+ /**
+ This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states
+
+ @class State
+ @namespace Ember
+ */
});
-enifed("morph/dom-helper",
- ["../morph/morph","./dom-helper/build-html-dom","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
+define("metamorph",
+ [],
+ function() {
"use strict";
- var Morph = __dependency1__["default"];
- var buildHTMLDOM = __dependency2__.buildHTMLDOM;
- var svgNamespace = __dependency2__.svgNamespace;
- var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints;
+ // ==========================================================================
+ // Project: metamorph
+ // Copyright: ©2014 Tilde, Inc. All rights reserved.
+ // ==========================================================================
- var deletesBlankTextNodes = (function(){
- var element = document.createElement('div');
- element.appendChild( document.createTextNode('') );
- var clonedElement = element.cloneNode(true);
- return clonedElement.childNodes.length === 0;
- })();
-
- var ignoresCheckedAttribute = (function(){
- var element = document.createElement('input');
- element.setAttribute('checked', 'checked');
- var clonedElement = element.cloneNode(false);
- return !clonedElement.checked;
- })();
-
- function isSVG(ns){
- return ns === svgNamespace;
- }
-
- // This is not the namespace of the element, but of
- // the elements inside that elements.
- function interiorNamespace(element){
- if (
- element &&
- element.namespaceURI === svgNamespace &&
- !svgHTMLIntegrationPoints[element.tagName]
- ) {
- return svgNamespace;
- } else {
- return null;
- }
- }
-
- // The HTML spec allows for "omitted start tags". These tags are optional
- // when their intended child is the first thing in the parent tag. For
- // example, this is a tbody start tag:
- //
- //
- //
- //
- //
- // The tbody may be omitted, and the browser will accept and render:
- //
- //
- //
- //
- // However, the omitted start tag will still be added to the DOM. Here
- // we test the string and context to see if the browser is about to
- // perform this cleanup.
- //
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags
- // describes which tags are omittable. The spec for tbody and colgroup
- // explains this behavior:
- //
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element
- //
-
- var omittedStartTagChildTest = /<([\w:]+)/;
- function detectOmittedStartTag(string, contextualElement){
- // Omitted start tags are only inside table tags.
- if (contextualElement.tagName === 'TABLE') {
- var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string);
- if (omittedStartTagChildMatch) {
- var omittedStartTagChild = omittedStartTagChildMatch[1];
- // It is already asserted that the contextual element is a table
- // and not the proper start tag. Just see if a tag was omitted.
- return omittedStartTagChild === 'tr' ||
- omittedStartTagChild === 'col';
- }
- }
- }
-
- function buildSVGDOM(html, dom){
- var div = dom.document.createElement('div');
- div.innerHTML = '';
- return div.firstChild.childNodes;
- }
-
- /*
- * A class wrapping DOM functions to address environment compatibility,
- * namespaces, contextual elements for morph un-escaped content
- * insertion.
- *
- * When entering a template, a DOMHelper should be passed:
- *
- * template(context, { hooks: hooks, dom: new DOMHelper() });
- *
- * TODO: support foreignObject as a passed contextual element. It has
- * a namespace (svg) that does not match its internal namespace
- * (xhtml).
- *
- * @class DOMHelper
- * @constructor
- * @param {HTMLDocument} _document The document DOM methods are proxied to
- */
- function DOMHelper(_document){
- this.document = _document || window.document;
- this.namespace = null;
- }
-
- var prototype = DOMHelper.prototype;
- prototype.constructor = DOMHelper;
-
- prototype.insertBefore = function(element, childElement, referenceChild) {
- return element.insertBefore(childElement, referenceChild);
- };
-
- prototype.appendChild = function(element, childElement) {
- return element.appendChild(childElement);
- };
-
- prototype.appendText = function(element, text) {
- return element.appendChild(this.document.createTextNode(text));
- };
-
- prototype.setAttribute = function(element, name, value) {
- element.setAttribute(name, value);
- };
-
- if (document.createElementNS) {
- // Only opt into namespace detection if a contextualElement
- // is passed.
- prototype.createElement = function(tagName, contextualElement) {
- var namespace = this.namespace;
- if (contextualElement) {
- if (tagName === 'svg') {
- namespace = svgNamespace;
+ var K = function() {},
+ guid = 0,
+ disableRange = (function(){
+ if ('undefined' !== typeof MetamorphENV) {
+ return MetamorphENV.DISABLE_RANGE_API;
+ } else if ('undefined' !== ENV) {
+ return ENV.DISABLE_RANGE_API;
} else {
- namespace = interiorNamespace(contextualElement);
+ return false;
}
- }
- if (namespace) {
- return this.document.createElementNS(namespace, tagName);
+ })(),
+
+ // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
+ 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 = typeof document !== 'undefined' && (function() {
+ var testEl = document.createElement('div');
+ testEl.innerHTML = "";
+ testEl.firstChild.innerHTML = "";
+ return testEl.firstChild.innerHTML === '';
+ })(),
+
+
+ // IE 8 (and likely earlier) likes to move whitespace preceeding
+ // a script tag to appear after it. This means that we can
+ // accidentally remove whitespace when updating a morph.
+ movesWhitespace = document && (function() {
+ var testEl = document.createElement('div');
+ testEl.innerHTML = "Test: Value";
+ return testEl.childNodes[0].nodeValue === 'Test:' &&
+ testEl.childNodes[2].nodeValue === ' Value';
+ })();
+
+ // Constructor that supports either Metamorph('foo') or new
+ // Metamorph('foo');
+ //
+ // Takes a string of HTML as the argument.
+
+ var Metamorph = function(html) {
+ var self;
+
+ if (this instanceof Metamorph) {
+ self = this;
+ } else {
+ self = new K();
+ }
+
+ self.innerHTML = html;
+ var myGuid = 'metamorph-'+(guid++);
+ self.start = myGuid + '-start';
+ self.end = myGuid + '-end';
+
+ return self;
+ };
+
+ K.prototype = Metamorph.prototype;
+
+ var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc;
+
+ outerHTMLFunc = function() {
+ return this.startTag() + this.innerHTML + this.endTag();
+ };
+
+ startTagFunc = function() {
+ /*
+ * We replace chevron by its hex code in order to prevent escaping problems.
+ * Check this thread for more explaination:
+ * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript
+ */
+ return "
hi |
";
+ * div.firstChild.firstChild.tagName //=> ""
+ *
+ * If our script markers are inside such a node, we need to find that
+ * node and use *it* as the marker.
+ */
+ var realNode = function(start) {
+ while (start.parentNode.tagName === "") {
+ start = start.parentNode;
+ }
+
+ return start;
+ };
+
+ /*
+ * When automatically adding a tbody, Internet Explorer inserts the
+ * tbody immediately before the first
. Other browsers create it
+ * before the first node, no matter what.
+ *
+ * This means the the following code:
+ *
+ * div = document.createElement("div");
+ * div.innerHTML = "
+ *
+ * Generates the following DOM in IE:
+ *
+ * + div
+ * + table
+ * - script id='first'
+ * + tbody
+ * + tr
+ * + td
+ * - "hi"
+ * - script id='last'
+ *
+ * Which means that the two script tags, even though they were
+ * inserted at the same point in the hierarchy in the original
+ * HTML, now have different parents.
+ *
+ * This code reparents the first script tag by making it the tbody's
+ * first child.
+ *
+ */
+ var fixParentage = function(start, end) {
+ if (start.parentNode !== end.parentNode) {
+ end.parentNode.insertBefore(start, end.parentNode.firstChild);
+ }
+ };
+
+ htmlFunc = function(html, outerToo) {
+ // get the real starting node. see realNode for details.
+ var start = realNode(document.getElementById(this.start));
+ var end = document.getElementById(this.end);
+ var parentNode = end.parentNode;
+ var node, nextSibling, last;
+
+ // make sure that the start and end nodes share the same
+ // parent. If not, fix it.
+ fixParentage(start, end);
+
+ // remove all of the nodes after the starting placeholder and
+ // before the ending placeholder.
+ node = start.nextSibling;
+ while (node) {
+ nextSibling = node.nextSibling;
+ last = node === end;
+
+ // if this is the last node, and we want to remove it as well,
+ // set the `end` node to the next sibling. This is because
+ // for the rest of the function, we insert the new nodes
+ // before the end (note that insertBefore(node, null) is
+ // the same as appendChild(node)).
+ //
+ // if we do not want to remove it, just break.
+ if (last) {
+ if (outerToo) { end = node.nextSibling; } else { break; }
+ }
+
+ node.parentNode.removeChild(node);
+
+ // if this is the last node and we didn't break before
+ // (because we wanted to remove the outer nodes), break
+ // now.
+ if (last) { break; }
+
+ node = nextSibling;
+ }
+
+ // get the first node for the HTML string, even in cases like
+ // tables and lists where a simple innerHTML on a div would
+ // 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) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, end);
+ node = nextSibling;
+ }
+ };
+
+ // remove the nodes in the DOM representing this metamorph.
+ //
+ // this includes the starting and ending placeholders.
+ removeFunc = function() {
+ var start = realNode(document.getElementById(this.start));
+ var end = document.getElementById(this.end);
+
+ this.html('');
+ start.parentNode.removeChild(start);
+ end.parentNode.removeChild(end);
+ };
+
+ appendToFunc = function(parentNode) {
+ var node = firstNodeFor(parentNode, this.outerHTML());
+ var nextSibling;
+
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.appendChild(node);
+ node = nextSibling;
+ }
+ };
+
+ afterFunc = function(html) {
+ // get the real starting node. see realNode for details.
+ var end = document.getElementById(this.end);
+ var insertBefore = end.nextSibling;
+ var parentNode = end.parentNode;
+ var nextSibling;
+ var node;
+
+ // get the first node for the HTML string, even in cases like
+ // tables and lists where a simple innerHTML on a div would
+ // swallow some of the content.
+ node = firstNodeFor(parentNode, html);
+
+ // copy the nodes for the HTML between the starting and ending
+ // placeholder.
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, insertBefore);
+ node = nextSibling;
+ }
+ };
+
+ prependFunc = function(html) {
+ var start = document.getElementById(this.start);
+ var parentNode = start.parentNode;
+ var nextSibling;
+ var node;
+
+ node = firstNodeFor(parentNode, html);
+ var insertBefore = start.nextSibling;
+
+ while (node) {
+ nextSibling = node.nextSibling;
+ parentNode.insertBefore(node, insertBefore);
+ node = nextSibling;
+ }
};
}
- prototype.setNamespace = function(ns) {
- this.namespace = ns;
+ Metamorph.prototype.html = function(html) {
+ this.checkRemoved();
+ if (html === undefined) { return this.innerHTML; }
+
+ htmlFunc.call(this, html);
+
+ this.innerHTML = html;
};
- prototype.detectNamespace = function(element) {
- this.namespace = interiorNamespace(element);
+ Metamorph.prototype.replaceWith = function(html) {
+ this.checkRemoved();
+ htmlFunc.call(this, html, true);
};
- prototype.createDocumentFragment = function(){
- return this.document.createDocumentFragment();
+ Metamorph.prototype.remove = removeFunc;
+ Metamorph.prototype.outerHTML = outerHTMLFunc;
+ Metamorph.prototype.appendTo = appendToFunc;
+ Metamorph.prototype.after = afterFunc;
+ Metamorph.prototype.prepend = prependFunc;
+ Metamorph.prototype.startTag = startTagFunc;
+ Metamorph.prototype.endTag = endTagFunc;
+
+ Metamorph.prototype.isRemoved = function() {
+ var before = document.getElementById(this.start);
+ var after = document.getElementById(this.end);
+
+ return !before || !after;
};
- prototype.createTextNode = function(text){
- return this.document.createTextNode(text);
- };
-
- prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){
- if (deletesBlankTextNodes && blankChildTextNodes.length > 0) {
- for (var i=0, len=blankChildTextNodes.length;i]*selected/;
- detectAutoSelectedOption = function detectAutoSelectedOption(select, option, html) { //jshint ignore:line
- return select.selectedIndex === 0 &&
- !detectAutoSelectedOptionRegex.test(html);
- };
- } else {
- detectAutoSelectedOption = function detectAutoSelectedOption(select, option, html) { //jshint ignore:line
- var selectedAttribute = option.getAttribute('selected');
- return select.selectedIndex === 0 && (
- selectedAttribute === null ||
- ( selectedAttribute !== '' && selectedAttribute.toLowerCase() !== 'selected' )
- );
- };
- }
-
- // IE 9 and earlier don't allow us to set innerHTML on col, colgroup, frameset,
- // html, style, table, tbody, tfoot, thead, title, tr. Detect this and add
- // them to an initial list of corrected tags.
- //
- // Here we are only dealing with the ones which can have child nodes.
- //
- var tagNamesRequiringInnerHTMLFix, tableNeedsInnerHTMLFix;
- var tableInnerHTMLTestElement = document.createElement('table');
- try {
- tableInnerHTMLTestElement.innerHTML = '';
- } catch (e) {
- } finally {
- tableNeedsInnerHTMLFix = (tableInnerHTMLTestElement.childNodes.length === 0);
- }
- if (tableNeedsInnerHTMLFix) {
- tagNamesRequiringInnerHTMLFix = {
- colgroup: ['table'],
- table: [],
- tbody: ['table'],
- tfoot: ['table'],
- thead: ['table'],
- tr: ['table', 'tbody']
- };
- }
-
- // IE 8 doesn't allow setting innerHTML on a select tag. Detect this and
- // add it to the list of corrected tags.
- //
- var selectInnerHTMLTestElement = document.createElement('select');
- selectInnerHTMLTestElement.innerHTML = '';
- if (selectInnerHTMLTestElement) {
- tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {};
- tagNamesRequiringInnerHTMLFix.select = [];
- }
-
- function scriptSafeInnerHTML(element, html) {
- // without a leading text node, IE will drop a leading script tag.
- html = ''+html;
-
- element.innerHTML = html;
-
- var nodes = element.childNodes;
-
- // Look for to remove it.
- var shyElement = nodes[0];
- while (shyElement.nodeType === 1 && !shyElement.nodeName) {
- shyElement = shyElement.firstChild;
- }
- // At this point it's the actual unicode character.
- if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
- var newValue = shyElement.nodeValue.slice(1);
- if (newValue.length) {
- shyElement.nodeValue = shyElement.nodeValue.slice(1);
- } else {
- shyElement.parentNode.removeChild(shyElement);
- }
- }
-
- return nodes;
- }
-
- function buildDOMWithFix(html, contextualElement){
- var tagName = contextualElement.tagName;
-
- // Firefox versions < 11 do not have support for element.outerHTML.
- var outerHTML = contextualElement.outerHTML || new XMLSerializer().serializeToString(contextualElement);
- if (!outerHTML) {
- throw "Can't set innerHTML on "+tagName+" in this browser";
- }
-
- var wrappingTags = tagNamesRequiringInnerHTMLFix[tagName.toLowerCase()];
- var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0];
- var endTag = ''+tagName+'>';
-
- var wrappedHTML = [startTag, html, endTag];
-
- var i = wrappingTags.length;
- var wrappedDepth = 1 + i;
- while(i--) {
- wrappedHTML.unshift('<'+wrappingTags[i]+'>');
- wrappedHTML.push(''+wrappingTags[i]+'>');
- }
-
- var wrapper = document.createElement('div');
- scriptSafeInnerHTML(wrapper, wrappedHTML.join(''));
- var element = wrapper;
- while (wrappedDepth--) {
- element = element.firstChild;
- while (element && element.nodeType !== 1) {
- element = element.nextSibling;
- }
- }
- while (element && element.tagName !== tagName) {
- element = element.nextSibling;
- }
- return element ? element.childNodes : [];
- }
-
- var buildDOM;
- if (needsShy) {
- buildDOM = function buildDOM(html, contextualElement, dom){
- contextualElement = dom.cloneNode(contextualElement, false);
- scriptSafeInnerHTML(contextualElement, html);
- return contextualElement.childNodes;
- };
- } else {
- buildDOM = function buildDOM(html, contextualElement, dom){
- contextualElement = dom.cloneNode(contextualElement, false);
- contextualElement.innerHTML = html;
- return contextualElement.childNodes;
- };
- }
-
- var buildIESafeDOM;
- if (tagNamesRequiringInnerHTMLFix || movesWhitespace) {
- buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) {
- // Make a list of the leading text on script nodes. Include
- // script tags without any whitespace for easier processing later.
- var spacesBefore = [];
- var spacesAfter = [];
- html = html.replace(/(\s*)(