@@ -677,6 +677,13 @@ the specific language governing permissions and limitations under the Apache Lic
677677
678678 this . container = this . createContainer ( ) ;
679679
680+ this . liveRegion = $ ( "<span>" , {
681+ role : "status" ,
682+ "aria-live" : "polite"
683+ } )
684+ . addClass ( "select2-hidden-accessible" )
685+ . appendTo ( document . body ) ;
686+
680687 this . containerId = "s2id_" + ( opts . element . attr ( "id" ) || "autogen" + nextUid ( ) ) . replace ( / ( [ ; & , \- \. \+ \* \~ ' : " \! \^ # $ % @ \[ \] \( \) = > \| ] ) / g, '\\$1' ) ;
681688 this . containerSelector = "#" + this . containerId ;
682689 this . container . attr ( "id" , this . containerId ) ;
@@ -763,7 +770,7 @@ the specific language governing permissions and limitations under the Apache Lic
763770 this . dropdown . on ( "click mouseup mousedown" , function ( e ) { e . stopPropagation ( ) ; } ) ;
764771
765772 this . nextSearchTerm = undefined ;
766-
773+
767774 if ( $ . isFunction ( this . opts . initSelection ) ) {
768775 // initialize selection based on the current value of the source element
769776 this . initSelection ( ) ;
@@ -791,7 +798,7 @@ the specific language governing permissions and limitations under the Apache Lic
791798 this . autofocus = opts . element . prop ( "autofocus" ) ;
792799 opts . element . prop ( "autofocus" , false ) ;
793800 if ( this . autofocus ) this . focus ( ) ;
794-
801+
795802 } ,
796803
797804 // abstract
@@ -804,6 +811,7 @@ the specific language governing permissions and limitations under the Apache Lic
804811
805812 if ( select2 !== undefined ) {
806813 select2 . container . remove ( ) ;
814+ select2 . liveRegion . remove ( ) ;
807815 select2 . dropdown . remove ( ) ;
808816 element
809817 . removeClass ( "select2-offscreen" )
@@ -861,7 +869,7 @@ the specific language governing permissions and limitations under the Apache Lic
861869
862870 opts = $ . extend ( { } , {
863871 populateResults : function ( container , results , query ) {
864- var populate , id = this . opts . id ;
872+ var populate , id = this . opts . id , liveRegion = this . liveRegion ;
865873
866874 populate = function ( results , container , depth ) {
867875
@@ -910,6 +918,8 @@ the specific language governing permissions and limitations under the Apache Lic
910918 node . data ( "select2-data" , result ) ;
911919 container . append ( node ) ;
912920 }
921+
922+ liveRegion . text ( opts . formatMatches ( results . length ) ) ;
913923 } ;
914924
915925 populate ( results , container , 0 ) ;
@@ -1484,6 +1494,8 @@ the specific language governing permissions and limitations under the Apache Lic
14841494
14851495 this . ensureHighlightVisible ( ) ;
14861496
1497+ this . liveRegion . text ( choice . text ( ) ) ;
1498+
14871499 data = choice . data ( "select2-data" ) ;
14881500 if ( data ) {
14891501 this . opts . element . trigger ( { type : "select2-highlight" , val : this . id ( data ) , choice : data } ) ;
@@ -1591,6 +1603,12 @@ the specific language governing permissions and limitations under the Apache Lic
15911603 function postRender ( ) {
15921604 search . removeClass ( "select2-active" ) ;
15931605 self . positionDropdown ( ) ;
1606+ if ( results . find ( '.select2-no-results,.select2-selection-limit,.select2-searching' ) . length ) {
1607+ self . liveRegion . text ( results . text ( ) ) ;
1608+ }
1609+ else {
1610+ self . liveRegion . text ( self . opts . formatMatches ( results . find ( '.select2-result-selectable' ) . length ) ) ;
1611+ }
15941612 }
15951613
15961614 function render ( html ) {
@@ -1828,9 +1846,11 @@ the specific language governing permissions and limitations under the Apache Lic
18281846 " <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>" ,
18291847 " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>" ,
18301848 "</a>" ,
1849+ "<label for='' class='select2-offscreen'></label>" ,
18311850 "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />" ,
18321851 "<div class='select2-drop select2-display-none'>" ,
18331852 " <div class='select2-search'>" ,
1853+ " <label for='' class='select2-offscreen'></label>" ,
18341854 " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'" ,
18351855 " aria-autocomplete='list' />" ,
18361856 " </div>" ,
@@ -1960,7 +1980,10 @@ the specific language governing permissions and limitations under the Apache Lic
19601980 // rewrite labels from original element to focusser
19611981 this . focusser . attr ( "id" , "s2id_autogen" + idSuffix ) ;
19621982
1963- elementLabel = $ ( "label[for='" + this . opts . element . attr ( "id" ) + "']" )
1983+ elementLabel = $ ( "label[for='" + this . opts . element . attr ( "id" ) + "']" ) ;
1984+
1985+ this . focusser . prev ( )
1986+ . text ( elementLabel . text ( ) )
19641987 . attr ( 'for' , this . focusser . attr ( 'id' ) ) ;
19651988
19661989 // Ensure the original element retains an accessible name
@@ -1969,6 +1992,13 @@ the specific language governing permissions and limitations under the Apache Lic
19691992
19701993 this . focusser . attr ( "tabindex" , this . elementTabIndex ) ;
19711994
1995+ // write label for search field using the label from the focusser element
1996+ this . search . attr ( "id" , this . focusser . attr ( 'id' ) + '_search' ) ;
1997+
1998+ this . search . prev ( )
1999+ . text ( $ ( "label[for='" + this . focusser . attr ( 'id' ) + "']" ) . text ( ) )
2000+ . attr ( 'for' , this . search . attr ( 'id' ) ) ;
2001+
19722002 this . search . on ( "keydown" , this . bind ( function ( e ) {
19732003 if ( ! this . isInterfaceEnabled ( ) ) return ;
19742004
@@ -2148,7 +2178,7 @@ the specific language governing permissions and limitations under the Apache Lic
21482178 self . nextSearchTerm = self . opts . nextSearchTerm ( selected , self . search . val ( ) ) ;
21492179 }
21502180 } ) ;
2151- }
2181+ }
21522182 } ,
21532183
21542184 isPlaceholderOptionSelected : function ( ) {
@@ -2410,6 +2440,7 @@ the specific language governing permissions and limitations under the Apache Lic
24102440 } ) . html ( [
24112441 "<ul class='select2-choices'>" ,
24122442 " <li class='select2-search-field'>" ,
2443+ " <label for='' class='select2-offscreen'></label>" ,
24132444 " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>" ,
24142445 " </li>" ,
24152446 "</ul>" ,
@@ -2521,7 +2552,9 @@ the specific language governing permissions and limitations under the Apache Lic
25212552
25222553 // rewrite labels from original element to focusser
25232554 this . search . attr ( "id" , "s2id_autogen" + nextUid ( ) ) ;
2524- $ ( "label[for='" + this . opts . element . attr ( "id" ) + "']" )
2555+
2556+ this . search . prev ( )
2557+ . text ( $ ( "label[for='" + this . opts . element . attr ( "id" ) + "']" ) . text ( ) )
25252558 . attr ( 'for' , this . search . attr ( 'id' ) ) ;
25262559
25272560 this . search . on ( "input paste" , this . bind ( function ( ) {
@@ -3257,6 +3290,7 @@ the specific language governing permissions and limitations under the Apache Lic
32573290 } ,
32583291 formatResultCssClass : function ( data ) { return data . css ; } ,
32593292 formatSelectionCssClass : function ( data , container ) { return undefined ; } ,
3293+ formatMatches : function ( matches ) { return matches + " results are available, use up and down arrow keys to navigate." ; } ,
32603294 formatNoMatches : function ( ) { return "No matches found" ; } ,
32613295 formatInputTooShort : function ( input , min ) { var n = min - input . length ; return "Please enter " + n + " or more character" + ( n == 1 ? "" : "s" ) ; } ,
32623296 formatInputTooLong : function ( input , max ) { var n = input . length - max ; return "Please delete " + n + " character" + ( n == 1 ? "" : "s" ) ; } ,
0 commit comments