From 534e7c06e9c2446028a82e2e6c695a130ee7f061 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Tue, 25 Feb 2014 21:02:04 -0800 Subject: [PATCH] Consolidate innerHTML setting logic See https://github.com/facebook/react/commit/7eb33ef#commitcomment-5447724. --- .../ui/ReactComponentBrowserEnvironment.js | 3 +- src/browser/ui/ReactDOMIDOperations.js | 33 +--------- src/browser/ui/dom/setInnerHTML.js | 64 +++++++++++++++++++ 3 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 src/browser/ui/dom/setInnerHTML.js diff --git a/src/browser/ui/ReactComponentBrowserEnvironment.js b/src/browser/ui/ReactComponentBrowserEnvironment.js index 12e4b59316..a04bb79067 100644 --- a/src/browser/ui/ReactComponentBrowserEnvironment.js +++ b/src/browser/ui/ReactComponentBrowserEnvironment.js @@ -28,6 +28,7 @@ var ReactReconcileTransaction = require('ReactReconcileTransaction'); var getReactRootElementInContainer = require('getReactRootElementInContainer'); var invariant = require('invariant'); +var setInnerHTML = require('setInnerHTML'); var ELEMENT_NODE_TYPE = 1; @@ -113,7 +114,7 @@ var ReactComponentBrowserEnvironment = { 'See renderComponentToString() for server rendering.' ); - container.innerHTML = markup; + setInnerHTML(container, markup); } ) }; diff --git a/src/browser/ui/ReactDOMIDOperations.js b/src/browser/ui/ReactDOMIDOperations.js index 898509f33b..ea206cd065 100644 --- a/src/browser/ui/ReactDOMIDOperations.js +++ b/src/browser/ui/ReactDOMIDOperations.js @@ -28,6 +28,7 @@ var ReactMount = require('ReactMount'); var ReactPerf = require('ReactPerf'); var invariant = require('invariant'); +var setInnerHTML = require('setInnerHTML'); /** * Errors for properties that should not be updated with `updatePropertyById()`. @@ -41,8 +42,6 @@ var INVALID_PROPERTY_ERRORS = { style: '`style` must be set using `updateStylesByID()`.' }; -var useWhitespaceWorkaround; - /** * Operations used to process updates to DOM nodes. This is made injectable via * `ReactComponent.BackendIDOperations`. @@ -131,35 +130,7 @@ var ReactDOMIDOperations = { 'updateInnerHTMLByID', function(id, html) { var node = ReactMount.getNode(id); - - // 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 - - if (useWhitespaceWorkaround === undefined) { - // Feature detection; only IE8 is known to behave improperly like this. - var temp = document.createElement('div'); - temp.innerHTML = ' '; - useWhitespaceWorkaround = temp.innerHTML === ''; - } - - if (useWhitespaceWorkaround) { - // 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. - node.parentNode.replaceChild(node, node); - } - - if (useWhitespaceWorkaround && html.match(/^[ \r\n\t\f]/)) { - // Recover leading whitespace by temporarily prepending any character. - // \uFEFF has the potential advantage of being zero-width/invisible. - node.innerHTML = '\uFEFF' + html; - node.firstChild.deleteData(0, 1); - } else { - node.innerHTML = html; - } + setInnerHTML(node, html); } ), diff --git a/src/browser/ui/dom/setInnerHTML.js b/src/browser/ui/dom/setInnerHTML.js new file mode 100644 index 0000000000..d3c3cb788c --- /dev/null +++ b/src/browser/ui/dom/setInnerHTML.js @@ -0,0 +1,64 @@ +/** + * Copyright 2013-2014 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule setInnerHTML + */ + +"use strict"; + +var ExecutionEnvironment = require('ExecutionEnvironment'); + +/** + * Set the innerHTML property of a node, ensuring that whitespace is preserved + * even in IE8. + * + * @param {DOMElement} node + * @param {string} html + * @internal + */ +var setInnerHTML = function(node, html) { + 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. + node.parentNode.replaceChild(node, node); + + if (html.match(/^[ \r\n\t\f]/)) { + // Recover leading whitespace by temporarily prepending any character. + // \uFEFF has the potential advantage of being zero-width/invisible. + node.innerHTML = '\uFEFF' + html; + node.firstChild.deleteData(0, 1); + } else { + node.innerHTML = html; + } + }; + } +} + +module.exports = setInnerHTML;