Bug 112978. HTML select options need to generate Accessibility API focus events, so screen readers can track user's movements through options. r=jgaunt, sr=attinasi, a=asa

This commit is contained in:
aaronl%netscape.com 2002-04-04 23:27:45 +00:00
parent 7fed76935a
commit be88fe4c6a
5 changed files with 69 additions and 26 deletions

View File

@ -376,7 +376,7 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
// Check to see if it's a select element. If so, need the currently focused option
nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(targetNode));
if (selectElement) // ----- Target Node is an HTML <select> element ------
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mPresShell, targetNode, optionTargetNode);
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(targetNode, optionTargetNode);
// for focus events on Radio Groups we give the focus to the selected button
nsCOMPtr<nsIDOMXULSelectControlElement> selectControl(do_QueryInterface(targetNode));
@ -393,7 +393,7 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
if (NS_SUCCEEDED(mAccService->GetAccessibleFor(targetNode, getter_AddRefs(accessible)))) {
if (eventType.EqualsIgnoreCase("focus") || eventType.EqualsIgnoreCase("DOMMenuItemActive")) {
if (selectControl && optionTargetNode &&
if (optionTargetNode &&
NS_SUCCEEDED(mAccService->GetAccessibleFor(optionTargetNode, getter_AddRefs(accessible)))) {
FireAccessibleFocusEvent(accessible, optionTargetNode);
}
@ -401,15 +401,10 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
FireAccessibleFocusEvent(accessible, targetNode);
}
else if (eventType.EqualsIgnoreCase("change")) {
if (optionTargetNode) { // Set to current option only for HTML selects
mListener->HandleEvent(nsIAccessibleEventListener::EVENT_SELECTION, accessible);
if (NS_SUCCEEDED(mAccService->GetAccessibleFor(optionTargetNode, getter_AddRefs(accessible))))
FireAccessibleFocusEvent(accessible, optionTargetNode);
}
else
if (!selectControl) // Don't use onchange to fire EVENT_STATE_CHANGE events for selects
mListener->HandleEvent(nsIAccessibleEventListener::EVENT_STATE_CHANGE, accessible);
}
else if (eventType.EqualsIgnoreCase("ListitemStateChange")){
else if (eventType.EqualsIgnoreCase("ListitemStateChange")) {
mListener->HandleEvent(nsIAccessibleEventListener::EVENT_STATE_CHANGE, accessible);
mListener->HandleEvent(nsIAccessibleEventListener::EVENT_FOCUS, accessible);
}

View File

@ -50,6 +50,7 @@
#include "nsIListControlFrame.h"
#include "nsIServiceManager.h"
#include "nsLayoutAtoms.h"
#include "nsIDocument.h"
/**
* Selects, Listboxes and Comboboxes, are made up of a number of different
@ -200,7 +201,7 @@ NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetAccState(PRUint32 *_retval)
nsCOMPtr<nsIDOMNode> focusedOptionNode, parentNode;
mParent->AccGetDOMNode(getter_AddRefs(parentNode));
// find out if we are the focused node
GetFocusedOptionNode(mPresShell, parentNode, focusedOptionNode);
GetFocusedOptionNode(parentNode, focusedOptionNode);
if (focusedOptionNode == mDOMNode)
*_retval |= STATE_FOCUSED;
@ -223,34 +224,43 @@ NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetAccState(PRUint32 *_retval)
* need to use the frame to get the focused option because for some reason we
* weren't getting the proper notification when the focus changed using the DOM
*/
nsresult nsHTMLSelectOptionAccessible::GetFocusedOptionNode(nsIWeakReference *aPresShell,
nsIDOMNode *aListNode,
nsresult nsHTMLSelectOptionAccessible::GetFocusedOptionNode(nsIDOMNode *aListNode,
nsCOMPtr<nsIDOMNode>& aFocusedOptionNode)
{
NS_ASSERTION(aListNode, "Called GetFocusedOptionNode without a valid list node");
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aPresShell));
nsCOMPtr<nsIContent> content(do_QueryInterface(aListNode));
nsCOMPtr<nsIDocument> document;
content->GetDocument(*getter_AddRefs(document));
nsCOMPtr<nsIPresShell> shell;
if (document)
document->GetShellAt(0,getter_AddRefs(shell));
if (!shell)
return NS_ERROR_FAILURE;
nsIFrame *frame = nsnull;
nsCOMPtr<nsIContent> content(do_QueryInterface(aListNode));
shell->GetPrimaryFrameFor(content, &frame);
nsCOMPtr<nsIListControlFrame> listFrame(do_QueryInterface(frame));
if (!listFrame)
return NS_ERROR_FAILURE;
// Get what's focused by asking frame for "selected item".
PRInt32 focusedOptionIndex = 0;
nsresult rv = listFrame->GetSelectedIndex(&focusedOptionIndex);
nsCOMPtr<nsIDOMHTMLCollection> options;
// Get options
nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(aListNode));
NS_ASSERTION(selectElement, "No select element where it should be");
nsCOMPtr<nsIDOMHTMLCollection> options;
nsresult rv = selectElement->GetOptions(getter_AddRefs(options));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(aListNode));
NS_ASSERTION(selectElement, "No select element where it should be");
rv = selectElement->GetOptions(getter_AddRefs(options));
nsCOMPtr<nsIListControlFrame> listFrame(do_QueryInterface(frame));
if (listFrame) {
// Get what's focused in listbox by asking frame for "selected item".
// Can't use dom interface for this, because it will always return the first selected item
// when there is more than 1 item selected. We need the focused item, not
// the first selected item.
rv = listFrame->GetSelectedIndex(&focusedOptionIndex);
}
else // Combo boxes can only have 1 selected option, so they can use the dom interface for this
rv = selectElement->GetSelectedIndex(&focusedOptionIndex);
}
// Either use options and focused index, or default to list node itself

View File

@ -102,7 +102,7 @@ public:
NS_IMETHOD GetAccNextSibling(nsIAccessible **_retval);
NS_IMETHOD GetAccPreviousSibling(nsIAccessible **_retval);
static nsresult GetFocusedOptionNode(nsIWeakReference *aPresShell, nsIDOMNode *aListNode, nsCOMPtr<nsIDOMNode>& aFocusedOptionNode);
static nsresult GetFocusedOptionNode(nsIDOMNode *aListNode, nsCOMPtr<nsIDOMNode>& aFocusedOptionNode);
};

View File

@ -63,6 +63,7 @@
#include "nsHTMLParts.h"
#include "nsIDOMEventReceiver.h"
#include "nsIEventStateManager.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIPrivateDOMEvent.h"
@ -1317,6 +1318,24 @@ nsListControlFrame::PerformSelection(PRInt32 aSelectedIndex,
printf("mLastEndIndex: %d\n", mLastEndIndex);
#endif
#ifdef ACCESSIBILITY
// Fire a custom DOM event for the change, so that accessibility can
// fire a native focus event for accessibility
// (Some 3rd party products need to track our focus)
nsCOMPtr<nsIDOMEvent> event;
nsCOMPtr<nsIEventListenerManager> manager;
mContent->GetListenerManager(getter_AddRefs(manager));
if (manager &&
NS_SUCCEEDED(manager->CreateEvent(mPresContext, nsnull, NS_LITERAL_STRING("Events"), getter_AddRefs(event)))) {
event->InitEvent(NS_LITERAL_STRING("DOMMenuItemActive"), PR_TRUE, PR_TRUE);
PRBool noDefault;
nsCOMPtr<nsIEventStateManager> esm;
mPresContext->GetEventStateManager(getter_AddRefs(esm));
if (esm)
esm->DispatchNewEvent(mContent, event, &noDefault);
}
#endif
return wasChanged;
}

View File

@ -63,6 +63,7 @@
#include "nsHTMLParts.h"
#include "nsIDOMEventReceiver.h"
#include "nsIEventStateManager.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIPrivateDOMEvent.h"
@ -1317,6 +1318,24 @@ nsListControlFrame::PerformSelection(PRInt32 aSelectedIndex,
printf("mLastEndIndex: %d\n", mLastEndIndex);
#endif
#ifdef ACCESSIBILITY
// Fire a custom DOM event for the change, so that accessibility can
// fire a native focus event for accessibility
// (Some 3rd party products need to track our focus)
nsCOMPtr<nsIDOMEvent> event;
nsCOMPtr<nsIEventListenerManager> manager;
mContent->GetListenerManager(getter_AddRefs(manager));
if (manager &&
NS_SUCCEEDED(manager->CreateEvent(mPresContext, nsnull, NS_LITERAL_STRING("Events"), getter_AddRefs(event)))) {
event->InitEvent(NS_LITERAL_STRING("DOMMenuItemActive"), PR_TRUE, PR_TRUE);
PRBool noDefault;
nsCOMPtr<nsIEventStateManager> esm;
mPresContext->GetEventStateManager(getter_AddRefs(esm));
if (esm)
esm->DispatchNewEvent(mContent, event, &noDefault);
}
#endif
return wasChanged;
}