Bug 550434 Clicking in an empty contenteditable element that has focus causes the caret to disappear (alternative approach) r=roc

This commit is contained in:
Masayuki Nakano 2010-06-14 12:11:30 +09:00
parent 94442dd89e
commit 6e00300d75
3 changed files with 44 additions and 35 deletions

View File

@ -371,8 +371,6 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
return rv;
}
EnsureSelectionInEditor(aMouseEvent, PR_FALSE);
// If we got a mouse down inside the editing area, we should force the
// IME to commit before we change the cursor position
mEditor->ForceCompositionEnd();
@ -857,21 +855,14 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_ARG(aEvent);
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
// turn on selection and caret
if (mEditor->IsDisabled()) {
return NS_OK;
}
EnsureSelectionInEditor(aEvent, PR_TRUE);
return NS_OK;
}
void
nsEditorEventListener::EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFocus)
{
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
PRBool targetIsEditableDoc = PR_FALSE;
@ -889,12 +880,12 @@ nsEditorEventListener::EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFo
// listener in the chain changed the focus.
if (editableRoot) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, );
NS_ENSURE_TRUE(fm, NS_OK);
nsCOMPtr<nsIDOMElement> element;
fm->GetFocusedElement(getter_AddRefs(element));
if (!SameCOMIdentity(element, target))
return;
return NS_OK;
}
}
else {
@ -910,24 +901,22 @@ nsEditorEventListener::EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFo
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
if (aOnFocus) {
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_FALSE);
if (selection) {
caret->SetCaretDOMSelection(selection);
}
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_FALSE);
if (selection) {
caret->SetCaretDOMSelection(selection);
}
}
selCon->SetCaretReadOnly(mEditor->IsReadonly());
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
}
selCon->SetCaretReadOnly(mEditor->IsReadonly());
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate)
@ -935,7 +924,7 @@ nsEditorEventListener::EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFo
selectionPrivate->SetAncestorLimiter(editableRoot);
}
if (aOnFocus && selection && !editableRoot) {
if (selection && !editableRoot) {
PRInt32 rangeCount;
selection->GetRangeCount(&rangeCount);
if (rangeCount == 0) {
@ -943,6 +932,7 @@ nsEditorEventListener::EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFo
}
}
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -107,8 +107,6 @@ protected:
nsresult DragGesture(nsIDOMDragEvent* aDragEvent);
already_AddRefed<nsIPresShell> GetPresShell();
void EnsureSelectionInEditor(nsIDOMEvent* aEvent, PRBool aOnFocus);
protected:
nsEditor* mEditor; // weak
nsRefPtr<nsCaret> mCaret;

View File

@ -2460,8 +2460,10 @@ static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
// frame is the result (in which case different handling is needed), and
// afterFrame says which end is repersented if frameEdge is true
struct FrameTarget {
FrameTarget(nsIFrame* aFrame, PRBool aFrameEdge, PRBool aAfterFrame) :
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame) { }
FrameTarget(nsIFrame* aFrame, PRBool aFrameEdge, PRBool aAfterFrame,
PRBool aEmptyBlock = PR_FALSE) :
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
emptyBlock(aEmptyBlock) { }
static FrameTarget Null() {
return FrameTarget(nsnull, PR_FALSE, PR_FALSE);
}
@ -2471,6 +2473,7 @@ struct FrameTarget {
nsIFrame* frame;
PRPackedBool frameEdge;
PRPackedBool afterFrame;
PRPackedBool emptyBlock;
};
// See function implementation for information
@ -2596,7 +2599,7 @@ static FrameTarget GetSelectionClosestFrameForLine(
// special because they represent paragraphs and because they are organized
// into lines, which have bounds that are not stored elsewhere in the
// frame tree. Returns a null FrameTarget for frames which are not
// blocks or blocks with no lines.
// blocks or blocks with no lines except editable one.
static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
nsPoint aPoint)
{
@ -2607,8 +2610,15 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
// This code searches for the correct line
nsBlockFrame::line_iterator firstLine = bf->begin_lines();
nsBlockFrame::line_iterator end = bf->end_lines();
if (firstLine == end)
if (firstLine == end) {
nsIContent *blockContent = aFrame->GetContent();
if (blockContent && blockContent->IsEditable()) {
// If the frame is ediable empty block, we should return it with empty
// flag.
return FrameTarget(aFrame, PR_FALSE, PR_FALSE, PR_TRUE);
}
return FrameTarget::Null();
}
nsBlockFrame::line_iterator curLine = firstLine;
nsBlockFrame::line_iterator closestLine = end;
while (curLine != end) {
@ -2825,6 +2835,17 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint);
if (closest.emptyBlock) {
ContentOffsets offsets;
NS_ASSERTION(closest.frame,
"closest.frame must not be null when it's empty");
offsets.content = closest.frame->GetContent();
offsets.offset = 0;
offsets.secondaryOffset = 0;
offsets.associateWithNext = PR_TRUE;
return offsets;
}
// If the correct offset is at one end of a frame, use offset-based
// calculation method
if (closest.frameEdge) {