зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1625192 - Support select element and its dropdown menu. r=morgan
Differential Revision: https://phabricator.services.mozilla.com/D75135
This commit is contained in:
Родитель
b0b8bbe697
Коммит
96db37abd6
|
@ -172,6 +172,8 @@ Class a11y::GetTypeFromRole(roles::Role aRole) {
|
|||
|
||||
switch (aRole) {
|
||||
case roles::COMBOBOX:
|
||||
return [mozPopupButtonAccessible class];
|
||||
|
||||
case roles::PUSHBUTTON:
|
||||
return [mozButtonAccessible class];
|
||||
|
||||
|
@ -214,6 +216,18 @@ Class a11y::GetTypeFromRole(roles::Role aRole) {
|
|||
return [mozOptionAccessible class];
|
||||
}
|
||||
|
||||
case roles::COMBOBOX_LIST:
|
||||
case roles::MENUBAR:
|
||||
case roles::MENUPOPUP: {
|
||||
return [mozMenuAccessible class];
|
||||
}
|
||||
|
||||
case roles::COMBOBOX_OPTION:
|
||||
case roles::PARENT_MENUITEM:
|
||||
case roles::MENUITEM: {
|
||||
return [mozMenuItemAccessible class];
|
||||
}
|
||||
|
||||
default:
|
||||
return [mozAccessible class];
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
- (BOOL)hasPopup;
|
||||
@end
|
||||
|
||||
@interface mozPopupButtonAccessible : mozButtonAccessible
|
||||
@end
|
||||
|
||||
@interface mozCheckboxAccessible : mozButtonAccessible
|
||||
// returns one of the constants defined in CheckboxValue
|
||||
- (int)isChecked;
|
||||
|
|
|
@ -58,11 +58,6 @@ enum CheckboxValue {
|
|||
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
|
||||
if ([self hasPopup]) return [self children];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityHasPopupAttribute]) {
|
||||
return [NSNumber numberWithBool:[self hasPopup]];
|
||||
}
|
||||
|
@ -86,6 +81,80 @@ enum CheckboxValue {
|
|||
|
||||
@end
|
||||
|
||||
@implementation mozPopupButtonAccessible
|
||||
- (NSString*)title {
|
||||
// Popup buttons don't have titles.
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSArray*)accessibilityAttributeNames {
|
||||
static NSMutableArray* supportedAttributes = nil;
|
||||
if (!supportedAttributes) {
|
||||
supportedAttributes = [[super accessibilityAttributeNames] mutableCopy];
|
||||
// We need to remove AXHasPopup from a AXPopupButton for it to be reported
|
||||
// as a popup button. Otherwise VO reports it as a button that has a popup
|
||||
// which is not consistent with Safari.
|
||||
[supportedAttributes removeObject:NSAccessibilityHasPopupAttribute];
|
||||
[supportedAttributes addObject:NSAccessibilityValueAttribute];
|
||||
}
|
||||
|
||||
return supportedAttributes;
|
||||
}
|
||||
|
||||
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if ([attribute isEqualToString:NSAccessibilityHasPopupAttribute]) {
|
||||
// We need to null on AXHasPopup for it to be reported as a popup button.
|
||||
// Otherwise VO reports it as a button that has a popup which is not
|
||||
// consistent with Safari.
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (NSArray*)children {
|
||||
if ([self stateWithMask:states::EXPANDED] == 0) {
|
||||
// If the popup button is collapsed don't return its children.
|
||||
return @[];
|
||||
}
|
||||
|
||||
return [super children];
|
||||
}
|
||||
|
||||
- (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
|
||||
|
||||
[super stateChanged:state isEnabled:enabled];
|
||||
|
||||
if (state == states::EXPANDED) {
|
||||
// If the EXPANDED state is updated, fire AXMenu events on the
|
||||
// popups child which is the actual menu.
|
||||
if (mozAccessible* popup = (mozAccessible*)[self childAt:0]) {
|
||||
[popup postNotification:(enabled ? @"AXMenuOpened" : @"AXMenuClosed")];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)ignoreWithParent:(mozAccessible*)parent {
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
if (accWrap->IsContent() && accWrap->GetContent()->IsXULElement(nsGkAtoms::menulist)) {
|
||||
// The way select elements work is that content has a COMBOBOX accessible, when it is clicked
|
||||
// it expands a COMBOBOX in our top-level main XUL window. The latter COMBOBOX is a stand-in
|
||||
// for the content one while it is expanded.
|
||||
// XXX: VO focus behaves weirdly if we expose the dummy XUL COMBOBOX in the tree.
|
||||
// We are only interested in its menu child.
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return [super ignoreWithParent:parent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation mozCheckboxAccessible
|
||||
|
||||
- (NSString*)accessibilityActionDescription:(NSString*)action {
|
||||
|
|
|
@ -26,3 +26,11 @@
|
|||
|
||||
@interface mozOptionAccessible : mozSelectableChildAccessible
|
||||
@end
|
||||
|
||||
@interface mozMenuAccessible : mozSelectableAccessible {
|
||||
BOOL mIsOpened;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface mozMenuItemAccessible : mozSelectableChildAccessible
|
||||
@end
|
||||
|
|
|
@ -250,3 +250,100 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation mozMenuAccessible
|
||||
|
||||
- (NSString*)title {
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString*)accessibilityLabel {
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (void)postNotification:(NSString*)notification {
|
||||
[super postNotification:notification];
|
||||
|
||||
if ([notification isEqualToString:@"AXMenuOpened"]) {
|
||||
mIsOpened = YES;
|
||||
} else if ([notification isEqualToString:@"AXMenuClosed"]) {
|
||||
mIsOpened = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)expire {
|
||||
if (mIsOpened) {
|
||||
// VO needs to receive a menu closed event when the menu goes away.
|
||||
// If the menu is being destroyed, send a menu closed event first.
|
||||
[self postNotification:@"AXMenuClosed"];
|
||||
}
|
||||
|
||||
[super expire];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation mozMenuItemAccessible
|
||||
|
||||
- (NSString*)accessibilityLabel {
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSArray*)accessibilityAttributeNames {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
static NSMutableArray* attributes = nil;
|
||||
|
||||
if (!attributes) {
|
||||
attributes = [[super accessibilityAttributeNames] mutableCopy];
|
||||
[attributes addObject:@"AXMenuItemMarkChar"];
|
||||
}
|
||||
|
||||
return attributes;
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if ([attribute isEqualToString:@"AXMenuItemMarkChar"]) {
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (accWrap && accWrap->IsContent() && accWrap->GetContent()->IsXULElement(nsGkAtoms::menuitem)) {
|
||||
// We need to provide a marker character. This is the visible "√" you see
|
||||
// on dropdown menus. In our a11y tree this is a single child text node
|
||||
// of the menu item.
|
||||
// We do this only with XUL menuitems that conform to the native theme, and not
|
||||
// with aria menu items that might have a pseudo element or something.
|
||||
if (accWrap->ChildCount() == 1 && accWrap->FirstChild()->Role() == roles::STATICTEXT) {
|
||||
nsAutoString marker;
|
||||
accWrap->FirstChild()->Name(marker);
|
||||
if (marker.Length() == 1) {
|
||||
return nsCocoaUtils::ToNSString(marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (BOOL)isSelected {
|
||||
// Our focused state is equivelent to native selected states for menus.
|
||||
return [self stateWithMask:states::FOCUSED] != 0;
|
||||
}
|
||||
|
||||
- (void)handleAccessibleEvent:(uint32_t)eventType {
|
||||
switch (eventType) {
|
||||
case nsIAccessibleEvent::EVENT_FOCUS:
|
||||
// Our focused state is equivelent to native selected states for menus.
|
||||
mozAccessible* parent = (mozAccessible*)[self parent];
|
||||
[parent postNotification:NSAccessibilitySelectedChildrenChangedNotification];
|
||||
break;
|
||||
}
|
||||
|
||||
[super handleAccessibleEvent:eventType];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Загрузка…
Ссылка в новой задаче