Bug 282098. Accessible focus can get trapped inside of popup. r=pkw, sr=jst

This commit is contained in:
aaronleventhal%moonset.net 2005-02-18 14:34:30 +00:00
Родитель 650f2060bf
Коммит 2bacd5d56c
2 изменённых файлов: 78 добавлений и 5 удалений

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

@ -55,6 +55,7 @@
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDocument.h"
#include "nsIHTMLDocument.h"
#include "nsIFocusController.h"
#include "nsIFrame.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIScriptGlobalObject.h"
@ -246,6 +247,9 @@ nsresult nsRootAccessible::AddEventListeners()
rv = target->AddEventListener(NS_LITERAL_STRING("popupshown"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
rv = target->AddEventListener(NS_LITERAL_STRING("popuphiding"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
@ -288,6 +292,7 @@ nsresult nsRootAccessible::RemoveEventListeners()
target->RemoveEventListener(NS_LITERAL_STRING("CheckboxStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("RadioStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("popupshown"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("popuphiding"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuItemActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
@ -459,6 +464,46 @@ void nsRootAccessible::FireDHTMLFocusRelatedEvents(nsIAccessible *aAccessible, P
}
}
void nsRootAccessible::FireCurrentFocusEvent()
{
nsCOMPtr<nsIDOMWindow> domWin;
GetWindow(getter_AddRefs(domWin));
nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(domWin));
if (!privateDOMWindow) {
return;
}
nsIFocusController *focusController = privateDOMWindow->GetRootFocusController();
if (!focusController) {
return;
}
nsCOMPtr<nsIDOMElement> focusedElement;
focusController->GetFocusedElement(getter_AddRefs(focusedElement));
nsCOMPtr<nsIDOMNode> focusedNode(do_QueryInterface(focusedElement));
if (!focusedNode) {
// Document itself may have focus
nsCOMPtr<nsIDOMWindowInternal> focusedWinInternal;
focusController->GetFocusedWindow(getter_AddRefs(focusedWinInternal));
if (focusedWinInternal) {
nsCOMPtr<nsIDOMDocument> focusedDOMDocument;
focusedWinInternal->GetDocument(getter_AddRefs(focusedDOMDocument));
focusedNode = do_QueryInterface(focusedDOMDocument);
}
if (!focusedNode) {
return; // Could not get a focused document either
}
}
nsCOMPtr<nsIPresShell> eventShell;
GetEventShell(focusedNode, getter_AddRefs(eventShell));
NS_ASSERTION(eventShell, "No presshell for focused node");
nsCOMPtr<nsIAccessible> accessible;
mAccService->GetAccessibleInShell(focusedNode, eventShell,
getter_AddRefs(accessible));
if (accessible) {
FireAccessibleFocusEvent(accessible, focusedNode);
}
}
void nsRootAccessible::GetEventShell(nsIDOMNode *aNode, nsIPresShell **aEventShell)
{
// XXX aaronl - this is not ideal.
@ -630,12 +675,23 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_MENUSTART, accessible, nsnull);
else if (eventType.LowerCaseEqualsLiteral("dommenubarinactive")) {
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_MENUEND, accessible, nsnull);
GetFocusedChild(getter_AddRefs(accessible)); // Returns null if no focus
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(accessible));
if (accessNode) {
accessNode->GetDOMNode(getter_AddRefs(targetNode));
FireAccessibleFocusEvent(accessible, targetNode);
FireCurrentFocusEvent();
}
else if (eventType.LowerCaseEqualsLiteral("popuphiding")) {
// If accessible focus was inside popup that closes,
// then restore it to true current focus.
// This is the case when we've been getting DOMMenuItemActive events
// inside of a combo box that closes. The real focus is on the combo box.
if (!gLastFocusedNode) {
return NS_OK;
}
nsCOMPtr<nsIDOMNode> parentOfFocus;
gLastFocusedNode->GetParentNode(getter_AddRefs(parentOfFocus));
if (parentOfFocus != targetNode) {
return NS_OK;
}
// Focus was inside of popup that's being hidden
FireCurrentFocusEvent();
}
else {
// Menu popup events
@ -716,6 +772,22 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
stateData.state = STATE_EXPANDED;
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, accessible, &stateData);
}
else if (eventType.LowerCaseEqualsLiteral("popuphiding")) {
// If accessible focus was inside popup that closes,
// then restore it to true current focus.
// This is the case when we've been getting DOMMenuItemActive events
// inside of a combo box that closes. The real focus is on the combo box.
if (!gLastFocusedNode) {
return NS_OK;
}
nsCOMPtr<nsIDOMNode> parentOfFocus;
gLastFocusedNode->GetParentNode(getter_AddRefs(parentOfFocus));
if (parentOfFocus != targetNode) {
return NS_OK;
}
// Focus was inside of popup that's being hidden
FireCurrentFocusEvent();
}
else if (eventType.LowerCaseEqualsLiteral("popupshown")) {
FireAccessibleFocusEvent(accessible, targetNode);
}

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

@ -108,6 +108,7 @@ class nsRootAccessible : public nsDocAccessibleWrap,
static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
void FireAccessibleFocusEvent(nsIAccessible *focusAccessible, nsIDOMNode *focusNode);
void FireDHTMLFocusRelatedEvents(nsIAccessible *aFocusAccessible, PRUint32 aRole);
void FireCurrentFocusEvent();
void GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget);
nsCOMPtr<nsIAccessibilityService> mAccService;
nsCOMPtr<nsIAccessibleCaret> mCaretAccessible;