Skip to content

Commit 05c133a

Browse files
joshhuntzpao
authored andcommitted
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 (cherry picked from commit 99d8524)
1 parent 92bda14 commit 05c133a

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

src/renderers/dom/client/utils/DOMLazyTree.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'use strict';
1313

1414
var DOMNamespaces = require('DOMNamespaces');
15+
var setInnerHTML = require('setInnerHTML');
1516

1617
var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
1718
var setTextContent = require('setTextContent');
@@ -50,7 +51,7 @@ function insertTreeChildren(tree) {
5051
insertTreeBefore(node, children[i], null);
5152
}
5253
} else if (tree.html != null) {
53-
node.innerHTML = tree.html;
54+
setInnerHTML(node, tree.html);
5455
} else if (tree.text != null) {
5556
setTextContent(node, tree.text);
5657
}
@@ -96,7 +97,7 @@ function queueHTML(tree, html) {
9697
if (enableLazy) {
9798
tree.html = html;
9899
} else {
99-
tree.node.innerHTML = html;
100+
setInnerHTML(tree.node, html);
100101
}
101102
}
102103

Original file line numberDiff line numberDiff line change
@@ -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
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@
1212
'use strict';
1313

1414
var ExecutionEnvironment = require('ExecutionEnvironment');
15+
var DOMNamespaces = require('DOMNamespaces');
1516

1617
var WHITESPACE_TEST = /^[ \r\n\t\f]/;
1718
var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
1819

1920
var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
2021

22+
// SVG temp container for IE lacking innerHTML
23+
var reusableSVGContainer;
24+
2125
/**
2226
* Set the innerHTML property of a node, ensuring that whitespace is preserved
2327
* even in IE8.
@@ -28,7 +32,19 @@ var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunc
2832
*/
2933
var setInnerHTML = createMicrosoftUnsafeLocalFunction(
3034
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+
}
3248
}
3349
);
3450

0 commit comments

Comments
 (0)