Bug 1258085 - Avoid empty whitespace nodes when editing

There are probably a lot more places that could use HandleEmptyText
thrown in, but this covers a few simple ones.
This commit is contained in:
Aryeh Gregor 2016-04-20 21:19:20 +03:00
parent b58b91c974
commit d2127d6d42
5 changed files with 106 additions and 1 deletions

View File

@ -2030,6 +2030,9 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
DeprecatedAbs(eo - so));
*aHandled = true;
NS_ENSURE_SUCCESS(res, res);
DeleteNodeIfCollapsedText(nodeAsText);
res = InsertBRIfNeeded(aSelection);
NS_ENSURE_SUCCESS(res, res);
@ -2471,6 +2474,18 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
}
}
}
// We might have left only collapsed whitespace in the start/end nodes
{
nsAutoTrackDOMPoint startTracker(mHTMLEditor->mRangeUpdater,
address_of(startNode), &startOffset);
nsAutoTrackDOMPoint endTracker(mHTMLEditor->mRangeUpdater,
address_of(endNode), &endOffset);
DeleteNodeIfCollapsedText(*startNode);
DeleteNodeIfCollapsedText(*endNode);
}
// If we're joining blocks: if deleting forward the selection should be
// collapsed to the end of the selection, if deleting backward the selection
// should be collapsed to the beginning of the selection. But if we're not
@ -2488,6 +2503,28 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
return NS_OK;
}
/**
* If aNode is a text node that contains only collapsed whitespace, delete it.
* It doesn't serve any useful purpose, and we don't want it to confuse code
* that doesn't correctly skip over it.
*
* If deleting the node fails (like if it's not editable), the caller should
* proceed as usual, so don't return any errors.
*/
void
nsHTMLEditRules::DeleteNodeIfCollapsedText(nsINode& aNode)
{
if (!aNode.GetAsText()) {
return;
}
bool empty;
nsresult res = mHTMLEditor->IsVisTextNode(aNode.AsContent(), &empty, false);
NS_ENSURE_SUCCESS_VOID(res);
if (empty) {
mHTMLEditor->DeleteNode(&aNode);
}
}
/*****************************************************************************************************
* InsertBRIfNeeded: determines if a br is needed for current selection to not be spastic.

View File

@ -106,6 +106,7 @@ public:
NS_IMETHOD DidDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength, nsresult aResult) override;
NS_IMETHOD WillDeleteSelection(nsISelection *aSelection) override;
NS_IMETHOD DidDeleteSelection(nsISelection *aSelection) override;
void DeleteNodeIfCollapsedText(nsINode& aNode);
protected:
virtual ~nsHTMLEditRules();

View File

@ -168,3 +168,4 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android' # chrome urls not available due to packaging
[test_bug1247483.html]
skip-if = toolkit == 'android'
[test_bug1258085.html]

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<title>Test for Bug 1186799</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<div contenteditable></div>
<script>
var div = document.querySelector("div");
function reset() {
div.innerHTML = "x<br> y";
div.focus();
synthesizeKey("VK_DOWN", {});
}
function checks(msg) {
is(div.innerHTML, "x<br><br>",
msg + ": Should add a second <br> to prevent collapse of first");
is(div.childNodes.length, 3, msg + ": No empty text nodes allowed");
ok(getSelection().isCollapsed, msg + ": Selection must be collapsed");
is(getSelection().focusNode, div, msg + ": Focus must be in div");
is(getSelection().focusOffset, 2,
msg + ": Focus must be between the two <br>s");
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
// Put selection after the "y" and backspace
reset();
synthesizeKey("VK_RIGHT", {});
synthesizeKey("VK_BACK_SPACE", {});
checks("Collapsed backspace");
// Now do the same with delete
reset();
synthesizeKey("VK_DELETE", {});
checks("Collapsed delete");
// Forward selection
reset();
synthesizeKey("VK_RIGHT", {shiftKey: true});
synthesizeKey("VK_BACK_SPACE", {});
checks("Forward-selected backspace");
// Backward selection
reset();
synthesizeKey("VK_RIGHT", {});
synthesizeKey("VK_LEFT", {shiftKey: true});
synthesizeKey("VK_BACK_SPACE", {});
checks("Backward-selected backspace");
// Make sure we're not deleting if the whitespace isn't actually collapsed
div.style.whiteSpace = "pre-wrap";
reset();
synthesizeKey("VK_RIGHT", {});
synthesizeKey("VK_RIGHT", {});
synthesizeKey("VK_BACK_SPACE", {});
if (div.innerHTML, "x<br> ", "pre-wrap: Don't delete uncollapsed space");
ok(getSelection().isCollapsed, "pre-wrap: Selection must be collapsed");
is(getSelection().focusNode, div.lastChild,
"pre-wrap: Focus must be in final text node");
is(getSelection().focusOffset, 1, "pre-wrap: Focus must be at end of node");
SimpleTest.finish();
});
</script>

View File

@ -138,7 +138,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
/* Last not least, some simple edge case tests. */
/*70*/[ "<div>test</div><pre>foobar\n</pre>baz", "<div>testfoobar\n</div>baz" ],
/*71*/[ "<div>test</div><pre>\nfoo\nbar</pre>", "<div>testfoo\n</div><pre>bar</pre>" ],
/*72*/[ "<div>test</div><pre>\n\nfoo\nbar</pre>", "<div>test\n</div><pre>foo\nbar</pre>" ],
/*72*/[ "<div>test</div><pre>\n\nfoo\nbar</pre>", "<div>test</div><pre>foo\nbar</pre>", "<div>test\n</div><pre>foo\nbar</pre>" ],
];
/** Test for Bug 772796 **/