@@ -151,7 +151,7 @@ define('select2/results',[
151151
152152 Results . prototype . render = function ( ) {
153153 var $results = $ (
154- '<ul class="options"></ul>'
154+ '<ul class="options" role="listbox" ></ul>'
155155 ) ;
156156
157157 this . $results = $results ;
@@ -191,28 +191,42 @@ define('select2/results',[
191191 return s . id . toString ( ) ;
192192 } ) ;
193193
194- self . $results . find ( '.option.selected' ) . removeClass ( 'selected' ) ;
195-
196- var $options = self . $results . find ( '.option' ) ;
194+ var $options = self . $results . find ( '.option[aria-selected]' ) ;
197195
198196 $options . each ( function ( ) {
199197 var $option = $ ( this ) ;
200198 var item = $option . data ( 'data' ) ;
201199
202200 if ( item . id != null && selectedIds . indexOf ( item . id . toString ( ) ) > - 1 ) {
203- $option . addClass ( 'selected' ) ;
201+ $option . attr ( 'aria-selected' , 'true' ) ;
202+ } else {
203+ $option . attr ( 'aria-selected' , 'false' ) ;
204204 }
205205 } ) ;
206+
207+ var $selected = $options . filter ( '[aria-selected=true]' ) ;
208+
209+ // Check if there are any selected options
210+ if ( $selected . length > 0 ) {
211+ // If there are selected options, highlight the first
212+ $selected . first ( ) . trigger ( 'mouseenter' ) ;
213+ } else {
214+ // If there are no selected options, highlight the first option
215+ // in the dropdown
216+ $options . first ( ) . trigger ( 'mouseenter' ) ;
217+ }
206218 } ) ;
207219 } ;
208220
209221 Results . prototype . option = function ( data ) {
210222 var $option = $ (
211- '<li class="option highlightable selectable "></li>'
223+ '<li class="option" role="option" aria-selected="false "></li>'
212224 ) ;
213225
214226 if ( data . children ) {
215- $option . addClass ( 'group' ) . removeClass ( 'highlightable selectable' ) ;
227+ $option
228+ . addClass ( 'group' )
229+ . removeAttr ( 'aria-selected' ) ;
216230
217231 var $label = $ ( '<strong class="group-label"></strong>' ) ;
218232 $label . html ( data . text ) ;
@@ -238,11 +252,13 @@ define('select2/results',[
238252 }
239253
240254 if ( data . disabled ) {
241- $option . removeClass ( 'selectable highlightable' ) . addClass ( 'disabled' ) ;
255+ $option
256+ . removeAttr ( 'aria-selected' )
257+ . attr ( 'aria-disabled' , 'true' ) ;
242258 }
243259
244260 if ( data . id == null ) {
245- $option . removeClass ( 'selectable highlightable ' ) ;
261+ $option . removeClass ( 'aria-selected ' ) ;
246262 }
247263
248264 $option . data ( 'data' , data ) ;
@@ -274,11 +290,40 @@ define('select2/results',[
274290 self . setClasses ( ) ;
275291 } ) ;
276292
277- this . $results . on ( 'mouseup' , '.option.selectable' , function ( evt ) {
293+ container . on ( 'open' , function ( ) {
294+ // When the dropdown is open, aria-expended="true"
295+ self . $results . attr ( 'aria-expanded' , 'true' ) ;
296+
297+ self . setClasses ( ) ;
298+ } ) ;
299+
300+ container . on ( 'close' , function ( ) {
301+ // When the dropdown is closed, aria-expended="false"
302+ self . $results . attr ( 'aria-expanded' , 'false' ) ;
303+ } ) ;
304+
305+ container . on ( 'results:select' , function ( ) {
306+ var $highlighted = self . $results . find ( '.highlighted' ) ;
307+
308+ var data = $highlighted . data ( 'data' ) ;
309+
310+ if ( $highlighted . attr ( 'aria-selected' ) == 'true' ) {
311+ self . trigger ( 'unselected' , {
312+ data : data
313+ } ) ;
314+ } else {
315+ self . trigger ( 'selected' , {
316+ data : data
317+ } ) ;
318+ }
319+ } ) ;
320+
321+ this . $results . on ( 'mouseup' , '.option[aria-selected]' , function ( evt ) {
278322 var $this = $ ( this ) ;
279323
280324 var data = $this . data ( 'data' ) ;
281- if ( $this . hasClass ( 'selected' ) ) {
325+
326+ if ( $this . attr ( 'aria-selected' ) === 'true' ) {
282327 self . trigger ( 'unselected' , {
283328 originalEvent : evt ,
284329 data : data
@@ -293,7 +338,7 @@ define('select2/results',[
293338 } ) ;
294339 } ) ;
295340
296- this . $results . on ( 'mouseenter' , '.option.highlightable ' , function ( evt ) {
341+ this . $results . on ( 'mouseenter' , '.option[aria-selected] ' , function ( evt ) {
297342 self . $results . find ( '.option.highlighted' ) . removeClass ( 'highlighted' ) ;
298343 $ ( this ) . addClass ( 'highlighted' ) ;
299344 } ) ;
@@ -337,10 +382,51 @@ define('select2/selection/base',[
337382 return BaseSelection ;
338383} ) ;
339384
385+ define ( 'select2/keys' , [
386+
387+ ] , function ( ) {
388+ var KEYS = {
389+ BACKSPACE : 8 ,
390+ TAB : 9 ,
391+ ENTER : 13 ,
392+ SHIFT : 16 ,
393+ CTRL : 17 ,
394+ ALT : 18 ,
395+ ESC : 27 ,
396+ SPACE : 32 ,
397+ PAGE_UP : 33 ,
398+ PAGE_DOWN : 34 ,
399+ END : 35 ,
400+ HOME : 36 ,
401+ LEFT : 37 ,
402+ UP : 38 ,
403+ RIGHT : 39 ,
404+ DOWN : 40 ,
405+ DELETE : 46 ,
406+
407+ isArrow : function ( k ) {
408+ k = k . which ? k . which : k ;
409+
410+ switch ( k ) {
411+ case KEY . LEFT :
412+ case KEY . RIGHT :
413+ case KEY . UP :
414+ case KEY . DOWN :
415+ return true ;
416+ }
417+
418+ return false ;
419+ }
420+ } ;
421+
422+ return KEYS ;
423+ } ) ;
424+
340425define ( 'select2/selection/single' , [
341426 './base' ,
342- '../utils'
343- ] , function ( BaseSelection , Utils ) {
427+ '../utils' ,
428+ '../keys'
429+ ] , function ( BaseSelection , Utils , KEYS ) {
344430 function SingleSelection ( ) {
345431 SingleSelection . __super__ . constructor . apply ( this , arguments ) ;
346432 }
@@ -349,11 +435,13 @@ define('select2/selection/single',[
349435
350436 SingleSelection . prototype . render = function ( ) {
351437 var $selection = $ (
352- '<span class="single-select">' +
438+ '<span class="single-select" tabindex="0" >' +
353439 '<span class="rendered-selection"></span>' +
354440 '</span>'
355441 ) ;
356442
443+ $selection . attr ( 'title' , this . $element . attr ( 'title' ) ) ;
444+
357445 this . $selection = $selection ;
358446
359447 return $selection ;
@@ -375,6 +463,28 @@ define('select2/selection/single',[
375463 } ) ;
376464 } ) ;
377465
466+ this . $selection . on ( 'focus' , function ( evt ) {
467+ // User focuses on the container
468+ } ) ;
469+
470+ this . $selection . on ( 'blur' , function ( evt ) {
471+ // User exits the container
472+ } ) ;
473+
474+ this . $selection . on ( 'keyup' , function ( evt ) {
475+ var key = evt . which ;
476+
477+ if ( container . isOpen ( ) ) {
478+ if ( key == KEYS . ENTER ) {
479+ self . trigger ( 'results:select' ) ;
480+ }
481+ } else {
482+ if ( key == KEYS . ENTER || key == KEYS . SPACE ) {
483+ self . trigger ( 'open' ) ;
484+ }
485+ }
486+ } ) ;
487+
378488 container . on ( 'selection:update' , function ( params ) {
379489 self . update ( params . data ) ;
380490 } ) ;
@@ -468,7 +578,7 @@ define('select2/selection/multiple',[
468578 MultipleSelection . prototype . selectionContainer = function ( ) {
469579 var $container = $ (
470580 '<li class="choice">' +
471- '<span class="remove">×</span>' +
581+ '<span class="remove" role="presentation" >×</span>' +
472582 '</li>'
473583 ) ;
474584
@@ -898,7 +1008,7 @@ define('select2/dropdown/search',[
8981008
8991009 var $search = $ (
9001010 '<span class="search">' +
901- '<input type="search" name="search" />' +
1011+ '<input type="search" name="search" tabindex="-1" role="textbox" />' +
9021012 '</span>'
9031013 ) ;
9041014
@@ -921,6 +1031,14 @@ define('select2/dropdown/search',[
9211031 } ) ;
9221032 } ) ;
9231033
1034+ container . on ( 'open' , function ( ) {
1035+ self . $search . attr ( 'tabindex' , 0 ) ;
1036+ } ) ;
1037+
1038+ container . on ( 'close' , function ( ) {
1039+ self . $search . attr ( 'tabindex' , - 1 ) ;
1040+ } ) ;
1041+
9241042 container . on ( 'results:all' , function ( params ) {
9251043 if ( params . query . term == null || params . query . term === '' ) {
9261044 var showSearch = self . showSearch ( params ) ;
@@ -1108,10 +1226,20 @@ define('select2/core',[
11081226 } ) ;
11091227 } ) ;
11101228
1229+ this . selection . on ( 'open' , function ( ) {
1230+ self . trigger ( 'open' ) ;
1231+ } ) ;
1232+ this . selection . on ( 'close' , function ( ) {
1233+ self . trigger ( 'close' ) ;
1234+ } ) ;
11111235 this . selection . on ( 'toggle' , function ( ) {
11121236 self . toggleDropdown ( ) ;
11131237 } ) ;
11141238
1239+ this . selection . on ( 'results:select' , function ( ) {
1240+ self . trigger ( 'results:select' ) ;
1241+ } ) ;
1242+
11151243 this . selection . on ( 'unselected' , function ( params ) {
11161244 self . trigger ( 'unselect' , params ) ;
11171245
@@ -1160,18 +1288,23 @@ define('select2/core',[
11601288 // Hide the original select
11611289
11621290 $element . hide ( ) ;
1291+ $element . attr ( 'tabindex' , '-1' ) ;
11631292 } ;
11641293
11651294 Utils . Extend ( Select2 , Utils . Observable ) ;
11661295
11671296 Select2 . prototype . toggleDropdown = function ( ) {
1168- if ( this . $container . hasClass ( 'open' ) ) {
1297+ if ( this . isOpen ( ) ) {
11691298 this . trigger ( 'close' ) ;
11701299 } else {
11711300 this . trigger ( 'open' ) ;
11721301 }
11731302 } ;
11741303
1304+ Select2 . prototype . isOpen = function ( ) {
1305+ return this . $container . hasClass ( 'open' ) ;
1306+ } ;
1307+
11751308 Select2 . prototype . render = function ( ) {
11761309 var $container = $ (
11771310 '<span class="select2 select2-container select2-theme-default">' +
0 commit comments