From b27db7e3b9a857b8f0890e91ae9c8a2d33bf9919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Zaefferer?= Date: Fri, 16 Nov 2012 20:24:57 +0100 Subject: [PATCH] Dialog: Extend autofocus, starting with [autofocus], then :tabbable content, then buttonpane, then close button, then dialog. Fixes #4731 - Dialog: Add option to set which element gains focus on open --- tests/unit/dialog/dialog_core.js | 42 ++++++++++++++++++++++++ tests/visual/dialog/complex-dialogs.html | 2 +- ui/jquery.ui.dialog.js | 22 +++++++++---- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/tests/unit/dialog/dialog_core.js b/tests/unit/dialog/dialog_core.js index b36f6204fc5..31b245a61f1 100644 --- a/tests/unit/dialog/dialog_core.js +++ b/tests/unit/dialog/dialog_core.js @@ -17,6 +17,8 @@ test("title id", function() { el.remove(); }); +// TODO test for aria-describedby +// add only when the attribute isn't anywhere yet test("ARIA", function() { expect(4); @@ -42,4 +44,44 @@ test("widget method", function() { deepEqual(dialog.parent()[0], dialog.dialog("widget")[0]); }); +test( "focus tabbable", function() { + expect( 5 ); + var el, + options = { + buttons: [{ + text: "Ok", + click: $.noop + }] + }; + + // 1. first element inside the dialog matching [autofocus] + el = $( "
" ).dialog( options ); + equal( document.activeElement, el.find( "input" )[ 1 ] ); + el.remove(); + + // 2. tabbable element inside the content element + el = $( "
" ).dialog( options ); + equal( document.activeElement, el.find( "input" )[ 0 ] ); + el.remove(); + + // 3. tabbable element inside the buttonpane + el = $( "
text
" ).dialog( options ); + equal( document.activeElement, el.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ] ); + el.remove(); + + // 4. the close button + el = $( "
text
" ).dialog(); + equal( document.activeElement, el.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ] ); + el.remove(); + + // 5. the dialog itself + el = $( "
text
" ).dialog({ + autoOpen: false + }); + el.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide(); + el.dialog( "open" ); + equal( document.activeElement, el.parent()[ 0 ] ); + el.remove(); +}); + })(jQuery); diff --git a/tests/visual/dialog/complex-dialogs.html b/tests/visual/dialog/complex-dialogs.html index 03bb160fb64..5c2e1d8a12c 100644 --- a/tests/visual/dialog/complex-dialogs.html +++ b/tests/visual/dialog/complex-dialogs.html @@ -107,7 +107,7 @@

Date:

-

+

diff --git a/ui/jquery.ui.dialog.js b/ui/jquery.ui.dialog.js index 0033898234a..c48d1a804e1 100644 --- a/ui/jquery.ui.dialog.js +++ b/ui/jquery.ui.dialog.js @@ -224,15 +224,24 @@ $.widget("ui.dialog", { return this; }, - // TODO check if dialog already has focus, merge with _keepFocus _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 - var hasFocus = this.element.find( ":tabbable" ); + // set focus to the first match: + // 1. first element inside the dialog matching [autofocus] + // 2. tabbable element inside the content element + // 3. tabbable element inside the buttonpane + // 4. the close button + // 5. the dialog itself + var hasFocus = this.element.find( "[autofocus]" ); if ( !hasFocus.length ) { - hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); + hasFocus = this.element.find( ":tabbable" ); if ( !hasFocus.length ) { - hasFocus = this.uiDialog; + hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; + } + } } } hasFocus.eq( 0 ).focus(); @@ -316,7 +325,6 @@ $.widget("ui.dialog", { .prependTo( this.uiDialog ); this._on( this.uiDialogTitlebar, { mousedown: function() { - // TODO call _focusTabbable or _keepFocus // Dialog isn't getting focus when dragging (#8063) this.uiDialog.focus(); }