Skip to content

Commit 1096f19

Browse files
committed
Dialog: Keep track of instances to focus when elements outside the dialog get focus. Works with inheritance. Adds tests for both. Fixes #9241 - Dialog: UI dialog inheritance causes undefined property '_focusTabbable' in IE9
1 parent 32a0060 commit 1096f19

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

tests/unit/dialog/dialog_core.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
(function($) {
66

7+
// TODO add teardown callback to remove dialogs
78
module("dialog: core");
89

910
test("title id", function() {
@@ -180,4 +181,51 @@ asyncTest( "#9048: multiple modal dialogs opened and closed in different order",
180181
start();
181182
});
182183
});
184+
185+
asyncTest( "interaction between overlay and other dialogs", function() {
186+
$.widget( "ui.testWidget", $.ui.dialog, {
187+
options: {
188+
modal: true,
189+
autoOpen: false
190+
}
191+
});
192+
expect( 2 );
193+
var first = $( "<div><input id='input-1'></div>" ).dialog({
194+
modal: true
195+
}),
196+
firstInput = first.find( "input" ),
197+
second = $( "<div><input id='input-2'></div>" ).testWidget(),
198+
secondInput = second.find( "input" );
199+
200+
// Support: IE8
201+
// For some reason the focus doesn't get set properly if we don't
202+
// focus the body first.
203+
$( "body" ).focus();
204+
205+
// Wait for the modal to init
206+
setTimeout(function() {
207+
second.testWidget( "open" );
208+
209+
// Simulate user tabbing from address bar to an element outside the dialog
210+
$( "#favorite-animal" ).focus();
211+
setTimeout(function() {
212+
equal( document.activeElement, secondInput[ 0 ] );
213+
214+
// Last active dialog must receive focus
215+
firstInput.focus();
216+
$( "#favorite-animal" ).focus();
217+
setTimeout(function() {
218+
equal( document.activeElement, firstInput[ 0 ] );
219+
220+
// Cleanup
221+
first.remove();
222+
second.remove();
223+
delete $.ui.testWidget;
224+
delete $.fn.testWidget;
225+
start();
226+
});
227+
});
228+
});
229+
});
230+
183231
})(jQuery);

ui/jquery.ui.dialog.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ $.widget( "ui.dialog", {
182182
this._isOpen = false;
183183
this._focusedElement = null;
184184
this._destroyOverlay();
185+
this._untrackInstance();
185186

186187
if ( !this.opener.filter( ":focusable" ).focus().length ) {
187188

@@ -562,11 +563,30 @@ $.widget( "ui.dialog", {
562563
_trackFocus: function() {
563564
this._on( this.widget(), {
564565
"focusin": function( event ) {
566+
this._untrackInstance();
567+
this._trackingInstances().unshift( this );
565568
this._focusedElement = $( event.target );
566569
}
567570
});
568571
},
569572

573+
_untrackInstance: function() {
574+
var instances = this._trackingInstances(),
575+
exists = $.inArray( this, instances );
576+
if ( exists !== -1 ) {
577+
instances.splice( exists, 1 );
578+
}
579+
},
580+
581+
_trackingInstances: function() {
582+
var instances = this.document.data( "ui-dialog-instances" );
583+
if ( !instances ) {
584+
instances = [];
585+
this.document.data( "ui-dialog-instances", instances );
586+
}
587+
return instances;
588+
},
589+
570590
_minHeight: function() {
571591
var options = this.options;
572592

@@ -783,8 +803,7 @@ $.widget( "ui.dialog", {
783803

784804
if ( !this._allowInteraction( event ) ) {
785805
event.preventDefault();
786-
this.document.find( ".ui-dialog:visible:last .ui-dialog-content" )
787-
.data( this.widgetFullName )._focusTabbable();
806+
this._trackingInstances()[ 0 ]._focusTabbable();
788807
}
789808
}
790809
});

0 commit comments

Comments
 (0)