Bug 462188. Make nsHTMLEditRules::WillDeleteSelection extend the selection before checking whether there's anything to delete. r+sr=peterv.

This commit is contained in:
Theppitak Karoonboonyanan 2009-01-27 13:50:32 +01:00
parent 506ca0e80c
commit 550bc8beb7
4 changed files with 240 additions and 183 deletions

View File

@ -1948,10 +1948,24 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
if (NS_FAILED(res)) return res;
if (*aCancel) return NS_OK;
res = mHTMLEditor->ExtendSelectionForDelete(aSelection, &aAction);
NS_ENSURE_SUCCESS(res, res);
// We should delete nothing.
if (aAction == nsIEditor::eNone)
return NS_OK;
// ExtendSelectionForDelete() may have changed the selection, update it
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(startNode), &startOffset);
if (NS_FAILED(res)) return res;
if (!startNode) return NS_ERROR_FAILURE;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
}
if (bCollapsed)
{
// what's in the direction we are deleting?
nsWSRunObject wsObj(mHTMLEditor, startNode, startOffset);
nsCOMPtr<nsIDOMNode> visNode;
@ -1996,9 +2010,6 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
}
else
{
res = mHTMLEditor->ExtendSelectionForDelete(aSelection, &aAction);
NS_ENSURE_SUCCESS(res, res);
nsCOMPtr<nsIDOMRange> range;
res = aSelection->GetRangeAt(0, getter_AddRefs(range));
NS_ENSURE_SUCCESS(res, res);
@ -2015,6 +2026,8 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
NS_ASSERTION(container == visNode, "selection end not in visNode");
#endif
res = range->GetStartOffset(&so);
NS_ENSURE_SUCCESS(res, res);
res = range->GetEndOffset(&eo);
NS_ENSURE_SUCCESS(res, res);
}

View File

@ -68,7 +68,7 @@ _TEST_FILES = test_bug288789.html \
test_bug469613.xul \
test_character_movement.html \
test_word_movement.html \
test_backspace_delete.html \
test_backspace_delete.xul \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -1,179 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test BackSpace/Delete Keys</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: block">
<div contentEditable id="editor"></div>
</div>
<p id="catch">Catch-all
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
/** Test for Bug 157546, 417745 **/
SimpleTest.waitForExplicitFinish();
// This seems to be necessary because the selection is not set up properly otherwise
setTimeout(test, 0);
var eatSpace;
function getPrefs() {
const prefSvcContractID = "@mozilla.org/preferences-service;1";
const prefSvcIID = Components.interfaces.nsIPrefService;
return Components.classes[prefSvcContractID].getService(prefSvcIID)
.getBranch("layout.word_select.");
}
function setEatSpace(newValue) {
getPrefs().setBoolPref("eat_space_to_next_word", newValue);
eatSpace = newValue;
}
function restoreEatSpace() {
try {
getPrefs().clearUserPref("eat_space_to_next_word");
} catch(ex) {}
}
function test() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var wordSelModifiers =
(navigator.platform.indexOf("Mac") >= 0) ?
{shiftKey:true, altKey:true} : {shiftKey:true, ctrlKey:true};
var sel = window.getSelection();
var editor = document.getElementById("editor");
function testRight(node, offset) {
synthesizeKey("VK_RIGHT", {});
is(sel.anchorNode, node, "Right movement broken in \"" + editor.innerHTML + "\"");
is(sel.anchorOffset, offset, "Right movement broken in \"" + editor.innerHTML + "\"");
}
function selErrString(dir) {
return dir + " selection broken with eatSpace=" + eatSpace + " in \"" + editor.innerHTML + "\"";
}
function testWordSelRight(startNode, startOffset, endNode, endOffset) {
synthesizeKey("VK_RIGHT", wordSelModifiers);
var selRange = sel.getRangeAt(0);
is(selRange.startContainer, startNode, selErrString("Word right"));
is(selRange.startOffset, startOffset, selErrString("Word right"));
is(selRange.endContainer, endNode, selErrString("Word right"));
is(selRange.endOffset, endOffset, selErrString("Word right"));
}
function testDelete(node, offset, text) {
synthesizeKey("VK_DELETE", {});
is(sel.anchorNode, node, "Delete broken in \"" + editor.innerHTML + "\"");
is(sel.anchorOffset, offset, "Delete broken in \"" + editor.innerHTML + "\"");
is(editor.textContent, text, "Delete broken in \"" + editor.innerHTML + "\"");
}
function testBackspace(node, offset, text) {
synthesizeKey("VK_BACK_SPACE", {});
is(sel.anchorNode, node, "Backspace broken in \"" + editor.innerHTML + "\"");
is(sel.anchorOffset, offset, "Backspace broken in \"" + editor.innerHTML + "\"");
is(editor.textContent, text, "Backspace broken in \"" + editor.innerHTML + "\"");
}
// Test cell-wise deletion of Delete
editor.innerHTML = "สวัสดีพ่อแม่พี่น้อง";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 1);
testDelete(editor.firstChild, 1, "สสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testDelete(editor.firstChild, 2, "สสพ่อแม่พี่น้อง");
testRight(editor.firstChild, 4);
testDelete(editor.firstChild, 4, "สสพ่แม่พี่น้อง");
testRight(editor.firstChild, 5);
testDelete(editor.firstChild, 5, "สสพ่แพี่น้อง");
testRight(editor.firstChild, 8);
testDelete(editor.firstChild, 8, "สสพ่แพี่อง");
testRight(editor.firstChild, 9);
testDelete(editor.firstChild, 9, "สสพ่แพี่อ");
// Test character-wise deletion of Backspace
editor.innerHTML = "สวัสดีพ่อแม่พี่น้อง";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 1);
testBackspace(editor.firstChild, 0, "วัสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testBackspace(editor.firstChild, 1, "วสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testBackspace(editor.firstChild, 1, "วดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 3);
testBackspace(editor.firstChild, 2, "วดพ่อแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพอแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพม่พี่น้อง");
testRight(editor.firstChild, 5);
testBackspace(editor.firstChild, 4, "วดพมพี่น้อง");
testRight(editor.firstChild, 7);
testBackspace(editor.firstChild, 6, "วดพมพีน้อง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีนอง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีนง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีน");
// Tests for Bug 417745
setEatSpace(true);
editor.innerHTML = "Quick yellow fox";
sel.collapse(editor.firstChild, 0);
testWordSelRight(editor.firstChild, 0, editor.firstChild, 6);
testDelete(editor.firstChild, 0, "yellow fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 7);
testDelete(editor.firstChild, 0, "fox");
setEatSpace(false);
editor.innerHTML = "Quick yellow fox";
sel.collapse(editor.firstChild, 0);
testWordSelRight(editor.firstChild, 0, editor.firstChild, 5);
// editor converts the leading space to an &nbsp;, otherwise it
// wouldn't show up which would confuse users
testDelete(editor.firstChild, 0, "\u00A0yellow fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 7);
testDelete(editor.firstChild, 0, "\u00A0fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 4);
testDelete(editor, 0, "");
restoreEatSpace();
// Tests for Bug 419217
editor.innerHTML = "foo<div>bar</div>";
sel.collapse(editor.firstChild, 3);
testDelete(editor.firstChild, 3, "foobar");
// Tests for Bug 419406
editor.innerHTML = "helloשלום";
sel.collapse(editor.firstChild, 4);
testRight(editor.firstChild, 5);
testDelete(editor.firstChild, 5, "helloשלום");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,223 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="Test BackSpace/Delete Keys">
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script class="testbody" type="application/javascript">
<![CDATA[
function execTests() {
var e = document.getElementById("edit");
var doc = e.contentDocument;
var win = e.contentWindow;
var root = doc.documentElement;
var editor = doc.body;
var sel = win.getSelection();
win.focus();
function setupTest(html, firstChildOffsetForCaret) {
// Work around bug 474255 --- we need to have nonempty content before we turn on
// editing, or the tests below break because the editor doesn't notice when we
// insert non-empty content using innerHTML.
doc.designMode = 'off';
editor.innerHTML = html;
doc.designMode = 'on';
sel.collapse(editor.firstChild, firstChildOffsetForCaret);
}
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var eatSpace;
function getPrefs() {
const prefSvcContractID = "@mozilla.org/preferences-service;1";
const prefSvcIID = Components.interfaces.nsIPrefService;
return Components.classes[prefSvcContractID].getService(prefSvcIID)
.getBranch("layout.word_select.");
}
function setEatSpace(newValue) {
getPrefs().setBoolPref("eat_space_to_next_word", newValue);
eatSpace = newValue;
}
function restoreEatSpace() {
try {
getPrefs().clearUserPref("eat_space_to_next_word");
} catch(ex) {}
}
function doCommand(cmd) {
var controller = document.commandDispatcher.getControllerForCommand(cmd);
if (controller) {
controller.doCommand(cmd);
}
}
function testRight(node, offset) {
doCommand("cmd_charNext");
var msg = "Right movement broken in \"" + editor.innerHTML + "\", offset " + offset;
is(sel.anchorNode, node, msg);
is(sel.anchorOffset, offset, msg);
}
function selErrString(dir) {
return dir + " selection broken with eatSpace=" + eatSpace + " in \"" + editor.innerHTML + "\"";
}
function testWordSelRight(startNode, startOffset, endNode, endOffset) {
doCommand("cmd_selectWordNext");
var selRange = sel.getRangeAt(0);
is(selRange.startContainer, startNode, selErrString("Word right"));
is(selRange.startOffset, startOffset, selErrString("Word right"));
is(selRange.endContainer, endNode, selErrString("Word right"));
is(selRange.endOffset, endOffset, selErrString("Word right"));
}
function testDelete(node, offset, text) {
doCommand("cmd_deleteCharForward");
var msg = "Delete broken in \"" + editor.innerHTML + "\", offset " + offset;
is(sel.anchorNode, node, msg);
is(sel.anchorOffset, offset, msg);
is(editor.textContent, text, msg);
}
function testBackspace(node, offset, text) {
doCommand("cmd_deleteCharBackward");
var msg = "Backspace broken in \"" + editor.innerHTML + "\", offset " + offset;
is(sel.anchorNode, node, msg);
is(sel.anchorOffset, offset, msg);
is(editor.textContent, text, msg);
}
function testDeletePrevWord(node, offset, text) {
doCommand("cmd_deleteWordBackward");
var msg = "Delete previous word broken in \"" + editor.innerHTML + "\", offset " + offset;
is(sel.anchorNode, node, msg);
is(sel.anchorOffset, offset, msg);
is(editor.textContent, text, msg);
}
function testDeleteNextWord(node, offset, text) {
doCommand("cmd_deleteWordForward");
var msg = "Delete next word broken in \"" + editor.innerHTML + "\", offset " + offset;
is(sel.anchorNode, node, msg);
is(sel.anchorOffset, offset, msg);
todo_is(editor.textContent, text, msg);
}
// Test cell-wise deletion of Delete
setupTest("สวัสดีพ่อแม่พี่น้อง", 0);
testRight(editor.firstChild, 1);
testDelete(editor.firstChild, 1, "สสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testDelete(editor.firstChild, 2, "สสพ่อแม่พี่น้อง");
testRight(editor.firstChild, 4);
testDelete(editor.firstChild, 4, "สสพ่แม่พี่น้อง");
testRight(editor.firstChild, 5);
testDelete(editor.firstChild, 5, "สสพ่แพี่น้อง");
testRight(editor.firstChild, 8);
testDelete(editor.firstChild, 8, "สสพ่แพี่อง");
testRight(editor.firstChild, 9);
testDelete(editor.firstChild, 9, "สสพ่แพี่อ");
// Test character-wise deletion of Backspace
setupTest("สวัสดีพ่อแม่พี่น้อง", 0);
testRight(editor.firstChild, 1);
testBackspace(editor.firstChild, 0, "วัสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testBackspace(editor.firstChild, 1, "วสดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 2);
testBackspace(editor.firstChild, 1, "วดีพ่อแม่พี่น้อง");
testRight(editor.firstChild, 3);
testBackspace(editor.firstChild, 2, "วดพ่อแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพอแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพแม่พี่น้อง");
testRight(editor.firstChild, 4);
testBackspace(editor.firstChild, 3, "วดพม่พี่น้อง");
testRight(editor.firstChild, 5);
testBackspace(editor.firstChild, 4, "วดพมพี่น้อง");
testRight(editor.firstChild, 7);
testBackspace(editor.firstChild, 6, "วดพมพีน้อง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีนอง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีนง");
testRight(editor.firstChild, 8);
testBackspace(editor.firstChild, 7, "วดพมพีน");
// Tests for Bug 417745
setEatSpace(true);
setupTest("Quick yellow fox", 0);
testWordSelRight(editor.firstChild, 0, editor.firstChild, 6);
testDelete(editor.firstChild, 0, "yellow fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 7);
testDelete(editor.firstChild, 0, "fox");
setEatSpace(false);
setupTest("Quick yellow fox", 0);
testWordSelRight(editor.firstChild, 0, editor.firstChild, 5);
// editor converts the leading space to an &nbsp;, otherwise it
// wouldn't show up which would confuse users
testDelete(editor.firstChild, 0, "\u00A0yellow fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 7);
testDelete(editor.firstChild, 0, "\u00A0fox");
testWordSelRight(editor.firstChild, 0, editor.firstChild, 4);
testDelete(editor, 0, "");
restoreEatSpace();
// Tests for Bug 419217
setupTest("foo<div>bar</div>", 3);
testDelete(editor.firstChild, 3, "foobar");
// Tests for Bug 419406
var s = "helloשלום";
setupTest(s, 4);
testRight(editor.firstChild, 5);
testDelete(editor.firstChild, 5, "helloשלום");
// Tests for Bug 462188
setupTest("You should not see this text.", 29);
testDeletePrevWord(editor.firstChild, 24, "You should not see this ");
testDeletePrevWord(editor.firstChild, 19, "You should not see ");
testDeletePrevWord(editor.firstChild, 15, "You should not ");
testDeletePrevWord(editor.firstChild, 11, "You should ");
testDeletePrevWord(editor.firstChild, 4, "You ");
testDeletePrevWord(editor, 0, "");
setupTest("You should not see this text.", 0);
testDeleteNextWord(editor.firstChild, 0, "\u00A0should not see this text.");
testDeleteNextWord(editor.firstChild, 0, "\u00A0not see this text.");
testDeleteNextWord(editor.firstChild, 0, "\u00A0see this text.");
testDeleteNextWord(editor.firstChild, 0, "\u00A0this text.");
testDeleteNextWord(editor.firstChild, 0, "\u00A0text.");
// testDeleteNextWord(editor, 0, "");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(execTests);
]]>
</script>
<body id="html_body" xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=462188">Mozilla Bug 462188</a>
<p id="display"></p>
<pre id="test">
</pre>
<iframe id="edit" width="200" height="100" src="about:blank"/>
</body>
</window>