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
Родитель 08582782fa
Коммит 7d94e7d9e2
3 изменённых файлов: 44 добавлений и 35 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -2460,8 +2460,10 @@ static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
// frame is the result (in which case different handling is needed), and // frame is the result (in which case different handling is needed), and
// afterFrame says which end is repersented if frameEdge is true // afterFrame says which end is repersented if frameEdge is true
struct FrameTarget { struct FrameTarget {
FrameTarget(nsIFrame* aFrame, PRBool aFrameEdge, PRBool aAfterFrame) : FrameTarget(nsIFrame* aFrame, PRBool aFrameEdge, PRBool aAfterFrame,
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame) { } PRBool aEmptyBlock = PR_FALSE) :
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
emptyBlock(aEmptyBlock) { }
static FrameTarget Null() { static FrameTarget Null() {
return FrameTarget(nsnull, PR_FALSE, PR_FALSE); return FrameTarget(nsnull, PR_FALSE, PR_FALSE);
} }
@ -2471,6 +2473,7 @@ struct FrameTarget {
nsIFrame* frame; nsIFrame* frame;
PRPackedBool frameEdge; PRPackedBool frameEdge;
PRPackedBool afterFrame; PRPackedBool afterFrame;
PRPackedBool emptyBlock;
}; };
// See function implementation for information // See function implementation for information
@ -2596,7 +2599,7 @@ static FrameTarget GetSelectionClosestFrameForLine(
// special because they represent paragraphs and because they are organized // special because they represent paragraphs and because they are organized
// into lines, which have bounds that are not stored elsewhere in the // into lines, which have bounds that are not stored elsewhere in the
// frame tree. Returns a null FrameTarget for frames which are not // 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, static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
nsPoint aPoint) nsPoint aPoint)
{ {
@ -2607,8 +2610,15 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
// This code searches for the correct line // This code searches for the correct line
nsBlockFrame::line_iterator firstLine = bf->begin_lines(); nsBlockFrame::line_iterator firstLine = bf->begin_lines();
nsBlockFrame::line_iterator end = bf->end_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(); return FrameTarget::Null();
}
nsBlockFrame::line_iterator curLine = firstLine; nsBlockFrame::line_iterator curLine = firstLine;
nsBlockFrame::line_iterator closestLine = end; nsBlockFrame::line_iterator closestLine = end;
while (curLine != end) { while (curLine != end) {
@ -2825,6 +2835,17 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint); 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 // If the correct offset is at one end of a frame, use offset-based
// calculation method // calculation method
if (closest.frameEdge) { if (closest.frameEdge) {