From 53e4c14b3065d51d6699bcc29214dd5de2854bc0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 18 May 2015 00:33:18 -0400 Subject: [PATCH] Prevent void elements from always including a comment node. Prior to this change calling `manualElement('input', {})` would result in the following DOM: ```html ``` This is incorrect because `input` is a void element. --- packages/htmlbars-runtime/lib/render.js | 9 +++++++-- packages/htmlbars-runtime/tests/main-test.js | 12 ++++++++++++ packages/htmlbars-syntax/lib/token-handlers.js | 13 +------------ packages/htmlbars-util/lib/void-tag-names.js | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 packages/htmlbars-util/lib/void-tag-names.js diff --git a/packages/htmlbars-runtime/lib/render.js b/packages/htmlbars-runtime/lib/render.js index b559fa74..7841112c 100644 --- a/packages/htmlbars-runtime/lib/render.js +++ b/packages/htmlbars-runtime/lib/render.js @@ -4,6 +4,7 @@ import ExpressionVisitor from "./expression-visitor"; import { AlwaysDirtyVisitor } from "./expression-visitor"; import Morph from "./morph"; import { clearMorph } from "../htmlbars-util/template-utils"; +import voidMap from '../htmlbars-util/void-tag-names'; var svgNamespace = "http://www.w3.org/2000/svg"; @@ -102,9 +103,13 @@ export function manualElement(tagName, attributes) { dom.setAttribute(el1, key, attributes[key]); } - var el2 = dom.createComment(""); - dom.appendChild(el1, el2); + if (!voidMap[tagName]) { + var el2 = dom.createComment(""); + dom.appendChild(el1, el2); + } + dom.appendChild(el0, el1); + return el0; }, buildRenderNodes: function buildRenderNodes(dom, fragment) { diff --git a/packages/htmlbars-runtime/tests/main-test.js b/packages/htmlbars-runtime/tests/main-test.js index 60e9c997..d75e5435 100644 --- a/packages/htmlbars-runtime/tests/main-test.js +++ b/packages/htmlbars-runtime/tests/main-test.js @@ -100,3 +100,15 @@ test("manualElement function honors namespaces", function() { ok(result.fragment.childNodes[1].childNodes[0] instanceof SVGLinearGradientElement); equalTokens(result.fragment, ''); }); + +test("manualElement function honors void elements", function() { + var attributes = { + class: 'foo-bar' + }; + var layout = manualElement('input', attributes); + var fragment = layout.buildFragment(new DOMHelper()); + + equal(fragment.childNodes.length, 1, 'includes a single element'); + equal(fragment.childNodes[0].childNodes.length, 0, 'no child nodes were added to `` because it is a void tag'); + equalTokens(fragment, ''); +}); diff --git a/packages/htmlbars-syntax/lib/token-handlers.js b/packages/htmlbars-syntax/lib/token-handlers.js index 6c141d3e..8771093e 100644 --- a/packages/htmlbars-syntax/lib/token-handlers.js +++ b/packages/htmlbars-syntax/lib/token-handlers.js @@ -1,20 +1,9 @@ -import { forEach } from "../htmlbars-util/array-utils"; import { buildProgram, buildComponent, buildElement, buildComment, buildText } from "./builders"; import { appendChild, parseComponentBlockParams } from "./utils"; - -// The HTML elements in this list are speced by -// http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, -// and will be forced to close regardless of if they have a -// self-closing /> at the end. -var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; -var voidMap = {}; - -forEach(voidTagNames.split(" "), function(tagName) { - voidMap[tagName] = true; -}); +import voidMap from '../htmlbars-util/void-tag-names'; // Except for `mustache`, all tokens are only allowed outside of // a start or end tag. diff --git a/packages/htmlbars-util/lib/void-tag-names.js b/packages/htmlbars-util/lib/void-tag-names.js new file mode 100644 index 00000000..08ce3bf5 --- /dev/null +++ b/packages/htmlbars-util/lib/void-tag-names.js @@ -0,0 +1,14 @@ +import { forEach } from "./array-utils"; + +// The HTML elements in this list are speced by +// http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, +// and will be forced to close regardless of if they have a +// self-closing /> at the end. +var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; +var voidMap = {}; + +forEach(voidTagNames.split(" "), function(tagName) { + voidMap[tagName] = true; +}); + +export default voidMap;