diff --git a/src/renderers/dom/client/utils/DOMLazyTree.js b/src/renderers/dom/client/utils/DOMLazyTree.js index 269f5c37145a2..c6c0b98f9e8ec 100644 --- a/src/renderers/dom/client/utils/DOMLazyTree.js +++ b/src/renderers/dom/client/utils/DOMLazyTree.js @@ -12,6 +12,7 @@ 'use strict'; var DOMNamespaces = require('DOMNamespaces'); +var setInnerHTML = require('setInnerHTML'); var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction'); var setTextContent = require('setTextContent'); @@ -50,7 +51,7 @@ function insertTreeChildren(tree) { insertTreeBefore(node, children[i], null); } } else if (tree.html != null) { - node.innerHTML = tree.html; + setInnerHTML(node, tree.html); } else if (tree.text != null) { setTextContent(node, tree.text); } @@ -96,7 +97,7 @@ function queueHTML(tree, html) { if (enableLazy) { tree.html = html; } else { - tree.node.innerHTML = html; + setInnerHTML(tree.node, html); } } diff --git a/src/renderers/dom/client/utils/__tests__/setInnerHTML.js b/src/renderers/dom/client/utils/__tests__/setInnerHTML.js new file mode 100644 index 0000000000000..2f4eccec4e8eb --- /dev/null +++ b/src/renderers/dom/client/utils/__tests__/setInnerHTML.js @@ -0,0 +1,42 @@ +/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails react-core + */ + +'use strict'; + +var setInnerHTML = require('setInnerHTML'); +var DOMNamespaces = require('DOMNamespaces'); + +describe('setInnerHTML', function() { + describe('when the node has innerHTML property', () => { + it('sets innerHTML on it', function() { + var node = document.createElement('div'); + var html = '

hello

'; + setInnerHTML(node, html); + expect(node.innerHTML).toBe(html); + }); + }); + + describe('when the node does not have an innerHTML property', () => { + it('sets innerHTML on it', function() { + // Create a mock node that looks like an SVG in IE (without innerHTML) + var node = { + namespaceURI: DOMNamespaces.svg, + appendChild: jasmine.createSpy(), + }; + + var html = ''; + setInnerHTML(node, html); + + expect(node.appendChild.calls.argsFor(0)[0].outerHTML).toBe(''); + expect(node.appendChild.calls.argsFor(1)[0].outerHTML).toBe(''); + }); + }); +}); diff --git a/src/renderers/dom/client/utils/setInnerHTML.js b/src/renderers/dom/client/utils/setInnerHTML.js index 1e491bfaf3820..59348fe3c3f70 100644 --- a/src/renderers/dom/client/utils/setInnerHTML.js +++ b/src/renderers/dom/client/utils/setInnerHTML.js @@ -12,12 +12,16 @@ 'use strict'; var ExecutionEnvironment = require('ExecutionEnvironment'); +var DOMNamespaces = require('DOMNamespaces'); var WHITESPACE_TEST = /^[ \r\n\t\f]/; var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/; var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction'); +// SVG temp container for IE lacking innerHTML +var reusableSVGContainer; + /** * Set the innerHTML property of a node, ensuring that whitespace is preserved * even in IE8. @@ -28,7 +32,19 @@ var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunc */ var setInnerHTML = createMicrosoftUnsafeLocalFunction( function(node, html) { - node.innerHTML = html; + // IE does not have innerHTML for SVG nodes, so instead we inject the + // new markup in a temp node and then move the child nodes across into + // the target node + if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) { + reusableSVGContainer = reusableSVGContainer || document.createElement('div'); + reusableSVGContainer.innerHTML = '' + html + ''; + var newNodes = reusableSVGContainer.firstChild.childNodes; + for (var i = 0; i < newNodes.length; i++) { + node.appendChild(newNodes[i]); + } + } else { + node.innerHTML = html; + } } );