Bug 157546. 'Delete' key should delete entire cluster. patch by Theppitak Karoonboonyanan, r+sr=roc,a=schrep
This commit is contained in:
Родитель
c1ecb791b4
Коммит
539c2b1cc9
|
@ -51,7 +51,7 @@ interface nsIDOMNode;
|
|||
interface nsISelection;
|
||||
interface nsISelectionDisplay;
|
||||
|
||||
[scriptable, uuid(39429306-4c81-4d8b-9421-eb7d9f43bfd0)]
|
||||
[scriptable, uuid(80d2e85a-4ad2-45be-88e7-8c1fe943ac4d)]
|
||||
interface nsISelectionController : nsISelectionDisplay
|
||||
{
|
||||
const short SELECTION_NONE=0;
|
||||
|
@ -154,6 +154,12 @@ interface nsISelectionController : nsISelectionDisplay
|
|||
*/
|
||||
void characterMove(in boolean forward, in boolean extend);
|
||||
|
||||
/** CharacterExtendForDelete will extend the selection one character cell
|
||||
* forward in the document.
|
||||
* this method is used internally for handling del key.
|
||||
*/
|
||||
[noscript] void characterExtendForDelete();
|
||||
|
||||
/** WordMove will move the selection one word forward/backward in the document.
|
||||
* this will also have the effect of collapsing the selection if the aExtend = PR_FALSE
|
||||
* the "point" of selection that is extended is considered the "focus" point.
|
||||
|
|
|
@ -678,6 +678,7 @@ NS_IMETHODIMP nsPlaintextEditor::DeleteSelection(nsIEditor::EDirection aAction)
|
|||
// This needs to happen inside selection batching,
|
||||
// otherwise the deleted text is autocopied to the clipboard.
|
||||
if (aAction == eNextWord || aAction == ePreviousWord
|
||||
|| (aAction == eNext && bCollapsed)
|
||||
|| aAction == eToBeginningOfLine || aAction == eToEndOfLine)
|
||||
{
|
||||
nsCOMPtr<nsISelectionController> selCont (do_QueryReferent(mSelConWeak));
|
||||
|
@ -696,6 +697,10 @@ NS_IMETHODIMP nsPlaintextEditor::DeleteSelection(nsIEditor::EDirection aAction)
|
|||
result = selCont->WordExtendForDelete(PR_FALSE);
|
||||
aAction = eNone;
|
||||
break;
|
||||
case eNext:
|
||||
result = selCont->CharacterExtendForDelete();
|
||||
aAction = eNone;
|
||||
break;
|
||||
case eToBeginningOfLine:
|
||||
selCont->IntraLineMove(PR_TRUE, PR_FALSE); // try to move to end
|
||||
result = selCont->IntraLineMove(PR_FALSE, PR_TRUE); // select to beginning
|
||||
|
|
|
@ -927,6 +927,7 @@ public:
|
|||
// nsISelectionController
|
||||
|
||||
NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
|
||||
NS_IMETHOD CharacterExtendForDelete();
|
||||
NS_IMETHOD WordMove(PRBool aForward, PRBool aExtend);
|
||||
NS_IMETHOD WordExtendForDelete(PRBool aForward);
|
||||
NS_IMETHOD LineMove(PRBool aForward, PRBool aExtend);
|
||||
|
@ -2716,6 +2717,12 @@ PresShell::CharacterMove(PRBool aForward, PRBool aExtend)
|
|||
return mSelection->CharacterMove(aForward, aExtend);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::CharacterExtendForDelete()
|
||||
{
|
||||
return mSelection->CharacterExtendForDelete();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::WordMove(PRBool aForward, PRBool aExtend)
|
||||
{
|
||||
|
|
|
@ -581,6 +581,7 @@ public:
|
|||
NS_IMETHOD GetCaretEnabled(PRBool *_retval);
|
||||
NS_IMETHOD SetCaretVisibilityDuringSelection(PRBool aVisibility);
|
||||
NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
|
||||
NS_IMETHOD CharacterExtendForDelete();
|
||||
NS_IMETHOD WordMove(PRBool aForward, PRBool aExtend);
|
||||
NS_IMETHOD WordExtendForDelete(PRBool aForward);
|
||||
NS_IMETHOD LineMove(PRBool aForward, PRBool aExtend);
|
||||
|
@ -794,6 +795,13 @@ nsTextInputSelectionImpl::CharacterMove(PRBool aForward, PRBool aExtend)
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputSelectionImpl::CharacterExtendForDelete()
|
||||
{
|
||||
if (mFrameSelection)
|
||||
return mFrameSelection->CharacterExtendForDelete();
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputSelectionImpl::WordMove(PRBool aForward, PRBool aExtend)
|
||||
|
|
|
@ -409,6 +409,12 @@ public:
|
|||
/*unsafe*/
|
||||
nsresult CharacterMove(PRBool aForward, PRBool aExtend);
|
||||
|
||||
/** CharacterExtendForDelete extends the selection forward (logically) to
|
||||
* the next character cell, so that the selected cell can be deleted.
|
||||
*/
|
||||
/*unsafe*/
|
||||
nsresult CharacterExtendForDelete();
|
||||
|
||||
/** WordMove will generally be called from the nsiselectioncontroller implementations.
|
||||
* the effect being the selection will move one word left or right.
|
||||
* @param aForward move forward in document.
|
||||
|
|
|
@ -2772,6 +2772,12 @@ nsFrameSelection::CharacterMove(PRBool aForward, PRBool aExtend)
|
|||
return MoveCaret(nsIDOMKeyEvent::DOM_VK_LEFT,aExtend,eSelectCharacter);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameSelection::CharacterExtendForDelete()
|
||||
{
|
||||
return MoveCaret(nsIDOMKeyEvent::DOM_VK_DELETE, PR_TRUE, eSelectCharacter);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameSelection::WordMove(PRBool aForward, PRBool aExtend)
|
||||
{
|
||||
|
|
|
@ -61,6 +61,7 @@ _TEST_FILES = test_bug288789.html \
|
|||
test_bug405178.html \
|
||||
test_character_movement.html \
|
||||
test_word_movement.html \
|
||||
test_backspace_delete.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
<!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 , 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();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче