Skip to content

Commit

Permalink
{{> UI.dynamic }} for easier dynamic template picking.
Browse files Browse the repository at this point in the history
See #2123.
  • Loading branch information
Emily Stark committed May 28, 2014
1 parent b63328c commit bd4a873
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 5 deletions.
22 changes: 17 additions & 5 deletions packages/spacebars-compiler/spacebars-compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,22 @@ var builtInBlockHelpers = {
'each': 'UI.Each'
};

// These must be prefixed with `UI.` when you use them in a template.
var builtInLexicals = {
// Some `UI.*` paths are special in that they generate code that
// doesn't folow the normal lookup rules for dotted symbols. The
// following names must be prefixed with `UI.` when you use them in a
// template.
var builtInUIPaths = {
// `template` is a local variable defined in the generated render
// function for the template in which `UI.contentBlock` (or
// `UI.elseBlock`) is invoked. `template` is a reference to the
// template itself.
'contentBlock': 'template.__content',
'elseBlock': 'template.__elseContent'
'elseBlock': 'template.__elseContent',

// `Template` is the global template namespace. If you define a
// template named `foo` in Spacebars, it gets defined as
// `Template.foo` in JavaScript.
'dynamic': 'Template.__dynamic'
};

// A "reserved name" can't be used as a <template> name. This
Expand Down Expand Up @@ -288,11 +300,11 @@ var codeGenPath = function (path, opts) {
// inclusion or as a block helper, in addition to supporting
// `{{> UI.contentBlock}}`.
if (path.length >= 2 &&
path[0] === 'UI' && builtInLexicals.hasOwnProperty(path[1])) {
path[0] === 'UI' && builtInUIPaths.hasOwnProperty(path[1])) {
if (path.length > 2)
throw new Error("Unexpected dotted path beginning with " +
path[0] + '.' + path[1]);
return builtInLexicals[path[1]];
return builtInUIPaths[path[1]];
}

var args = [toJSLiteral(path[0])];
Expand Down
1 change: 1 addition & 0 deletions packages/ui-dynamic-template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.build*
19 changes: 19 additions & 0 deletions packages/ui-dynamic-template/dynamic-tests.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template name="ui-dynamic-test">
{{> UI.dynamic templateName=templateName dataContext=templateData}}
</template>

<template name="ui-dynamic-test-no-data">
{{> UI.dynamic templateName=templateName}}
</template>

<template name="ui-dynamic-test-inherited-data">
{{#with context}}
{{> UI.dynamic templateName=templateName}}
{{else}}
{{> UI.dynamic templateName=templateName}}
{{/with}}
</template>

<template name="ui-dynamic-test-sub">
test{{foo}}
</template>
87 changes: 87 additions & 0 deletions packages/ui-dynamic-template/dynamic-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copied from spacebars-tests
var renderToDiv = function (comp) {
var div = document.createElement("DIV");
UI.materialize(comp, div);
return div;
};

Tinytest.add(
"ui-dynamic-template - render template dynamically", function (test, expect) {
var tmpl = Template["ui-dynamic-test"];

var rvName = new ReactiveVar;
var rvData = new ReactiveVar;
tmpl.templateName = function () {
return rvName.get();
};
tmpl.templateData = function () {
return rvData.get();
};

// No template chosen
var div = renderToDiv(tmpl);
test.equal(div.innerHTML.trim(), "");

// Choose the "ui-dynamic-test-sub" template, with no data context
// passed in.
rvName.set("ui-dynamic-test-sub");
Deps.flush();
test.equal(div.innerHTML.trim(), "test");

// Set a data context.
rvData.set({ foo: "bar" });
Deps.flush();
test.equal(div.innerHTML.trim(), "testbar");
});

// Same test as above, but the {{> UI.dynamic}} inclusion has no
// `dataContext` argument.
Tinytest.add(
"ui-dynamic-template - render template dynamically, no data context",
function (test, expect) {
var tmpl = Template["ui-dynamic-test-no-data"];

var rvName = new ReactiveVar;
tmpl.templateName = function () {
return rvName.get();
};

var div = renderToDiv(tmpl);
test.equal(div.innerHTML.trim(), "");

rvName.set("ui-dynamic-test-sub");
Deps.flush();
test.equal(div.innerHTML.trim(), "test");
});


Tinytest.add(
"ui-dynamic-template - render template " +
"dynamically, data context gets inherited",
function (test, expect) {
var tmpl = Template["ui-dynamic-test-inherited-data"];

var rvName = new ReactiveVar();
var rvData = new ReactiveVar();
tmpl.templateName = function () {
return rvName.get();
};
tmpl.context = function () {
return rvData.get();
};

var div = renderToDiv(tmpl);
test.equal(div.innerHTML.trim(), "");

rvName.set("ui-dynamic-test-sub");
Deps.flush();
test.equal(div.innerHTML.trim(), "test");

// Set the top-level template's data context; this should be
// inherited by the dynamically-chosen template, since the {{>
// UI.dynamic}} inclusion didn't include a data argument.
rvData.set({ foo: "bar" });
Deps.flush();
test.equal(div.innerHTML.trim(), "testbar");
}
);
18 changes: 18 additions & 0 deletions packages/ui-dynamic-template/dynamic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template name="__dynamicWithDataContext">
{{#with chooseTemplate templateName}}
{{#with ../dataContext}} {{! original 'dataContext' argument to __dynamic}}
{{> ..}} {{! return value from chooseTemplate(templateName) }}
{{else}} {{! if the 'dataContext' argument was falsey }}
{{> .}} {{! return value from chooseTemplate(templateName) }}
{{/with}}
{{/with}}
</template>

<template name="__dynamic">
{{#if dataContext}}
{{> __dynamicWithDataContext}}
{{else}}
{{! if there was no explicit dataContext argument, use the parent context}}
{{> __dynamicWithDataContext templateName=templateName dataContext=..}}
{{/if}}
</template>
3 changes: 3 additions & 0 deletions packages/ui-dynamic-template/dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Template.__dynamicWithDataContext.chooseTemplate = function (name) {
return Template[name] || null;
};
15 changes: 15 additions & 0 deletions packages/ui-dynamic-template/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Package.describe({
summary: "Component for dynamically rendering templates",
internal: true
});

Package.on_use(function (api) {
api.use('templating');
api.add_files(['dynamic.html', 'dynamic.js'], 'client');
});

Package.on_test(function (api) {
api.use(["ui-dynamic-template", "tinytest", "test-helpers"]);
api.use("templating", "client");
api.add_files(["dynamic-tests.html", "dynamic-tests.js"], "client");
});

0 comments on commit bd4a873

Please sign in to comment.