-
-
Notifications
You must be signed in to change notification settings - Fork 637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add additional element types to the elements list in browse mode #588 #6131
Conversation
With so many radio button options a dropdown menu would make more sense, since it is a lot more compact. However some logic will need to be added to ensure that the keyboard shortcuts still work. |
@michaelDCurran, I think we discussed this a while ago, but clearly didn't document our conclusions. :( I'm not convinced we need to have all of these element types; the use case is sketchy at best. I can probably see the point in form fields, graphics and maybe buttons, but I don't see any use in listing separate form field types. |
I implemented an alternative for this, didn't seod in a pr for that yet. It allows you to set a hotkey in browse mode to directly jump to a specific element in the list. For example, alt nvda h opens the elements list with headings selected.Ho about such a thing?
N.B. Sent on behalf of @BabbageCom
… Op 9 dec. 2016 om 03:42 heeft Reef Turner ***@***.***> het volgende geschreven:
With so many radio button options a dropdown menu would make more sense, since it is a lot more compact. However some logic will need to be added to ensure that the keyboard shortcuts still work.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@jcsteh: From a programmers perspective, I can understand perfectly why
you think that listing separate form fields in here is slightly
overkill. However, in my work as an AT trainer, I've met several people
who used this element specific functionality, due to several reasons:
* When you often navigate edit boxes with e or buttons with b, it is a
little step to add modifiers like insert and alt to that hotkey in order
to get a list of the element you're navigating. That's what I know many
JAWS users do. Not that we blindly want to copy JAWS of course, but
people who are accustomed to listing edit boxes might consider form
field listing to give too much info.
* Some people simply do not know that an edit field is a form field. I
think they should know such things when they want to use a screen reader
reliably, but it's a thing we might or might not keep in mind.
But again, I can see why you think form fields is enough, and I will not
oppose that. No problem to remove them from the pr. Just wanted to bring
in some other arguments.
|
What often might be very useful would be some way to know if a combo box was
'normal' ie you just use cursors to go around the selections, or one of
those 'ever so unhelpful' ones where you need to hold another key down to
stop it leaping off to somewhere if you pause for a moment while
cursoring!Brian
bglists@blueyonder.co.uk
Sent via blueyonder.
Please address personal email to:-
briang1@blueyonder.co.uk, putting 'Brian Gaff'
in the display name field.
----- Original Message -----
From: "James Teh" <notifications@github.com>
To: "nvaccess/nvda" <nvda@noreply.github.com>
Sent: Friday, December 09, 2016 3:20 AM
Subject: Re: [nvaccess/nvda] Add additional element types to the elements
list in browse mode #588 (#6131)
… @michaelDCurran, I think we discussed this a while ago, but clearly didn't
document our conclusions. :( I'm not convinced we need to have all of
these element types; the use case is sketchy at best. I can probably see
the point in form fields, graphics and maybe buttons, but I don't see any
use in listing separate form field types.
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
#6131 (comment)
|
As a rule of thumb, press alt+down to always do this, and when done,
press enter. This is the correct way to use combo boxes, although some
systems let you arrow around without this.
…On 12/11/2016 3:57 AM, Brian1Gaff wrote:
What often might be very useful would be some way to know if a combo
box was
'normal' ie you just use cursors to go around the selections, or one of
those 'ever so unhelpful' ones where you need to hold another key down to
stop it leaping off to somewhere if you pause for a moment while
cursoring!Brian
***@***.***
Sent via blueyonder.
Please address personal email to:-
***@***.***, putting 'Brian Gaff'
in the display name field.
----- Original Message -----
From: "James Teh" ***@***.***>
To: "nvaccess/nvda" ***@***.***>
Sent: Friday, December 09, 2016 3:20 AM
Subject: Re: [nvaccess/nvda] Add additional element types to the elements
list in browse mode #588 (#6131)
> @michaelDCurran, I think we discussed this a while ago, but clearly
didn't
> document our conclusions. :( I'm not convinced we need to have all of
> these element types; the use case is sketchy at best. I can probably
see
> the point in form fields, graphics and maybe buttons, but I don't
see any
> use in listing separate form field types.
>
> --
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly or view it on GitHub:
> #6131 (comment)
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#6131 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFGivc9EC4vjTxNzHFyRGIdEPemHY_SAks5rG9cagaJpZM4JDrTK>.
--
------------------------------------------------------------------------
Derek Riemer
* Department of computer science, third year undergraduate student.
* Proud user of the NVDA screen reader.
* Open source enthusiast.
* Member of Bridge Cu
* Avid skiier.
Websites:
Honors portfolio <http://derekriemer.com>
Awesome little hand built weather app!
<http://django.derekriemer.com/weather/>
email me at derek.riemer@colorado.edu <mailto:derek.riemer@colorado.edu>
Phone: (303) 906-2194
|
Have been thinking about this a little longer, and I wonder, is it clear for everyone that a button is a form field? Any how, if we remove buttons and only have form fields, it won't be possible to activate buttons from the elements list. @feerrenrut: I assume four radio buttons isn't a problem from a visual perspective? Excel elements list has five of them. |
I understand your arguments regarding check boxes, edit fields, etc. Nevertheless, I'd prefer to leave these out for now. We can always add them later if there's high demand, but it's much harder to remove them later. :) So, please go with form fields and buttons for now. |
Sounds ok. How about graphics?
|
Is there a good use case for listing graphics? Why would one need to list
graphics? I can understand wanting to find the next or previous one, but
I'm not as clear as to why one would want to list them.
|
Honestly, I added them just to be complete, so I will remove them as well.
|
There you go, al additional form fields (except for buttons) and
graphics have been removed.
|
@LeonarddeR It's hard to say. It will really depend on the length of the text and the size of the dialog. There are different recommendations depending on where you look. The following two links from |
@feerrenrut, thanks for your info. The current state of the request is actually ready for review. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've had a look at this. I think the number over radio buttons is ok. I would not want to add more though.
I terms of the implementation, I'm not very familiar with this area of code. It looks ok to me, but I'm unlikely to spot issues that may crop up in code that depends on the changed areas. Perhaps @jcsteh will have a quick look over it?
@@ -109,14 +109,30 @@ def obj(self): | |||
|
|||
@property | |||
def label(self): | |||
if self.itemType == "landmark": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would love to see some documentation added here. Specifically talking about what label
is and how its expected to be used. I realise that you didn't introduce this, but since you are in the area and have taken the time to understand this code it would be beneficial if this was documented better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation for this property belongs in browseMode.TextInfoQuickNavItem.label, as that's where the base property is defined. Only because this touches a completely different file, I'd suggest we leave this for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! The essentials look great, though I do have some concerns regarding the states stuff.
source/virtualBuffers/__init__.py
Outdated
value = super(VirtualBufferQuickNavItem,self).label | ||
# Translators: Reported label in the elements list for an element which which has no name and value | ||
unlabeled = _("Unlabeled") | ||
if self.itemType is not "heading": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be easier to follow if you move the heading code first, since there's only a tiny bit of code for headings and a lot for other stuff. In fact, you can just return early for headings and then you can get rid of a whole extra level of indentation for the rest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point there.
source/virtualBuffers/__init__.py
Outdated
name += " " | ||
return name + aria.landmarkRoles[attrs["landmark"]] | ||
realStates=attrs["states"] | ||
positiveStates = " ".join(controlTypes.stateLabels[st] for st in controlTypes.processPositiveStates(roleRaw, realStates, controlTypes.REASON_ELEMENTSLIST, realStates)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This states stuff seems a bit arbitrary at the moment.
- Do we really need states at all here? Sure, I guess this means you get to hear "check box not checked" or the like, but I'm not convinced we need that in the Elements List anyway. If the user is using the list, they are trying to find a specific control. If they want an overview of the form's values, they should be using quick navigation, no?
- I'm a bit bothered by introducing REASON_ELEMENTSLIST when it's really only used for states calculation. Furthermore, we just use it to kill the collapsed state... but why the collapsed state? If we really do want specific states, I feel we should perhaps be explicit about that. Otherwise, we could just be continually adding more and more exceptions in controlTypes.
- Perhaps we can answer both of these questions if you can give me some specific use cases you had in mind here.
- At the very least, we'd need some comments here explaining why these choices were made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Do we really need states at all here? Sure, I guess this means you get to hear "check box not checked" or the like, but I'm not convinced we need that in the Elements List anyway. If the user is using the list, they are trying to find a specific control. If they want an overview of the form's values, they should be using quick navigation, no?
One reason to do it like this, is that the other screen readers with elements lists (SuperNova and JAWS) also show the element states. Note that one who uses the elements list doesn't necessarily use it to find a particular element, but can also use it to get an overview of elements as well as review input in a form. I agree that quick navigation has preference in most, but not all cases. Imagine the case where you have a form full of check boxes, including an "i agree" one. An elements list with states would allow a user to quickly jump to that particular control with first letter navigation, thereby hearing the current state.
- I'm a bit bothered by introducing REASON_ELEMENTSLIST when it's really only used for states calculation. Furthermore, we just use it to kill the collapsed state... but why the collapsed state? If we really do want specific states, I feel we should perhaps be explicit about that. Otherwise, we could just be continually adding more and more exceptions in controlTypes.
I added this because reporting the collapsed state doesn't make any sense in the elements list, as a collapsible item like a combo box isn't usually expanded when you are in the elements list. It is one of the states you wouldn't bother about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jcsteh: Do the explanationss above sound sensible to you?
I've been thinking about it a bit more and I agree that REASON_ELEMENTSLIST should be avoided here. We can discard the collapsed state in the elements list code anyway, if we still want that.
…ed for form controls, such as edit and check boxes.
…ment lists label retrival
@jcsteh or @feerrenrut, this is ready for another review if you'd like. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it's taken me so long to get back to this.
Thanks for the explanation and use case regarding why you're including states. It makes sense. That said:
- I would still prefer that we got rid of REASON_ELEMENTSLIST. As you noted, we can put code to discard specific states in
QuickNavItem.label
. - The decision as to what to include still seems a bit arbitrary to me. For example, we only include positive states for buttons, but both positive and negative for other form fields. Why? There might be a good reason, but if there is, it needs to be commented.
- Speaking of commenting, it'd be good if you could include some comments with example output for each case you handle. That might make it easier to see what's going on here.
No problem
No problem. The question is though, what reason should I use instead? REASON_QUERY seems not ok, since that will keep states like STATE_READONLY for elements other than ROLE_EDITABLETEXT and ROLE_CHECKBOX. Or shouldn't we bother about that?
It has been too long ago I wrote this code. I see no valid reason for why I did this, so Negative states will now be reported for buttons as well. We do have toggle buttons where this is relevant.
I will do that as soon as the reason issue has been tackled. |
Ah, REASON_QUERY also keeps STATE_LINKED, so we definitely need to discard some states. Alternatively, we can just pass None as the reason, but I do not prefer that... |
Sorry for spamming so much. I got one additional alternative, REASON_QUICKNAV. Since the label property is part of a TextInfoQuickNavItem, this sounds quite reasonable. |
I actually like this approach a lot. In the case of UIA, it will not work for landmark as that is no object property, but we can work around that of course. We can also consider setting a landmark property on the Edge UIA objects by default, which could be added to #7328. But, I'm reluctant to do such a thing. |
I'd like to see this fully implemented soon as it will really help in my work testing websites for developers. Being able to show them a list of all the elements or separate elements is key. I often have to switch to jaws to get screenshots of what graphic labels are or screenshots of different form controls. I would really like you to add the graphics and individual form controls.it would be key to accessibility testers like myself to be able to show these types of elements separately and together less often together. This would mean one last task I have to do in jaws when it comes to writing reports on improper labeled controls elements and so forth. |
@accessaces commented on 27 Jul 2017, 10:54 GMT+10:
While accessibility testing is a use case we obviously want to support as much as we can, we can't do that at the expense of normal usage. Adding all of these options clutters the UI significantly, and as I explained in previous comments, there's no real world use case for this (in normal usage). If we did want to support all of these elements for accessibility testing, perhaps this could be done in an add-on somehow. |
@LeonarddeR, status update? Were you going to make changes based on #6131 (comment)? |
I've actually been waiting for #7328 to be merged in Master, which it is now. I can start working on this again in the near future. @jcsteh commented on 2 aug. 2017 03:18 CEST:
Yes. |
@jcsteh: this is ready for another round of review. |
@@ -196,6 +196,44 @@ 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a line after this which is something like the following:
This can be used by subclasses to implement the L{label} property.
source/browseMode.py
Outdated
def _getLabelForProperties(self, labelPropertyGetter): | ||
""" | ||
Fetches required properties for this L{TextInfoQuickNavItem} and constructs a label to be shown in an elements list. | ||
@Param labelPropertyGetter: A callable taking 1 argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clarify what the argument is; e.g. "taking one argument specifying the property to fetch".
source/browseMode.py
Outdated
""" | ||
Fetches required properties for this L{TextInfoQuickNavItem} and constructs a label to be shown in an elements list. | ||
@Param labelPropertyGetter: A callable taking 1 argument. | ||
For example, if L{itemType} is landmark, the callable must return the landmark type when the landmark argument is provided to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'when the landmark argument is provided to it': This would be clearer as something like 'when "landmark" is passed as the property argument'
source/browseMode.py
Outdated
Fetches required properties for this L{TextInfoQuickNavItem} and constructs a label to be shown in an elements list. | ||
@Param labelPropertyGetter: A callable taking 1 argument. | ||
For example, if L{itemType} is landmark, the callable must return the landmark type when the landmark argument is provided to it. | ||
Alternative attributes or dictionary keys might be name or value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps 'Alternative property names might be "name" or "value"'? I understand why you're talking about attributes/keys here, but I'm finding this confusing to read given that this thing talks about property getting.
source/browseMode.py
Outdated
For example, if L{itemType} is landmark, the callable must return the landmark type when the landmark argument is provided to it. | ||
Alternative attributes or dictionary keys might be name or value. | ||
An expected callable might be the __getattribute__ method on an L{NVDAObject}, or the get method on a L{Dict}. | ||
Note that L{Dict.get} doesn't raise an exception, it returns None instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than talking about dict.get here, it's probably best to say that the callable must return None if the property doesn't exist rather than raising an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there such a callable for objects, instead of getattribute? For objects, we're never fetching attributes that an object does not have, so in theory, getattribute is ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just use: lambda prop: getattr(obj, prop, None)
.
source/browseMode.py
Outdated
An expected callable might be the __getattribute__ method on an L{NVDAObject}, or the get method on a L{Dict}. | ||
Note that L{Dict.get} doesn't raise an exception, it returns None instead. | ||
""" | ||
value = self.textInfo.text.strip() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be better to name this variable text
or content
rather than value
, as value
is confusing with respect to buttons, etc.
source/browseMode.py
Outdated
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): | ||
labelParts = (value or name or unlabeled, roleText, positiveStates, negativeStates) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to have a comment with example content that might be produced by each of these conditions:
# For example: "Mute toggle button pressed"
source/virtualBuffers/__init__.py
Outdated
return name + aria.landmarkRoles[attrs["landmark"]] | ||
else: | ||
return super(VirtualBufferQuickNavItem,self).label | ||
value = super(VirtualBufferQuickNavItem,self).label |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This always gets executed, but it's only used for "heading". But we also fetch the text of the TextInfo in _getLabelForProperties
, which results in a wasted call (this property isn't cached). So, I think this call to super should be moved inside the if
block.
source/virtualBuffers/__init__.py
Outdated
return super(VirtualBufferQuickNavItem,self).label | ||
value = super(VirtualBufferQuickNavItem,self).label | ||
if self.itemType is "heading": | ||
# Explicitly handle headings here as well, to avoid requesting the Control field attribs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment says "as well". As well as what? Unless I'm missing something, "as well" should be removed.
source/virtualBuffers/__init__.py
Outdated
return super(VirtualBufferQuickNavItem,self).label | ||
value = super(VirtualBufferQuickNavItem,self).label | ||
if self.itemType is "heading": | ||
# Explicitly handle headings here as well, to avoid requesting the Control field attribs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way of doing this so you can rely entirely on _getLabelForProperties
would be to make a lazy fetcher for control field attributes. This might be overkill, but I'll let you decide. It would go something like this:
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)
@jcsteh: I addressed your comments. Furthermore, I decided that it would be more readable for users to have a semicolon between the label parts ("mute; toggle button; pressed" instead of "mute toggle button pressed"). Especially when there is no role, such as for links and buttons, having the state directly behind the name or content can be misinterpreted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic, except for one tiny tiny nit.
source/browseMode.py
Outdated
""" | ||
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". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spurious '"' character before full stop. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I did review this before incubating; just forgot to hit approve. :)
From ticket #588:
I agree with this proposal where it proposes adding additional elements to the elements list. This pull request does the following:
Fixes #588