diff --git a/render/render.js b/render/render.js index 6888d06f5..3e06418d5 100644 --- a/render/render.js +++ b/render/render.js @@ -676,7 +676,7 @@ module.exports = function() { } } function setAttr(vnode, key, old, value, ns) { - if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return + if (key === "key" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) else if (key === "style") updateStyle(vnode.dom, old, value) @@ -746,11 +746,8 @@ module.exports = function() { if (old && old === attrs) { console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major") } - if (attrs != null) { - for (var key in attrs) { - setAttr(vnode, key, old && old[key], attrs[key], ns) - } - } + // Some attributes may NOT be case-sensitive (e.g. data-***), + // so removal should be done first to prevent accidental removal for newly setting values. var val if (old != null) { for (var key in old) { @@ -759,6 +756,11 @@ module.exports = function() { } } } + if (attrs != null) { + for (var key in attrs) { + setAttr(vnode, key, old && old[key], attrs[key], ns) + } + } } function isFormAttribute(vnode, attr) { return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === activeElement(vnode.dom) || vnode.tag === "option" && vnode.dom.parentNode === activeElement(vnode.dom) @@ -800,6 +802,15 @@ module.exports = function() { } } else { // Both old & new are (different) objects. + // Remove style properties that no longer exist. + // Style properties may have two cases(dash-case and camelCase), + // so removal should be done first to prevent accidental removal for newly setting values. + for (var key in old) { + if (old[key] != null && style[key] == null) { + if (key[0] === "-" && key[1] === "-") element.style.removeProperty(key) + else element.style[key] = "" + } + } // Update style properties that have changed for (var key in style) { var value = style[key] @@ -808,13 +819,6 @@ module.exports = function() { else element.style[key] = value } } - // Remove style properties that no longer exist - for (var key in old) { - if (old[key] != null && style[key] == null) { - if (key[0] === "-" && key[1] === "-") element.style.removeProperty(key) - else element.style[key] = "" - } - } } } diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 1daed5e5f..267cee26a 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -80,8 +80,8 @@ o.spec("attributes", function() { o(spies[0].callCount).equals(0) o(spies[2].callCount).equals(0) o(spies[3].calls).deepEquals([{this: spies[3].elem, args: ["custom", "x"]}]) - o(spies[4].calls).deepEquals([{this: spies[4].elem, args: ["custom", "x"]}]) - o(spies[5].calls).deepEquals([{this: spies[5].elem, args: ["custom", "x"]}]) + o(spies[4].calls).deepEquals([{this: spies[4].elem, args: ["is", "something-special"]} ,{this: spies[4].elem, args: ["custom", "x"]}]) + o(spies[5].calls).deepEquals([{this: spies[5].elem, args: ["is", "something-special"]} ,{this: spies[5].elem, args: ["custom", "x"]}]) }) o("when vnode is customElement with property, custom setAttribute not called", function(){ @@ -124,8 +124,8 @@ o.spec("attributes", function() { o(spies[1].callCount).equals(0) o(spies[2].callCount).equals(0) o(spies[3].callCount).equals(0) - o(spies[4].callCount).equals(0) - o(spies[5].callCount).equals(0) + o(spies[4].callCount).equals(1) // setAttribute("is", "something-special") is called + o(spies[5].callCount).equals(1) // setAttribute("is", "something-special") is called o(getters[0].callCount).equals(0) o(getters[1].callCount).equals(0) o(getters[2].callCount).equals(0)