From dd7bc6a988d5b75275ca8c727980eaa9e49230fd Mon Sep 17 00:00:00 2001 From: Jacob Wright Date: Thu, 23 Aug 2018 21:57:32 -0600 Subject: [PATCH] Keeps undefined from showing in template Removes attributes which have a value of undefined. ```html
``` ```html

Hello undefined!

Hello !

``` This may be considered backwards incompatable and may need to wait until Svelte 3. If existing apps rely on e.g. querySelector('[id="undefined"]') then this could require changes. --- src/compile/nodes/Attribute.ts | 13 +++++----- src/compile/nodes/Element.ts | 16 +++++++----- src/shared/dom.js | 26 ++++++++++++++++--- src/shared/ssr.js | 2 +- test/cli/samples/dev/expected/Main.js | 2 +- test/cli/samples/globals/expected/Main.js | 4 +-- test/cli/samples/store/expected/Main.js | 4 +-- .../expected-bundle.js | 4 +-- .../js/samples/debug-empty/expected-bundle.js | 4 +-- .../expected-bundle.js | 4 +-- test/js/samples/debug-foo/expected-bundle.js | 4 +-- .../deconflict-builtins/expected-bundle.js | 4 +-- .../expected-bundle.js | 4 +-- .../samples/do-use-dataset/expected-bundle.js | 18 ++++++++++--- test/js/samples/do-use-dataset/expected.js | 6 ++--- .../expected-bundle.js | 12 +++++++-- .../expected-bundle.js | 10 ++++++- .../expected-bundle.js | 4 +-- .../expected-bundle.js | 4 +-- .../each-block-keyed/expected-bundle.js | 4 +-- .../expected-bundle.js | 22 ++++++++++++---- .../inline-style-unoptimized/expected.js | 10 +++---- .../js/samples/input-files/expected-bundle.js | 10 ++++++- .../js/samples/input-range/expected-bundle.js | 10 ++++++- .../expected-bundle.js | 10 ++++++- .../non-imported-component/expected-bundle.js | 2 +- test/js/samples/svg-title/expected-bundle.js | 2 +- .../expected-bundle.js | 2 +- .../window-binding-scroll/expected-bundle.js | 4 +-- .../attribute-undefined-data/_config.js | 7 +++++ .../attribute-undefined-data/main.html | 1 + .../attribute-undefined-prop/_config.js | 7 +++++ .../attribute-undefined-prop/main.html | 1 + .../samples/attribute-undefined/_config.js | 7 +++++ .../samples/attribute-undefined/main.html | 1 + .../samples/binding-input-number/_config.js | 2 +- test/runtime/samples/onstate-event/_config.js | 2 +- .../set-undefined-text-node/_config.js | 11 ++++++++ .../samples/set-undefined-text-node/main.html | 1 + 39 files changed, 192 insertions(+), 69 deletions(-) create mode 100644 test/runtime/samples/attribute-undefined-data/_config.js create mode 100644 test/runtime/samples/attribute-undefined-data/main.html create mode 100644 test/runtime/samples/attribute-undefined-prop/_config.js create mode 100644 test/runtime/samples/attribute-undefined-prop/main.html create mode 100644 test/runtime/samples/attribute-undefined/_config.js create mode 100644 test/runtime/samples/attribute-undefined/main.html create mode 100644 test/runtime/samples/set-undefined-text-node/_config.js create mode 100644 test/runtime/samples/set-undefined-text-node/main.html diff --git a/src/compile/nodes/Attribute.ts b/src/compile/nodes/Attribute.ts index 0165dc98fb..4c93835d5f 100644 --- a/src/compile/nodes/Attribute.ts +++ b/src/compile/nodes/Attribute.ts @@ -181,12 +181,13 @@ export default class Attribute extends Node { let updater; const init = shouldCache ? `${last} = ${value}` : value; + const updaterValue = shouldCache ? last : value; if (isLegacyInputType) { block.builders.hydrate.addLine( `@setInputType(${node.var}, ${init});` ); - updater = `@setInputType(${node.var}, ${shouldCache ? last : value});`; + updater = `@setInputType(${node.var}, ${updaterValue});`; } else if (isSelectValueAttribute) { // annoying special case const isMultipleSelect = node.getStaticAttributeValue('multiple'); @@ -216,19 +217,19 @@ export default class Attribute extends Node { `); } else if (propertyName) { block.builders.hydrate.addLine( - `${node.var}.${propertyName} = ${init};` + `@setProperty(${node.var}, "${propertyName}", "${name}", ${init});` ); - updater = `${node.var}.${propertyName} = ${shouldCache ? last : value};`; + updater = `@setProperty(${node.var}, "${propertyName}", "${name}", ${updaterValue});`; } else if (isDataSet) { block.builders.hydrate.addLine( - `${node.var}.dataset.${camelCaseName} = ${init};` + `@setDataSet(${node.var}, "${camelCaseName}", "${name}", ${init});` ); - updater = `${node.var}.dataset.${camelCaseName} = ${shouldCache ? last : value};`; + updater = `@setDataSet(${node.var}, "${camelCaseName}", "${name}", ${updaterValue});`; } else { block.builders.hydrate.addLine( `${method}(${node.var}, "${name}", ${init});` ); - updater = `${method}(${node.var}, "${name}", ${shouldCache ? last : value});`; + updater = `${method}(${node.var}, "${name}", ${updaterValue});`; } if (this.dependencies.size || isSelectValueAttribute) { diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index 43e690bfd7..77c47b0d8c 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -970,13 +970,15 @@ export default class Element extends Node { textareaContents = attribute.stringifyForSsr(); } else if (attribute.isTrue) { openingTag += ` ${attribute.name}`; - } else if ( - booleanAttributes.has(attribute.name) && - attribute.chunks.length === 1 && - attribute.chunks[0].type !== 'Text' - ) { - // a boolean attribute with one non-Text chunk - openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }'; + } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { + if (booleanAttributes.has(attribute.name)) { + // a boolean attribute with one non-Text chunk + openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }'; + } else { + openingTag += '${ (' + attribute.chunks[0].snippet + ') !== undefined ? ` ' + + ` ${attribute.name}="${attribute.stringifyForSsr()}"` + + '` : "" }'; + } } else { openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`; } diff --git a/src/shared/dom.js b/src/shared/dom.js index d428e92f1c..f48829a303 100644 --- a/src/shared/dom.js +++ b/src/shared/dom.js @@ -66,7 +66,7 @@ export function createSvgElement(name) { } export function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } export function createComment() { @@ -82,7 +82,11 @@ export function removeListener(node, event, handler) { } export function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } } export function setAttributes(node, attributes) { @@ -110,6 +114,22 @@ export function removeAttribute(node, attribute) { node.removeAttribute(attribute); } +export function setProperty(node, prop, attribute, value) { + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node[prop] = value; + } +} + +export function setDataSet(node, prop, attribute, value) { + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.dataset[prop] = value; + } +} + export function setXlinkAttribute(node, attribute, value) { node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value); } @@ -166,7 +186,7 @@ export function claimText (nodes, data) { } export function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } export function setInputType(input, type) { diff --git a/src/shared/ssr.js b/src/shared/ssr.js index 3e5a4568e6..99daf82b5d 100644 --- a/src/shared/ssr.js +++ b/src/shared/ssr.js @@ -32,7 +32,7 @@ export const escaped = { }; export function escape(html) { - return String(html).replace(/["'&<>]/g, match => escaped[match]); + return html === undefined ? '' : String(html).replace(/["'&<>]/g, match => escaped[match]); } export function each(items, assign, fn) { diff --git a/test/cli/samples/dev/expected/Main.js b/test/cli/samples/dev/expected/Main.js index e32ea9a61e..a1ade1b63c 100644 --- a/test/cli/samples/dev/expected/Main.js +++ b/test/cli/samples/dev/expected/Main.js @@ -64,7 +64,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function addLoc(element, file, line, column, char) { diff --git a/test/cli/samples/globals/expected/Main.js b/test/cli/samples/globals/expected/Main.js index 62d5a02694..a8414b91d7 100644 --- a/test/cli/samples/globals/expected/Main.js +++ b/test/cli/samples/globals/expected/Main.js @@ -69,7 +69,7 @@ var Main = (function(answer) { "use strict"; } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function insert(target, node, anchor) { @@ -81,7 +81,7 @@ var Main = (function(answer) { "use strict"; } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function detachNode(node) { diff --git a/test/cli/samples/store/expected/Main.js b/test/cli/samples/store/expected/Main.js index e3beb9d80f..a1a4a2e789 100644 --- a/test/cli/samples/store/expected/Main.js +++ b/test/cli/samples/store/expected/Main.js @@ -64,7 +64,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function insert(target, node, anchor) { @@ -76,7 +76,7 @@ function append(target, node) { } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function detachNode(node) { diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 58f2fbb09c..78fe70624a 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -22,11 +22,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/debug-empty/expected-bundle.js b/test/js/samples/debug-empty/expected-bundle.js index 0faf822be3..f8f1797184 100644 --- a/test/js/samples/debug-empty/expected-bundle.js +++ b/test/js/samples/debug-empty/expected-bundle.js @@ -28,11 +28,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/debug-foo-bar-baz-things/expected-bundle.js b/test/js/samples/debug-foo-bar-baz-things/expected-bundle.js index 521d57af5b..9c895bd261 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected-bundle.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected-bundle.js @@ -34,11 +34,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/debug-foo/expected-bundle.js b/test/js/samples/debug-foo/expected-bundle.js index 5cc1c7a469..b670fd84ef 100644 --- a/test/js/samples/debug-foo/expected-bundle.js +++ b/test/js/samples/debug-foo/expected-bundle.js @@ -34,11 +34,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/deconflict-builtins/expected-bundle.js b/test/js/samples/deconflict-builtins/expected-bundle.js index eae32e976c..6f9b8f1a40 100644 --- a/test/js/samples/deconflict-builtins/expected-bundle.js +++ b/test/js/samples/deconflict-builtins/expected-bundle.js @@ -28,7 +28,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function createComment() { @@ -36,7 +36,7 @@ function createComment() { } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/dev-warning-missing-data-computed/expected-bundle.js b/test/js/samples/dev-warning-missing-data-computed/expected-bundle.js index 73fdae3223..ac2fd9a374 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected-bundle.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected-bundle.js @@ -28,11 +28,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/do-use-dataset/expected-bundle.js b/test/js/samples/do-use-dataset/expected-bundle.js index d981b929a7..505bc1dfd2 100644 --- a/test/js/samples/do-use-dataset/expected-bundle.js +++ b/test/js/samples/do-use-dataset/expected-bundle.js @@ -18,7 +18,19 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); +} + +function setDataSet(node, prop, attribute, value) { + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.dataset[prop] = value; + } } function blankObject() { @@ -156,7 +168,7 @@ function create_main_fragment(component, ctx) { text = createText("\n"); div_1 = createElement("div"); div.dataset.foo = "bar"; - div_1.dataset.foo = ctx.bar; + setDataSet(div_1, "foo", "data-foo", ctx.bar); }, m(target, anchor) { @@ -167,7 +179,7 @@ function create_main_fragment(component, ctx) { p(changed, ctx) { if (changed.bar) { - div_1.dataset.foo = ctx.bar; + setDataSet(div_1, "foo", "data-foo", ctx.bar); } }, diff --git a/test/js/samples/do-use-dataset/expected.js b/test/js/samples/do-use-dataset/expected.js index 29340df872..e8ed60a5ea 100644 --- a/test/js/samples/do-use-dataset/expected.js +++ b/test/js/samples/do-use-dataset/expected.js @@ -1,5 +1,5 @@ /* generated by Svelte vX.Y.Z */ -import { assign, createElement, createText, detachNode, init, insert, proto } from "svelte/shared.js"; +import { assign, createElement, createText, detachNode, init, insert, proto, setDataSet } from "svelte/shared.js"; function create_main_fragment(component, ctx) { var div, text, div_1; @@ -10,7 +10,7 @@ function create_main_fragment(component, ctx) { text = createText("\n"); div_1 = createElement("div"); div.dataset.foo = "bar"; - div_1.dataset.foo = ctx.bar; + setDataSet(div_1, "foo", "data-foo", ctx.bar); }, m(target, anchor) { @@ -21,7 +21,7 @@ function create_main_fragment(component, ctx) { p(changed, ctx) { if (changed.bar) { - div_1.dataset.foo = ctx.bar; + setDataSet(div_1, "foo", "data-foo", ctx.bar); } }, diff --git a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js index 3be0e2a270..46ace73f91 100644 --- a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js @@ -18,11 +18,19 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); } function blankObject() { diff --git a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js index 5b73e51762..5e2dd6503d 100644 --- a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js @@ -22,7 +22,15 @@ function createSvgElement(name) { } function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); } function blankObject() { diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index ce97c56af5..0b6d2458b1 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -34,11 +34,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/js/samples/each-block-keyed-animated/expected-bundle.js b/test/js/samples/each-block-keyed-animated/expected-bundle.js index 1cfdf681f0..419f11fcbb 100644 --- a/test/js/samples/each-block-keyed-animated/expected-bundle.js +++ b/test/js/samples/each-block-keyed-animated/expected-bundle.js @@ -22,7 +22,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function createComment() { @@ -30,7 +30,7 @@ function createComment() { } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function linear(t) { diff --git a/test/js/samples/each-block-keyed/expected-bundle.js b/test/js/samples/each-block-keyed/expected-bundle.js index 1cc34f4455..e71181347a 100644 --- a/test/js/samples/each-block-keyed/expected-bundle.js +++ b/test/js/samples/each-block-keyed/expected-bundle.js @@ -22,7 +22,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function createComment() { @@ -30,7 +30,7 @@ function createComment() { } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function destroyBlock(block, lookup) { diff --git a/test/js/samples/inline-style-unoptimized/expected-bundle.js b/test/js/samples/inline-style-unoptimized/expected-bundle.js index b46055315e..22245e3797 100644 --- a/test/js/samples/inline-style-unoptimized/expected-bundle.js +++ b/test/js/samples/inline-style-unoptimized/expected-bundle.js @@ -18,7 +18,19 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); +} + +function setProperty(node, prop, attribute, value) { + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node[prop] = value; + } } function blankObject() { @@ -155,8 +167,8 @@ function create_main_fragment(component, ctx) { div = createElement("div"); text = createText("\n"); div_1 = createElement("div"); - div.style.cssText = ctx.style; - div_1.style.cssText = div_1_style_value = "" + ctx.key + ": " + ctx.value; + setProperty(div, "style.cssText", "style", ctx.style); + setProperty(div_1, "style.cssText", "style", div_1_style_value = "" + ctx.key + ": " + ctx.value); }, m(target, anchor) { @@ -167,11 +179,11 @@ function create_main_fragment(component, ctx) { p(changed, ctx) { if (changed.style) { - div.style.cssText = ctx.style; + setProperty(div, "style.cssText", "style", ctx.style); } if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) { - div_1.style.cssText = div_1_style_value; + setProperty(div_1, "style.cssText", "style", div_1_style_value); } }, diff --git a/test/js/samples/inline-style-unoptimized/expected.js b/test/js/samples/inline-style-unoptimized/expected.js index 88f242f3ae..1b3b013f4e 100644 --- a/test/js/samples/inline-style-unoptimized/expected.js +++ b/test/js/samples/inline-style-unoptimized/expected.js @@ -1,5 +1,5 @@ /* generated by Svelte vX.Y.Z */ -import { assign, createElement, createText, detachNode, init, insert, proto } from "svelte/shared.js"; +import { assign, createElement, createText, detachNode, init, insert, proto, setProperty } from "svelte/shared.js"; function create_main_fragment(component, ctx) { var div, text, div_1, div_1_style_value; @@ -9,8 +9,8 @@ function create_main_fragment(component, ctx) { div = createElement("div"); text = createText("\n"); div_1 = createElement("div"); - div.style.cssText = ctx.style; - div_1.style.cssText = div_1_style_value = "" + ctx.key + ": " + ctx.value; + setProperty(div, "style.cssText", "style", ctx.style); + setProperty(div_1, "style.cssText", "style", div_1_style_value = "" + ctx.key + ": " + ctx.value); }, m(target, anchor) { @@ -21,11 +21,11 @@ function create_main_fragment(component, ctx) { p(changed, ctx) { if (changed.style) { - div.style.cssText = ctx.style; + setProperty(div, "style.cssText", "style", ctx.style); } if ((changed.key || changed.value) && div_1_style_value !== (div_1_style_value = "" + ctx.key + ": " + ctx.value)) { - div_1.style.cssText = div_1_style_value; + setProperty(div_1, "style.cssText", "style", div_1_style_value); } }, diff --git a/test/js/samples/input-files/expected-bundle.js b/test/js/samples/input-files/expected-bundle.js index b3218c7fd4..b5153c247b 100644 --- a/test/js/samples/input-files/expected-bundle.js +++ b/test/js/samples/input-files/expected-bundle.js @@ -26,7 +26,15 @@ function removeListener(node, event, handler) { } function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); } function blankObject() { diff --git a/test/js/samples/input-range/expected-bundle.js b/test/js/samples/input-range/expected-bundle.js index 2f53e740ea..f6fd3deafc 100644 --- a/test/js/samples/input-range/expected-bundle.js +++ b/test/js/samples/input-range/expected-bundle.js @@ -26,7 +26,15 @@ function removeListener(node, event, handler) { } function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); } function toNumber(value) { diff --git a/test/js/samples/input-without-blowback-guard/expected-bundle.js b/test/js/samples/input-without-blowback-guard/expected-bundle.js index b5f7a90f8c..b85a8fa52d 100644 --- a/test/js/samples/input-without-blowback-guard/expected-bundle.js +++ b/test/js/samples/input-without-blowback-guard/expected-bundle.js @@ -26,7 +26,15 @@ function removeListener(node, event, handler) { } function setAttribute(node, attribute, value) { - node.setAttribute(attribute, value); + if (value === undefined) { + removeAttribute(node, attribute); + } else { + node.setAttribute(attribute, value); + } +} + +function removeAttribute(node, attribute) { + node.removeAttribute(attribute); } function blankObject() { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index b890d8bed5..0b78dc1f40 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -16,7 +16,7 @@ function detachNode(node) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function blankObject() { diff --git a/test/js/samples/svg-title/expected-bundle.js b/test/js/samples/svg-title/expected-bundle.js index 269f6ca1f3..e8af2a56d9 100644 --- a/test/js/samples/svg-title/expected-bundle.js +++ b/test/js/samples/svg-title/expected-bundle.js @@ -22,7 +22,7 @@ function createSvgElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function blankObject() { diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index 4065ba55ad..bbfb5b91d1 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -22,7 +22,7 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function createComment() { diff --git a/test/js/samples/window-binding-scroll/expected-bundle.js b/test/js/samples/window-binding-scroll/expected-bundle.js index 7823390a2c..453b901a05 100644 --- a/test/js/samples/window-binding-scroll/expected-bundle.js +++ b/test/js/samples/window-binding-scroll/expected-bundle.js @@ -22,11 +22,11 @@ function createElement(name) { } function createText(data) { - return document.createTextNode(data); + return document.createTextNode(data === undefined ? '' : data); } function setData(text, data) { - text.data = '' + data; + text.data = data === undefined ? '' : '' + data; } function blankObject() { diff --git a/test/runtime/samples/attribute-undefined-data/_config.js b/test/runtime/samples/attribute-undefined-data/_config.js new file mode 100644 index 0000000000..024e3b6950 --- /dev/null +++ b/test/runtime/samples/attribute-undefined-data/_config.js @@ -0,0 +1,7 @@ +export default { + html: ``, + test (assert, component, target) { + const textarea = target.querySelector('textarea'); + assert.ok(textarea.hasAttribute('data-foo') === false); + }, +}; diff --git a/test/runtime/samples/attribute-undefined-data/main.html b/test/runtime/samples/attribute-undefined-data/main.html new file mode 100644 index 0000000000..2d85bd7f81 --- /dev/null +++ b/test/runtime/samples/attribute-undefined-data/main.html @@ -0,0 +1 @@ + diff --git a/test/runtime/samples/attribute-undefined-prop/_config.js b/test/runtime/samples/attribute-undefined-prop/_config.js new file mode 100644 index 0000000000..61d664a9a7 --- /dev/null +++ b/test/runtime/samples/attribute-undefined-prop/_config.js @@ -0,0 +1,7 @@ +export default { + html: ``, + test (assert, component, target) { + const textarea = target.querySelector('textarea'); + assert.ok(textarea.hasAttribute('readonly') === false); + }, +}; diff --git a/test/runtime/samples/attribute-undefined-prop/main.html b/test/runtime/samples/attribute-undefined-prop/main.html new file mode 100644 index 0000000000..c71f38dfb6 --- /dev/null +++ b/test/runtime/samples/attribute-undefined-prop/main.html @@ -0,0 +1 @@ + diff --git a/test/runtime/samples/attribute-undefined/_config.js b/test/runtime/samples/attribute-undefined/_config.js new file mode 100644 index 0000000000..ae17298a29 --- /dev/null +++ b/test/runtime/samples/attribute-undefined/_config.js @@ -0,0 +1,7 @@ +export default { + html: ``, + test (assert, component, target) { + const textarea = target.querySelector('textarea'); + assert.ok(textarea.hasAttribute('foo') === false); + }, +}; diff --git a/test/runtime/samples/attribute-undefined/main.html b/test/runtime/samples/attribute-undefined/main.html new file mode 100644 index 0000000000..b903c8cb50 --- /dev/null +++ b/test/runtime/samples/attribute-undefined/main.html @@ -0,0 +1 @@ + diff --git a/test/runtime/samples/binding-input-number/_config.js b/test/runtime/samples/binding-input-number/_config.js index 66e0df8a35..7f09baad14 100644 --- a/test/runtime/samples/binding-input-number/_config.js +++ b/test/runtime/samples/binding-input-number/_config.js @@ -37,7 +37,7 @@ export default { assert.equal( component.get().count, undefined ); assert.htmlEqual( target.innerHTML, ` -

undefined undefined

+

undefined

` ); } }; diff --git a/test/runtime/samples/onstate-event/_config.js b/test/runtime/samples/onstate-event/_config.js index d3f24376f9..590f1ae764 100644 --- a/test/runtime/samples/onstate-event/_config.js +++ b/test/runtime/samples/onstate-event/_config.js @@ -7,7 +7,7 @@ export default { html: `

woo!

-

undefined

+

`, test(assert, component, target) { diff --git a/test/runtime/samples/set-undefined-text-node/_config.js b/test/runtime/samples/set-undefined-text-node/_config.js new file mode 100644 index 0000000000..fea10d1dc2 --- /dev/null +++ b/test/runtime/samples/set-undefined-text-node/_config.js @@ -0,0 +1,11 @@ +export default { + html: 'foo is ', + + test(assert, component, target) { + component.set({ foo: 42 }); + assert.htmlEqual(target.innerHTML, 'foo is 42'); + + component.set({ foo: undefined }); + assert.htmlEqual(target.innerHTML, 'foo is '); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/set-undefined-text-node/main.html b/test/runtime/samples/set-undefined-text-node/main.html new file mode 100644 index 0000000000..bf9a9ffe59 --- /dev/null +++ b/test/runtime/samples/set-undefined-text-node/main.html @@ -0,0 +1 @@ +foo is {foo} \ No newline at end of file