Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maintain childViews array. #11211

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/morphs/attr-morph.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export var styleWarning = '' +

function EmberAttrMorph(element, attrName, domHelper, namespace) {
HTMLBarsAttrMorph.call(this, element, attrName, domHelper, namespace);

this.streamUnsubscribers = null;
this.isAttrMorph = true;
}

var proto = EmberAttrMorph.prototype = o_create(HTMLBarsAttrMorph.prototype);
Expand Down
1 change: 1 addition & 0 deletions packages/ember-htmlbars/lib/morphs/morph.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let guid = 1;
function EmberMorph(DOMHelper, contextualElement) {
this.HTMLBarsMorph$constructor(DOMHelper, contextualElement);

this.isElementMorph = true;
this.emberView = null;
this.emberToDestroy = null;
this.streamUnsubscribers = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ ViewNodeManager.create = function(renderNode, env, attrs, found, parentView, pat
} else {
componentInfo.layout = getTemplate(component) || componentInfo.layout;
}

renderNode.emberView = component;
}

Ember.assert("BUG: ViewNodeManager.create can take a scope or a self, but not both", !(contentScope && found.self));
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/tests/helpers/collection_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ var TemplateTests, registry, container, lookup;


function nthChild(view, nth) {
return get(view, 'childViews').objectAt(nth || 0);
return get(view, 'childViews')[nth || 0];
}

var firstChild = nthChild;

function firstGrandchild(view) {
return get(get(view, 'childViews').objectAt(0), 'childViews').objectAt(0);
return get(get(view, 'childViews')[0], 'childViews')[0];
}

QUnit.module("collection helper", {
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/tests/helpers/each_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ QUnit.test("it supports itemController", function() {

assertText(view, "controller:Trek Glowackicontroller:Geoffrey Grosenbach");

strictEqual(view.childViews[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly");
strictEqual(get(view, 'childViews')[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly");
});

QUnit.test("itemController should not affect the DOM structure", function() {
Expand Down Expand Up @@ -1044,7 +1044,7 @@ function testEachWithItem(moduleName, useBlockParams) {

assertText(view, "controller:parentController - controller:Trek Glowacki - controller:parentController - controller:Geoffrey Grosenbach - ");

strictEqual(view.childViews[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly");
strictEqual(get(view, 'childViews')[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly");
});

QUnit.test("itemController specified in ArrayController with name binding does not change context", function() {
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/tests/helpers/input_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ QUnit.test("cursor position is not lost when updating content", function() {
// set the cursor position to 3 (no selection)
run(function() {
input.value = 'derp';
view.childViews[0]._elementValueDidChange();
view.get('childViews')[0]._elementValueDidChange();
input.selectionStart = 3;
input.selectionEnd = 3;
});
Expand Down
8 changes: 4 additions & 4 deletions packages/ember-htmlbars/tests/helpers/view_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ var view, originalLookup, registry, container, lookup;
var trim = jQuery.trim;

function firstGrandchild(view) {
return get(get(view, 'childViews').objectAt(0), 'childViews').objectAt(0);
return get(get(view, 'childViews')[0], 'childViews')[0];
}

function nthChild(view, nth) {
return get(view, 'childViews').objectAt(nth || 0);
return get(view, 'childViews')[nth || 0];
}

function viewClass(options) {
Expand Down Expand Up @@ -715,7 +715,7 @@ QUnit.test('Template views add an elementId to child views created using the vie

runAppend(view);

var childView = get(view, 'childViews.firstObject');
var childView = get(view, 'childViews')[0];
equal(view.$().children().first().children().first().attr('id'), get(childView, 'elementId'));
});

Expand Down Expand Up @@ -1157,7 +1157,7 @@ QUnit.test('should expose a controller keyword that persists through Ember.Conta

runAppend(view);

var containerView = get(view, 'childViews.firstObject');
var containerView = get(view, 'childViews')[0];
var viewInstanceToBeInserted = EmberView.create({
template: compile('{{controller.foo}}')
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ QUnit.test('willDestroyElement is only called once when a component leaves scope
runAppend(component);

assert.equal(component.$().text(), 'Truthy', 'precond - truthy template is displayed');
assert.equal(component.get('childViews.length'), 1);

run(function() {
set(component, 'switch', false);
Expand Down
5 changes: 5 additions & 0 deletions packages/ember-metal-views/lib/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Renderer.prototype.dispatchLifecycleHooks =
}

this.didRender(hook.view);
this.internalDidRender(hook.view);
}

ownerView._dispatching = null;
Expand Down Expand Up @@ -159,6 +160,10 @@ Renderer.prototype.didRender = function (view) {
if (view.trigger) { view.trigger('didRender'); }
};

Renderer.prototype.internalDidRender = function (view) {
if (view.trigger) { view.trigger('_internalDidRender'); }
};

Renderer.prototype.updateAttrs = function (view, attrs) {
this.setAttrs(view, attrs);
}; // setting new attrs
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-views/lib/mixins/legacy_view_support.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ var LegacyViewSupport = Mixin.create({
afterRender(buffer) {},

walkChildViews(callback) {
var childViews = this.childViews.slice();
var childViews = get(this, 'childViews').slice();

while (childViews.length) {
var view = childViews.pop();
callback(view);
childViews.push(...view.childViews);
childViews.push(...get(view, 'childViews'));
}
},

Expand Down
52 changes: 37 additions & 15 deletions packages/ember-views/lib/mixins/view_child_views_support.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
*/
import Ember from 'ember-metal/core';
import { Mixin } from "ember-metal/mixin";
import { removeObject } from "ember-metal/enumerable_utils";
import { get } from "ember-metal/property_get";
import { set } from "ember-metal/property_set";
import setProperties from "ember-metal/set_properties";

var EMPTY_ARRAY = [];
import { computed } from "ember-metal/computed";

var ViewChildViewsSupport = Mixin.create({
/**
Expand All @@ -21,20 +18,44 @@ var ViewChildViewsSupport = Mixin.create({
@default []
@private
*/
childViews: EMPTY_ARRAY,
childViews: computed(function() {

if (!this._renderNode || !this._renderNode.childNodes) {
return Ember.A();
}

let currentElementMorph, index, length;
let childNodes = this._renderNode.childNodes;

for (index = 0, length = this._renderNode.childNodes.length; index < length; index++) {
let node = childNodes[index];
if (node.isElementMorph) {
currentElementMorph = node;
break;
}
}

var childViews = [];
if (currentElementMorph.childNodes) {
for (index = 0, length = currentElementMorph.childNodes.length; index < length; index++) {
let node = currentElementMorph.childNodes[index];

if (node.isElementMorph && node.emberView) {
childViews.push(node.emberView);
}
}
}

return childViews;
}),

init() {
this._super(...arguments);

// setup child views. be sure to clone the child views array first
// 2.0TODO: Remove Ember.A() here
this.childViews = Ember.A(this.childViews.slice());
this.ownerView = this;
},

appendChild(view) {
this.linkChild(view);
this.childViews.push(view);
},

destroyChild(view) {
Expand All @@ -58,11 +79,6 @@ var ViewChildViewsSupport = Mixin.create({
// update parent node
this.unlinkChild(view);

// remove view from childViews array.
var childViews = get(this, 'childViews');

removeObject(childViews, view);

return this;
},

Expand Down Expand Up @@ -131,6 +147,12 @@ var ViewChildViewsSupport = Mixin.create({
unlinkChild(instance) {
set(instance, 'parentView', null);
instance.trigger('parentViewDidChange');
},

_internalDidRender() {
this._super(...arguments);

this.notifyPropertyChange('childViews');
}
});

Expand Down
24 changes: 20 additions & 4 deletions packages/ember-views/lib/views/container_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
beforeObserver
} from "ember-metal/mixin";
import { on } from "ember-metal/events";
import { indexOf } from "ember-metal/array";

import containerViewTemplate from "ember-htmlbars/templates/container-view";
containerViewTemplate.meta.revision = 'Ember@VERSION_STRING_PLACEHOLDER';
Expand Down Expand Up @@ -178,6 +179,8 @@ var ContainerView = View.extend(MutableArray, {
);
},

childViews: [],

init() {
this._super(...arguments);

Expand All @@ -187,7 +190,7 @@ var ContainerView = View.extend(MutableArray, {
// redefine view's childViews property that was obliterated
// 2.0TODO: Don't Ember.A() this so users disabling prototype extensions
// don't pay a penalty.
var childViews = this.childViews = Ember.A([]);
var childViews = this.childViews = [];

forEach(userChildViews, function(viewName, idx) {
var view;
Expand All @@ -205,7 +208,7 @@ var ContainerView = View.extend(MutableArray, {

var currentView = get(this, 'currentView');
if (currentView) {
if (!childViews.length) { childViews = this.childViews = Ember.A(this.childViews.slice()); }
if (!childViews.length) { childViews = this.childViews = this.childViews.slice(); }
childViews.push(this.createChildView(currentView));
}

Expand Down Expand Up @@ -242,9 +245,19 @@ var ContainerView = View.extend(MutableArray, {

layout: containerViewTemplate,

removeChild(childView) {
if (!this.isDestroyed) {
var idx = indexOf.call(this.childViews, childView);
if (idx !== -1) {
this.replace(idx, 1);
}
}
return this._super(childView);
},

replace(idx, removedCount, addedViews=[]) {
var addedCount = get(addedViews, 'length');
var childViews = get(this, 'childViews');
var childViews = this.childViews;

Ember.assert("You can't add a child to a container - the child is already a child of another view", () => {
for (var i=0, l=addedViews.length; i<l; i++) {
Expand Down Expand Up @@ -300,7 +313,10 @@ var ContainerView = View.extend(MutableArray, {
this.renderer.didDestroyElement(childViews[i]);
}
}
})
}),

// override default hook which notifies `childViews` property
_internalDidRender() { }
});

export default ContainerView;
15 changes: 0 additions & 15 deletions packages/ember-views/lib/views/states/in_dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,7 @@ merge(inDOM, {

exit(view) {
view._unregister();
},

appendAttr(view, attrNode) {
var childViews = view.childViews;

if (!childViews.length) { childViews = view.childViews = childViews.slice(); }
childViews.push(attrNode);

attrNode.parentView = view;
view.renderer.appendAttrTo(attrNode, view.element, attrNode.attrName);

view.propertyDidChange('childViews');

return attrNode;
}

});

export default inDOM;
2 changes: 1 addition & 1 deletion packages/ember-views/lib/views/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ var View = CoreView.extend(
},

forEachChildView(callback) {
var childViews = this.childViews;
var childViews = get(this, 'childViews');

if (!childViews) { return this; }

Expand Down
2 changes: 1 addition & 1 deletion packages/ember-views/tests/views/select_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function append() {
}

function selectedOptions() {
return select.get('childViews').mapBy('selected');
return Ember.A(select.get('childViews')).mapBy('selected');
}

QUnit.test('using the Ember.Select global is deprecated', function(assert) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ QUnit.test("if it has a element, calls willDestroyElement on receiver and child
equal(parentCount, 1, 'invoked destroy element on the parent');
equal(childCount, 1, 'invoked destroy element on the child');
ok(!get(view, 'element'), 'view no longer has element');
ok(!get(get(view, 'childViews').objectAt(0), 'element'), 'child no longer has an element');
ok(!get(get(view, 'childViews')[0], 'element'), 'child no longer has an element');
});

QUnit.test("returns receiver", function() {
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-views/tests/views/view/element_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ QUnit.test("returns null if the view has no element and parent view has no eleme
parentView = ContainerView.create({
childViews: [EmberView.extend()]
});
view = get(parentView, 'childViews').objectAt(0);
view = get(parentView, 'childViews')[0];

equal(get(view, 'parentView'), parentView, 'precond - has parent view');
equal(get(parentView, 'element'), null, 'parentView has no element');
Expand Down
5 changes: 2 additions & 3 deletions packages/ember-views/tests/views/view/is_visible_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ QUnit.test("view should be notified after isVisible is set to false and the elem

QUnit.test("view should be notified after isVisible is set to false and the element has been hidden", function() {
view = View.create({ isVisible: true });
//var childView = view.get('childViews').objectAt(0);

run(function() {
view.append();
Expand Down Expand Up @@ -237,7 +236,7 @@ QUnit.test("view should be notified after isVisible is set to true and the eleme

QUnit.test("if a view descends from a hidden view, making isVisible true should not trigger becameVisible", function() {
view = View.create({ isVisible: true });
var childView = view.get('childViews').objectAt(0);
var childView = view.get('childViews')[0];

run(function() {
view.append();
Expand Down Expand Up @@ -266,7 +265,7 @@ QUnit.test("if a view descends from a hidden view, making isVisible true should

QUnit.test("if a child view becomes visible while its parent is hidden, if its parent later becomes visible, it receives a becameVisible callback", function() {
view = View.create({ isVisible: false });
var childView = view.get('childViews').objectAt(0);
var childView = view.get('childViews')[0];

run(function() {
view.append();
Expand Down
Loading