def _normalizeControlField(self, attrs): stdName = attrs.get("acrobat::stdname", "") try: role, level = normalizeStdName(stdName) except LookupError: role, level = None, None if not role: role = IAccessibleHandler.NVDARoleFromAttr( attrs['IAccessible::role']) states = IAccessibleHandler.getStatesSetFromIAccessibleAttrs(attrs) role, states = controlTypes.transformRoleStates(role, states) if (role == controlTypes.Role.EDITABLETEXT and states.issuperset({ controlTypes.State.READONLY, controlTypes.State.FOCUSABLE, controlTypes.State.LINKED })): # HACK: Acrobat sets focus states on text nodes beneath links, # making them appear as read only editable text fields. states.difference_update( {controlTypes.State.FOCUSABLE, controlTypes.State.FOCUSED}) attrs['role'] = role attrs['states'] = states if level: attrs["level"] = level return super(AdobeAcrobat_TextInfo, self)._normalizeControlField(attrs)
def _normalizeControlField(self, attrs: textInfos.ControlField): # noqa: C901 level = None isCurrent = self._getIsCurrentAttribute(attrs) if isCurrent != controlTypes.IsCurrent.NO: attrs['current'] = isCurrent placeholder = self._getPlaceholderAttribute( attrs, 'HTMLAttrib::aria-placeholder') if placeholder: attrs['placeholder'] = placeholder nodeName = attrs.get('IHTMLDOMNode::nodeName', "") roleAttrib = attrs.get("HTMLAttrib::role", "") ariaRoles = [ar for ar in roleAttrib.split(" ") if ar] #choose role #Priority is aria role -> HTML tag name -> IAccessible role role = next((aria.ariaRolesToNVDARoles[ar] for ar in ariaRoles if ar in aria.ariaRolesToNVDARoles), controlTypes.Role.UNKNOWN) if role == controlTypes.Role.UNKNOWN and nodeName: role = NVDAObjects.IAccessible.MSHTML.nodeNamesToNVDARoles.get( nodeName, controlTypes.Role.UNKNOWN) if role == controlTypes.Role.UNKNOWN: role = IAccessibleHandler.NVDARoleFromAttr( attrs.get('IAccessible::role')) roleText = attrs.get('HTMLAttrib::aria-roledescription') if roleText: attrs['roleText'] = roleText states = IAccessibleHandler.getStatesSetFromIAccessibleAttrs(attrs) role, states = controlTypes.transformRoleStates(role, states) if attrs.get('HTMLAttrib::longdesc'): states.add(controlTypes.State.HASLONGDESC) #IE exposes destination anchors as links, this is wrong if nodeName == "A" and role == controlTypes.Role.LINK and controlTypes.State.LINKED not in states: role = controlTypes.Role.TEXTFRAME if 'IHTMLElement::isContentEditable' in attrs: states.add(controlTypes.State.EDITABLE) if 'HTMLAttrib::onclick' in attrs or 'HTMLAttrib::onmousedown' in attrs or 'HTMLAttrib::onmouseup' in attrs: states.add(controlTypes.State.CLICKABLE) if 'HTMLAttrib::required' in attrs or attrs.get( 'HTMLAttrib::aria-required', 'false') == 'true': states.add(controlTypes.State.REQUIRED) description = None ariaDescribedBy = attrs.get('HTMLAttrib::aria-describedby') if ariaDescribedBy: ariaDescribedByIds = ariaDescribedBy.split() description = "" for ariaDescribedById in ariaDescribedByIds: descNode = None try: descNode = self.obj.rootNVDAObject.HTMLNode.document.getElementById( ariaDescribedById) except (COMError, NameError): descNode = None if not descNode: try: descNode = NVDAObjects.IAccessible.MSHTML.locateHTMLElementByID( self.obj.rootNVDAObject.HTMLNode.document, ariaDescribedById) except (COMError, NameError): descNode = None if descNode: try: description = description + " " + self.obj.makeTextInfo( NVDAObjects.IAccessible.MSHTML.MSHTML( HTMLNode=descNode)).text except: pass ariaSort = attrs.get('HTMLAttrib::aria-sort') state = aria.ariaSortValuesToNVDAStates.get(ariaSort) if state is not None: states.add(state) ariaSelected = attrs.get('HTMLAttrib::aria-selected') if ariaSelected == "true": states.add(controlTypes.State.SELECTED) elif ariaSelected == "false": states.discard(controlTypes.State.SELECTED) ariaExpanded = attrs.get('HTMLAttrib::aria-expanded') if ariaExpanded == "true": states.add(controlTypes.State.EXPANDED) elif ariaExpanded == "false": states.add(controlTypes.State.COLLAPSED) if attrs.get('HTMLAttrib::aria-invalid', 'false') == 'true': states.add(controlTypes.State.INVALID_ENTRY) if attrs.get('HTMLAttrib::aria-multiline', 'false') == 'true': states.add(controlTypes.State.MULTILINE) if attrs.get('HTMLAttrib::aria-dropeffect', 'none') != 'none': states.add(controlTypes.State.DROPTARGET) ariaGrabbed = attrs.get('HTMLAttrib::aria-grabbed', None) if ariaGrabbed == 'false': states.add(controlTypes.State.DRAGGABLE) elif ariaGrabbed == 'true': states.add(controlTypes.State.DRAGGING) if nodeName == "TEXTAREA": states.add(controlTypes.State.MULTILINE) if "H1" <= nodeName <= "H6": level = nodeName[1:] if nodeName in ("UL", "OL", "DL"): states.add(controlTypes.State.READONLY) if role == controlTypes.Role.UNKNOWN: role = controlTypes.Role.TEXTFRAME if role == controlTypes.Role.GRAPHIC: # MSHTML puts the unavailable state on all graphics when the showing of graphics is disabled. # This is rather annoying and irrelevant to our users, so discard it. states.discard(controlTypes.State.UNAVAILABLE) lRole = aria.htmlNodeNameToAriaRoles.get(nodeName.lower()) if lRole: ariaRoles.append(lRole) # If the first role is a landmark role, use it. landmark = ariaRoles[ 0] if ariaRoles and ariaRoles[0] in aria.landmarkRoles else None ariaLevel = attrs.get('HTMLAttrib::aria-level', None) ariaLevel = int(ariaLevel) if ariaLevel is not None else None if ariaLevel: level = ariaLevel if role: attrs['role'] = role attrs['states'] = states if level: attrs["level"] = level if landmark: attrs["landmark"] = landmark if description: attrs["description"] = description return super(MSHTMLTextInfo, self)._normalizeControlField(attrs)
def _normalizeControlField(self, attrs): # noqa: C901 for attr in ("table-rownumber-presentational", "table-columnnumber-presentational", "table-rowcount-presentational", "table-columncount-presentational"): attrVal = attrs.get(attr) if attrVal is not None and attrVal.lstrip('-').isdigit(): attrs[attr] = int(attrVal) else: attrs[attr] = None attrs["_description-from"] = self._calculateDescriptionFrom(attrs) attrs.update(_getNormalizedCurrentAttrs(attrs)) placeholder = self._getPlaceholderAttribute( attrs, "IAccessible2::attribute_placeholder") if placeholder is not None: attrs['placeholder'] = placeholder role = IAccessibleHandler.NVDARoleFromAttr(attrs['IAccessible::role']) if attrs.get('IAccessible2::attribute_tag', "").lower() == "blockquote": role = controlTypes.Role.BLOCKQUOTE states = IAccessibleHandler.getStatesSetFromIAccessibleAttrs(attrs) states |= IAccessibleHandler.getStatesSetFromIAccessible2Attrs(attrs) role, states = controlTypes.transformRoleStates(role, states) if role == controlTypes.Role.EDITABLETEXT and not ( controlTypes.State.FOCUSABLE in states or controlTypes.State.UNAVAILABLE in states or controlTypes.State.EDITABLE in states): # This is a text leaf. # See NVDAObjects.Iaccessible.mozilla.findOverlayClasses for an explanation of these checks. role = controlTypes.Role.STATICTEXT if attrs.get("IAccessibleAction_showlongdesc") is not None: states.add(controlTypes.State.HASLONGDESC) if "IAccessibleAction_click" in attrs: states.add(controlTypes.State.CLICKABLE) grabbed = attrs.get("IAccessible2::attribute_grabbed") if grabbed == "false": states.add(controlTypes.State.DRAGGABLE) elif grabbed == "true": states.add(controlTypes.State.DRAGGING) sorted = attrs.get("IAccessible2::attribute_sort") if sorted == "ascending": states.add(controlTypes.State.SORTED_ASCENDING) elif sorted == "descending": states.add(controlTypes.State.SORTED_DESCENDING) elif sorted == "other": states.add(controlTypes.State.SORTED) roleText = attrs.get("IAccessible2::attribute_roledescription") if roleText: attrs['roleText'] = roleText if attrs.get("IAccessible2::attribute_dropeffect", "none") != "none": states.add(controlTypes.State.DROPTARGET) if role == controlTypes.Role.LINK and controlTypes.State.LINKED not in states: # This is a named link destination, not a link which can be activated. The user doesn't care about these. role = controlTypes.Role.TEXTFRAME level = attrs.get('IAccessible2::attribute_level', "") xmlRoles = attrs.get("IAccessible2::attribute_xml-roles", "").split(" ") landmark = next((xr for xr in xmlRoles if xr in aria.landmarkRoles), None) if landmark and role != controlTypes.Role.LANDMARK and landmark != xmlRoles[ 0]: # Ignore the landmark role landmark = None if role == controlTypes.Role.DOCUMENT and xmlRoles[0] == "article": role = controlTypes.Role.ARTICLE elif role == controlTypes.Role.GROUPING and xmlRoles[0] == "figure": role = controlTypes.Role.FIGURE elif role in (controlTypes.Role.LANDMARK, controlTypes.Role.SECTION) and xmlRoles[0] == "region": role = controlTypes.Role.REGION elif xmlRoles[0] == "switch": # role="switch" gets mapped to IA2_ROLE_TOGGLE_BUTTON, but it uses the # checked state instead of pressed. The simplest way to deal with this # identity crisis is to map it to a check box. role = controlTypes.Role.CHECKBOX states.discard(controlTypes.State.PRESSED) attrs['role'] = role attrs['states'] = states if level != "" and level is not None: attrs['level'] = level if landmark: attrs["landmark"] = landmark return super(Gecko_ia2_TextInfo, self)._normalizeControlField(attrs)