Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/core/ReactDOMIDOperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var INVALID_PROPERTY_ERRORS = {
*/
var textContentAccessor = getTextContentAccessor() || 'NA';

var LEADING_SPACE = /^ /;
var useWhitespaceWorkaround;

/**
* Operations used to process updates to DOM nodes. This is made injectable via
Expand Down Expand Up @@ -124,9 +124,35 @@ var ReactDOMIDOperations = {
*/
updateInnerHTMLByID: function(id, html) {
var node = ReactMount.getNode(id);
// HACK: IE8- normalize whitespace in innerHTML, removing leading spaces.

// 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
node.innerHTML = html.replace(LEADING_SPACE, ' ');

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;
}
},

/**
Expand Down
8 changes: 5 additions & 3 deletions src/core/__tests__/ReactDOMIDOperations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,21 @@ describe('ReactDOMIDOperations', function() {
).toBe(0);
});

it('should update innerHTML and special-case whitespace', function() {
it('should update innerHTML and preserve whitespace', function() {
var stubNode = document.createElement('div');
spyOn(ReactMount, "getNode").andReturn(stubNode);

var html = '\n \t <span> \n testContent \t </span> \n \t';

ReactDOMIDOperations.updateInnerHTMLByID(
'testID',
' testContent'
html
);

expect(
ReactMount.getNode.argsForCall[0][0]
).toBe('testID');

expect(stubNode.innerHTML).toBe('&nbsp;testContent');
expect(stubNode.innerHTML).toBe(html);
});
});