]> source.dussan.org Git - jquery-ui.git/commitdiff
Tabs: Suppress automatic activation when navigating with COMMAND
authorScott González <scott.gonzalez@gmail.com>
Mon, 3 Nov 2014 20:06:12 +0000 (15:06 -0500)
committerScott González <scott.gonzalez@gmail.com>
Mon, 9 Feb 2015 16:50:05 +0000 (11:50 -0500)
Fixes #9621
Closes gh-1383
(cherry picked from commit 6a242ab4ebdcec265826b959fa27881dcf462c96)

tests/unit/tabs/tabs_core.js
ui/tabs.js

index 2e094e11b0aa616d3b2f4611c0ab86e2cd3e50fd..2d18a6f1ab7556efc5e3d30da1ef33acf3503850 100644 (file)
@@ -299,197 +299,224 @@ asyncTest( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER",
        setTimeout( step1, 1 );
 });
 
-asyncTest( "keyboard support - CTRL navigation", function() {
-       expect( 115 );
-       var element = $( "#tabs1" ).tabs(),
-               tabs = element.find( ".ui-tabs-nav li" ),
-               panels = element.find( ".ui-tabs-panel" ),
-               keyCode = $.ui.keyCode;
-
-       element.tabs( "instance" ).delay = 50;
-
-       equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" );
-       tabs.eq( 0 ).simulate( "focus" );
-
-       // down
-       function step1() {
-               ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-
-               tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } );
-               ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" );
-               ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" );
-               equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
-               equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
-               equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               setTimeout( step2, 100 );
-       }
-
-       // right
-       function step2() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-               ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
-               equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
-               equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
-
-               tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT, ctrlKey: true } );
-               ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" );
-               equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               setTimeout( step3, 100 );
-       }
-
-       // down (wrap)
-       function step3() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
-
-               tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } );
-               ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               setTimeout( step4, 100 );
-       }
-
-       // up (wrap)
-       function step4() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } );
-               ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" );
-               equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               setTimeout( step5, 100 );
-       }
-
-       // left
-       function step5() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
-
-               tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT, ctrlKey: true } );
-               ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" );
-               equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
-               equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
-               equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-
-               setTimeout( step6, 100 );
-       }
-
-       // home
-       function step6() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-               ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
-               equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
-               equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
-
-               tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME, ctrlKey: true } );
-               ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
-               ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
-               equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
-               equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+// Navigation with CTRL and COMMAND (both behave the same)
+$.each({
+       ctrl: "CTRL",
+       meta: "COMMAND"
+}, function( modifier, label ) {
+       asyncTest( "keyboard support - " + label + " navigation", function() {
+               expect( 115 );
+               var element = $( "#tabs1" ).tabs(),
+                       tabs = element.find( ".ui-tabs-nav li" ),
+                       panels = element.find( ".ui-tabs-panel" ),
+                       keyCode = $.ui.keyCode;
+
+               element.tabs( "instance" ).delay = 50;
+
+               equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" );
+               tabs.eq( 0 ).simulate( "focus" );
+
+               // down
+               function step1() {
+                       var eventProperties = { keyCode: keyCode.DOWN };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+
+                       tabs.eq( 0 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" );
+                       ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" );
+                       equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+                       equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
+                       equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step2, 100 );
+               }
 
-               setTimeout( step7, 100 );
-       }
+               // right
+               function step2() {
+                       var eventProperties = { keyCode: keyCode.RIGHT };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+                       ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
+                       equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
+                       equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+
+                       tabs.eq( 1 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" );
+                       equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step3, 100 );
+               }
 
-       // end
-       function step7() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+               // down (wrap)
+               function step3() {
+                       var eventProperties = { keyCode: keyCode.DOWN };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+                       tabs.eq( 2 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step4, 100 );
+               }
 
-               tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END, ctrlKey: true } );
-               ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" );
-               equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+               // up (wrap)
+               function step4() {
+                       var eventProperties = { keyCode: keyCode.UP };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       tabs.eq( 0 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" );
+                       equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step5, 100 );
+               }
 
-               setTimeout( step8, 100 );
-       }
+               // left
+               function step5() {
+                       var eventProperties = { keyCode: keyCode.LEFT };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+                       tabs.eq( 2 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" );
+                       equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+                       equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
+                       equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step6, 100 );
+               }
 
-       // space
-       function step8() {
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
-               ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
-               ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+               // home
+               function step6() {
+                       var eventProperties = { keyCode: keyCode.HOME };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+                       ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" );
+                       equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
+                       equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+
+                       tabs.eq( 1 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" );
+                       ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" );
+                       equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" );
+                       equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step7, 100 );
+               }
 
-               tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.SPACE } );
-               equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
-               equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
-               ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
-               equal( tabs.eq( 2 ).attr( "aria-expanded" ), "true", "third tab has aria-expanded=true" );
-               equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
-               ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
-               equal( tabs.eq( 0 ).attr( "aria-expanded" ), "false", "first tab has aria-expanded=false" );
-               equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+               // end
+               function step7() {
+                       var eventProperties = { keyCode: keyCode.END };
+                       eventProperties[ modifier + "Key" ] = true;
+
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       tabs.eq( 0 ).simulate( "keydown", eventProperties );
+                       ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" );
+                       equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+
+                       setTimeout( step8, 100 );
+               }
 
-               setTimeout( start, 1 );
-       }
+               // space
+               function step8() {
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" );
+                       ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" );
+                       ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" );
+
+                       tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.SPACE } );
+                       equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" );
+                       equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" );
+                       ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" );
+                       equal( tabs.eq( 2 ).attr( "aria-expanded" ), "true", "third tab has aria-expanded=true" );
+                       equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" );
+                       ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" );
+                       equal( tabs.eq( 0 ).attr( "aria-expanded" ), "false", "first tab has aria-expanded=false" );
+                       equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" );
+
+                       setTimeout( start, 1 );
+               }
 
-       setTimeout( step1, 1 );
+               setTimeout( step1, 1 );
+       });
 });
 
 asyncTest( "keyboard support - CTRL+UP, ALT+PAGE_DOWN, ALT+PAGE_UP", function() {
index e45a97c726c7f7fe11122c07f6ed2baefa944419..808f53fbb1b5188c18e9df73642a1ca503d07746 100644 (file)
@@ -201,8 +201,9 @@ return $.widget( "ui.tabs", {
                clearTimeout( this.activating );
                selectedIndex = this._focusNextTab( selectedIndex, goingForward );
 
-               // Navigating with control key will prevent automatic activation
-               if ( !event.ctrlKey ) {
+               // Navigating with control/command key will prevent automatic activation
+               if ( !event.ctrlKey && !event.metaKey ) {
+
                        // Update aria-selected immediately so that AT think the tab is already selected.
                        // Otherwise AT may confuse the user by stating that they need to activate the tab,
                        // but the tab will already be activated by the time the announcement finishes.