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