/** * 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. * */ 'use strict'; var ExecutionEnvironment = require('fbjs/lib/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 = '' + html + ''; 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;