@samitouri / QOS-React / commits / 99d8524d23

Fix #6950, work around IE missing innerHTML on SVG nodes (#6982)

* Workaround IE lacking innerHTML on SVG elements * Add tests for setInnerHTML * Correctly check if node has innerHTML property * Ensure tests for setInnerHTML actually tests both codepaths * Provide mock element for setInnerHTML tests * Only use SVG setInnerHTML workaround for SVG elements

Josh Hunt committed Jun 9, 2016 at 03:00 UTC 99d8524d2398910fff8c351b5307a0dd9f0133a4
3 files changed +62 -3
src/renderers/dom/client/utils/DOMLazyTree.js
+3 -2
@@ -12,6 +12,7 @@
12 'use strict';
13
14 var DOMNamespaces = require('DOMNamespaces');
15 +var setInnerHTML = require('setInnerHTML');
16
17 var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
18 var setTextContent = require('setTextContent');
@@ -50,7 +51,7 @@ function insertTreeChildren(tree) {
51 insertTreeBefore(node, children[i], null);
52 }
53 } else if (tree.html != null) {
53 - node.innerHTML = tree.html;
54 + setInnerHTML(node, tree.html);
55 } else if (tree.text != null) {
56 setTextContent(node, tree.text);
57 }
@@ -96,7 +97,7 @@ function queueHTML(tree, html) {
97 if (enableLazy) {
98 tree.html = html;
99 } else {
99 - tree.node.innerHTML = html;
100 + setInnerHTML(tree.node, html);
101 }
102 }
103
src/renderers/dom/client/utils/__tests__/setInnerHTML.js new
+42
@@ -0,0 +1,42 @@
1 +/**
2 + * Copyright 2016-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +'use strict';
13 +
14 +var setInnerHTML = require('setInnerHTML');
15 +var DOMNamespaces = require('DOMNamespaces');
16 +
17 +describe('setInnerHTML', function() {
18 + describe('when the node has innerHTML property', () => {
19 + it('sets innerHTML on it', function() {
20 + var node = document.createElement('div');
21 + var html = '<h1>hello</h1>';
22 + setInnerHTML(node, html);
23 + expect(node.innerHTML).toBe(html);
24 + });
25 + });
26 +
27 + describe('when the node does not have an innerHTML property', () => {
28 + it('sets innerHTML on it', function() {
29 + // Create a mock node that looks like an SVG in IE (without innerHTML)
30 + var node = {
31 + namespaceURI: DOMNamespaces.svg,
32 + appendChild: jasmine.createSpy(),
33 + };
34 +
35 + var html = '<circle></circle><rect></rect>';
36 + setInnerHTML(node, html);
37 +
38 + expect(node.appendChild.calls.argsFor(0)[0].outerHTML).toBe('<circle></circle>');
39 + expect(node.appendChild.calls.argsFor(1)[0].outerHTML).toBe('<rect></rect>');
40 + });
41 + });
42 +});
src/renderers/dom/client/utils/setInnerHTML.js
+17 -1
@@ -12,12 +12,16 @@
12 'use strict';
13
14 var ExecutionEnvironment = require('ExecutionEnvironment');
15 +var DOMNamespaces = require('DOMNamespaces');
16
17 var WHITESPACE_TEST = /^[ \r\n\t\f]/;
18 var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
19
20 var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
21
22 +// SVG temp container for IE lacking innerHTML
23 +var reusableSVGContainer;
24 +
25 /**
26 * Set the innerHTML property of a node, ensuring that whitespace is preserved
27 * even in IE8.
@@ -28,7 +32,19 @@ var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunc
32 */
33 var setInnerHTML = createMicrosoftUnsafeLocalFunction(
34 function(node, html) {
31 - node.innerHTML = html;
35 + // IE does not have innerHTML for SVG nodes, so instead we inject the
36 + // new markup in a temp node and then move the child nodes across into
37 + // the target node
38 + if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) {
39 + reusableSVGContainer = reusableSVGContainer || document.createElement('div');
40 + reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>';
41 + var newNodes = reusableSVGContainer.firstChild.childNodes;
42 + for (var i = 0; i < newNodes.length; i++) {
43 + node.appendChild(newNodes[i]);
44 + }
45 + } else {
46 + node.innerHTML = html;
47 + }
48 }
49 );
50