@@ -176,8 +176,7 @@ $.widget( "ui.tabs", {
176
176
} ,
177
177
178
178
_tabKeydown : function ( event ) {
179
- var focusedAnchor = $ ( this . document [ 0 ] . activeElement ) . closest ( "a" ) ,
180
- focusedTab = focusedAnchor . closest ( "li" ) ,
179
+ var focusedTab = $ ( this . document [ 0 ] . activeElement ) . closest ( "li" ) ,
181
180
selectedIndex = this . tabs . index ( focusedTab ) ,
182
181
goingForward = true ;
183
182
@@ -203,12 +202,14 @@ $.widget( "ui.tabs", {
203
202
break ;
204
203
case $ . ui . keyCode . SPACE :
205
204
205
+ // Activate only, no collapsing
206
206
event . preventDefault ( ) ;
207
207
clearTimeout ( this . activating ) ;
208
208
this . _activate ( selectedIndex ) ;
209
209
return ;
210
210
case $ . ui . keyCode . ENTER :
211
211
212
+ // Toggle (cancel delayed activation, allow collapsing)
212
213
event . preventDefault ( ) ;
213
214
clearTimeout ( this . activating ) ;
214
215
@@ -227,8 +228,11 @@ $.widget( "ui.tabs", {
227
228
// Navigating with control/command key will prevent automatic activation
228
229
if ( ! event . ctrlKey && ! event . metaKey ) {
229
230
230
- focusedAnchor . attr ( "aria-selected" , "false" ) ;
231
- this . anchors . eq ( selectedIndex ) . attr ( "aria-selected" , "true" ) ;
231
+ // Update aria-selected immediately so that AT think the tab is already selected.
232
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
233
+ // but the tab will already be activated by the time the announcement finishes.
234
+ focusedTab . attr ( "aria-selected" , "false" ) ;
235
+ this . tabs . eq ( selectedIndex ) . attr ( "aria-selected" , "true" ) ;
232
236
233
237
this . activating = this . _delay ( function ( ) {
234
238
this . option ( "active" , selectedIndex ) ;
@@ -282,7 +286,7 @@ $.widget( "ui.tabs", {
282
286
283
287
_focusNextTab : function ( index , goingForward ) {
284
288
index = this . _findNextTab ( index , goingForward ) ;
285
- this . anchors . eq ( index ) . trigger ( "focus" ) ;
289
+ this . tabs . eq ( index ) . trigger ( "focus" ) ;
286
290
return index ;
287
291
} ,
288
292
@@ -407,32 +411,42 @@ $.widget( "ui.tabs", {
407
411
}
408
412
} ) ;
409
413
410
- this . tabs = this . tablist . find ( "> li:has(a[href])" )
414
+ this . tabs = this . tablist . find ( "> li:has(a[href]) > a " )
411
415
. attr ( {
412
- role : "presentation"
416
+ role : "tab" ,
417
+ tabindex : - 1
413
418
} ) ;
414
419
this . _addClass ( this . tabs , "ui-tabs-tab" , "ui-state-default" ) ;
415
-
416
- this . anchors = this . tabs . map ( function ( ) {
417
- return $ ( "a" , this ) [ 0 ] ;
418
- } )
420
+ this . tablist . find ( "> li:has(a[href])" )
419
421
. attr ( {
420
- role : "tab" ,
421
- tabIndex : - 1
422
+ role : "presentation"
422
423
} ) ;
424
+
425
+ this . anchors = this . tabs ;
426
+ this . _addClass ( this . tabs , "ui-tabs-tab" , "ui-state-default" ) ;
423
427
this . _addClass ( this . anchors , "ui-tabs-anchor" ) ;
424
428
425
429
this . panels = $ ( ) ;
426
430
427
431
this . anchors . each ( function ( i , anchor ) {
428
432
var selector , panel , panelId ,
429
433
anchorId = $ ( anchor ) . uniqueId ( ) . attr ( "id" ) ,
430
- tab = $ ( anchor ) . closest ( "li" ) ,
434
+ tab = $ ( anchor ) ,
431
435
originalAriaControls = tab . attr ( "aria-controls" ) ;
432
436
433
437
// Inline tab
434
438
if ( that . _isLocal ( anchor ) ) {
435
439
440
+ // The "scrolling to a fragment" section of the HTML spec:
441
+ // https://html.spec.whatwg.org/#scrolling-to-a-fragment
442
+ // uses a concept of document's indicated part:
443
+ // https://html.spec.whatwg.org/#the-indicated-part-of-the-document
444
+ // Slightly below there's an algorithm to compute the indicated
445
+ // part:
446
+ // https://html.spec.whatwg.org/#the-indicated-part-of-the-document
447
+ // First, the algorithm tries the hash as-is, without decoding.
448
+ // Then, if one is not found, the same is attempted with a decoded
449
+ // hash. Replicate this logic.
436
450
selector = anchor . hash ;
437
451
panelId = selector . substring ( 1 ) ;
438
452
panel = that . element . find ( "#" + CSS . escape ( panelId ) ) ;
@@ -441,8 +455,11 @@ $.widget( "ui.tabs", {
441
455
panel = that . element . find ( "#" + CSS . escape ( panelId ) ) ;
442
456
}
443
457
458
+ // remote tab
444
459
} else {
445
460
461
+ // If the tab doesn't already have aria-controls,
462
+ // generate an id by using a throw-away element
446
463
panelId = tab . attr ( "aria-controls" ) || $ ( { } ) . uniqueId ( ) [ 0 ] . id ;
447
464
selector = "#" + panelId ;
448
465
panel = that . element . find ( selector ) ;
@@ -537,7 +554,7 @@ $.widget( "ui.tabs", {
537
554
this . _on ( this . tabs , { keydown : "_tabKeydown" } ) ;
538
555
this . _on ( this . panels , { keydown : "_panelKeydown" } ) ;
539
556
540
- this . _focusable ( this . anchors ) ;
557
+ this . _focusable ( this . tabs ) ;
541
558
this . _hoverable ( this . tabs ) ;
542
559
} ,
543
560
@@ -580,7 +597,7 @@ $.widget( "ui.tabs", {
580
597
var options = this . options ,
581
598
active = this . active ,
582
599
anchor = $ ( event . currentTarget ) ,
583
- tab = anchor . closest ( "li" ) ,
600
+ tab = anchor ,
584
601
clickedIsActive = tab [ 0 ] === active [ 0 ] ,
585
602
collapsing = clickedIsActive && options . collapsible ,
586
603
toShow = collapsing ? $ ( ) : this . _getPanelForTab ( tab ) ,
@@ -641,7 +658,7 @@ $.widget( "ui.tabs", {
641
658
}
642
659
643
660
function show ( ) {
644
- that . _addClass ( eventData . newTab . closest ( "li" ) , "ui-tabs-active" , "ui-state-active" ) ;
661
+ that . _addClass ( eventData . newTab , "ui-tabs-active" , "ui-state-active" ) ;
645
662
646
663
if ( toShow . length && that . options . show ) {
647
664
that . _show ( toShow , that . options . show , complete ) ;
@@ -654,12 +671,12 @@ $.widget( "ui.tabs", {
654
671
// Start out by hiding, then showing, then completing
655
672
if ( toHide . length && this . options . hide ) {
656
673
this . _hide ( toHide , this . options . hide , function ( ) {
657
- that . _removeClass ( eventData . oldTab . closest ( "li" ) ,
674
+ that . _removeClass ( eventData . oldTab ,
658
675
"ui-tabs-active" , "ui-state-active" ) ;
659
676
show ( ) ;
660
677
} ) ;
661
678
} else {
662
- this . _removeClass ( eventData . oldTab . closest ( "li" ) ,
679
+ this . _removeClass ( eventData . oldTab ,
663
680
"ui-tabs-active" , "ui-state-active" ) ;
664
681
toHide . hide ( ) ;
665
682
show ( ) ;
@@ -818,7 +835,7 @@ $.widget( "ui.tabs", {
818
835
index = this . _getIndex ( index ) ;
819
836
var that = this ,
820
837
tab = this . tabs . eq ( index ) ,
821
- anchor = tab . find ( ".ui-tabs-anchor" ) ,
838
+ anchor = tab ,
822
839
panel = this . _getPanelForTab ( tab ) ,
823
840
eventData = {
824
841
tab : tab ,
@@ -894,3 +911,4 @@ if ( $.uiBackCompat === true ) {
894
911
return $ . ui . tabs ;
895
912
896
913
} ) ;
914
+
0 commit comments