@@ -1319,7 +1319,7 @@ S2.define('select2/selection/base',[
13191319 } ) ;
13201320
13211321 this . $selection . on ( 'blur' , function ( evt ) {
1322- self . trigger ( 'blur' , evt ) ;
1322+ self . _handleBlur ( evt ) ;
13231323 } ) ;
13241324
13251325 this . $selection . on ( 'keydown' , function ( evt ) {
@@ -1366,6 +1366,24 @@ S2.define('select2/selection/base',[
13661366 } ) ;
13671367 } ;
13681368
1369+ BaseSelection . prototype . _handleBlur = function ( evt ) {
1370+ var self = this ;
1371+
1372+ // This needs to be delayed as the actve element is the body when the tab
1373+ // key is pressed, possibly along with others.
1374+ window . setTimeout ( function ( ) {
1375+ // Don't trigger `blur` if the focus is still in the selection
1376+ if (
1377+ ( document . activeElement == self . $selection [ 0 ] ) ||
1378+ ( $ . contains ( self . $selection [ 0 ] , document . activeElement ) )
1379+ ) {
1380+ return ;
1381+ }
1382+
1383+ self . trigger ( 'blur' , evt ) ;
1384+ } , 1 ) ;
1385+ } ;
1386+
13691387 BaseSelection . prototype . _attachCloseHandler = function ( container ) {
13701388 var self = this ;
13711389
@@ -1475,11 +1493,11 @@ S2.define('select2/selection/single',[
14751493 this . $selection . find ( '.select2-selection__rendered' ) . empty ( ) ;
14761494 } ;
14771495
1478- SingleSelection . prototype . display = function ( data ) {
1496+ SingleSelection . prototype . display = function ( data , container ) {
14791497 var template = this . options . get ( 'templateSelection' ) ;
14801498 var escapeMarkup = this . options . get ( 'escapeMarkup' ) ;
14811499
1482- return escapeMarkup ( template ( data ) ) ;
1500+ return escapeMarkup ( template ( data , container ) ) ;
14831501 } ;
14841502
14851503 SingleSelection . prototype . selectionContainer = function ( ) {
@@ -1494,9 +1512,9 @@ S2.define('select2/selection/single',[
14941512
14951513 var selection = data [ 0 ] ;
14961514
1497- var formatted = this . display ( selection ) ;
1498-
14991515 var $rendered = this . $selection . find ( '.select2-selection__rendered' ) ;
1516+ var formatted = this . display ( selection , $rendered ) ;
1517+
15001518 $rendered . empty ( ) . append ( formatted ) ;
15011519 $rendered . prop ( 'title' , selection . title || selection . text ) ;
15021520 } ;
@@ -1556,11 +1574,11 @@ S2.define('select2/selection/multiple',[
15561574 this . $selection . find ( '.select2-selection__rendered' ) . empty ( ) ;
15571575 } ;
15581576
1559- MultipleSelection . prototype . display = function ( data ) {
1577+ MultipleSelection . prototype . display = function ( data , container ) {
15601578 var template = this . options . get ( 'templateSelection' ) ;
15611579 var escapeMarkup = this . options . get ( 'escapeMarkup' ) ;
15621580
1563- return escapeMarkup ( template ( data ) ) ;
1581+ return escapeMarkup ( template ( data , container ) ) ;
15641582 } ;
15651583
15661584 MultipleSelection . prototype . selectionContainer = function ( ) {
@@ -1587,8 +1605,8 @@ S2.define('select2/selection/multiple',[
15871605 for ( var d = 0 ; d < data . length ; d ++ ) {
15881606 var selection = data [ d ] ;
15891607
1590- var formatted = this . display ( selection ) ;
15911608 var $selection = this . selectionContainer ( ) ;
1609+ var formatted = this . display ( selection , $selection ) ;
15921610
15931611 $selection . append ( formatted ) ;
15941612 $selection . prop ( 'title' , selection . title || selection . text ) ;
@@ -1777,6 +1795,8 @@ S2.define('select2/selection/search',[
17771795
17781796 var $rendered = decorated . call ( this ) ;
17791797
1798+ this . _transferTabIndex ( ) ;
1799+
17801800 return $rendered ;
17811801 } ;
17821802
@@ -1786,32 +1806,34 @@ S2.define('select2/selection/search',[
17861806 decorated . call ( this , container , $container ) ;
17871807
17881808 container . on ( 'open' , function ( ) {
1789- self . $search . attr ( 'tabindex' , 0 ) ;
1790-
1791- self . $search . focus ( ) ;
1809+ self . $search . trigger ( 'focus' ) ;
17921810 } ) ;
17931811
17941812 container . on ( 'close' , function ( ) {
1795- self . $search . attr ( 'tabindex' , - 1 ) ;
1796-
17971813 self . $search . val ( '' ) ;
1798- self . $search . focus ( ) ;
1814+ self . $search . trigger ( 'focus' ) ;
17991815 } ) ;
18001816
18
133E
011817 container . on ( 'enable' , function ( ) {
18021818 self . $search . prop ( 'disabled' , false ) ;
1819+
1820+ self . _transferTabIndex ( ) ;
18031821 } ) ;
18041822
18051823 container . on ( 'disable' , function ( ) {
18061824 self . $search . prop ( 'disabled' , true ) ;
18071825 } ) ;
18081826
1827+ container . on ( 'focus' , function ( evt ) {
1828+ self . $search . trigger ( 'focus' ) ;
1829+ } ) ;
1830+
18091831 this . $selection . on ( 'focusin' , '.select2-search--inline' , function ( evt ) {
18101832 self . trigger ( 'focus' , evt ) ;
18111833 } ) ;
18121834
18131835 this . $selection . on ( 'focusout' , '.select2-search--inline' , function ( evt ) {
1814- self . trigger ( 'blur' , evt ) ;
1836+ self . _handleBlur ( evt ) ;
18151837 } ) ;
18161838
18171839 this . $selection . on ( 'keydown' , '.select2-search--inline' , function ( evt ) {
@@ -1847,10 +1869,34 @@ S2.define('select2/selection/search',[
18471869
18481870 this . $selection . on ( 'keyup.search input' , '.select2-search--inline' ,
18491871 function ( evt ) {
1872+ var key = evt . which ;
1873+
1874+ // We can freely ignore events from modifier keys
1875+ if ( key == KEYS . SHIFT || key == KEYS . CTRL || key == KEYS . ALT ) {
1876+ return ;
1877+ }
1878+
1879+ // Tabbing will be handled during the `keydown` phase
1880+ if ( key == KEYS . TAB ) {
1881+ return ;
1882+ }
1883+
18501884 self . handleSearch ( evt ) ;
18511885 } ) ;
18521886 } ;
18531887
1888+ /**
1889+ * This method will transfer the tabindex attribute from the rendered
1890+ * selection to the search box. This allows for the search box to be used as
1891+ * the primary focus instead of the selection container.
1892+ *
1893+ * @private
1894+ */
1895+ Search . prototype . _transferTabIndex = function ( decorated ) {
1896+ this . $search . attr ( 'tabindex' , this . $selection . attr ( 'tabindex' ) ) ;
1897+ this . $selection . attr ( 'tabindex' , '-1' ) ;
1898+ } ;
1899+
18541900 Search . prototype . createPlaceholder = function ( decorated , placeholder ) {
18551901 this . $search . attr ( 'placeholder' , placeholder . text ) ;
18561902 } ;
@@ -3259,7 +3305,7 @@ S2.define('select2/data/ajax',[
32593305 this . processResults = this . ajaxOptions . processResults ;
32603306 }
32613307
3262- ArrayAdapter . __super__ . constructor . call ( this , $element , options ) ;
3308+ AjaxAdapter . __super__ . constructor . call ( this , $element , options ) ;
32633309 }
32643310
32653311 Utils . Extend ( AjaxAdapter , ArrayAdapter ) ;
@@ -4868,8 +4914,8 @@ S2.define('select2/core',[
48684914
48694915 // Hide the original select
48704916 $element . addClass ( 'select2-hidden-accessible' ) ;
4871- $element . attr ( 'aria-hidden' , 'true' ) ;
4872-
4917+ $element . attr ( 'aria-hidden' , 'true' ) ;
4918+
48734919 // Synchronize any monitored attributes
48744920 this . _syncAttributes ( ) ;
48754921
@@ -5004,12 +5050,16 @@ S2.define('select2/core',[
50045050
50055051 Select2 . prototype . _registerSelectionEvents = function ( ) {
50065052 var self = this ;
5007- var nonRelayEvents = [ 'toggle' ] ;
5053+ var nonRelayEvents = [ 'toggle' , 'focus' ] ;
50085054
50095055 this . selection . on ( 'toggle' , function ( ) {
50105056 self . toggleDropdown ( ) ;
50115057 } ) ;
50125058
5059+ this . selection . on ( 'focus' , function (params ) {
5060+ self . focus ( params ) ;
5061+ } ) ;
5062+
50135063 this . selection . on ( '*' , function ( name , params ) {
50145064 if ( $ . inArray ( name , nonRelayEvents ) !== - 1 ) {
50155065 return ;
@@ -5054,10 +5104,6 @@ S2.define('select2/core',[
50545104 self . $container . addClass ( 'select2-container--disabled' ) ;
50555105 } ) ;
50565106
5057- this . on ( 'focus' , function ( ) {
5058- self . $container . addClass ( 'select2-container--focus' ) ;
5059- } ) ;
5060-
50615107 this . on ( 'blur' , function ( ) {
50625108 self . $container . removeClass ( 'select2-container--focus' ) ;
50635109 } ) ;
@@ -5201,6 +5247,20 @@ S2.define('select2/core',[
52015247 return this . $container . hasClass ( 'select2-container--open' ) ;
52025248 } ;
52035249
5250+ Select2 . prototype . hasFocus = function ( ) {
5251+ return this . $container . hasClass ( 'select2-container--focus' ) ;
5252+ } ;
5253+
5254+ Select2 . prototype . focus = function ( data ) {
5255+ // No need to re-trigger focus events if we are already focused
5256+ if ( this . hasFocus ( ) ) {
5257+ return ;
5258+ }
5259+
5260+ this . $container . addClass ( 'select2-container--focus' ) ;
5261+ this . trigger ( 'focus' ) ;
5262+ } ;
5263+
52045264 Select2 . prototype . enable = function ( args ) {
52055265 if ( this . options . get ( 'debug' ) && window . console && console . warn ) {
52065266 console . warn (
@@ -5281,7 +5341,7 @@ S2.define('select2/core',[
52815341 this . $element . attr ( 'tabindex' , this . $element . data ( 'old-tabindex' ) ) ;
52825342
52835343 this . $element . removeClass ( 'select2-hidden-accessible' ) ;
<
23A
/tr>5284- this . $element . attr ( 'aria-hidden' , 'false' ) ;
5344+ this . $element . attr ( 'aria-hidden' , 'false' ) ;
52855345 this . $element . removeData ( 'select2' ) ;
52865346
52875347 this . dataAdapter . destroy ( ) ;
@@ -5385,7 +5445,7 @@ S2.define('select2/compat/containerCss',[
53855445 containerCssAdapter = containerCssAdapter || _containerAdapter ;
53865446
53875447 if ( containerCssClass . indexOf ( ':all:' ) !== - 1 ) {
5388- containerCssClass = containerCssClass . replace ( ':all' , '' ) ;
5448+ containerCssClass = containerCssClass . replace ( ':all: ' , '' ) ;
53895449
53905450 var _cssAdapter = containerCssAdapter ;
53915451
@@ -5442,7 +5502,7 @@ S2.define('select2/compat/dropdownCss',[
54425502 dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter ;
54435503
54445504 if ( dropdownCssClass . indexOf ( ':all:' ) !== - 1 ) {
5445- dropdownCssClass = dropdownCssClass . replace ( ':all' , '' ) ;
5505+ dropdownCssClass = dropdownCssClass . replace ( ':all: ' , '' ) ;
54465506
54475507 var _cssAdapter = dropdownCssAdapter ;
54485508
0 commit comments