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 @@ + + 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) {