2017-05-03 15:35:00 +02:00
|
|
|
/**
|
|
|
|
* 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 = '<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
|
2017-08-14 05:01:11 +02:00
|
|
|
node.innerHTML = String.fromCharCode(0xfeff) + html;
|
2017-05-03 15:35:00 +02:00
|
|
|
|
|
|
|
// 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;
|