From 3d7a1192ee35aff0e7c6cc0f727ea236ec64aeca Mon Sep 17 00:00:00 2001 From: IsaDC <70024509+IsaDC@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:16:45 -0600 Subject: [PATCH 1/3] Refactor Action Menu Button Example Using aria-activedescendant Test Plan to V2 Test Format (pull #1092) * Convert test plan to v2 vormat * Update example and remove previous directories * add State 'collapsed' is conveyed assertion * test remove assertion for state collapsed * Remove state collapsed assertion * Add mode change and state collapsed assertions * Add assertion exception for mode change to VoiceOver Commands * Remove previous version files * Add switching to interaction mode assertion to test 1 for tab and shift+tab commands for JAWS and NVDA * Clarify assertion for name of the menu button * Add refIds to assertions * Editorial changes to assertion statements and phrases * update references * Assert that insert+tab in JAWS and NVDA and ctrl-opt-f3 give the name and role of the menu * Add Virtual Cursor and Browse Mode to the Request information about a menu item test * Reorder JAWS and NVDA commands * Move after link to be just after menu button * In tests 4,5, and 6, replace assertion 'nameActions' with new assertion 'nameMenuActions' * Set posinset and setsize assertions to priority 2, set roleMenu assertion priority to 3 * Remove unnecessary priority overrid in tests.csv for assertion 'roleMenu' in test 6 * Revise order of assertions in each test for consistency * Add mode switching assertion to first two tests --------- Co-authored-by: Matt King --- .../data/assertions.csv | 15 + .../data/commands.csv | 42 --- .../data/jaws-commands.csv | 32 ++ .../data/nvda-commands.csv | 32 ++ .../data/references.csv | 31 +- .../data/scripts.csv | 6 + .../data/tests.csv | 39 +- .../data/voiceover_macos-commands.csv | 24 ++ ...menu-button-actions-active-descendant.html | 57 --- .../css/menu-button-actions.css | 4 +- .../css/menu-button-links.css | 78 ++++ .../menu-button-actions-active-descendant.js | 4 +- .../js/menu-button-actions.js | 346 ++++++++++++++++++ .../2024-7-21_174946/js/menu-button-links.js | 328 +++++++++++++++++ ...menu-button-actions-active-descendant.html | 61 +++ ...endant.openMenuAndSetFocusToFirstItem.html | 52 +-- ...cendant.openMenuAndSetFocusToLastItem.html | 52 +-- ...ve-descendant.setFocusAfterMenuButton.html | 52 +-- ...e-descendant.setFocusBeforeMenuButton.html | 52 +-- ...ctive-descendant.setFocusOnMenuButton.html | 52 +-- 20 files changed, 1095 insertions(+), 264 deletions(-) create mode 100644 tests/menu-button-actions-active-descendant/data/assertions.csv delete mode 100644 tests/menu-button-actions-active-descendant/data/commands.csv create mode 100644 tests/menu-button-actions-active-descendant/data/jaws-commands.csv create mode 100644 tests/menu-button-actions-active-descendant/data/nvda-commands.csv create mode 100644 tests/menu-button-actions-active-descendant/data/scripts.csv create mode 100644 tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv delete mode 100644 tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/css/menu-button-actions.css (97%) create mode 100644 tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/js/menu-button-actions-active-descendant.js (98%) create mode 100644 tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js create mode 100644 tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js create mode 100644 tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html (61%) rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/menu-button-actions-active-descendant.openMenuAndSetFocusToLastItem.html (61%) rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/menu-button-actions-active-descendant.setFocusAfterMenuButton.html (60%) rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/menu-button-actions-active-descendant.setFocusBeforeMenuButton.html (60%) rename tests/menu-button-actions-active-descendant/reference/{2021-1-14_171136 => 2024-7-21_174946}/menu-button-actions-active-descendant.setFocusOnMenuButton.html (60%) diff --git a/tests/menu-button-actions-active-descendant/data/assertions.csv b/tests/menu-button-actions-active-descendant/data/assertions.csv new file mode 100644 index 000000000..2a1b356da --- /dev/null +++ b/tests/menu-button-actions-active-descendant/data/assertions.csv @@ -0,0 +1,15 @@ +assertionId,priority,assertionStatement,assertionPhrase,refIds +nameActions,1,"Name of the menu button, 'Actions', is conveyed","convey name of the menu button, 'Actions'",button +nameMenuActions,3,"Name of the menu, 'Actions', is conveyed","convey name of the menu, 'Actions'",menu aria-labelledby +nameFocusedItemAction1,1,"Name of the focused item, 'Action 1', is conveyed","convey name of the focused item, 'Action 1'",aria-activedescendant +nameFocusedItemAction2,1,"Name of the focused item, 'Action 2', is conveyed","convey name of the focused item, 'Action 2'",aria-activedescendant +nameFocusedItemAction4,1,"Name of the focused item, 'Action 4', is conveyed","convey name of the focused item, 'Action 4'",aria-activedescendant +numberItemsMenu4,2,"Number of items in the menu,'(4', is conveyed","convey number of items in the menu, '4'",aria-setsize +roleFocusedItemMenuItem,2,"Role of the focused item, 'menu item', is conveyed","convey role of the focused item, 'menu item'",menuitem +roleMenu,3,Role 'menu' is conveyed,convey role 'menu',menu +roleMenuButton,1,Role 'menu button' is conveyed,convey role 'menu button',button aria-haspopup +stateCollapsed,1,State 'collapsed' is conveyed,convey state 'collapsed',aria-expanded +interactionModeEnabled,2,Screen reader switched from reading mode to interaction mode|{screenReader} switched from {readingMode} to {interactionMode},switch from reading mode to interaction mode|switch from {readingMode} to {interactionMode}, +positionFocusedItemMenu1,2,"Position of the focused item in the menu, '1', is conveyed","convey position of the focused item in the menu, '1'",aria-posinset aria-activedescendant +positionFocusedItemMenu2,2,"Position of the focused item in the menu, '2', is conveyed","convey position of the focused item in the menu, '2'",aria-posinset aria-activedescendant +positionFocusedItemMenu4,2,"Position of the focused item in the menu, '4', is conveyed","convey position of the focused item in the menu, '4'",aria-posinset aria-activedescendant diff --git a/tests/menu-button-actions-active-descendant/data/commands.csv b/tests/menu-button-actions-active-descendant/data/commands.csv deleted file mode 100644 index 888bd5281..000000000 --- a/tests/menu-button-actions-active-descendant/data/commands.csv +++ /dev/null @@ -1,42 +0,0 @@ -testId,task,mode,at,commandA,commandB,commandC,commandD,commandE,commandF -1,navigate forwards to menu button,reading,JAWS,B,F,TAB,DOWN,, -1,navigate forwards to menu button,reading,NVDA,B,F,TAB,DOWN,, -2,navigate backwards to menu button,reading,JAWS,SHIFT_B,SHIFT_F,SHIFT_TAB,UP,, -2,navigate backwards to menu button,reading,NVDA,SHIFT_B,SHIFT_F,SHIFT_TAB,UP,, -3,navigate forwards to menu button,interaction,JAWS,TAB,,,,, -3,navigate forwards to menu button,interaction,NVDA,TAB,,,,, -4,navigate backwards to menu button,interaction,JAWS,SHIFT_TAB,,,,, -4,navigate backwards to menu button,interaction,NVDA,SHIFT_TAB,,,,, -5,navigate forwards to menu button,interaction,voiceover_macos,TAB,CTRL_OPT_RIGHT,CTRL_OPT_CMD_J,,, -6,navigate backwards to menu button,interaction,voiceover_macos,SHIFT_TAB,CTRL_OPT_LEFT,SHIFT_CTRL_OPT_CMD_J,,, -7,read information about menu button,reading,JAWS,INS_TAB,INS_UP,,,, -7,read information about menu button,reading,NVDA,INS_TAB,INS_UP,,,, -8,read information about menu button,interaction,JAWS,INS_TAB,INS_UP,,,, -8,read information about menu button,interaction,NVDA,INS_TAB,INS_UP,,,, -9,read information about menu button,interaction,voiceover_macos,CTRL_OPT_F3,CTRL_OPT_F4,,,, -10,open menu,reading,JAWS,SPACE,ENTER,,,, -10,open menu,reading,NVDA,SPACE,ENTER,,,, -11,open menu,interaction,JAWS,SPACE,ENTER,DOWN,,, -11,open menu,interaction,NVDA,SPACE,ENTER,DOWN,,, -12,open menu,interaction,voiceover_macos,CTRL_OPT_SPACE,SPACE,ENTER,DOWN,, -13,open menu to last item,interaction,JAWS,UP,,,,, -13,open menu to last item,interaction,NVDA,UP,,,,, -14,open menu to last item,interaction,voiceover_macos,UP,,,,, -15,read information about menu item,interaction,JAWS,INS_TAB,INS_UP,,,, -15,read information about menu item,interaction,NVDA,INS_TAB,INS_UP,,,, -16,read information about menu item,interaction,voiceover_macos,CTRL_OPT_F3,CTRL_OPT_F4,,,, -17,navigate to first item in menu,interaction,JAWS,HOME,DOWN,,,, -17,navigate to first item in menu,interaction,NVDA,HOME,DOWN,,,, -18,navigate to first item in menu,interaction,voiceover_macos,HOME,DOWN,,,, -19,navigate to last item in menu,interaction,JAWS,END,UP,,,, -19,navigate to last item in menu,interaction,NVDA,END,UP,,,, -20,navigate to last item in menu,interaction,voiceover_macos,END,UP,,,, -21,navigate to item in menu by typing character,interaction,JAWS,A,,,,, -21,navigate to item in menu by typing character,interaction,NVDA,A,,,,, -22,navigate to item in menu by typing character,interaction,voiceover_macos,A,,,,, -23,activate menu item,interaction,JAWS,ENTER,,,,, -23,activate menu item,interaction,NVDA,ENTER,,,,, -24,activate menu item,interaction,voiceover_macos,CTRL_OPT_SPACE,ENTER,,,, -25,close menu,interaction,JAWS,ESC,,,,, -25,close menu,interaction,NVDA,ESC,,,,, -26,close menu,interaction,voiceover_macos,ESC,,,,, diff --git a/tests/menu-button-actions-active-descendant/data/jaws-commands.csv b/tests/menu-button-actions-active-descendant/data/jaws-commands.csv new file mode 100644 index 000000000..bef2cb964 --- /dev/null +++ b/tests/menu-button-actions-active-descendant/data/jaws-commands.csv @@ -0,0 +1,32 @@ +testId,command,settings,assertionExceptions,presentationNumber +navForwardsToMenuButton,b,virtualCursor,,1 +navForwardsToMenuButton,f,virtualCursor,,1.1 +navForwardsToMenuButton,tab,virtualCursor,2:interactionModeEnabled,1.2 +navForwardsToMenuButton,down,virtualCursor,,1.3 +navBackToMenuButton,shift+b,virtualCursor,,2 +navBackToMenuButton,shift+f,virtualCursor,,2.1 +navBackToMenuButton,shift+tab,virtualCursor,2:interactionModeEnabled,2.2 +navBackToMenuButton,up,virtualCursor,,2.3 +navForwardsToMenuButton,tab,pcCursor,,3 +navBackToMenuButton,shift+tab,pcCursor,,4 +reqInfoAboutMenuButton,ins+tab,virtualCursor,,7 +reqInfoAboutMenuButton,ins+up,virtualCursor,,7.1 +reqInfoAboutMenuButton,ins+tab,pcCursor,,8 +reqInfoAboutMenuButton,ins+up,pcCursor,,8.1 +openMenu,space,virtualCursor,2:interactionModeEnabled,10 +openMenu,enter,virtualCursor,2:interactionModeEnabled,10.1 +openMenu,space,pcCursor,,11 +openMenu,enter,pcCursor,,11.1 +openMenu,down,pcCursor,,11.2 +openMenuToLastItem,up,pcCursor,,13 +reqInfoAboutMenuItem,ins+tab,virtualCursor,,15 +reqInfoAboutMenuItem,ins+up,virtualCursor,,15.1 +reqInfoAboutMenuItem,ins+tab,pcCursor,,15.2 +reqInfoAboutMenuItem,ins+up,pcCursor,,15.3 +navToFirstItemMenu,home,pcCursor,,17 +navToFirstItemMenu,down,pcCursor,,17.1 +navToLastItemMenu,end,pcCursor,,19 +navToLastItemMenu,up,pcCursor,,19.1 +navToItemMenuByTypingCharacter,a,pcCursor,,21 +activateMenuItem,enter,pcCursor,,23 +closeMenu,esc,pcCursor,,25 diff --git a/tests/menu-button-actions-active-descendant/data/nvda-commands.csv b/tests/menu-button-actions-active-descendant/data/nvda-commands.csv new file mode 100644 index 000000000..995a4431c --- /dev/null +++ b/tests/menu-button-actions-active-descendant/data/nvda-commands.csv @@ -0,0 +1,32 @@ +testId,command,settings,assertionExceptions,presentationNumber +navForwardsToMenuButton,b,browseMode,,1 +navForwardsToMenuButton,f,browseMode,,1.1 +navForwardsToMenuButton,tab,browseMode,2:interactionModeEnabled,1.2 +navForwardsToMenuButton,down,browseMode,,1.3 +navBackToMenuButton,shift+b,browseMode,,2 +navBackToMenuButton,shift+f,browseMode,,2.1 +navBackToMenuButton,shift+tab,browseMode,2:interactionModeEnabled,2.2 +navBackToMenuButton,up,browseMode,,2.3 +navForwardsToMenuButton,tab,focusMode,,3 +navBackToMenuButton,shift+tab,focusMode,,4 +reqInfoAboutMenuButton,ins+tab,browseMode,,7 +reqInfoAboutMenuButton,ins+up,browseMode,,7.1 +reqInfoAboutMenuButton,ins+tab,focusMode,,8 +reqInfoAboutMenuButton,ins+up,focusMode,,8.1 +openMenu,space,browseMode,2:interactionModeEnabled,10 +openMenu,enter,browseMode,2:interactionModeEnabled,10.1 +openMenu,space,focusMode,,11 +openMenu,enter,focusMode,,11.1 +openMenu,down,focusMode,,11.2 +openMenuToLastItem,up,focusMode,,13 +reqInfoAboutMenuItem,ins+tab,browseMode,,15 +reqInfoAboutMenuItem,ins+up,browseMode,,15.1 +reqInfoAboutMenuItem,ins+tab,focusMode,,15.2 +reqInfoAboutMenuItem,ins+up,focusMode,,15.3 +navToFirstItemMenu,home,focusMode,,17 +navToFirstItemMenu,down,focusMode,,17.1 +navToLastItemMenu,end,focusMode,,19 +navToLastItemMenu,up,focusMode,,19.1 +navToItemMenuByTypingCharacter,a,focusMode,,21 +activateMenuItem,enter,focusMode,,23 +closeMenu,esc,focusMode,,25 diff --git a/tests/menu-button-actions-active-descendant/data/references.csv b/tests/menu-button-actions-active-descendant/data/references.csv index c34bf8d85..937d3520d 100644 --- a/tests/menu-button-actions-active-descendant/data/references.csv +++ b/tests/menu-button-actions-active-descendant/data/references.csv @@ -1,14 +1,17 @@ -refId,value -author,Isabel Del Castillo -authorEmail,isa.delcastillo5@gmail.com -title,Action Menu Button Example Using aria-activedescendant -reference,reference/2021-1-14_171136/menu-button-actions-active-descendant.html -designPattern,https://w3c.github.io/aria-practices/#menubutton -example,https://w3c.github.io/aria-practices/examples/menu-button/menu-button-actions-active-descendant.html -menu,https://w3c.github.io/aria/#menu -menuitem,https://w3c.github.io/aria/#menuitem -aria-haspopup,https://w3c.github.io/aria/#aria-haspopup -aria-controls,https://w3c.github.io/aria/#aria-controls -aria-activedescendant,https://w3c.github.io/aria/#aria-activedescendant -aria-labelledby,https://w3c.github.io/aria/#aria-labelledby -aria-expanded,https://w3c.github.io/aria/#aria-expanded +refId,type,value,linkText +author,metadata,Isabel Del Castillo, +authorEmail,metadata,isa.delcastillo5@gmail.com, +title,metadata,Action Menu Button Example Using aria-activedescendant, +reference,metadata,reference/2024-7-21_174946/menu-button-actions-active-descendant.html,Test Case Page for Action Menu Button Example Using aria-activedescendant +designPattern,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/,APG Pattern: Menu Button +example,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant/,APG Example: Actions Menu Button Using aria-activedescendant +menu,aria,menu,menu +menuitem,aria,menuitem,menuitem +aria-haspopup,aria,aria-haspopup,aria-haspopup +aria-controls,aria,aria-controls,aria-controls +aria-activedescendant,aria,aria-activedescendant,aria-activedescendant +aria-labelledby,aria,aria-labelledby,aria-labelledby +aria-expanded,aria,aria-expanded,aria-expanded +aria-posinset,aria,aria-posinset,aria-posinset +aria-setsize,aria,aria-setsize,aria-setsize +button,htmlAam,button,button diff --git a/tests/menu-button-actions-active-descendant/data/scripts.csv b/tests/menu-button-actions-active-descendant/data/scripts.csv new file mode 100644 index 000000000..25e1351da --- /dev/null +++ b/tests/menu-button-actions-active-descendant/data/scripts.csv @@ -0,0 +1,6 @@ +setupScript,setupScriptDescription +openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'" +openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'" +setFocusAfterMenuButton,sets focus on a link after the menu button +setFocusBeforeMenuButton,sets focus on a link before the menu button +setFocusOnMenuButton,sets focus on the menu button diff --git a/tests/menu-button-actions-active-descendant/data/tests.csv b/tests/menu-button-actions-active-descendant/data/tests.csv index 8033c0a56..4204d1a26 100644 --- a/tests/menu-button-actions-active-descendant/data/tests.csv +++ b/tests/menu-button-actions-active-descendant/data/tests.csv @@ -1,27 +1,12 @@ -testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 -1,Navigate forwards to a menu button in reading mode,"JAWS,NVDA",reading,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -2,Navigate backwards to a menu button in reading mode,"JAWS,NVDA",reading,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -3,Navigate forwards to a menu button in interaction mode,"JAWS,NVDA",interaction,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -4,Navigate backwards to a menu button in interaction mode,"JAWS,NVDA",interaction,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -5,Navigate forwards to a menu button,voiceover_macos,interaction,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -6,Navigate backwards to a menu button,voiceover_macos,interaction,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -7,Read information about a menu button in reading mode,"JAWS,NVDA",reading,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With the reading cursor on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -8,Read information about a menu button in interaction mode,"JAWS,NVDA",interaction,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With focus on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -9,Read information about a menu button,voiceover_macos,interaction,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With focus on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -10,Open a menu in reading mode,"JAWS,NVDA",reading,open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With the reading cursor on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed, -11,Open a menu in interaction mode,"JAWS,NVDA",interaction,open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed, -12,Open a menu,voiceover_macos,interaction,Open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed, -13,Open a menu to the last item in interaction mode,"JAWS,NVDA",interaction,Open menu to last item,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed, -14,Open a menu to the last item,voiceover_macos,interaction,Open menu to last item,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed, -15,Read information about a menu item in interaction mode,"JAWS,NVDA",interaction,Read information about menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, read information about the menu item.","Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,, -16,Read information about a menu item,voiceover_macos,interaction,Read information about menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, read information about the menu item.","Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,, -17,Navigate to the first item in a menu in interaction mode,"JAWS,NVDA",interaction,navigate to first item in menu,openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'",menuitem aria-activedescendant,"With focus on the 'Action 4' menu item, navigate to the first menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,, -18,Navigate to the first item in a menu,voiceover_macos,interaction,navigate to first item in menu,openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'",menuitem aria-activedescendant,"With focus on the 'Action 4' menu item, navigate to the first menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,, -19,Navigate to the last item in a menu in interaction mode,"JAWS,NVDA",interaction,navigate to last item in menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, navigate to the last menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,,, -20,Navigate to the last item in a menu,voiceover_macos,interaction,navigate to last item in menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, navigate to the last menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,,, -21,Navigate to an item in a menu by typing a character in interaction mode,"JAWS,NVDA",interaction,navigate to item in menu by typing character,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, type a character to navigate to a different menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 2', is conveyed",Position of the focused item in the menu (2) is conveyed,Number of items in the menu (4) is conveyed,,, -22,Navigate to an item in a menu by typing a character,voiceover_macos,interaction,navigate to item in menu by typing character,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, type a character to navigate to a different menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 2', is conveyed",Position of the focused item in the menu (2) is conveyed,Number of items in the menu (4) is conveyed,,, -23,Activate a menu item in interaction mode,"JAWS,NVDA",interaction,activate menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, activate the menu item.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -24,Activate a menu item,voiceover_macos,interaction,activate menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, activate the menu item.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -25,Close a menu in interaction mode,"JAWS,NVDA",interaction,close menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, close the menu.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, -26,Close a menu,voiceover_macos,interaction,close menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, close the menu.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,, +testId,title,presentationNumber,setupScript,instructions,assertions +navForwardsToMenuButton,Navigate forwards to a menu button,5,setFocusBeforeMenuButton,"Starting at the 'Navigate forwards from here' link,, navigate to the menu button.",nameActions roleMenuButton stateCollapsed 0:interactionModeEnabled +navBackToMenuButton,Navigate backwards to a menu button,6,setFocusAfterMenuButton,"Starting at the 'Navigate backwards from here' link,, navigate to the menu button.",nameActions roleMenuButton stateCollapsed 0:interactionModeEnabled +reqInfoAboutMenuButton,Request information about a menu button,9,setFocusOnMenuButton,"Starting at the 'Actions' menu button, read information about the menu button.",nameActions roleMenuButton stateCollapsed +openMenu,Open a menu,12,setFocusOnMenuButton,"Starting at the 'Actions' menu button, open the menu.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4 nameMenuActions roleMenu 0:interactionModeEnabled +openMenuToLastItem,Open a menu to the last item,14,setFocusOnMenuButton,"Starting at the 'Actions' menu button, open the menu.",nameFocusedItemAction4 roleFocusedItemMenuItem positionFocusedItemMenu4 numberItemsMenu4 nameMenuActions roleMenu +reqInfoAboutMenuItem,Request information about a menu item,16,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, read information about the menu item.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4 nameMenuActions roleMenu +navToFirstItemMenu,Navigate to the first item in a menu,18,openMenuAndSetFocusToLastItem,"Starting at the 'Action 4' menu item, navigate to the first menu item.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4 +navToLastItemMenu,Navigate to the last item in a menu,20,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, navigate to the last menu item.",nameFocusedItemAction4 roleFocusedItemMenuItem positionFocusedItemMenu4 numberItemsMenu4 +navToItemMenuByTypingCharacter,Navigate to an item in a menu by typing a character,22,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, type a character to navigate to a different menu item.",nameFocusedItemAction2 roleFocusedItemMenuItem positionFocusedItemMenu2 numberItemsMenu4 +activateMenuItem,Activate a menu item,24,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, activate the menu item.",nameActions roleMenuButton stateCollapsed +closeMenu,Close a menu,26,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, close the menu.",nameActions roleMenuButton stateCollapsed diff --git a/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv b/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv new file mode 100644 index 000000000..0afa44aef --- /dev/null +++ b/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv @@ -0,0 +1,24 @@ +testId,command,settings,assertionExceptions,presentationNumber +navForwardsToMenuButton,tab,,,5.0 +navForwardsToMenuButton,ctrl+opt+right,,,5.1 +navForwardsToMenuButton,j,quickNavOn,,5.2 +navBackToMenuButton,shift+tab,,,6.0 +navBackToMenuButton,ctrl+opt+left,,,6.1 +navBackToMenuButton,j,quickNavOn,,6.2 +reqInfoAboutMenuButton,ctrl+opt+f3,,,9.0 +reqInfoAboutMenuButton,ctrl+opt+f4,,,9.1 +openMenu,ctrl+opt+space,,,12.0 +openMenu,space,,,12.1 +openMenu,enter,,,12.2 +openMenu,down,quickNavOff,,12.3 +openMenuToLastItem,up,quickNavOff,,14.0 +reqInfoAboutMenuItem,ctrl+opt+f3,,,16.0 +reqInfoAboutMenuItem,ctrl+opt+f4,,,16.1 +navToFirstItemMenu,home,,,18.0 +navToFirstItemMenu,down,quickNavOff,,18.1 +navToLastItemMenu,end,,,20.0 +navToLastItemMenu,up,quickNavOff,,20.1 +navToItemMenuByTypingCharacter,a,,,22.0 +activateMenuItem,ctrl+opt+space,,,24.0 +activateMenuItem,enter,,,24.1 +closeMenu,esc,,,26.0 diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html b/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html deleted file mode 100644 index 1fb1900c9..000000000 --- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - Actions Menu Button Example Using aria-activedescendant - - - - - - -
-

Actions Menu Button Example Using aria-activedescendant

-

- This example demonstrates how the - menu button design pattern - can be used to create a button that opens an actions menu. - In this example, choosing an action from the menu will cause the chosen action to be displayed in the Last Action edit box. -

-
-
-

Example

-
- - Navigate forwards from here -
- - Navigate backwards from here -

- -

-
- -
-
- - diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css similarity index 97% rename from tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css rename to tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css index 391043fa3..ec0375f1f 100644 --- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css @@ -45,8 +45,8 @@ .menu-button-actions button svg.down { padding-left: 0.125em; - fill: currentColor; - stroke: currentColor; + fill: currentcolor; + stroke: currentcolor; } .menu-button-actions button[aria-expanded="true"] svg.down { diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css new file mode 100644 index 000000000..6ab2b3680 --- /dev/null +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css @@ -0,0 +1,78 @@ +.menu-button-links { + margin: 0; + font-size: 110%; +} + +.menu-button-links button { + margin: 0; + padding: 6px; + display: inline-block; + position: relative; + background-color: #034575; + border: 1px solid #034575; + font-size: 0.9em; + color: white; + border-radius: 5px; +} + +.menu-button-links [role="menu"] { + margin: 0; + padding: 7px 4px; + list-style: none; + display: none; + position: absolute; + border: 2px solid #034575; + border-radius: 5px; + background-color: #eee; +} + +.menu-button-links [role="menuitem"], +.menu-button-links [role="separator"] { + margin: 0; + padding: 6px; + display: block; + width: 24em; + background-color: #eee; + border: none; + color: black; + border-radius: 5px; +} + +.menu-button-links [role="separator"] { + padding-top: 3px; + background-image: url("../images/separator.svg"); + background-position: center; + background-repeat: repeat-x; +} + +.menu-button-links button svg.down { + padding-left: 0.125em; + fill: currentcolor; + stroke: currentcolor; +} + +.menu-button-links button[aria-expanded="true"] svg.down { + transform: rotate(180deg); +} + +/* focus styling */ + +.menu-button-links button:hover, +.menu-button-links button:focus, +.menu-button-links button[aria-expanded="true"] { + padding: 4px; + border: 3px solid #034575; + background: #eee; + color: #222; + outline: none; + margin: 0; +} + +.menu-button-links [role="menuitem"]:focus { + padding: 4px; + border: 2px solid #034575; + background: #034575; + color: #fff; + outline: none; + margin: 0; +} diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js similarity index 98% rename from tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js rename to tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js index 685e270ef..5783b2d84 100644 --- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js @@ -162,9 +162,9 @@ class MenuButtonActionsActiveDescendant { closePopup() { if (this.isOpen()) { - this.buttonNode.removeAttribute('aria-expanded'); + this.buttonNode.setAttribute('aria-expanded', 'false'); this.menuNode.setAttribute('aria-activedescendant', ''); - for (var i = 0; i < this.menuitemNodes.length; i++) { + for (let i = 0; i < this.menuitemNodes.length; i++) { this.menuitemNodes[i].classList.remove('focus'); } this.menuNode.style.display = 'none'; diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js new file mode 100644 index 000000000..cd69d5621 --- /dev/null +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js @@ -0,0 +1,346 @@ +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: menu-button-actions.js + * + * Desc: Creates a menu button that opens a menu of actions + */ + +'use strict'; + +class MenuButtonActions { + constructor(domNode, performMenuAction) { + this.domNode = domNode; + this.performMenuAction = performMenuAction; + this.buttonNode = domNode.querySelector('button'); + this.menuNode = domNode.querySelector('[role="menu"]'); + this.menuitemNodes = []; + this.firstMenuitem = false; + this.lastMenuitem = false; + this.firstChars = []; + + this.buttonNode.addEventListener( + 'keydown', + this.onButtonKeydown.bind(this) + ); + this.buttonNode.addEventListener('click', this.onButtonClick.bind(this)); + + var nodes = domNode.querySelectorAll('[role="menuitem"]'); + + for (var i = 0; i < nodes.length; i++) { + var menuitem = nodes[i]; + this.menuitemNodes.push(menuitem); + menuitem.tabIndex = -1; + this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase()); + + menuitem.addEventListener('keydown', this.onMenuitemKeydown.bind(this)); + + menuitem.addEventListener('click', this.onMenuitemClick.bind(this)); + + menuitem.addEventListener( + 'mouseover', + this.onMenuitemMouseover.bind(this) + ); + + if (!this.firstMenuitem) { + this.firstMenuitem = menuitem; + } + this.lastMenuitem = menuitem; + } + + domNode.addEventListener('focusin', this.onFocusin.bind(this)); + domNode.addEventListener('focusout', this.onFocusout.bind(this)); + + window.addEventListener( + 'mousedown', + this.onBackgroundMousedown.bind(this), + true + ); + } + + setFocusToMenuitem(newMenuitem) { + this.menuitemNodes.forEach(function (item) { + if (item === newMenuitem) { + item.tabIndex = 0; + newMenuitem.focus(); + } else { + item.tabIndex = -1; + } + }); + } + + setFocusToFirstMenuitem() { + this.setFocusToMenuitem(this.firstMenuitem); + } + + setFocusToLastMenuitem() { + this.setFocusToMenuitem(this.lastMenuitem); + } + + setFocusToPreviousMenuitem(currentMenuitem) { + var newMenuitem, index; + + if (currentMenuitem === this.firstMenuitem) { + newMenuitem = this.lastMenuitem; + } else { + index = this.menuitemNodes.indexOf(currentMenuitem); + newMenuitem = this.menuitemNodes[index - 1]; + } + + this.setFocusToMenuitem(newMenuitem); + + return newMenuitem; + } + + setFocusToNextMenuitem(currentMenuitem) { + var newMenuitem, index; + + if (currentMenuitem === this.lastMenuitem) { + newMenuitem = this.firstMenuitem; + } else { + index = this.menuitemNodes.indexOf(currentMenuitem); + newMenuitem = this.menuitemNodes[index + 1]; + } + this.setFocusToMenuitem(newMenuitem); + + return newMenuitem; + } + + setFocusByFirstCharacter(currentMenuitem, char) { + var start, index; + + if (char.length > 1) { + return; + } + + char = char.toLowerCase(); + + // Get start index for search based on position of currentItem + start = this.menuitemNodes.indexOf(currentMenuitem) + 1; + if (start >= this.menuitemNodes.length) { + start = 0; + } + + // Check remaining slots in the menu + index = this.firstChars.indexOf(char, start); + + // If not found in remaining slots, check from beginning + if (index === -1) { + index = this.firstChars.indexOf(char, 0); + } + + // If match was found... + if (index > -1) { + this.setFocusToMenuitem(this.menuitemNodes[index]); + } + } + + // Utilities + + getIndexFirstChars(startIndex, char) { + for (var i = startIndex; i < this.firstChars.length; i++) { + if (char === this.firstChars[i]) { + return i; + } + } + return -1; + } + + // Popup menu methods + + openPopup() { + this.menuNode.style.display = 'block'; + this.buttonNode.setAttribute('aria-expanded', 'true'); + } + + closePopup() { + if (this.isOpen()) { + this.buttonNode.setAttribute('aria-expanded', 'false'); + this.menuNode.style.display = 'none'; + } + } + + isOpen() { + return this.buttonNode.getAttribute('aria-expanded') === 'true'; + } + + // Menu event handlers + + onFocusin() { + this.domNode.classList.add('focus'); + } + + onFocusout() { + this.domNode.classList.remove('focus'); + } + + onButtonKeydown(event) { + var key = event.key, + flag = false; + + switch (key) { + case ' ': + case 'Enter': + case 'ArrowDown': + case 'Down': + this.openPopup(); + this.setFocusToFirstMenuitem(); + flag = true; + break; + + case 'Esc': + case 'Escape': + this.closePopup(); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + this.openPopup(); + this.setFocusToLastMenuitem(); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } + } + + onButtonClick(event) { + if (this.isOpen()) { + this.closePopup(); + this.buttonNode.focus(); + } else { + this.openPopup(); + this.setFocusToFirstMenuitem(); + } + + event.stopPropagation(); + event.preventDefault(); + } + + onMenuitemKeydown(event) { + var tgt = event.currentTarget, + key = event.key, + flag = false; + + function isPrintableCharacter(str) { + return str.length === 1 && str.match(/\S/); + } + + if (event.ctrlKey || event.altKey || event.metaKey) { + return; + } + + if (event.shiftKey) { + if (isPrintableCharacter(key)) { + this.setFocusByFirstCharacter(tgt, key); + flag = true; + } + + if (event.key === 'Tab') { + this.buttonNode.focus(); + this.closePopup(); + flag = true; + } + } else { + switch (key) { + case ' ': + case 'Enter': + this.closePopup(); + this.performMenuAction(tgt); + this.buttonNode.focus(); + flag = true; + break; + + case 'Esc': + case 'Escape': + this.closePopup(); + this.buttonNode.focus(); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + this.setFocusToPreviousMenuitem(tgt); + flag = true; + break; + + case 'ArrowDown': + case 'Down': + this.setFocusToNextMenuitem(tgt); + flag = true; + break; + + case 'Home': + case 'PageUp': + this.setFocusToFirstMenuitem(); + flag = true; + break; + + case 'End': + case 'PageDown': + this.setFocusToLastMenuitem(); + flag = true; + break; + + case 'Tab': + this.closePopup(); + break; + + default: + if (isPrintableCharacter(key)) { + this.setFocusByFirstCharacter(tgt, key); + flag = true; + } + break; + } + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } + } + + onMenuitemClick(event) { + var tgt = event.currentTarget; + this.closePopup(); + this.buttonNode.focus(); + this.performMenuAction(tgt); + } + + onMenuitemMouseover(event) { + var tgt = event.currentTarget; + tgt.focus(); + } + + onBackgroundMousedown(event) { + if (!this.domNode.contains(event.target)) { + if (this.isOpen()) { + this.closePopup(); + this.buttonNode.focus(); + } + } + } +} + +// Initialize menu buttons +window.addEventListener('load', function () { + document.getElementById('action_output').value = 'none'; + + function performMenuAction(node) { + document.getElementById('action_output').value = node.textContent.trim(); + } + + var menuButtons = document.querySelectorAll('.menu-button-actions'); + for (var i = 0; i < menuButtons.length; i++) { + new MenuButtonActions(menuButtons[i], performMenuAction); + } +}); diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js new file mode 100644 index 000000000..757aac226 --- /dev/null +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js @@ -0,0 +1,328 @@ +/* + * This content is licensed according to the W3C Software License at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + * + * File: menu-button-links.js + * + * Desc: Creates a menu button that opens a menu of links + */ + +'use strict'; + +class MenuButtonLinks { + constructor(domNode) { + this.domNode = domNode; + this.buttonNode = domNode.querySelector('button'); + this.menuNode = domNode.querySelector('[role="menu"]'); + this.menuitemNodes = []; + this.firstMenuitem = false; + this.lastMenuitem = false; + this.firstChars = []; + + this.buttonNode.addEventListener( + 'keydown', + this.onButtonKeydown.bind(this) + ); + this.buttonNode.addEventListener('click', this.onButtonClick.bind(this)); + + var nodes = domNode.querySelectorAll('[role="menuitem"]'); + + for (var i = 0; i < nodes.length; i++) { + var menuitem = nodes[i]; + this.menuitemNodes.push(menuitem); + menuitem.tabIndex = -1; + this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase()); + + menuitem.addEventListener('keydown', this.onMenuitemKeydown.bind(this)); + + menuitem.addEventListener( + 'mouseover', + this.onMenuitemMouseover.bind(this) + ); + + if (!this.firstMenuitem) { + this.firstMenuitem = menuitem; + } + this.lastMenuitem = menuitem; + } + + domNode.addEventListener('focusin', this.onFocusin.bind(this)); + domNode.addEventListener('focusout', this.onFocusout.bind(this)); + + window.addEventListener( + 'mousedown', + this.onBackgroundMousedown.bind(this), + true + ); + } + + setFocusToMenuitem(newMenuitem) { + this.menuitemNodes.forEach(function (item) { + if (item === newMenuitem) { + item.tabIndex = 0; + newMenuitem.focus(); + } else { + item.tabIndex = -1; + } + }); + } + + setFocusToFirstMenuitem() { + this.setFocusToMenuitem(this.firstMenuitem); + } + + setFocusToLastMenuitem() { + this.setFocusToMenuitem(this.lastMenuitem); + } + + setFocusToPreviousMenuitem(currentMenuitem) { + var newMenuitem, index; + + if (currentMenuitem === this.firstMenuitem) { + newMenuitem = this.lastMenuitem; + } else { + index = this.menuitemNodes.indexOf(currentMenuitem); + newMenuitem = this.menuitemNodes[index - 1]; + } + + this.setFocusToMenuitem(newMenuitem); + + return newMenuitem; + } + + setFocusToNextMenuitem(currentMenuitem) { + var newMenuitem, index; + + if (currentMenuitem === this.lastMenuitem) { + newMenuitem = this.firstMenuitem; + } else { + index = this.menuitemNodes.indexOf(currentMenuitem); + newMenuitem = this.menuitemNodes[index + 1]; + } + this.setFocusToMenuitem(newMenuitem); + + return newMenuitem; + } + + setFocusByFirstCharacter(currentMenuitem, char) { + var start, index; + + if (char.length > 1) { + return; + } + + char = char.toLowerCase(); + + // Get start index for search based on position of currentItem + start = this.menuitemNodes.indexOf(currentMenuitem) + 1; + if (start >= this.menuitemNodes.length) { + start = 0; + } + + // Check remaining slots in the menu + index = this.firstChars.indexOf(char, start); + + // If not found in remaining slots, check from beginning + if (index === -1) { + index = this.firstChars.indexOf(char, 0); + } + + // If match was found... + if (index > -1) { + this.setFocusToMenuitem(this.menuitemNodes[index]); + } + } + + // Utilities + + getIndexFirstChars(startIndex, char) { + for (var i = startIndex; i < this.firstChars.length; i++) { + if (char === this.firstChars[i]) { + return i; + } + } + return -1; + } + + // Popup menu methods + + openPopup() { + this.menuNode.style.display = 'block'; + this.buttonNode.setAttribute('aria-expanded', 'true'); + } + + closePopup() { + if (this.isOpen()) { + this.buttonNode.setAttribute('aria-expanded', 'false'); + this.menuNode.style.display = 'none'; + } + } + + isOpen() { + return this.buttonNode.getAttribute('aria-expanded') === 'true'; + } + + // Menu event handlers + + onFocusin() { + this.domNode.classList.add('focus'); + } + + onFocusout() { + this.domNode.classList.remove('focus'); + } + + onButtonKeydown(event) { + var key = event.key, + flag = false; + + switch (key) { + case ' ': + case 'Enter': + case 'ArrowDown': + case 'Down': + this.openPopup(); + this.setFocusToFirstMenuitem(); + flag = true; + break; + + case 'Esc': + case 'Escape': + this.closePopup(); + this.buttonNode.focus(); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + this.openPopup(); + this.setFocusToLastMenuitem(); + flag = true; + break; + + default: + break; + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } + } + + onButtonClick(event) { + if (this.isOpen()) { + this.closePopup(); + this.buttonNode.focus(); + } else { + this.openPopup(); + this.setFocusToFirstMenuitem(); + } + + event.stopPropagation(); + event.preventDefault(); + } + + onMenuitemKeydown(event) { + var tgt = event.currentTarget, + key = event.key, + flag = false; + + function isPrintableCharacter(str) { + return str.length === 1 && str.match(/\S/); + } + + if (event.ctrlKey || event.altKey || event.metaKey) { + return; + } + + if (event.shiftKey) { + if (isPrintableCharacter(key)) { + this.setFocusByFirstCharacter(tgt, key); + flag = true; + } + + if (event.key === 'Tab') { + this.buttonNode.focus(); + this.closePopup(); + flag = true; + } + } else { + switch (key) { + case ' ': + window.location.href = tgt.href; + break; + + case 'Esc': + case 'Escape': + this.closePopup(); + this.buttonNode.focus(); + flag = true; + break; + + case 'Up': + case 'ArrowUp': + this.setFocusToPreviousMenuitem(tgt); + flag = true; + break; + + case 'ArrowDown': + case 'Down': + this.setFocusToNextMenuitem(tgt); + flag = true; + break; + + case 'Home': + case 'PageUp': + this.setFocusToFirstMenuitem(); + flag = true; + break; + + case 'End': + case 'PageDown': + this.setFocusToLastMenuitem(); + flag = true; + break; + + case 'Tab': + this.closePopup(); + break; + + default: + if (isPrintableCharacter(key)) { + this.setFocusByFirstCharacter(tgt, key); + flag = true; + } + break; + } + } + + if (flag) { + event.stopPropagation(); + event.preventDefault(); + } + } + + onMenuitemMouseover(event) { + var tgt = event.currentTarget; + tgt.focus(); + } + + onBackgroundMousedown(event) { + if (!this.domNode.contains(event.target)) { + if (this.isOpen()) { + this.closePopup(); + this.buttonNode.focus(); + } + } + } +} + +// Initialize menu buttons + +window.addEventListener('load', function () { + var menuButtons = document.querySelectorAll('.menu-button-links'); + for (let i = 0; i < menuButtons.length; i++) { + new MenuButtonLinks(menuButtons[i]); + } +}); diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html new file mode 100644 index 000000000..a203fc37f --- /dev/null +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html @@ -0,0 +1,61 @@ + + + + + + Actions Menu Button Example Using aria-activedescendant + + + + + + + + + + + + + + +
+

Actions Menu Button Example Using aria-activedescendant

+ +
+

+ This example demonstrates how the Menu Button Pattern can be used to create a button that opens an actions menu. + In this example, choosing an action from the menu will cause the chosen action to be displayed in the Last Action edit box. +

+ section> + +
+
+

Example

+
+ + Navigate forwards from here +
+ + Navigate backwards from here +

+ +

+
+ +
+
+ + diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html similarity index 61% rename from tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html rename to tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html index c7265f552..b24f9dde0 100644 --- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html +++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.openMenuAndSetFocusToFirstItem.html @@ -1,11 +1,21 @@ - - + + + + Actions Menu Button Example Using aria-activedescendant + + + + + + + + - + + + + + - + + + + + - + + + + + - + + + + + - +