Bug 507936 - Should join node when deleting at end of paragraph. r=peterv

This commit is contained in:
liucougar@gmail.com 2010-03-23 09:23:23 +01:00
parent 992145aea6
commit cb757fbca3
2 changed files with 78 additions and 13 deletions

View File

@ -1920,10 +1920,17 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
nsresult res = NS_OK;
PRBool bPlaintext = mFlags & nsIPlaintextEditor::eEditorPlaintextMask;
PRBool bCollapsed;
PRBool bCollapsed, join = PR_FALSE;
res = aSelection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
// origCollapsed is used later to determine whether we should join
// blocks. We don't really care about bCollapsed because it will be
// modified by ExtendSelectionForDelete later. JoinBlocks should
// happen if the original selection is collapsed and the cursor is
// at the end of a block element, in which case ExtendSelectionForDelete
// would always make the selection not collapsed.
PRBool origCollapsed = bCollapsed;
nsCOMPtr<nsIDOMNode> startNode, selNode;
PRInt32 startOffset, selOffset;
@ -2467,6 +2474,8 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_UNEXPECTED;
join = PR_TRUE;
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
{
nsCOMPtr<nsISupports> currentItem;
@ -2493,6 +2502,17 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
nsIDOMNode* somenode = arrayOfNodes[0];
res = DeleteNonTableElements(somenode);
arrayOfNodes.RemoveObjectAt(0);
// If something visible is deleted, no need to join.
// Visible means all nodes except non-visible textnodes and breaks.
if (join && origCollapsed) {
if (mHTMLEditor->IsTextNode(somenode)) {
mHTMLEditor->IsVisTextNode(somenode, &join, PR_TRUE);
}
else {
join = nsTextEditUtils::IsBreak(somenode) &&
!mHTMLEditor->IsVisBreak(somenode);
}
}
}
}
@ -2526,14 +2546,6 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
}
}
PRBool join = leftBlockParent == rightBlockParent;
if (!join) {
nsCOMPtr<nsINode> parent1 = do_QueryInterface(leftParent);
nsCOMPtr<nsINode> parent2 = do_QueryInterface(rightParent);
PRUint16 pos = nsContentUtils::ComparePosition(parent1, parent2);
join = (pos & (nsIDOM3Node::DOCUMENT_POSITION_CONTAINS |
nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY)) != 0;
}
if (join) {
res = JoinBlocks(address_of(leftParent), address_of(rightParent),
aCancel);
@ -2542,7 +2554,15 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
}
}
}
if (aAction == nsIEditor::eNext)
//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
//joining then the selection should collapse to the beginning of the
//selection if we'redeleting forward, because the end of the selection will
//still be in the next block. And same thing for deleting backwards
//(selection should collapse to the end, because the beginning will still
//be in the first block). See Bug 507936
if (join ? aAction == nsIEditor::eNext : aAction == nsIEditor::ePrevious)
{
res = aSelection->Collapse(endNode,endOffset);
}

View File

@ -19,14 +19,18 @@ function execTests() {
var sel = win.getSelection();
win.focus();
function setupTest(html, firstChildOffsetForCaret) {
function setupTest(html, firstChildOffsetForCaret, node) {
// 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);
var n = editor.firstChild;
if (node) {
n = node();
}
sel.collapse(n, firstChildOffsetForCaret);
}
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@ -211,6 +215,47 @@ function execTests() {
setupTest("<p>Bug</p>\n<p>502259</p>", 1);
testDelete(function(){return editor.firstChild.firstChild;}, 3, "<p>Bug502259</p>", true);
// Tests for Bug 507936
var nodecallback = function(){return editor.firstChild.firstChild.lastChild.firstChild.lastChild;};
setupTest("<ol><li>one<ol><li>two</li></ol></li></ol>\n<p>three</p>", 3, nodecallback);
testDelete(nodecallback, 0, "<ol><li>one<ol><li>twothree</li></ol></li></ol>", true);
setupTest("<ol><li>one<ol><li>two</li></ol></li></ol>\n<hr>\n<p>three</p>", 3, nodecallback);
testDelete(nodecallback, 3,
"<ol><li>one<ol><li>two</li></ol></li></ol><p>three</p>", true);
// Tests for Bug 519751
var nodecallback = function(){return editor.firstChild.lastChild;};
setupTest("<p>one</p><ol><li>two</li><li>three</li></ol>", 3, nodecallback);
testDelete(nodecallback, 0, "<p>onetwo</p><ol><li>three</li></ol>", true);
nodecallback = function(){return editor.firstChild.childNodes[1].firstChild;};
setupTest("<ol><li>one</li><li>two</li></ol><ol><li>three</li><li>four</li></ol>", 3, nodecallback);
testDelete(function(){return editor.firstChild.childNodes[2].firstChild;},
0, "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>", true);
/*todo_is(false, true, 'The above testDelete should use the same nodecallback' +
'as in the proceeding setupTest: the cursor should stay at the end of "two", while currently it is at the beginning of "three" after delete');*/
// More Tests for Bug 507936
nodecallback = function(){return editor.firstChild.firstChild.firstChild;}
setupTest("<div><div>abcdef</div><div>bar</div><div>ghi</div></div>", 5, nodecallback);
sel.extend(editor.lastChild.lastChild.lastChild, 1);
testDelete(editor.lastChild.lastChild.lastChild, 5, "<div><div>abcdehi</div></div>", true);
setupTest("<div><div>abcdef</div><div>ghi</div></div>", 5, nodecallback);
sel.extend(editor.lastChild.lastChild.lastChild, 1);
testDelete(editor.lastChild.lastChild.lastChild, 5, "<div><div>abcdehi</div></div>", true);
nodecallback = function(){return editor.firstChild.firstChild;}
setupTest("<div>abcdef<div><div>bar</div>ghi</div></div>", 5, nodecallback);
sel.extend(editor.lastChild.lastChild.lastChild, 1);
expectednodecallback = function(){return editor.lastChild.lastChild;}
testDelete(expectednodecallback, 0, "<div>abcdehi</div>", true);
setupTest("<div>abcdef<div>ghi</div></div>", 5, nodecallback);
sel.extend(editor.lastChild.lastChild.lastChild, 1);
testDelete(expectednodecallback, 0, "<div>abcdehi</div>", true);
SimpleTest.finish();
}