зеркало из https://github.com/mozilla/pjs.git
Bug 280871. Fix various problems with how we expose HTML and XUL combo boxes via accessibility APIs
This commit is contained in:
Родитель
9942ee6c00
Коммит
2405f82c91
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче