diff --git a/render/render.js b/render/render.js index 909477a2..c31a79ce 100644 --- a/render/render.js +++ b/render/render.js @@ -135,7 +135,7 @@ module.exports = function($window) { else { var recycling = isRecyclable(old, vnodes) if (recycling) old = old.concat(old.pool) - + var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map while (oldEnd >= oldStart && end >= start) { var o = old[oldStart], v = vnodes[start] @@ -347,7 +347,7 @@ module.exports = function($window) { var content = children[0].children if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content } - else if (children != null || vnode.text != null) throw new Error("Child node of a contenteditable must be trusted") + else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 6df82eaf..73cbd685 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -79,9 +79,9 @@ o.spec("attributes", function() { o.spec("canvas width and height", function() { o("uses attribute API", function() { var canvas = {tag: "canvas", attrs: {width: "100%"}} - + render(root, canvas) - + o(canvas.dom.attributes["width"].nodeValue).equals("100%") o(canvas.dom.width).equals(100) }) @@ -95,4 +95,58 @@ o.spec("attributes", function() { o(a.dom.attributes["class"].nodeValue).equals("test") }) }) + o.spec("contenteditable throws on untrusted children", function() { + o("including text nodes", function() { + var div = {tag: "div", attrs: {contenteditable: true}, text: ''} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(false) + }) + o("including elements", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: [{tag: "script", attrs: {src: "http://evil.com"}}]} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(false) + }) + o("tolerating empty children", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: []} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(true) + }) + o("tolerating trusted content", function() { + var div = {tag: "div", attrs: {contenteditable: true}, children: [{tag: "<", children: ""}]} + var succeeded = false + + try { + render(root, div) + + succeeded = true + } + catch(e){} + + o(succeeded).equals(true) + }) + }) })