Skip to content

Commit

Permalink
Support for {{yield to="inverse"}}
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 committed May 11, 2015
1 parent fd3d54d commit c564be6
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"express": "^4.5.0",
"github": "^0.2.3",
"glob": "~4.3.2",
"htmlbars": "0.13.16",
"htmlbars": "0.13.17",
"qunit-extras": "^1.3.0",
"qunitjs": "^1.16.0",
"route-recognizer": "0.1.5",
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/lib/hooks/component.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ComponentNodeManager from "ember-htmlbars/node-managers/component-node-manager";

export default function componentHook(renderNode, env, scope, tagName, params, attrs, template, visitor) {
export default function componentHook(renderNode, env, scope, tagName, params, attrs, templates, visitor) {
var state = renderNode.state;

// Determine if this is an initial render or a re-render
Expand All @@ -17,7 +17,7 @@ export default function componentHook(renderNode, env, scope, tagName, params, a
params,
attrs,
parentView,
template,
templates,
parentScope: scope
});

Expand Down
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/hooks/create-fresh-scope.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default function createFreshScope() {
return {
self: null,
block: null,
blocks: {},
component: null,
view: null,
attrs: null,
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/lib/hooks/get-root.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export default function getRoot(scope, key) {
if (key === 'this') {
return [scope.self];
} else if (key === 'hasBlock') {
return [!!scope.block];
return [!!scope.blocks.default];
} else if (key === 'hasBlockParams') {
return [!!(scope.block && scope.block.arity)];
return [!!(scope.blocks.default && scope.blocks.default.arity)];
} else if (isGlobal(key) && Ember.lookup[key]) {
return [getGlobal(key)];
} else if (scope.locals[key]) {
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/keywords/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ function render(morph, env, scope, params, hash, template, inverse, visitor) {
return;
}

env.hooks.component(morph, env, scope, componentPath, params, hash, template, visitor);
env.hooks.component(morph, env, scope, componentPath, params, hash, { default: template, inverse }, visitor);
}
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/keywords/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default {
},

render(morph, env, scope, params, hash, template, inverse, visitor) {
env.hooks.component(morph, env, scope, morph.state.componentName, params, hash, template, visitor);
env.hooks.component(morph, env, scope, morph.state.componentName, params, hash, { default: template, inverse }, visitor);
},

rerender(...args) {
Expand Down
6 changes: 3 additions & 3 deletions packages/ember-htmlbars/lib/keywords/legacy-yield.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ProxyStream from "ember-metal/streams/proxy-stream";
export default function legacyYield(morph, env, _scope, params, hash, template, inverse, visitor) {
let scope = _scope;

if (scope.block.arity === 0) {
if (scope.blocks.default.arity === 0) {
// Typically, the `controller` local is persists through lexical scope.
// However, in this case, the `{{legacy-yield}}` in the legacy each view
// needs to override the controller local for the template it is yielding.
Expand All @@ -14,9 +14,9 @@ export default function legacyYield(morph, env, _scope, params, hash, template,
scope.locals.controller = new ProxyStream(hash.controller, "controller");
scope.overrideController = true;
}
scope.block(env, [], params[0], morph, scope, visitor);
scope.blocks.default(env, [], params[0], morph, scope, visitor);
} else {
scope.block(env, params, undefined, morph, scope, visitor);
scope.blocks.default(env, params, undefined, morph, scope, visitor);
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/keywords/textarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
*/

export default function textarea(morph, env, scope, originalParams, hash, template, inverse, visitor) {
env.hooks.component(morph, env, scope, '-text-area', originalParams, hash, template, visitor);
env.hooks.component(morph, env, scope, '-text-area', originalParams, hash, { default: template, inverse }, visitor);
return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ComponentNodeManager.create = function(renderNode, env, options) {
attrs,
parentView,
parentScope,
template } = options;
templates } = options;

attrs = attrs || {};

Expand Down Expand Up @@ -80,9 +80,9 @@ ComponentNodeManager.create = function(renderNode, env, options) {

// There is no block template provided but the component has a
// `template` property.
if (!template && componentTemplate) {
if ((!templates || !templates.default) && componentTemplate) {
Ember.deprecate("Using deprecated `template` property on a Component.");
template = componentTemplate.raw;
templates = { default: componentTemplate.raw };
}
} else if (componentTemplate) {
// If the component has a `template` but no `layout`, use the template
Expand All @@ -105,7 +105,7 @@ ComponentNodeManager.create = function(renderNode, env, options) {
}

var results = buildComponentTemplate({ layout: layout, component: component }, attrs, {
template: template,
templates,
scope: parentScope
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ ViewNodeManager.create = function(renderNode, env, attrs, found, parentView, pat
Ember.assert("BUG: ViewNodeManager.create can take a scope or a self, but not both", !(contentScope && found.self));

var results = buildComponentTemplate(componentInfo, attrs, {
template: contentTemplate,
templates: { default: contentTemplate },
scope: contentScope,
self: found.self
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,88 @@ if (Ember.FEATURES.isEnabled('ember-htmlbars-component-helper')) {
equal(jQuery('#qunit-fixture').text(), 'Edward5');
});
}

QUnit.test('yield to inverse', function() {
registry.register('template:components/my-if', compile('{{#if predicate}}Yes:{{yield someValue}}{{else}}No:{{yield to="inverse"}}{{/if}}'));

view = EmberView.extend({
layout: compile('{{#my-if predicate=activated someValue=42 as |result|}}Hello{{result}}{{else}}Goodbye{{/my-if}}'),
container: container,
context: {
activated: true
}
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture').text(), 'Yes:Hello42');
run(function() {
Ember.set(view.context, 'activated', false);
});

equal(jQuery('#qunit-fixture').text(), 'No:Goodbye');
});

QUnit.test('parameterized hasBlock inverse', function() {
registry.register('template:components/check-inverse', compile('{{#if (hasBlock "inverse")}}Yes{{else}}No{{/if}}'));

view = EmberView.extend({
layout: compile('{{#check-inverse id="expect-no"}}{{/check-inverse}} {{#check-inverse id="expect-yes"}}{{else}}{{/check-inverse}}'),
container: container
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture #expect-no').text(), 'No');
equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes');
});

QUnit.test('parameterized hasBlock default', function() {
registry.register('template:components/check-block', compile('{{#if (hasBlock)}}Yes{{else}}No{{/if}}'));

view = EmberView.extend({
layout: compile('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}'),
container: container
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture #expect-no').text(), 'No');
equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes');
});

QUnit.test('non-expression hasBlock ', function() {
registry.register('template:components/check-block', compile('{{#if hasBlock}}Yes{{else}}No{{/if}}'));

view = EmberView.extend({
layout: compile('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}'),
container: container
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture #expect-no').text(), 'No');
equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes');
});

QUnit.test('parameterized hasBlockParams', function() {
registry.register('template:components/check-params', compile('{{#if (hasBlockParams)}}Yes{{else}}No{{/if}}'));

view = EmberView.extend({
layout: compile('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}'),
container: container
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture #expect-no').text(), 'No');
equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes');
});

QUnit.test('non-expression hasBlockParams', function() {
registry.register('template:components/check-params', compile('{{#if hasBlockParams}}Yes{{else}}No{{/if}}'));

view = EmberView.extend({
layout: compile('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}'),
container: container
}).create();

runAppend(view);
equal(jQuery('#qunit-fixture #expect-no').text(), 'No');
equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes');
});
2 changes: 1 addition & 1 deletion packages/ember-metal-views/lib/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Renderer.prototype.prerenderTopLevelView =

var block = buildComponentTemplate(componentInfo, {}, {
self: view,
template: template && template.raw
templates: template ? { default: template.raw } : undefined
}).block;

view.renderBlock(block, renderNode);
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-routing-htmlbars/lib/keywords/link-to.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ export default {

attrs.escaped = !morph.parseTextAsHTML;

env.hooks.component(morph, env, scope, '-link-to', params, attrs, template, visitor);
env.hooks.component(morph, env, scope, '-link-to', params, attrs, { default: template }, visitor);
},

rerender(morph, env, scope, params, hash, template, inverse, visitor) {
Expand Down
29 changes: 22 additions & 7 deletions packages/ember-views/lib/system/build-component-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ export default function buildComponentTemplate({ component, layout }, attrs, con
component = null;
}

if (content.template) {
meta = content.template.meta;
blockToRender = createContentBlock(content.template, content.scope, content.self, component);
}

if (layout && layout.raw) {
let yieldTo = createContentBlocks(content.templates, content.scope, content.self, component);
blockToRender = createLayoutBlock(layout.raw, yieldTo, content.self, component, attrs);
meta = layout.raw.meta;
blockToRender = createLayoutBlock(layout.raw, blockToRender, content.self, component, attrs);
} else if (content.templates && content.templates.default) {
blockToRender = createContentBlock(content.templates.default, content.scope, content.self, component);
meta = content.templates.default.meta;
}

if (component) {
Expand Down Expand Up @@ -59,9 +58,25 @@ function createContentBlock(template, scope, self, component) {
});
}

function createContentBlocks(templates, scope, self, component) {
if (!templates) {
return;
}
var output = {};
for (var name in templates) {
if (templates.hasOwnProperty(name)) {
var template = templates[name];
if (template) {
output[name] = createContentBlock(templates[name], scope, self, component);
}
}
}
return output;
}

function createLayoutBlock(template, yieldTo, self, component, attrs) {
return blockFor(template, {
yieldTo: yieldTo,
yieldTo,

// If we have an old-style Controller with a template it will be
// passed as our `self` argument, and it should be the context for
Expand Down

0 comments on commit c564be6

Please sign in to comment.