Skip to content

Commit

Permalink
Implement remaining lifecycle hooks
Browse files Browse the repository at this point in the history
The original implementation of the hooks in HTMLBars does a deeper walk
than necessary (using the AlwaysDirty validator), resulting in executing
the experimental "new hooks" too often.

In particular, hooks were executed downstream from the original call to
`rerender()` even if the rerendering component did not use `this.set()`
to update the arguments of downstream components.

Because Glimmer uses a pull-based model instead of a blunt push-based
model, we can avoid a deeper traversal than is necessary.
  • Loading branch information
Godhuda committed Apr 29, 2016
1 parent 168a72a commit 1581583
Show file tree
Hide file tree
Showing 12 changed files with 635 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"express": "^4.5.0",
"finalhandler": "^0.4.0",
"github": "^0.2.3",
"glimmer-engine": "tildeio/glimmer#591a188",
"glimmer-engine": "tildeio/glimmer#2c22999",
"glob": "^5.0.13",
"htmlbars": "0.14.16",
"mocha": "^2.4.5",
Expand Down
55 changes: 35 additions & 20 deletions packages/ember-glimmer/lib/components/curly-component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { StatementSyntax, ValueReference } from 'glimmer-runtime';
import { AttributeBindingReference, RootReference, applyClassNameBinding } from '../utils/references';
import { DIRTY_TAG } from '../ember-views/component';
import EmptyObject from 'ember-metal/empty_object';

export class CurlyComponentSyntax extends StatementSyntax {
Expand All @@ -19,7 +20,7 @@ export class CurlyComponentSyntax extends StatementSyntax {
function attrsToProps(keys, attrs) {
let merged = new EmptyObject();

merged.attrs = merged;
merged.attrs = attrs;

for (let i = 0, l = keys.length; i < l; i++) {
let name = keys[i];
Expand All @@ -32,9 +33,10 @@ function attrsToProps(keys, attrs) {
}

class ComponentStateBucket {
constructor(component) {
constructor(component, args) {
this.component = component;
this.classRef = null;
this.argsRevision = args.tag.value();
}
}

Expand All @@ -46,17 +48,19 @@ class CurlyComponentManager {
let attrs = args.named.value();
let props = attrsToProps(args.named.keys, attrs);

props.renderer = parentView.renderer;

let component = klass.create(props);

dynamicScope.view = component;
parentView.appendChild(component);

// component.trigger('didInitAttrs', { attrs });
// component.trigger('didReceiveAttrs', { newAttrs: attrs });
// component.trigger('willInsertElement');
// component.trigger('willRender');
component.trigger('didInitAttrs', { attrs });
component.trigger('didReceiveAttrs', { newAttrs: attrs });
component.trigger('willInsertElement');
component.trigger('willRender');

let bucket = new ComponentStateBucket(component);
let bucket = new ComponentStateBucket(component, args);

if (args.named.has('class')) {
bucket.classRef = args.named.get('class');
Expand Down Expand Up @@ -99,30 +103,41 @@ class CurlyComponentManager {
component._transitionTo('hasElement');
}

getTag({ component }) {
return component[DIRTY_TAG];
}

didCreate({ component }) {
component.trigger('didInsertElement');
// component.trigger('didRender');
component.trigger('didRender');
component._transitionTo('inDOM');
}

update({ component }, args, dynamicScope) {
let attrs = args.named.value();
let props = attrsToProps(args.named.keys, attrs);
update(bucket, args, dynamicScope) {
let { component, argsRevision } = bucket;

// let oldAttrs = component.attrs;
// let newAttrs = attrs;
if (!args.tag.validate(argsRevision)) {
bucket.argsRevision = args.tag.value();

component.setProperties(props);
let attrs = args.named.value();
let props = attrsToProps(args.named.keys, attrs);

let oldAttrs = component.attrs;
let newAttrs = attrs;

component.setProperties(props);

component.trigger('didUpdateAttrs', { oldAttrs, newAttrs });
component.trigger('didReceiveAttrs', { oldAttrs, newAttrs });
}

// component.trigger('didUpdateAttrs', { oldAttrs, newAttrs });
// component.trigger('didReceiveAttrs', { oldAttrs, newAttrs });
// component.trigger('willUpdate');
// component.trigger('willRender');
component.trigger('willUpdate');
component.trigger('willRender');
}

didUpdate({ component }) {
// component.trigger('didUpdate');
// component.trigger('didRender');
component.trigger('didUpdate');
component.trigger('didRender');
}

getDestructor({ component }) {
Expand Down
4 changes: 4 additions & 0 deletions packages/ember-glimmer/lib/components/outlet.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ class AbstractOutletComponentManager {
return new RootReference(state.render.controller);
}

getTag(state) {
return null;
}

getDestructor(state) {
return null;
}
Expand Down
9 changes: 8 additions & 1 deletion packages/ember-glimmer/lib/ember-metal-views/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,15 @@ class Renderer {
}

remove(view) {
view.trigger('willDestroyElement');
view._transitionTo('destroying');
view['_renderResult'].destroy();

let { _renderResult } = view;

if (_renderResult) {
_renderResult.destroy();
}

view.destroy();
}

Expand Down
10 changes: 10 additions & 0 deletions packages/ember-glimmer/lib/ember-views/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import InstrumentationSupport from 'ember-views/mixins/instrumentation_support';
import AriaRoleSupport from 'ember-views/mixins/aria_role_support';
import ViewMixin from 'ember-views/mixins/view_support';
import EmberView from 'ember-views/views/view';
import symbol from 'ember-metal/symbol';
import { DirtyableTag } from 'glimmer-reference';

export const DIRTY_TAG = symbol('DIRTY_TAG');

export default CoreView.extend(
ChildViewsSupport,
Expand All @@ -22,6 +26,12 @@ export default CoreView.extend(
init() {
this._super(...arguments);
this._viewRegistry = this._viewRegistry || EmberView.views;
this[DIRTY_TAG] = new DirtyableTag();
},

rerender() {
this[DIRTY_TAG].dirty();
this._super();
},

__defineNonEnumerable(property) {
Expand Down
9 changes: 8 additions & 1 deletion packages/ember-glimmer/lib/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import { default as get } from './helpers/get';
import { default as hash } from './helpers/hash';
import { default as loc } from './helpers/loc';
import { default as log } from './helpers/log';
import { default as classHelper } from './helpers/-class';
import { default as readonly } from './helpers/readonly';
import { default as unbound } from './helpers/unbound';
import { default as classHelper } from './helpers/-class';
import { OWNER } from 'container/owner';

const builtInHelpers = {
Expand All @@ -38,6 +39,7 @@ const builtInHelpers = {
hash,
loc,
log,
readonly,
unbound,
'-class': classHelper
};
Expand Down Expand Up @@ -163,6 +165,11 @@ export default class Environment extends GlimmerEnvironment {
return createIterable(ref, keyPath);
}

didCreate(component, manager) {
this.createdComponents.unshift(component);
this.createdManagers.unshift(manager);
}

didDestroy(destroyable) {
destroyable.destroy();
}
Expand Down
7 changes: 7 additions & 0 deletions packages/ember-glimmer/lib/helpers/readonly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { helper } from '../helper';

function readonly(args) {
return args[0];
}

export default helper(readonly);
Loading

0 comments on commit 1581583

Please sign in to comment.