Bug 280871. Fix various problems with how we expose HTML and XUL combo boxes via accessibility APIs

This commit is contained in:
aaronleventhal%moonset.net 2005-02-07 23:11:30 +00:00
Родитель 9942ee6c00
Коммит 2405f82c91
11 изменённых файлов: 90 добавлений и 45 удалений

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

@ -613,8 +613,9 @@ NS_IMETHODIMP nsAccessible::GetState(PRUint32 *aState)
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::disabled)) {
*aState |= STATE_UNAVAILABLE;
}
else if (!mRoleMapEntry || content->IsFocusable()) {
// Default state is focusable unless role manually set
else if ((!mRoleMapEntry && content->IsContentOfType(nsIContent::eELEMENT)) ||
content->IsFocusable()) {
// Default state for element accessible is focusable unless role manually set
// Subclasses of nsAccessible will clear focusable state if necessary
*aState |= STATE_FOCUSABLE;
if (gLastFocusedNode == mDOMNode) {
@ -1217,7 +1218,7 @@ nsIContent *nsAccessible::GetLabelForId(nsIContent *aLookContent,
* the DOM tree to the form, concatonating label elements as it goes. Then checks for
* labels with the for="controlID" property.
*/
nsresult nsAccessible::GetHTMLName(nsAString& aLabel)
nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtree)
{
if (!mWeakShell || !mDOMNode) {
return NS_ERROR_FAILURE; // Node shut down
@ -1235,6 +1236,13 @@ nsresult nsAccessible::GetHTMLName(nsAString& aLabel)
}
}
if (!aCanAggregateSubtree) {
// Don't use AppendFlatStringFromSubtree for container widgets like menulist
// Still try the title as as fallback method in that case.
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, aLabel);
return NS_OK;
}
return nsAccessible::GetName(aLabel);
}
@ -1250,7 +1258,7 @@ nsresult nsAccessible::GetHTMLName(nsAString& aLabel)
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
nsresult nsAccessible::GetXULName(nsAString& aLabel)
nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree)
{
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ASSERTION(content, "No nsIContent for DOM node");
@ -1289,7 +1297,14 @@ nsresult nsAccessible::GetXULName(nsAString& aLabel)
aLabel = label;
return NS_OK;
}
if (!aCanAggregateSubtree) {
// Don't use AppendFlatStringFromSubtree for container widgets like menulist
// Still try the title as as fallback method in that case.
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, aLabel);
return NS_OK;
}
return AppendFlatStringFromSubtree(content, &aLabel);
}
@ -1323,7 +1338,7 @@ nsRoleMapEntry nsAccessible::gWAIRoleMap[] =
{"menubar", ROLE_MENUBAR, eTitleOnly, 0, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{"menuitem", ROLE_MENUITEM, eAggregateSubtree, 0, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{"menuitem-checkbox", ROLE_MENUITEM, eAggregateSubtree, 0, {"checked", "true", STATE_CHECKED}, {0, 0, 0}, {0, 0, 0}},
{"grid", ROLE_TABLE, eTitleOnly, 0, {"readonly", 0, STATE_READONLY}, {"multiselect", 0, STATE_EXTSELECTABLE | STATE_MULTISELECTABLE}, {0, 0, 0}},
{"grid", ROLE_TABLE, eTitleOnly, STATE_FOCUSABLE, {"readonly", 0, STATE_READONLY}, {"multiselect", 0, STATE_EXTSELECTABLE | STATE_MULTISELECTABLE}, {0, 0, 0}},
{"gridcell", ROLE_CELL, eAggregateSubtree, STATE_SELECTABLE, {"selected", 0, STATE_SELECTED}, {0, 0, 0}, {0, 0, 0}},
{"option", ROLE_LISTITEM, eAggregateSubtree, STATE_SELECTABLE, {"selected", 0, STATE_SELECTED}, {0, 0, 0}, {0, 0, 0}},
{"progress-meter", ROLE_PROGRESSBAR, eTitleOnly, STATE_READONLY, {"valuenow", "unknown", STATE_MIXED}, {0, 0, 0}, {0, 0, 0}},
@ -1395,6 +1410,8 @@ NS_IMETHODIMP nsAccessible::GetFinalState(PRUint32 *aState)
return rv;
}
*aState &= ~STATE_READONLY; // Once DHTML role is used, we're only readonly if DHTML readonly used
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (content) {
*aState |= mRoleMapEntry->state |

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

@ -127,8 +127,8 @@ protected:
const nsAString *aId);
static nsIContent *GetXULLabelContent(nsIContent *aForNode);
static nsIContent *GetHTMLLabelContent(nsIContent *aForNode);
nsresult GetHTMLName(nsAString& _retval);
nsresult GetXULName(nsAString& _retval);
nsresult GetHTMLName(nsAString& _retval, PRBool aCanAggregateSubtree = PR_TRUE);
nsresult GetXULName(nsAString& aName, PRBool aCanAggregateSubtree = PR_TRUE);
// For accessibles that are not lists of choices, the name of the subtree should be the
// sum of names in the subtree
nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString);

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

@ -486,8 +486,7 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
// Turn DOM events in accessibility events
// Get info about event and target
// optionTargetNode is set to current option for HTML selects
nsCOMPtr<nsIDOMNode> targetNode, optionTargetNode;
nsCOMPtr<nsIDOMNode> targetNode;
GetTargetNode(aEvent, getter_AddRefs(targetNode));
if (!targetNode)
return NS_ERROR_FAILURE;
@ -506,19 +505,6 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
}
#endif
// 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(targetNode, getter_AddRefs(optionTargetNode));
// for focus events on Radio Groups we give the focus to the selected button
nsCOMPtr<nsIDOMXULSelectControlElement> selectControl(do_QueryInterface(targetNode));
if (selectControl) {
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectItem;
selectControl->GetSelectedItem(getter_AddRefs(selectItem));
optionTargetNode = do_QueryInterface(selectItem);
}
nsCOMPtr<nsIPresShell> eventShell;
GetEventShell(targetNode, getter_AddRefs(eventShell));
@ -596,24 +582,26 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
return NS_OK;
}
#endif
if (eventType.LowerCaseEqualsLiteral("focus") ||
eventType.LowerCaseEqualsLiteral("dommenuitemactive")) {
if (optionTargetNode &&
NS_SUCCEEDED(mAccService->GetAccessibleInShell(optionTargetNode, eventShell,
getter_AddRefs(accessible)))) {
if (eventType.LowerCaseEqualsLiteral("focus")) {
nsCOMPtr<nsIAccessible> selectAccessible;
mAccService->GetAccessibleInShell(targetNode, eventShell,
getter_AddRefs(selectAccessible));
if (selectAccessible) {
FireAccessibleFocusEvent(selectAccessible, targetNode);
}
else if (eventType.LowerCaseEqualsLiteral("dommenuitemactive")) {
nsCOMPtr<nsIAccessible> containerAccessible = accessible;
PRUint32 containerState = 0;
do {
nsIAccessible *tempAccessible = containerAccessible;
tempAccessible->GetParent(getter_AddRefs(containerAccessible));
if (!containerAccessible) {
break;
}
FireAccessibleFocusEvent(accessible, optionTargetNode);
containerAccessible->GetFinalState(&containerState);
}
else
while ((containerState & STATE_HASPOPUP) == 0);
// Only fire focus event for DOMMenuItemActive is not inside collapsed popup
if (0 == (containerState & STATE_COLLAPSED)) {
FireAccessibleFocusEvent(accessible, targetNode);
}
}
else if (eventType.LowerCaseEqualsLiteral("focus")) {
FireAccessibleFocusEvent(accessible, targetNode);
}
else if (eventType.LowerCaseEqualsLiteral("valuechange")) {
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
@ -687,10 +675,6 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_ATK_LINK_SELECTED, accessible, &selectedLink);
}
}
else if (optionTargetNode && // use focused option
NS_SUCCEEDED(mAccService->GetAccessibleInShell(optionTargetNode, eventShell,
getter_AddRefs(accessible))))
FireAccessibleFocusEvent(accessible, optionTargetNode);
else
FireAccessibleFocusEvent(accessible, targetNode);
}
@ -706,6 +690,9 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
// XXX todo: value change events for ATK are done with
// AtkPropertyChange, PROP_VALUE. Need the old and new value.
// Not sure how we'll get the old value.
// Aaron: I think this is a problem with the ATK API -- it's much harder to
// grab the old value for all the application developers than it is for
// AT's to cache old values when they need to (when would that be!?)
else if (eventType.LowerCaseEqualsLiteral("valuechange")) {
privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
accessible, nsnull);

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

@ -82,6 +82,8 @@ public:
nsHTMLSelectableAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell);
virtual ~nsHTMLSelectableAccessible() {}
NS_IMETHOD GetName(nsAString &aName) { return GetHTMLName(aName, PR_FALSE); }
protected:
NS_IMETHOD ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);

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

@ -103,6 +103,7 @@ NS_IMETHODIMP nsHTMLTableAccessible::GetRole(PRUint32 *aResult)
NS_IMETHODIMP nsHTMLTableAccessible::GetState(PRUint32 *aResult)
{
nsAccessible::GetState(aResult);
*aResult |= STATE_READONLY;
*aResult &= ~STATE_FOCUSABLE; // Inherit all states except focusable state since tables cannot be focused
return NS_OK;
}

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

@ -77,9 +77,9 @@ nsAccessibleWrap(aDOMNode, aShell)
{
}
NS_IMETHODIMP nsXULSelectableAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP nsXULSelectableAccessible::GetName(nsAString& aName)
{
return GetXULName(_retval);
return GetXULName(aName, PR_FALSE);
}
NS_IMPL_ISUPPORTS_INHERITED1(nsXULSelectableAccessible, nsAccessible, nsIAccessibleSelectable)

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

@ -58,6 +58,7 @@
#include "nsIView.h"
#include "nsIScrollableView.h"
#include "nsIEventStateManager.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMNode.h"
#include "nsIPrivateDOMEvent.h"
#include "nsISupportsArray.h"
@ -2379,6 +2380,7 @@ nsComboboxControlFrame::OnOptionSelected(nsPresContext* aPresContext,
} else {
if (aSelected) {
RedisplayText(aIndex);
FireValueChangeEvent();
} else {
RedisplaySelectedText();
}
@ -2387,6 +2389,21 @@ nsComboboxControlFrame::OnOptionSelected(nsPresContext* aPresContext,
return NS_OK;
}
void nsComboboxControlFrame::FireValueChangeEvent()
{
// Fire ValueChange event to indicate data value of combo box has changed
nsCOMPtr<nsIDOMEvent> event;
nsCOMPtr<nsIEventListenerManager> manager;
mContent->GetListenerManager(getter_AddRefs(manager));
nsPresContext* presContext = GetPresContext();
if (manager &&
NS_SUCCEEDED(manager->CreateEvent(presContext, nsnull, NS_LITERAL_STRING("Events"), getter_AddRefs(event)))) {
event->InitEvent(NS_LITERAL_STRING("ValueChange"), PR_TRUE, PR_TRUE);
PRBool noDefault;
presContext->EventStateManager()->DispatchNewEvent(mContent, event, &noDefault);
}
}
NS_IMETHODIMP
nsComboboxControlFrame::OnOptionTextChanged(nsIDOMHTMLOptionElement* option)
{

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

@ -246,6 +246,7 @@ protected:
void SetChildFrameSize(nsIFrame* aFrame, nscoord aWidth, nscoord aHeight);
void InitTextStr();
void CheckFireOnChange();
void FireValueChangeEvent();
nsresult RedisplayText(PRInt32 aIndex);
nsresult ActuallyDisplayText(nsAString& aText, PRBool aNotify);
nsresult GetPrimaryComboFrame(nsPresContext* aPresContext, nsIContent* aContent, nsIFrame** aFrame);

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

@ -2546,6 +2546,17 @@ PRBool nsListControlFrame::IsClickingInCombobox(nsIDOMEvent* aMouseEvent)
void
nsListControlFrame::FireMenuItemActiveEvent()
{
PRInt32 focusedIndex;
GetSelectedIndex(&focusedIndex);
if (focusedIndex == kNothingSelected) {
return;
}
nsCOMPtr<nsIContent> optionContent = GetOptionContent(focusedIndex);
if (!optionContent) {
return;
}
nsCOMPtr<nsIDOMEvent> event;
nsCOMPtr<nsIEventListenerManager> manager;
mContent->GetListenerManager(getter_AddRefs(manager));
@ -2554,7 +2565,8 @@ nsListControlFrame::FireMenuItemActiveEvent()
NS_SUCCEEDED(manager->CreateEvent(presContext, nsnull, NS_LITERAL_STRING("Events"), getter_AddRefs(event)))) {
event->InitEvent(NS_LITERAL_STRING("DOMMenuItemActive"), PR_TRUE, PR_TRUE);
PRBool noDefault;
presContext->EventStateManager()->DispatchNewEvent(mContent, event,
presContext->EventStateManager()->DispatchNewEvent(optionContent, event,
&noDefault);
}
}

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

@ -182,6 +182,10 @@
this.setAttribute('label', val.getAttribute('label'));
this.setAttribute('description', val.getAttribute('description'));
var event = document.createEvent("Events");
event.initEvent("ValueChange", true, true);
this.dispatchEvent(event);
return val;
]]>
</setter>

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

@ -182,6 +182,10 @@
this.setAttribute('label', val.getAttribute('label'));
this.setAttribute('description', val.getAttribute('description'));
var event = document.createEvent("Events");
event.initEvent("ValueChange", true, true);
this.dispatchEvent(event);
return val;
]]>
</setter>