From 8ee8046c029354501bc6d1690b3ac84edf23efd7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=B6rn=20Zaefferer?= Date: Fri, 26 Oct 2012 10:59:41 -0400 Subject: [PATCH] Dialog: Keep focus inside modal dialog, by handling focus events on elements outside of it --- ui/jquery.ui.dialog.js | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/ui/jquery.ui.dialog.js b/ui/jquery.ui.dialog.js index 892dd72b0..ed1e55beb 100644 --- a/ui/jquery.ui.dialog.js +++ b/ui/jquery.ui.dialog.js @@ -282,8 +282,7 @@ $.widget("ui.dialog", { return; } - var hasFocus, - options = this.options, + var options = this.options, uiDialog = this.uiDialog; this.opener = $( this.document[ 0 ].activeElement ); @@ -294,22 +293,26 @@ $.widget("ui.dialog", { this.moveToTop( null, true ); this._show( uiDialog, options.show ); + this._focusTabbable(); + + this._isOpen = true; + this._trigger( "open" ); + this._trigger( "focus" ); + + return this; + }, + + _focusTabbable: function() { // set focus to the first tabbable element in the content area or the first button // if there are no tabbable elements, set focus on the dialog itself - hasFocus = this.element.find( ":tabbable" ); + var hasFocus = this.element.find( ":tabbable" ); if ( !hasFocus.length ) { hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); if ( !hasFocus.length ) { - hasFocus = uiDialog; + hasFocus = this.uiDialog; } } hasFocus.eq( 0 ).focus(); - - this._isOpen = true; - this._trigger( "open" ); - this._trigger( "focus" ); - - return this; }, _keepFocus: function( event ) { @@ -318,7 +321,7 @@ $.widget("ui.dialog", { isActive = this.uiDialog[ 0 ] === activeElement || $.contains( this.uiDialog[ 0 ], activeElement ); if ( !isActive ) { - this.uiDialog.focus(); + this._focusTabbable(); } } event.preventDefault(); @@ -659,6 +662,22 @@ $.extend( $.ui.dialog.overlay, { // reuse old instances due to IE memory leak with alpha transparency (see #5185) oldInstances: [], create: function( dialog ) { + if ( this.instances.length === 0 ) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + // handle $(el).dialog().dialog('close') (see #4065) + if ( $.ui.dialog.overlay.instances.length ) { + $( document ).bind( "focusin.dialog-overlay", function( event ) { + if ( !$( event.target ).closest( ".ui-dialog").length ) { + event.preventDefault(); + $( ".ui-dialog:visible:last .ui-dialog-content" ).data( "ui-dialog" )._focusTabbable(); + } + }); + } + }, 1 ); + } var $el = ( this.oldInstances.pop() || $( "
" ).addClass( "ui-widget-overlay ui-front" ) ); -- 2.39.5