mirror of
https://github.com/jquery/jquery-ui.git
synced 2024-11-21 11:04:24 +00:00
Dialog: Restore focus to the previously focused element when window regains focus. Fixes #9101 - Dialog: Track last focused element instead of always focusing the first tabbable element
This commit is contained in:
parent
ce5539f368
commit
0e5a2e126a
@ -40,7 +40,7 @@ test("widget method", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
asyncTest( "focus tabbable", function() {
|
asyncTest( "focus tabbable", function() {
|
||||||
expect( 5 );
|
expect( 6 );
|
||||||
var element,
|
var element,
|
||||||
options = {
|
options = {
|
||||||
buttons: [{
|
buttons: [{
|
||||||
@ -50,6 +50,12 @@ asyncTest( "focus tabbable", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function checkFocus( markup, options, testFn, next ) {
|
function checkFocus( markup, options, testFn, next ) {
|
||||||
|
|
||||||
|
// Support: IE8
|
||||||
|
// For some reason the focus doesn't get set properly if we don't
|
||||||
|
// focus the body first.
|
||||||
|
$( "body" ).focus();
|
||||||
|
|
||||||
element = $( markup ).dialog( options );
|
element = $( markup ).dialog( options );
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
testFn();
|
testFn();
|
||||||
@ -59,43 +65,57 @@ asyncTest( "focus tabbable", function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function step1() {
|
function step1() {
|
||||||
checkFocus( "<div><input><input autofocus></div>", options, function() {
|
element = $( "<div><input><input></div>" ).dialog( options );
|
||||||
equal( document.activeElement, element.find( "input" )[ 1 ],
|
setTimeout(function() {
|
||||||
"1. first element inside the dialog matching [autofocus]" );
|
var input = element.find( "input:last" ).focus().blur();
|
||||||
}, step2 );
|
element.dialog( "instance" )._focusTabbable();
|
||||||
|
setTimeout(function() {
|
||||||
|
equal( document.activeElement, input[ 0 ],
|
||||||
|
"1. an element that was focused previously." );
|
||||||
|
element.remove();
|
||||||
|
setTimeout( step2 );
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function step2() {
|
function step2() {
|
||||||
checkFocus( "<div><input><input></div>", options, function() {
|
checkFocus( "<div><input><input autofocus></div>", options, function() {
|
||||||
equal( document.activeElement, element.find( "input" )[ 0 ],
|
equal( document.activeElement, element.find( "input" )[ 1 ],
|
||||||
"2. tabbable element inside the content element" );
|
"2. first element inside the dialog matching [autofocus]" );
|
||||||
}, step3 );
|
}, step3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
function step3() {
|
function step3() {
|
||||||
checkFocus( "<div>text</div>", options, function() {
|
checkFocus( "<div><input><input></div>", options, function() {
|
||||||
equal( document.activeElement,
|
equal( document.activeElement, element.find( "input" )[ 0 ],
|
||||||
element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ],
|
"3. tabbable element inside the content element" );
|
||||||
"3. tabbable element inside the buttonpane" );
|
|
||||||
}, step4 );
|
}, step4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
function step4() {
|
function step4() {
|
||||||
checkFocus( "<div>text</div>", {}, function() {
|
checkFocus( "<div>text</div>", options, function() {
|
||||||
equal( document.activeElement,
|
equal( document.activeElement,
|
||||||
element.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ],
|
element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ],
|
||||||
"4. the close button" );
|
"4. tabbable element inside the buttonpane" );
|
||||||
}, step5 );
|
}, step5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
function step5() {
|
function step5() {
|
||||||
|
checkFocus( "<div>text</div>", {}, function() {
|
||||||
|
equal( document.activeElement,
|
||||||
|
element.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ],
|
||||||
|
"5. the close button" );
|
||||||
|
}, step6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
function step6() {
|
||||||
element = $( "<div>text</div>" ).dialog({
|
element = $( "<div>text</div>" ).dialog({
|
||||||
autoOpen: false
|
autoOpen: false
|
||||||
});
|
});
|
||||||
element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide();
|
element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide();
|
||||||
element.dialog( "open" );
|
element.dialog( "open" );
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
equal( document.activeElement, element.parent()[ 0 ], "5. the dialog itself" );
|
equal( document.activeElement, element.parent()[ 0 ], "6. the dialog itself" );
|
||||||
element.remove();
|
element.remove();
|
||||||
start();
|
start();
|
||||||
});
|
});
|
||||||
|
35
ui/jquery.ui.dialog.js
vendored
35
ui/jquery.ui.dialog.js
vendored
@ -118,6 +118,8 @@ $.widget( "ui.dialog", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._isOpen = false;
|
this._isOpen = false;
|
||||||
|
|
||||||
|
this._trackFocus();
|
||||||
},
|
},
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
@ -178,6 +180,7 @@ $.widget( "ui.dialog", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._isOpen = false;
|
this._isOpen = false;
|
||||||
|
this._focusedElement = null;
|
||||||
this._destroyOverlay();
|
this._destroyOverlay();
|
||||||
|
|
||||||
if ( !this.opener.filter(":focusable").focus().length ) {
|
if ( !this.opener.filter(":focusable").focus().length ) {
|
||||||
@ -256,20 +259,24 @@ $.widget( "ui.dialog", {
|
|||||||
|
|
||||||
_focusTabbable: function() {
|
_focusTabbable: function() {
|
||||||
// Set focus to the first match:
|
// Set focus to the first match:
|
||||||
// 1. First element inside the dialog matching [autofocus]
|
// 1. An element that was focused previously
|
||||||
// 2. Tabbable element inside the content element
|
// 2. First element inside the dialog matching [autofocus]
|
||||||
// 3. Tabbable element inside the buttonpane
|
// 3. Tabbable element inside the content element
|
||||||
// 4. The close button
|
// 4. Tabbable element inside the buttonpane
|
||||||
// 5. The dialog itself
|
// 5. The close button
|
||||||
var hasFocus = this.element.find("[autofocus]");
|
// 6. The dialog itself
|
||||||
if ( !hasFocus.length ) {
|
var hasFocus = this._focusedElement;
|
||||||
hasFocus = this.element.find(":tabbable");
|
if ( !hasFocus ) {
|
||||||
|
hasFocus = this.element.find( "[autofocus]" );
|
||||||
}
|
}
|
||||||
if ( !hasFocus.length ) {
|
if ( !hasFocus.length ) {
|
||||||
hasFocus = this.uiDialogButtonPane.find(":tabbable");
|
hasFocus = this.element.find( ":tabbable" );
|
||||||
}
|
}
|
||||||
if ( !hasFocus.length ) {
|
if ( !hasFocus.length ) {
|
||||||
hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
|
hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
|
||||||
|
}
|
||||||
|
if ( !hasFocus.length ) {
|
||||||
|
hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
|
||||||
}
|
}
|
||||||
if ( !hasFocus.length ) {
|
if ( !hasFocus.length ) {
|
||||||
hasFocus = this.uiDialog;
|
hasFocus = this.uiDialog;
|
||||||
@ -552,6 +559,14 @@ $.widget( "ui.dialog", {
|
|||||||
.css( "position", position );
|
.css( "position", position );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_trackFocus: function() {
|
||||||
|
this._on( this.widget(), {
|
||||||
|
"focusin": function( event ) {
|
||||||
|
this._focusedElement = $( event.target );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_minHeight: function() {
|
_minHeight: function() {
|
||||||
var options = this.options;
|
var options = this.options;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user