From 80ca2e255f2c3833c09875b9843aa5a6f592a8a7 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 24 Aug 2016 18:22:02 -0400 Subject: [PATCH 1/2] Fix HTML to DOM client parser `DOMParser` was nesting certain elements (e.g., div) in `` and `body` so formatting the child nodes of document gave incorrect results. Update logic so that the correct nodes are parsed and formatted. --- lib/html-to-dom-client.js | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/html-to-dom-client.js b/lib/html-to-dom-client.js index b5abd8d3..a2900de0 100644 --- a/lib/html-to-dom-client.js +++ b/lib/html-to-dom-client.js @@ -102,22 +102,45 @@ function formatDOM(nodes, parentNode) { * @return {Object} - The DOM nodes. */ function htmlToDOMClient(html) { - var root; + var match = typeof html === 'string' ? html.match(/<(.+?)>/) : null; + var tagName; + var parentNode; + var nodes; + + if (match && typeof match[1] === 'string') { + tagName = match[1].toLowerCase(); + } // `DOMParser` can parse full HTML // https://developer.mozilla.org/en-US/docs/Web/API/DOMParser - if (window.DOMParser) { + if (tagName && window.DOMParser) { var parser = new window.DOMParser(); - root = parser.parseFromString(html, 'text/html'); + var doc = parser.parseFromString(html, 'text/html'); + + // and are siblings + if (tagName === 'head' || tagName === 'body') { + nodes = doc.getElementsByTagName(tagName); + + // document's child nodes + } else if (tagName === 'html') { + nodes = doc.childNodes; + + // get the element's parent's child nodes + // do this in case of adjacent elements + } else { + parentNode = doc.getElementsByTagName(tagName)[0].parentNode; + nodes = parentNode.childNodes; + } // otherwise, use `innerHTML` // but this will strip out tags like and } else { - root = document.createElement('div'); - root.innerHTML = html; + parentNode = document.createElement('div'); + parentNode.innerHTML = html; + nodes = parentNode.childNodes; } - return formatDOM(root.childNodes); + return formatDOM(nodes); } /** From 8cd62a8058cd23818646cc6db1fdcd398abcc8bd Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 24 Aug 2016 18:44:21 -0400 Subject: [PATCH 2/2] Throw an error if the first argument for the parser is not a string This is to give the user gets feedback if the first argument is invalid. Also, add tests to confirm behavior. --- index.js | 3 +++ test/html-to-react.js | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/index.js b/index.js index 0cec5db6..7d4ba8fc 100644 --- a/index.js +++ b/index.js @@ -51,6 +51,9 @@ * @return {ReactElement|Array} */ function HTMLReactParser(html, options) { + if (typeof html !== 'string') { + throw new Error('`HTMLReactParser`: The first argument must be a string.'); + } return domToReact(htmlToDOM(html), options); } diff --git a/test/html-to-react.js b/test/html-to-react.js index b4c74a5e..6ae575ef 100644 --- a/test/html-to-react.js +++ b/test/html-to-react.js @@ -29,6 +29,18 @@ describe('html-to-react', function() { */ describe('parser', function() { + it('throws an error if first argument is not a string', function() { + assert.throws(function() { Parser(); }); + + [undefined, null, {}, [], 42].forEach(function(arg) { + assert.throws(function() { Parser(arg); }); + }); + }); + + it('returns string if cannot be parsed to HTML', function() { + assert.equal(Parser('foo'), 'foo'); + }); + it('converts single HTML element to React', function() { var html = data.html.single; var reactElement = Parser(html);