diff --git a/package.json b/package.json index 4e5d5b073b3..f203bd2dd6f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "git-repo-info": "^1.1.4", "git-repo-version": "^0.3.1", "github": "^0.2.3", - "glimmer-engine": "0.11.3", + "glimmer-engine": "0.11.4", "glob": "^5.0.13", "html-differ": "^1.3.4", "mocha": "^2.4.5", diff --git a/packages/ember-glimmer/lib/environment.js b/packages/ember-glimmer/lib/environment.js index 9f73ec3b860..c11f6463f6a 100644 --- a/packages/ember-glimmer/lib/environment.js +++ b/packages/ember-glimmer/lib/environment.js @@ -4,7 +4,8 @@ import { Environment as GlimmerEnvironment, AttributeChangeList, isSafeString, - compileLayout + compileLayout, + getDynamicVar } from 'glimmer-runtime'; import Cache from 'ember-metal/cache'; import { assert, warn, runInDebug } from 'ember-metal/debug'; @@ -108,7 +109,8 @@ export default class Environment extends GlimmerEnvironment { '-each-in': eachIn, '-input-type': inputTypeHelper, '-normalize-class': normalizeClassHelper, - '-html-safe': htmlSafeHelper + '-html-safe': htmlSafeHelper, + '-get-dynamic-var': { glimmerNativeHelper: getDynamicVar } }; } @@ -290,6 +292,8 @@ export default class Environment extends GlimmerEnvironment { return (vm, args) => SimpleHelperReference.create(helper.compute, args); } else if (helper.isHelperFactory) { return (vm, args) => ClassBasedHelperReference.create(helper, vm, args); + } else if (helper.glimmerNativeHelper) { + return helper.glimmerNativeHelper; } else { throw new Error(`${nameParts} is not a helper`); } diff --git a/packages/ember-glimmer/lib/renderer.js b/packages/ember-glimmer/lib/renderer.js index 797b130435e..6537c22636d 100644 --- a/packages/ember-glimmer/lib/renderer.js +++ b/packages/ember-glimmer/lib/renderer.js @@ -38,6 +38,15 @@ class DynamicScope { this.view, this.outletState, this.rootOutletState, this.isTopLevel, this.targetObject ); } + + get(key) { + return this[key]; + } + + set(key, value) { + this[key] = value; + return value; + } } const renderers = []; diff --git a/packages/ember-glimmer/lib/syntax.js b/packages/ember-glimmer/lib/syntax.js index 62d51095a7d..442a47af760 100644 --- a/packages/ember-glimmer/lib/syntax.js +++ b/packages/ember-glimmer/lib/syntax.js @@ -3,6 +3,8 @@ import { OutletSyntax } from './syntax/outlet'; import { MountSyntax } from './syntax/mount'; import { DynamicComponentSyntax } from './syntax/dynamic-component'; import { InputSyntax } from './syntax/input'; +import { WithDynamicVarsSyntax } from 'glimmer-runtime'; + let syntaxKeys = []; let syntaxes = []; @@ -25,3 +27,8 @@ registerSyntax('outlet', OutletSyntax); registerSyntax('mount', MountSyntax); registerSyntax('component', DynamicComponentSyntax); registerSyntax('input', InputSyntax); +registerSyntax('-with-dynamic-vars', class { + static create(environment, args, templates, symbolTable) { + return new WithDynamicVarsSyntax({ args, templates }); + } +}); diff --git a/packages/ember-glimmer/lib/syntax/outlet.js b/packages/ember-glimmer/lib/syntax/outlet.js index 18ed05562c3..cf3d8d56834 100644 --- a/packages/ember-glimmer/lib/syntax/outlet.js +++ b/packages/ember-glimmer/lib/syntax/outlet.js @@ -88,7 +88,7 @@ class OutletComponentReference { let outletName = outletNameRef.value(); - let outletStateRef = parentOutletStateRef.get(outletName); + let outletStateRef = parentOutletStateRef.get('outlets').get(outletName); let newState = this.lastState = outletStateRef.value(); this.outletStateTag.update(outletStateRef.tag); @@ -201,7 +201,7 @@ const TOP_LEVEL_MANAGER = new TopLevelOutletComponentManager(); class OutletComponentManager extends AbstractOutletComponentManager { create(definition, args, dynamicScope) { - let outletStateReference = dynamicScope.outletState = dynamicScope.outletState.get(definition.outletName); + let outletStateReference = dynamicScope.outletState = dynamicScope.outletState.get('outlets').get(definition.outletName); let outletState = outletStateReference.value(); dynamicScope.targetObject = outletState.render.controller; return new StateBucket(outletState); diff --git a/packages/ember-glimmer/lib/views/outlet.js b/packages/ember-glimmer/lib/views/outlet.js index 86b6cf2a420..b1c8f2ec843 100644 --- a/packages/ember-glimmer/lib/views/outlet.js +++ b/packages/ember-glimmer/lib/views/outlet.js @@ -79,7 +79,7 @@ class ChildOutletStateReference { } value() { - return this.parent.value().outlets[this.key]; + return this.parent.value()[this.key]; } get isTopLevel() { diff --git a/packages/ember-glimmer/tests/integration/outlet-test.js b/packages/ember-glimmer/tests/integration/outlet-test.js index 590ec6353a9..0afca2b89ec 100644 --- a/packages/ember-glimmer/tests/integration/outlet-test.js +++ b/packages/ember-glimmer/tests/integration/outlet-test.js @@ -278,4 +278,50 @@ moduleFor('outlet view', class extends RenderingTest { this.assertText('HIBAR'); } + + ['@test outletState can pass through user code (liquid-fire initimate API) ']() { + this.registerTemplate('outer', 'A{{#-with-dynamic-vars outletState=(identity (-get-dynamic-var "outletState"))}}B{{outlet}}D{{/-with-dynamic-vars}}E'); + this.registerTemplate('inner', 'C'); + + // This looks like it doesn't do anything, but its presence + // guarantees that the outletState gets converted from a reference + // to a value and then back to a reference. That is what we're + // testing here. + this.registerHelper('identity', ([a]) => a); + + let outletState = { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'outer', + controller: {}, + ViewClass: undefined, + template: this.owner.lookup('template:outer') + }, + outlets: { + main: { + render: { + owner: this.owner, + into: undefined, + outlet: 'main', + name: 'inner', + controller: {}, + ViewClass: undefined, + template: this.owner.lookup('template:inner') + }, + outlets: Object.create(null) + } + } + }; + + this.runTask(() => this.component.setOutletState({ render: {}, outlets: { main: outletState } }) ); + + runAppend(this.component); + + this.assertText('ABCDE'); + + this.assertStableRerender(); + } + });