Skip to content

Commit

Permalink
In web browsers, the Elements List can now list form fields and butto…
Browse files Browse the repository at this point in the history
…ns. (issue #588, PR #6131)
  • Loading branch information
Leonard de Ruijter authored and jcsteh committed Aug 31, 2017
1 parent e71a06a commit d869253
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 16 deletions.
6 changes: 1 addition & 5 deletions source/UIABrowseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import textInfos
import browseMode
from NVDAObjects.UIA import UIA
import aria

class UIATextRangeQuickNavItem(browseMode.TextInfoQuickNavItem):

Expand All @@ -40,10 +39,7 @@ def obj(self):

@property
def label(self):
if self.itemType=="landmark":
obj=self.obj
return " ".join(x for x in (obj.name,aria.landmarkRoles.get(obj.landmark)) if x)
return super(UIATextRangeQuickNavItem,self).label
return self._getLabelForProperties(lambda prop: getattr(self.obj, prop, None))

class HeadingUIATextInfoQuickNavItem(browseMode.TextInfoQuickNavItem):

Expand Down
55 changes: 53 additions & 2 deletions source/browseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,51 @@ def isAfterSelection(self):
caret=self.document.makeTextInfo(textInfos.POSITION_CARET)
return self.textInfo.compareEndPoints(caret, "startToStart") > 0

def _getLabelForProperties(self, labelPropertyGetter):
"""
Fetches required properties for this L{TextInfoQuickNavItem} and constructs a label to be shown in an elements list.
This can be used by subclasses to implement the L{label} property.
@Param labelPropertyGetter: A callable taking 1 argument, specifying the property to fetch.
For example, if L{itemType} is landmark, the callable must return the landmark type when "landmark" is passed as the property argument.
Alternative property names might be name or value.
The callable must return None if the property doesn't exist.
An expected callable might be get method on a L{Dict},
or "lambda property: getattr(self.obj, property, None)" for an L{NVDAObject}.
"""
content = self.textInfo.text.strip()
if self.itemType is "heading":
# Output: displayed text of the heading.
return content
labelParts = None
name = labelPropertyGetter("name")
if self.itemType is "landmark":
landmark = aria.landmarkRoles.get(labelPropertyGetter("landmark"))
# Example output: main menu; navigation
labelParts = (name, landmark)
else:
role = labelPropertyGetter("role")
roleText = controlTypes.roleLabels[role]
# Translators: Reported label in the elements list for an element which which has no name and value
unlabeled = _("Unlabeled")
realStates = labelPropertyGetter("states")
positiveStates = " ".join(controlTypes.stateLabels[st] for st in controlTypes.processPositiveStates(role, realStates, controlTypes.REASON_FOCUS, realStates))
negativeStates = " ".join(controlTypes.negativeStateLabels[st] for st in controlTypes.processNegativeStates(role, realStates, controlTypes.REASON_FOCUS, realStates))
if self.itemType is "formField":
if role in (controlTypes.ROLE_BUTTON,controlTypes.ROLE_DROPDOWNBUTTON,controlTypes.ROLE_TOGGLEBUTTON,controlTypes.ROLE_SPLITBUTTON,controlTypes.ROLE_MENUBUTTON,controlTypes.ROLE_DROPDOWNBUTTONGRID,controlTypes.ROLE_SPINBUTTON,controlTypes.ROLE_TREEVIEWBUTTON):
# Example output: Mute; toggle button; pressed
labelParts = (content or name or unlabeled, roleText, positiveStates, negativeStates)
else:
# Example output: Find a repository...; edit; has auto complete; NVDA
labelParts = (name or unlabeled, roleText, positiveStates, negativeStates, content)
elif self.itemType in ("link", "button"):
# Example output: You have unread notifications; visited
labelParts = (content or name or unlabeled, positiveStates, negativeStates)
if labelParts:
label = "; ".join(lp for lp in labelParts if lp)
else:
label = content
return label

class BrowseModeTreeInterceptor(treeInterceptorHandler.TreeInterceptor):
scriptCategory = inputCore.SCRCAT_BROWSEMODE
disableAutoPassThrough = False
Expand Down Expand Up @@ -708,6 +753,12 @@ class ElementsListDialog(wx.Dialog):
("heading", _("&Headings")),
# Translators: The label of a radio button to select the type of element
# in the browse mode Elements List dialog.
("formField", _("&Form fields")),
# Translators: The label of a radio button to select the type of element
# in the browse mode Elements List dialog.
("button", _("&Buttons")),
# Translators: The label of a radio button to select the type of element
# in the browse mode Elements List dialog.
("landmark", _("Lan&dmarks")),
)

Expand Down Expand Up @@ -778,8 +829,8 @@ def onElementTypeChange(self, evt):
self.lastSelectedElementType=elementType

def initElementType(self, elType):
if elType == "link":
# Links can be activated.
if elType in ("link","button"):
# Links and buttons can be activated.
self.activateButton.Enable()
self.SetAffirmativeId(self.activateButton.GetId())
else:
Expand Down
18 changes: 10 additions & 8 deletions source/virtualBuffers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,16 @@ def obj(self):

@property
def label(self):
if self.itemType == "landmark":
attrs = self.textInfo._getControlFieldAttribs(self.vbufFieldIdentifier[0], self.vbufFieldIdentifier[1])
name = attrs.get("name", "")
if name:
name += " "
return name + aria.landmarkRoles[attrs["landmark"]]
else:
return super(VirtualBufferQuickNavItem,self).label
attrs = {}

def propertyGetter(prop):
if not attrs:
# Lazily fetch the attributes the first time they're needed.
# We do this because we don't want to do this if they're not needed at all.
attrs.update(self.textInfo._getControlFieldAttribs(self.vbufFieldIdentifier[0], self.vbufFieldIdentifier[1]))
return attrs.get(prop)

return self._getLabelForProperties(propertyGetter)

def isChild(self,parent):
if self.itemType == "heading":
Expand Down
2 changes: 1 addition & 1 deletion user_docs/en/userGuide.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ To toggle single letter navigation on and off for the current document, press NV

++ The Elements List ++
The elements list provides access to a list of various types of elements in the document as appropriate for the application.
For example, in web browsers, the elements list can list links, headings or landmarks.
For example, in web browsers, the elements list can list links, headings, form fields, buttons or landmarks.
Radio buttons allow you to switch between the different types of elements.
An edit field is also provided in the dialog which allows you to filter the list to help you search for a particular item on the page.
Once you have chosen an item, you can use the provided buttons in the dialog to move to or activate that item.
Expand Down

0 comments on commit d869253

Please sign in to comment.