From ffba906cf250e707f7383e51e995f27a683445d1 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Fri, 10 Apr 2015 12:24:59 -0700 Subject: [PATCH] Handle XHTML self-closing void tag behavior Also wrap createDocument correctly for handling doctypes. Fixes #278 ShadowDOM.js causing unclosed img tags in XHTML --- src/ShadowDOM/wrappers/Document.js | 9 +++++++-- src/ShadowDOM/wrappers/HTMLElement.js | 25 +++++++++++++++++++++---- tests/ShadowDOM/js/Document.js | 7 +++++++ tests/ShadowDOM/js/HTMLElement.js | 8 ++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/ShadowDOM/wrappers/Document.js b/src/ShadowDOM/wrappers/Document.js index 7dc3875..b11134f 100644 --- a/src/ShadowDOM/wrappers/Document.js +++ b/src/ShadowDOM/wrappers/Document.js @@ -332,6 +332,12 @@ setWrapper(impl, this); } + var originalCreateDocument = document.implementation.createDocument; + DOMImplementation.prototype.createDocument = function() { + arguments[2] = unwrap(arguments[2]); + return wrap(originalCreateDocument.apply(unsafeUnwrap(this), arguments)); + }; + function wrapImplMethod(constructor, name) { var original = document.implementation[name]; constructor.prototype[name] = function() { @@ -347,7 +353,6 @@ } wrapImplMethod(DOMImplementation, 'createDocumentType'); - wrapImplMethod(DOMImplementation, 'createDocument'); wrapImplMethod(DOMImplementation, 'createHTMLDocument'); forwardImplMethod(DOMImplementation, 'hasFeature'); @@ -356,8 +361,8 @@ forwardMethodsToWrapper([ window.DOMImplementation, ], [ - 'createDocumentType', 'createDocument', + 'createDocumentType', 'createHTMLDocument', 'hasFeature', ]); diff --git a/src/ShadowDOM/wrappers/HTMLElement.js b/src/ShadowDOM/wrappers/HTMLElement.js index 7326dc3..fbc2c40 100644 --- a/src/ShadowDOM/wrappers/HTMLElement.js +++ b/src/ShadowDOM/wrappers/HTMLElement.js @@ -93,6 +93,20 @@ 'noscript' ]); + var XHTML_NS = 'http://www.w3.org/1999/xhtml'; + + function needsSelfClosingSlash(node) { + // if the namespace is not XHTML_NS, this is probably an XML or SVG Document + // and will need a closing slash on void elements + if (node.namespaceURI !== XHTML_NS) + return true; + + var doctype = node.ownerDocument.doctype; + // doctype is null for quirksmode documents + // publicId and systemId are required for XHTML, and are null for HTML5 + return doctype && doctype.publicId && doctype.systemId; + } + function getOuterHTML(node, parentNode) { switch (node.nodeType) { case Node.ELEMENT_NODE: @@ -102,11 +116,14 @@ for (var i = 0, attr; attr = attrs[i]; i++) { s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"'; } - s += '>'; - if (voidElements[tagName]) - return s; - return s + getInnerHTML(node) + ''; + if (voidElements[tagName]) { + if (needsSelfClosingSlash(node)) + s += '/'; + return s + '>'; + } + + return s + '>' + getInnerHTML(node) + ''; case Node.TEXT_NODE: var data = node.data; diff --git a/tests/ShadowDOM/js/Document.js b/tests/ShadowDOM/js/Document.js index 45f2453..a0cf3c7 100644 --- a/tests/ShadowDOM/js/Document.js +++ b/tests/ShadowDOM/js/Document.js @@ -33,6 +33,13 @@ htmlSuite('Document', function() { assert.equal(doc2.lastElementChild.tagName, 'HTML'); }); + test('Create XHTML Document', function() { + var docType = wrap(document).implementation.createDocumentType('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'); + var doc = wrap(document).implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', docType); + assert(doc); + }); + test('document.documentElement', function() { var doc = wrap(document); assert.equal(doc.documentElement.ownerDocument, doc); diff --git a/tests/ShadowDOM/js/HTMLElement.js b/tests/ShadowDOM/js/HTMLElement.js index f6d30a3..488df58 100644 --- a/tests/ShadowDOM/js/HTMLElement.js +++ b/tests/ShadowDOM/js/HTMLElement.js @@ -114,4 +114,12 @@ suite('HTMLElement', function() { div.hidden = false; assert.isFalse(div.hasAttribute('hidden')); }); + + test('img outerHTML in XHTML documents', function() { + var docType = document.implementation.createDocumentType('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'); + var doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', docType); + var img = doc.createElement('img'); + assert.equal(img.outerHTML, ''); + }); });