Permalink
Browse files

Add a goog.editor.node.replaceInnerHtml, which detaches children

before setting innerHTML

R=jamisong
DELTA=40 (28 added, 0 deleted, 12 changed)


Revision created by MOE tool push_codebase.
MOE_MIGRATION=6066


git-svn-id: http://closure-library.googlecode.com/svn/trunk@2411 0b95b8e8-c90f-11de-9d4f-f947ee5921c8
  • Loading branch information...
nicksantos@google.com
nicksantos@google.com committed Jan 3, 2013
1 parent da2ae1b commit cae70d825ff88530facabab27624cd6fa3b561d5
@@ -1230,7 +1230,7 @@ goog.editor.Field.prototype.injectContents = function(contents, field) {
var styles = {};
var newHtml = this.getInjectableContents(contents, styles);
goog.style.setStyle(field, styles);
- field.innerHTML = newHtml;
+ goog.editor.node.replaceInnerHtml(field, newHtml);
};
@@ -2441,7 +2441,7 @@ goog.editor.Field.prototype.makeUneditable = function(opt_skipRestore) {
// so that the original node will have the same properties as it did before
// it was made editable.
if (goog.isString(html)) {
- field.innerHTML = html;
+ goog.editor.node.replaceInnerHtml(field, html);
this.resetOriginalElemProperties();
}
@@ -29,6 +29,7 @@ goog.require('goog.iter');
goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.string.Unicode');
+goog.require('goog.userAgent');
/**
@@ -455,3 +456,28 @@ goog.editor.node.getSecondHalfOfNode_ = function(node, startNode, firstChild) {
goog.editor.node.transferChildren = function(newNode, oldNode) {
goog.dom.append(newNode, oldNode.childNodes);
};
+
+
+/**
+ * Replaces the innerHTML of a node.
+ *
+ * IE has serious problems if you try to set innerHTML of an editable node with
+ * any selection. Early versions of IE tear up the old internal tree storage, to
+ * help avoid ref-counting loops. But this sometimes leaves the selection object
+ * in a bad state and leads to segfaults.
+ *
+ * Removing the nodes first prevents IE from tearing them up. This is not
+ * strictly necessary in nodes that do not have the selection. You should always
+ * use this function when setting innerHTML inside of a field.
+ *
+ * @param {Node} node A node.
+ * @param {string} html The innerHTML to set on the node.
+ */
+goog.editor.node.replaceInnerHtml = function(node, html) {
+ // Only do this IE. On gecko, we use element change events, and don't
+ // want to trigger spurious events.
+ if (goog.userAgent.IE) {
+ goog.dom.removeChildren(node);
+ }
+ node.innerHTML = html;
+};
@@ -588,9 +588,10 @@ goog.editor.plugins.BasicTextFormatter.prototype.convertBreaksToDivs_ =
// div's. The reason may be hidden in CLs 5332866 and 8530601.
var attribute = 'trtempbr';
var value = 'temp_br';
- parent.innerHTML = parent.innerHTML.replace(
+ var newHtml = parent.innerHTML.replace(
goog.editor.plugins.BasicTextFormatter.BR_REGEXP_,
'<p$1 ' + attribute + '="' + value + '">');
+ goog.editor.node.replaceInnerHtml(parent, newHtml);
var paragraphs =
goog.array.toArray(parent.getElementsByTagName(goog.dom.TagName.P));
@@ -660,7 +660,7 @@ goog.editor.plugins.EnterHandler.deleteW3cRange_ = function(range) {
// Don't break Opera's native break-out-of-lists behavior.
html = '<br>';
}
- container.innerHTML = html;
+ goog.editor.node.replaceInnerHtml(container, html);
goog.editor.range.selectNodeStart(container.firstChild);
reselect = false;
}
@@ -283,11 +283,11 @@ goog.editor.plugins.RemoveFormatting.prototype.pasteHtml_ = function(html) {
// remove parentNodes of the span while they are empty.
if (goog.userAgent.GECKO) {
- parent.innerHTML =
- parent.innerHTML.replace(dummyImageNodePattern, html);
+ goog.editor.node.replaceInnerHtml(parent,
+ parent.innerHTML.replace(dummyImageNodePattern, html));
} else {
- parent.innerHTML =
- parent.innerHTML.replace(dummyImageNodePattern, dummySpanText);
+ goog.editor.node.replaceInnerHtml(parent,
+ parent.innerHTML.replace(dummyImageNodePattern, dummySpanText));
var dummySpan = dh.getElement(dummyNodeId);
parent = dummySpan;
while ((parent = dummySpan.parentNode) &&
@@ -307,8 +307,8 @@ goog.editor.plugins.RemoveFormatting.prototype.pasteHtml_ = function(html) {
goog.dom.insertSiblingAfter(dummySpan, parent);
goog.dom.removeNode(parent);
}
- parent.innerHTML =
- parent.innerHTML.replace(new RegExp(dummySpanText, 'i'), html);
+ goog.editor.node.replaceInnerHtml(parent,
+ parent.innerHTML.replace(new RegExp(dummySpanText, 'i'), html));
}
}
@@ -29,6 +29,7 @@ goog.require('goog.editor.BrowserFeature');
goog.require('goog.editor.Command');
goog.require('goog.editor.Field.EventType');
goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
goog.require('goog.editor.plugins.UndoRedoManager');
goog.require('goog.editor.plugins.UndoRedoState');
goog.require('goog.events');
@@ -411,7 +412,7 @@ goog.editor.plugins.UndoRedo.prototype.restoreState = function(
// We specifically set the raw innerHTML of the field here as that's what
// we get from the field when we save an undo/redo state. There's
// no need to clean/unclean the contents in either direction.
- fieldObj.getElement().innerHTML = content;
+ goog.editor.node.replaceInnerHtml(fieldObj.getElement(), content);
if (cursorPosition) {
cursorPosition.select();
@@ -667,7 +667,7 @@ goog.editor.SeamlessField.prototype.attachIframe = function(iframe) {
goog.style.setStyle(field, 'lineHeight', '0');
}
- field.innerHTML = html;
+ goog.editor.node.replaceInnerHtml(field, html);
// Set the initial size
goog.style.setSize(iframe, width, height);
goog.style.setSize(field, oldWidth, oldHeight);

0 comments on commit cae70d8

Please sign in to comment.