@@ -95,6 +95,47 @@ function attachOneDropdownAria($dropdown) {
9595 $dropdown . on ( 'keyup' , ( e ) => { if ( e . key . startsWith ( 'Arrow' ) ) deferredRefreshAria ( ) ; } ) ;
9696}
9797
98+ function attachOneDropdownAriaTemplated ( $dropdown ) {
99+ window . console && console . log ( '[attachOneDropdownAriaTemplated] ' + $dropdown . prop ( 'id' ) ) ;
100+ if ( $dropdown . attr ( 'data-aria-attached' ) ) return ;
101+ $dropdown . attr ( 'data-aria-attached' , 1 ) ;
102+
103+ const $menu = $dropdown . find ( '> .menu' ) ;
104+ // update aria attributes according to current active/selected item
105+ const refreshAria = ( ) => {
106+ const isMenuVisible = ! $menu . is ( '.hidden' ) && ! $menu . is ( '.animating.out' ) ;
107+ isMenuVisible ? $dropdown . attr ( 'aria-expanded' , 'true' ) : $dropdown . removeAttr ( 'aria-expanded' ) ;
108+
109+ let $active = $menu . find ( '> .item.active' ) ;
110+ //if (!$active.length) $active = $menu.find('> .item.selected'); // it's strange that we need this fallback at the moment
111+
112+ // if there is an active item, use its id. if no active item, then the empty string is set
113+ $dropdown . attr ( 'aria-activedescendant' , $active . attr ( 'id' ) ) ;
114+ } ;
115+
116+ $dropdown . on ( 'keydown' , ( e ) => {
117+ window . console && console . log ( 'keydown:' + e . key ) ;
118+ // here it must use keydown event before dropdown's keyup handler, otherwise there is no Enter event in our keyup handler
119+ if ( e . key === 'Enter' ) {
120+ const $item = $dropdown . dropdown ( 'get item' , $dropdown . dropdown ( 'get value' ) ) ;
121+ // if the selected item is clickable, then trigger the click event. in the future there could be a special CSS class for it.
122+ if ( $item ) $item [ 0 ] . click ( ) ;
123+ }
124+ else if ( e . key === 'ESC' ) {
125+ $dropdown . dropdown ( 'hide' ) ;
126+ $dropdown . removeAttr ( 'aria-expanded' ) ;
127+ }
128+ } ) ;
129+
130+ // use setTimeout to run the refreshAria in next tick (to make sure the Fomantic UI code has finished its work)
131+ const deferredRefreshAria = ( ) => { setTimeout ( refreshAria , 0 ) } ; // do not return any value, jQuery has return-value related behaviors.
132+ $dropdown . on ( 'focus' , deferredRefreshAria ) ;
133+ $dropdown . on ( 'mouseup' , deferredRefreshAria ) ;
134+ $dropdown . on ( 'blur' , deferredRefreshAria ) ;
135+ $dropdown . on ( 'keyup' , ( e ) => { if ( e . key . startsWith ( 'Arrow' ) ) deferredRefreshAria ( ) ; } ) ;
136+ }
137+
98138export function attachDropdownAria ( $dropdowns ) {
99- $dropdowns . each ( ( _ , e ) => attachOneDropdownAria ( $ ( e ) ) ) ;
139+ $dropdowns . filter ( ':not([data-aria-templated])' ) . each ( ( _ , e ) => attachOneDropdownAria ( $ ( e ) ) ) ;
140+ $dropdowns . filter ( '[data-aria-templated]' ) . each ( ( _ , e ) => attachOneDropdownAriaTemplated ( $ ( e ) ) ) ;
100141}
0 commit comments