@@ -95,6 +95,47 @@ function attachOneDropdownAria($dropdown) {
95
95
$dropdown . on ( 'keyup' , ( e ) => { if ( e . key . startsWith ( 'Arrow' ) ) deferredRefreshAria ( ) ; } ) ;
96
96
}
97
97
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
+
98
138
export 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 ) ) ) ;
100
141
}
0 commit comments