diff options
author | Jörn Zaefferer <joern.zaefferer@gmail.com> | 2013-11-16 12:21:02 +0100 |
---|---|---|
committer | Jörn Zaefferer <joern.zaefferer@gmail.com> | 2013-11-20 16:04:13 +0100 |
commit | 1096f19f37d6075328509d62a4c2c6d6a53d4b37 (patch) | |
tree | 83e790a0fd890f9459aacdfab866533294bbae5d | |
parent | 32a00607f1c74b5ee12db005e7524ec1783bb2ac (diff) | |
download | jquery-ui-1096f19f37d6075328509d62a4c2c6d6a53d4b37.tar.gz jquery-ui-1096f19f37d6075328509d62a4c2c6d6a53d4b37.zip |
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
-rw-r--r-- | tests/unit/dialog/dialog_core.js | 48 | ||||
-rw-r--r-- | ui/jquery.ui.dialog.js | 23 |
2 files changed, 69 insertions, 2 deletions
diff --git a/tests/unit/dialog/dialog_core.js b/tests/unit/dialog/dialog_core.js index 062d44576..c08019da9 100644 --- a/tests/unit/dialog/dialog_core.js +++ b/tests/unit/dialog/dialog_core.js @@ -4,6 +4,7 @@ (function($) { +// TODO add teardown callback to remove dialogs module("dialog: core"); test("title id", function() { @@ -180,4 +181,51 @@ asyncTest( "#9048: multiple modal dialogs opened and closed in different order", start(); }); }); + +asyncTest( "interaction between overlay and other dialogs", function() { + $.widget( "ui.testWidget", $.ui.dialog, { + options: { + modal: true, + autoOpen: false + } + }); + expect( 2 ); + var first = $( "<div><input id='input-1'></div>" ).dialog({ + modal: true + }), + firstInput = first.find( "input" ), + second = $( "<div><input id='input-2'></div>" ).testWidget(), + secondInput = second.find( "input" ); + + // Support: IE8 + // For some reason the focus doesn't get set properly if we don't + // focus the body first. + $( "body" ).focus(); + + // Wait for the modal to init + setTimeout(function() { + second.testWidget( "open" ); + + // Simulate user tabbing from address bar to an element outside the dialog + $( "#favorite-animal" ).focus(); + setTimeout(function() { + equal( document.activeElement, secondInput[ 0 ] ); + + // Last active dialog must receive focus + firstInput.focus(); + $( "#favorite-animal" ).focus(); + setTimeout(function() { + equal( document.activeElement, firstInput[ 0 ] ); + + // Cleanup + first.remove(); + second.remove(); + delete $.ui.testWidget; + delete $.fn.testWidget; + start(); + }); + }); + }); +}); + })(jQuery); diff --git a/ui/jquery.ui.dialog.js b/ui/jquery.ui.dialog.js index d3ce333f4..7f90908bd 100644 --- a/ui/jquery.ui.dialog.js +++ b/ui/jquery.ui.dialog.js @@ -182,6 +182,7 @@ $.widget( "ui.dialog", { this._isOpen = false; this._focusedElement = null; this._destroyOverlay(); + this._untrackInstance(); if ( !this.opener.filter( ":focusable" ).focus().length ) { @@ -562,11 +563,30 @@ $.widget( "ui.dialog", { _trackFocus: function() { this._on( this.widget(), { "focusin": function( event ) { + this._untrackInstance(); + this._trackingInstances().unshift( this ); this._focusedElement = $( event.target ); } }); }, + _untrackInstance: function() { + var instances = this._trackingInstances(), + exists = $.inArray( this, instances ); + if ( exists !== -1 ) { + instances.splice( exists, 1 ); + } + }, + + _trackingInstances: function() { + var instances = this.document.data( "ui-dialog-instances" ); + if ( !instances ) { + instances = []; + this.document.data( "ui-dialog-instances", instances ); + } + return instances; + }, + _minHeight: function() { var options = this.options; @@ -783,8 +803,7 @@ $.widget( "ui.dialog", { if ( !this._allowInteraction( event ) ) { event.preventDefault(); - this.document.find( ".ui-dialog:visible:last .ui-dialog-content" ) - .data( this.widgetFullName )._focusTabbable(); + this._trackingInstances()[ 0 ]._focusTabbable(); } } }); |