diff options
author | Hans Hillen <hans.hillen@gmail.com> | 2011-05-25 14:58:26 +0200 |
---|---|---|
committer | Hans Hillen <hans.hillen@gmail.com> | 2011-05-25 14:58:26 +0200 |
commit | f45fc08f8638640ac30a47d9acbdb0a544a275d9 (patch) | |
tree | 59b9e373b8fac56c9183a184804118333910d4eb /ui/jquery.ui.popup.js | |
parent | 63b89b7884d72d026f67c29eb234ebc1be738aa0 (diff) | |
download | jquery-ui-f45fc08f8638640ac30a47d9acbdb0a544a275d9.tar.gz jquery-ui-f45fc08f8638640ac30a47d9acbdb0a544a275d9.zip |
wrapping tab order for popup
Diffstat (limited to 'ui/jquery.ui.popup.js')
-rw-r--r-- | ui/jquery.ui.popup.js | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/ui/jquery.ui.popup.js b/ui/jquery.ui.popup.js index 10361a35c..10e6931b8 100644 --- a/ui/jquery.ui.popup.js +++ b/ui/jquery.ui.popup.js @@ -35,7 +35,7 @@ $.widget( "ui.popup", { if ( !this.element.attr( "role" ) ) { // TODO alternatives to tooltip are dialog and menu, all three aren't generic popups - this.element.attr( "role", "tooltip" ); + this.element.attr( "role", "dialog" ); this.generatedRole = true; } @@ -80,19 +80,22 @@ $.widget( "ui.popup", { }); this._bind(this.element, { - // TODO use focusout so that element itself doesn't need to be focussable - blur: function( event ) { + focusout: function( event ) { var that = this; // use a timer to allow click to clear it and letting that // handle the closing instead of opening again that.closeTimer = setTimeout( function() { that.close( event ); }, 100); - } + }, + focusin: function( event ) { + var that = this; + clearTimeout( that.closeTimer ); + } }); this._bind({ - // TODO only triggerd on element if it can receive focus + // TODO only triggered on element if it can receive focus // bind to document instead? // either element itself or a child should be focusable keyup: function( event ) { @@ -141,14 +144,43 @@ $.widget( "ui.popup", { .show() .attr( "aria-hidden", false ) .attr( "aria-expanded", true ) - .position( position ) - // TODO find a focussable child, otherwise put focus on element, add tabIndex=0 if not focussable - .focus(); - - if (this.element.is(":ui-menu")) { + .position( position ); + + if (this.element.is(":ui-menu")) { //popup is a menu + this.element.focus(); this.element.menu("focus", event, this.element.children( "li" ).first() ); + this.element.focus(); } - + // TODO add other special use cases that differ from the default dialog style keyboard mechanism + else { + //default use case, popup could be anything (e.g. a form) + this.element + .bind( "keypress.ui-popup", function( event ) { + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + var tabbables = $( ":tabbable", this ), + first = tabbables.filter( ":first" ), + last = tabbables.filter( ":last" ); + if ( event.target === last[0] && !event.shiftKey ) { + first.focus( 1 ); + return false; + } else if ( event.target === first[0] && event.shiftKey ) { + last.focus( 1 ); + return false; + } + }); + + // set focus to the first tabbable element in the popup container + // if there are no tabbable elements, set focus on the popup itself + var tabbables = this.element.find( ":tabbable" ); + if (!tabbables.length) { + this.element.attr("tabindex", "0"); + tabbables.add(this.element); + } + tabbables.eq( 0 ).focus(1); + } + // take trigger out of tab order to allow shift-tab to skip trigger this.options.trigger.attr("tabindex", -1); @@ -160,7 +192,8 @@ $.widget( "ui.popup", { this.element .hide() .attr( "aria-hidden", true ) - .attr( "aria-expanded", false ); + .attr( "aria-expanded", false ) + .unbind( "keypress.ui-popup"); this.options.trigger.attr("tabindex", 0); |