diff --git a/packages/html/parse.js b/packages/html/parse.js
index 1c27e6f898..dd8f872f2d 100644
--- a/packages/html/parse.js
+++ b/packages/html/parse.js
@@ -210,9 +210,8 @@ getRCData = function (scanner, tagName, shouldStopFunc) {
} else if (token.t === 'CharRef') {
items.push(convertCharRef(token));
} else if (token.t === 'Special') {
- scanner.fatal("NOT IMPLEMENTED: Can't have template tags in " + tagName);
// token.v is an object `{ ... }`
- //items.push(HTML.Special(token.v));
+ items.push(HTML.Special(token.v));
} else {
// (can't happen)
scanner.fatal("Unknown or unexpected token type: " + token.t);
diff --git a/packages/htmljs/html.js b/packages/htmljs/html.js
index 833e92f73d..15a0fc9523 100644
--- a/packages/htmljs/html.js
+++ b/packages/htmljs/html.js
@@ -52,25 +52,29 @@ var extendAttrs = function (tgt, src, parentComponent) {
}
};
-HTML.Tag.prototype.evaluateDynamicAttributes = function (parentComponent) {
- if (this.attrs && (this.attrs.$dynamic instanceof Array)) {
- var attrs = {};
- extendAttrs(attrs, this.attrs, parentComponent);
- // iterate over this.attrs.$dynamic, calling each element if it
- // is a function and then using it to extend `attrs`.
- var dynamics = this.attrs.$dynamic;
+HTML.evaluateDynamicAttributes = function (attrs, parentComponent) {
+ if (attrs && (attrs.$dynamic instanceof Array)) {
+ var result = {};
+ extendAttrs(result, attrs, parentComponent);
+ // iterate over attrs.$dynamic, calling each element if it
+ // is a function and then using it to extend `result`.
+ var dynamics = attrs.$dynamic;
for (var i = 0; i < dynamics.length; i++) {
var moreAttrs = dynamics[i];
if (typeof moreAttrs === 'function')
moreAttrs = moreAttrs();
- extendAttrs(attrs, moreAttrs, parentComponent);
+ extendAttrs(result, moreAttrs, parentComponent);
}
- return attrs;
+ return result;
} else {
- return this.attrs;
+ return attrs;
}
};
+HTML.Tag.prototype.evaluateDynamicAttributes = function (parentComponent) {
+ return HTML.evaluateDynamicAttributes(this.attrs, parentComponent);
+};
+
// Given "P" create the function `HTML.P`.
var makeTagConstructor = function (tagName) {
// Do a little dance so that tags print nicely in the Chrome console.
diff --git a/packages/spacebars-tests/template_tests.html b/packages/spacebars-tests/template_tests.html
index bd051a6904..185d19ea72 100644
--- a/packages/spacebars-tests/template_tests.html
+++ b/packages/spacebars-tests/template_tests.html
@@ -235,3 +235,7 @@
{{#constant}}hello{{/constant}}
+
+
+
+
diff --git a/packages/spacebars-tests/template_tests.js b/packages/spacebars-tests/template_tests.js
index 74406c2746..e4f0a4f81a 100644
--- a/packages/spacebars-tests/template_tests.js
+++ b/packages/spacebars-tests/template_tests.js
@@ -668,3 +668,23 @@ Tinytest.add('spacebars - templates - constant', function (test) {
test.equal(canonicalizeHtml(div.innerHTML), 'hello');
});
+
+Tinytest.add('spacebars - templates - textarea', function (test) {
+ var tmpl = Template.spacebars_template_test_textarea;
+
+ var R = ReactiveVar('hello');
+
+ tmpl.foo = function () {
+ return R.get();
+ };
+
+ debugger;
+ var div = renderToDiv(tmpl);
+ var textarea = div.querySelector('textarea');
+ test.equal(textarea.value, 'hello');
+
+ R.set('world');
+ Deps.flush();
+ test.equal(textarea.value, 'world');
+
+});
diff --git a/packages/spacebars/compile_tests.js b/packages/spacebars/compile_tests.js
index fd2ef8631b..8ec14dc262 100644
--- a/packages/spacebars/compile_tests.js
+++ b/packages/spacebars/compile_tests.js
@@ -233,4 +233,12 @@ Tinytest.add("spacebars - compiler output", function (test) {
});
});
+ run("",
+ function () {
+ var self = this;
+ return HTML.TEXTAREA(function () {
+ return Spacebars.mustache(self.lookup("foo"));
+ });
+ });
+
});
diff --git a/packages/ui/attrs.js b/packages/ui/attrs.js
index b6b4a507f5..5f3f2b83fd 100644
--- a/packages/ui/attrs.js
+++ b/packages/ui/attrs.js
@@ -74,25 +74,34 @@ var ClassHandler = AttributeHandler.extend({
}
});
-var SelectedHandler = AttributeHandler.extend({
+var BooleanHandler = AttributeHandler.extend({
update: function (element, oldValue, value) {
+ var name = this.name;
if (value == null) {
if (oldValue != null)
- element.selected = false;
+ element[name] = false;
} else {
- element.selected = true;
+ element[name] = true;
}
}
});
+var ValueHandler = AttributeHandler.extend({
+ update: function (element, oldValue, value) {
+ element.value = value;
+ }
+});
+
// XXX make it possible for users to register attribute handlers!
-makeAttributeHandler = function (name, value) {
+makeAttributeHandler = function (tagName, name, value) {
// XXX will need one for 'style' on IE, though modern browsers
// seem to handle setAttribute ok.
if (name === 'class') {
return new ClassHandler(name, value);
} else if (name === 'selected') {
- return new SelectedHandler(name, value);
+ return new BooleanHandler(name, value);
+ } else if (tagName === 'TEXTAREA' && name === 'value') {
+ return new ValueHandler(name, value);
} else {
return new AttributeHandler(name, value);
}
diff --git a/packages/ui/render.js b/packages/ui/render.js
index 797ae0d672..26f3b51ebe 100644
--- a/packages/ui/render.js
+++ b/packages/ui/render.js
@@ -217,7 +217,7 @@ var updateAttributes = function(elem, newAttrs, handlers) {
if ((! handlers) || (! handlers.hasOwnProperty(k))) {
if (value !== null) {
// make new handler
- handler = makeAttributeHandler(k, value);
+ handler = makeAttributeHandler(elem.tagName, k, value);
if (handlers)
handlers[k] = handler;
oldValue = null;
@@ -300,13 +300,21 @@ var materialize = function (node, parent, before, parentComponent) {
insert(range, parent, before);
} else if (node instanceof HTML.Tag) {
var elem = document.createElement(node.tagName);
- if (node.attrs) {
+ var rawAttrs = node.attrs;
+ var children = node.children;
+ if (node.tagName === 'TEXTAREA') {
+ rawAttrs = (rawAttrs || {});
+ rawAttrs.value = children;
+ children = [];
+ };
+
+ if (rawAttrs) {
var attrUpdater = Deps.autorun(function (c) {
if (! c.handlers)
c.handlers = {};
try {
- var attrs = node.evaluateDynamicAttributes(parentComponent);
+ var attrs = HTML.evaluateDynamicAttributes(rawAttrs, parentComponent);
var stringAttrs = {};
if (attrs) {
for (var k in attrs) {
@@ -323,11 +331,8 @@ var materialize = function (node, parent, before, parentComponent) {
attrUpdater.stop();
});
}
- if (node.tagName === 'TEXTAREA') {
- elem.value = HTML.toText(node.children, HTML.TEXTMODE.STRING, parentComponent);
- } else {
- materialize(node.children, elem, null, parentComponent);
- }
+ materialize(children, elem, null, parentComponent);
+
insert(elem, parent, before);
} else if (typeof node.instantiate === 'function') {
// component
diff --git a/packages/ui/render_tests.js b/packages/ui/render_tests.js
index 65c646ce3c..8dcd3e4ea8 100644
--- a/packages/ui/render_tests.js
+++ b/packages/ui/render_tests.js
@@ -89,7 +89,8 @@ Tinytest.add("ui - render - textarea", function (test) {
test.equal(div.querySelector('textarea').value, text);
test.equal(toHTML(node), html);
- test.equal(toCode(node), code);
+ if (typeof code === 'string')
+ test.equal(toCode(node), code);
};
run('Hello',
@@ -109,6 +110,10 @@ Tinytest.add("ui - render - textarea", function (test) {
'',
'HTML.TEXTAREA(HTML.CharRef({html: "&", str: "&"}))');
+ run(['a', function () { return 'b'; }, 'c'],
+ 'abc',
+ '');
+
});
Tinytest.add("ui - render - closures", function (test) {