Permalink
| /** | |
| * Copyright 2013-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. | |
| * | |
| * @providesModule setInnerHTML | |
| */ | |
| '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. | |
| * | |
| * @param {DOMElement} node | |
| * @param {string} html | |
| * @internal | |
| */ | |
| var setInnerHTML = createMicrosoftUnsafeLocalFunction( | |
| function(node, 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 = '<svg>' + html + '</svg>'; | |
| var svgNode = reusableSVGContainer.firstChild; | |
| while (svgNode.firstChild) { | |
| node.appendChild(svgNode.firstChild); | |
| } | |
| } else { | |
| node.innerHTML = html; | |
| } | |
| } | |
| ); | |
| if (ExecutionEnvironment.canUseDOM) { | |
| // IE8: When updating a just created node with innerHTML only leading | |
| // whitespace is removed. When updating an existing node with innerHTML | |
| // whitespace in root TextNodes is also collapsed. | |
| // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html | |
| // Feature detection; only IE8 is known to behave improperly like this. | |
| var testElement = document.createElement('div'); | |
| testElement.innerHTML = ' '; | |
| if (testElement.innerHTML === '') { | |
| setInnerHTML = function(node, html) { | |
| // Magic theory: IE8 supposedly differentiates between added and updated | |
| // nodes when processing innerHTML, innerHTML on updated nodes suffers | |
| // from worse whitespace behavior. Re-adding a node like this triggers | |
| // the initial and more favorable whitespace behavior. | |
| // TODO: What to do on a detached node? | |
| if (node.parentNode) { | |
| node.parentNode.replaceChild(node, node); | |
| } | |
| // We also implement a workaround for non-visible tags disappearing into | |
| // thin air on IE8, this only happens if there is no visible text | |
| // in-front of the non-visible tags. Piggyback on the whitespace fix | |
| // and simply check if any non-visible tags appear in the source. | |
| if (WHITESPACE_TEST.test(html) || | |
| html[0] === '<' && NONVISIBLE_TEST.test(html)) { | |
| // Recover leading whitespace by temporarily prepending any character. | |
| // \uFEFF has the potential advantage of being zero-width/invisible. | |
| // UglifyJS drops U+FEFF chars when parsing, so use String.fromCharCode | |
| // in hopes that this is preserved even if "\uFEFF" is transformed to | |
| // the actual Unicode character (by Babel, for example). | |
| // https://github.com/mishoo/UglifyJS2/blob/v2.4.20/lib/parse.js#L216 | |
| node.innerHTML = String.fromCharCode(0xFEFF) + html; | |
| // deleteData leaves an empty `TextNode` which offsets the index of all | |
| // children. Definitely want to avoid this. | |
| var textNode = node.firstChild; | |
| if (textNode.data.length === 1) { | |
| node.removeChild(textNode); | |
| } else { | |
| textNode.deleteData(0, 1); | |
| } | |
| } else { | |
| node.innerHTML = html; | |
| } | |
| }; | |
| } | |
| testElement = null; | |
| } | |
| module.exports = setInnerHTML; |