Skip to content

Commit 37ebddf

Browse files
Merge 7fcfe7d into 7b68a1a
2 parents 7b68a1a + 7fcfe7d commit 37ebddf

11 files changed

Lines changed: 157 additions & 6 deletions

File tree

include/w3c-aria-practices

Submodule w3c-aria-practices updated 418 files

source/NVDAObjects/IAccessible/ia2Web.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,15 @@ class Switch(Ia2Web):
274274
# role="switch" gets mapped to IA2_ROLE_TOGGLE_BUTTON, but it uses the
275275
# checked state instead of pressed. The simplest way to deal with this
276276
# identity crisis is to map it to a check box.
277-
role = controlTypes.Role.CHECKBOX
277+
role = controlTypes.Role.SWITCH
278278

279279
def _get_states(self):
280280
states = super().states
281281
states.discard(controlTypes.State.PRESSED)
282+
states.discard(controlTypes.State.CHECKABLE)
283+
if controlTypes.State.CHECKED in states:
284+
states.discard(controlTypes.State.CHECKED)
285+
states.add(controlTypes.State.ON)
282286
return states
283287

284288

source/braille.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@
208208
controlTypes.Role.SUGGESTION: _("sggstn"),
209209
# Translators: Displayed in braille when an object is a definition.
210210
controlTypes.Role.DEFINITION: _("definition"),
211+
# Translators: Displayed in braille when an object is a switch control
212+
controlTypes.Role.SWITCH: _("swtch"),
211213
}
212214

213215
positiveStateLabels = {
@@ -251,6 +253,8 @@
251253
controlTypes.State.HASFORMULA: _("frml"),
252254
# Translators: Displayed in braille when there is a comment for a spreadsheet cell or piece of text in a document.
253255
controlTypes.State.HASCOMMENT: _("cmnt"),
256+
# Translators: Displayed in braille when a control is switched on
257+
controlTypes.State.ON: u"⣏⣿⣹",
254258
}
255259
negativeStateLabels = {
256260
# Translators: Displayed in braille when an object is not selected.
@@ -259,6 +263,8 @@
259263
controlTypes.State.PRESSED: u"⢎⣀⡱",
260264
# Displayed in braille when an object (e.g. a check box) is not checked.
261265
controlTypes.State.CHECKED: u"⣏⣀⣹",
266+
# Displayed in braille when an object (e.g. a switch control) is switched off.
267+
controlTypes.State.ON: u"⣏⣀⣹",
262268
}
263269

264270
landmarkLabels = {

source/controlTypes/processAndLabelStates.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def _processNegativeStates(
128128
speakNegatives.add(State.CHECKED)
129129
if role == Role.TOGGLEBUTTON and State.HALF_PRESSED not in states:
130130
speakNegatives.add(State.PRESSED)
131+
if role is Role.SWITCH and State.ON not in states:
132+
speakNegatives.add(State.ON)
131133
if reason == OutputReason.CHANGE:
132134
# We want to speak this state only if it is changing to negative.
133135
speakNegatives.add(State.DROPTARGET)

source/controlTypes/role.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def _displayStringLabels(self):
201201
COMMENT = 155
202202
SUGGESTION = 156
203203
DEFINITION = 157
204+
SWITCH = 158
204205

205206

206207
_roleLabels: Dict[Role, str] = {
@@ -528,6 +529,9 @@ def _displayStringLabels(self):
528529
Role.SUGGESTION: _("suggestion"),
529530
# Translators: Identifies a definition.
530531
Role.DEFINITION: _("definition"),
532+
# Translators: The word role for a switch control
533+
# I.e. a control that can be switched on or off.
534+
Role.SWITCH: _("switch"),
531535
}
532536

533537

source/controlTypes/state.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def negativeDisplayString(self) -> str:
9797
# when combined with role of 'progress bar', role is mutated to 'busy indicator'
9898
INDETERMINATE = setBit(44)
9999
HALF_PRESSED = setBit(45)
100+
ON = setBit(46)
100101

101102

102103
STATES_SORTED = frozenset([State.SORTED, State.SORTED_ASCENDING, State.SORTED_DESCENDING])
@@ -188,6 +189,9 @@ def negativeDisplayString(self) -> str:
188189
State.UNLOCKED: _("unlocked"),
189190
# Translators: a state that denotes the existence of a note.
190191
State.HASNOTE: _("has note"),
192+
# Translators: a state that denotes a control is currently on
193+
# E.g. a switch control.
194+
State.ON: _("on"),
191195
}
192196

193197

@@ -201,4 +205,6 @@ def negativeDisplayString(self) -> str:
201205
# Translators: This is presented when drag and drop is finished.
202206
# This is only reported for objects which support accessible drag and drop.
203207
State.DROPTARGET: _("done dragging"),
208+
# Translators: This is presented when a switch control is off.
209+
State.ON: _("off"),
204210
}

source/textInfos/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def getPresentationCategory(
119119
controlTypes.Role.BUTTON,
120120
controlTypes.Role.RADIOBUTTON,
121121
controlTypes.Role.CHECKBOX,
122+
controlTypes.Role.SWITCH,
122123
controlTypes.Role.GRAPHIC,
123124
controlTypes.Role.CHART,
124125
controlTypes.Role.MENUITEM,

source/virtualBuffers/gecko_ia2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,14 @@ def _normalizeControlField(self, attrs): # noqa: C901
155155
role = controlTypes.Role.REGION
156156
elif xmlRoles[0] == "switch":
157157
# role="switch" gets mapped to IA2_ROLE_TOGGLE_BUTTON, but it uses the
158-
# checked state instead of pressed. The simplest way to deal with this
159-
# identity crisis is to map it to a check box.
160-
role = controlTypes.Role.CHECKBOX
158+
# checked state instead of pressed.
159+
# We want to map this to our own Switch role and On state.
160+
role = controlTypes.Role.SWITCH
161161
states.discard(controlTypes.State.PRESSED)
162+
states.discard(controlTypes.State.CHECKABLE)
163+
if controlTypes.State.CHECKED in states:
164+
states.discard(controlTypes.State.CHECKED)
165+
states.add(controlTypes.State.ON)
162166
attrs['role']=role
163167
attrs['states']=states
164168
if level != "" and level is not None:

tests/checkPot.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
'gesture map File Error',
3939
'text \\"%s\\" not found',
4040
'Find Error',
41-
'on',
4241
'Type help(object) to get help about object.',
4342
'Type exit() to exit the console',
4443
'NVDA Python Console',

tests/system/robot/chromeTests.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,3 +2104,125 @@ def test_focus_mode_on_focusable_read_only_lists():
21042104
]),
21052105
message="focus mode - focus list item and turn on focus mode"
21062106
)
2107+
2108+
2109+
def test_ARIASwitchRole():
2110+
"""
2111+
Ensure that ARIA switch controls have an appropriate role and states in browse mode.
2112+
"""
2113+
testFile = os.path.join(ARIAExamplesDir, "switch", "switch.html")
2114+
_chrome.prepareChrome(
2115+
f"""
2116+
<iframe src="{testFile}"></iframe>
2117+
"""
2118+
)
2119+
# Jump to the first heading 2 in the iframe.
2120+
actualSpeech = _chrome.getSpeechAfterKey("2")
2121+
_asserts.strings_match(
2122+
actualSpeech,
2123+
SPEECH_SEP.join([
2124+
"frame",
2125+
"main landmark",
2126+
"Example",
2127+
"heading level 2"
2128+
]),
2129+
message="Move to first heading 2 in frame",
2130+
)
2131+
# Tab to the switch control
2132+
actualSpeech = _chrome.getSpeechAfterKey("tab")
2133+
_asserts.strings_match(
2134+
actualSpeech,
2135+
SPEECH_SEP.join([
2136+
"Notifications",
2137+
"switch",
2138+
"off",
2139+
]),
2140+
message="tab to switch control",
2141+
)
2142+
# Read the current line
2143+
actualSpeech = _chrome.getSpeechAfterKey("numpad8")
2144+
_asserts.strings_match(
2145+
actualSpeech,
2146+
SPEECH_SEP.join([
2147+
"switch",
2148+
"off",
2149+
"Notifications",
2150+
]),
2151+
message="Read current line",
2152+
)
2153+
# Report the current focus
2154+
actualSpeech = _chrome.getSpeechAfterKey("NVDA+tab")
2155+
_asserts.strings_match(
2156+
actualSpeech,
2157+
SPEECH_SEP.join([
2158+
"Notifications",
2159+
"switch",
2160+
"focused",
2161+
"off",
2162+
]),
2163+
message="Report focus",
2164+
)
2165+
# Toggle the switch on
2166+
actualSpeech = _chrome.getSpeechAfterKey("space")
2167+
_asserts.strings_match(
2168+
actualSpeech,
2169+
SPEECH_SEP.join([
2170+
"on",
2171+
]),
2172+
message="Toggle switch control on",
2173+
)
2174+
# Read the current line
2175+
actualSpeech = _chrome.getSpeechAfterKey("numpad8")
2176+
_asserts.strings_match(
2177+
actualSpeech,
2178+
SPEECH_SEP.join([
2179+
"switch",
2180+
"on",
2181+
"Notifications",
2182+
]),
2183+
message="Read current line",
2184+
)
2185+
# Report the current focus
2186+
actualSpeech = _chrome.getSpeechAfterKey("NVDA+tab")
2187+
_asserts.strings_match(
2188+
actualSpeech,
2189+
SPEECH_SEP.join([
2190+
"Notifications",
2191+
"switch",
2192+
"focused",
2193+
"on",
2194+
]),
2195+
message="Report focus",
2196+
)
2197+
# Toggle the switch off
2198+
actualSpeech = _chrome.getSpeechAfterKey("space")
2199+
_asserts.strings_match(
2200+
actualSpeech,
2201+
SPEECH_SEP.join([
2202+
"off",
2203+
]),
2204+
message="Toggle switch control off",
2205+
)
2206+
# Read the current line
2207+
actualSpeech = _chrome.getSpeechAfterKey("numpad8")
2208+
_asserts.strings_match(
2209+
actualSpeech,
2210+
SPEECH_SEP.join([
2211+
"switch",
2212+
"off",
2213+
"Notifications",
2214+
]),
2215+
message="Read current line",
2216+
)
2217+
# Report the current focus
2218+
actualSpeech = _chrome.getSpeechAfterKey("NVDA+tab")
2219+
_asserts.strings_match(
2220+
actualSpeech,
2221+
SPEECH_SEP.join([
2222+
"Notifications",
2223+
"switch",
2224+
"focused",
2225+
"off",
2226+
]),
2227+
message="Report focus",
2228+
)

0 commit comments

Comments
 (0)