Fix some issues related to focus changes in onfocus and onblur handlers:

- Abort firing blur events on the document and/or window if one of the blur handlers focuses something else.  This ensures that the caret doesn't get confused about whether it should be active.
  - Release any mouse or key grab when the view manager sees a deactivate event; this fixes event targeting when a mousedown handler opens a modal dialog.
  - Make sure the editor element is actually focused before activating the caret. Just receiving a focus event isn't good enough, since a focus change does not cancel propagation of the original event.

Bug 53579, r=jkeiser, sr=roc.
This commit is contained in:
bryner%netscape.com 2003-07-01 22:46:55 +00:00
Родитель 5e33fad8a7
Коммит 6d59e7a395
3 изменённых файлов: 82 добавлений и 2 удалений

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

@ -4145,9 +4145,13 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
{
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
nsCOMPtr<nsIContent> previousFocus = mCurrentFocus;
if (nsnull != gLastFocusedPresContext) {
nsCOMPtr<nsIContent> focusAfterBlur;
if (gLastFocusedContent && gLastFocusedContent != mFirstBlurEvent) {
//Store the first blur event we fire and don't refire blur
@ -4215,6 +4219,7 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
temp->HandleDOMEvent(oldPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
pusher.Pop();
focusAfterBlur = mCurrentFocus;
esm->SetFocusedContent(nsnull);
}
}
@ -4222,6 +4227,12 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
if (clearFirstBlurEvent) {
mFirstBlurEvent = nsnull;
}
if (previousFocus != focusAfterBlur) {
// The content node's blur handler focused something else.
// In this case, abort firing any more blur or focus events.
return NS_OK;
}
}
// Go ahead and fire a blur on the window.
@ -4269,8 +4280,20 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
temp->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
pusher.Pop();
if (mCurrentFocus != previousFocus) {
// The document's blur handler focused something else.
// Abort firing any additional blur or focus events.
return NS_OK;
}
pusher.Push(globalObject);
globalObject->HandleDOMEvent(gLastFocusedPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
if (mCurrentFocus != previousFocus) {
// The window's blur handler focused something else.
// Abort firing any additional blur or focus events.
return NS_OK;
}
}
}

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

@ -87,6 +87,8 @@
#include "nsLayoutCID.h"
#include "nsIDOMNSRange.h"
#include "nsEditorUtils.h"
#include "nsIDOMEventTarget.h"
#include "nsIEventStateManager.h"
// Drag & Drop, Clipboard Support
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
@ -989,9 +991,61 @@ nsTextEditorFocusListener::HandleEvent(nsIDOMEvent* aEvent)
return NS_OK;
}
static PRBool
IsTargetFocused(nsIDOMEventTarget* aTarget)
{
// The event target could be either a content node or a document.
nsCOMPtr<nsIDocument> doc;
nsCOMPtr<nsIContent> content = do_QueryInterface(aTarget);
if (content)
content->GetDocument(getter_AddRefs(doc));
else
doc = do_QueryInterface(aTarget);
if (!doc)
return PR_FALSE;
nsCOMPtr<nsIPresShell> shell;
doc->GetShellAt(0, getter_AddRefs(shell));
if (!shell)
return PR_FALSE;
nsCOMPtr<nsIPresContext> presContext;
shell->GetPresContext(getter_AddRefs(presContext));
if (!presContext)
return PR_FALSE;
nsCOMPtr<nsIEventStateManager> esm;
presContext->GetEventStateManager(getter_AddRefs(esm));
if (!esm)
return PR_FALSE;
nsCOMPtr<nsIContent> focusedContent;
esm->GetFocusedContent(getter_AddRefs(focusedContent));
// focusedContent will be null in the case where the document has focus,
// and so will content.
return (focusedContent == content);
}
nsresult
nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
{
// It's possible for us to receive a focus when we're really not focused.
// This happens, for example, when an onfocus handler that's hooked up
// before this listener focuses something else. In that case, all of the
// onblur handlers will be fired synchronously, then the remaining focus
// handlers will be fired from the original event. So, check to see that
// we're really focused. (Note that the analogous situation does not
// happen for blurs, due to the ordering in
// nsEventStateManager::SendFocuBlur().
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
if (!IsTargetFocused(target))
return NS_OK;
// turn on selection and caret
if (mEditor)
{

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

@ -2003,6 +2003,9 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
//Find the view whose coordinates system we're in.
baseView = nsView::GetViewFor(aEvent->widget);
if (aEvent->message == NS_DEACTIVATE)
mMouseGrabber = mKeyGrabber = nsnull;
//Find the view to which we're initially going to send the event
//for hittesting.
if (nsnull != mMouseGrabber && (NS_IS_MOUSE_EVENT(aEvent) || (NS_IS_DRAG_EVENT(aEvent)))) {