зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
08582782fa
Коммит
7d94e7d9e2
|
@ -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) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче