diff options
author | Felix Nagel <info@felixnagel.com> | 2012-01-22 19:19:37 +0100 |
---|---|---|
committer | Felix Nagel <info@felixnagel.com> | 2012-01-22 19:22:57 +0100 |
commit | 4dbbd0598a58277816289441f3278a65025515d3 (patch) | |
tree | 42c08e34020690baeb7e954db73157bc97fab43b | |
parent | 50c308339c44f17b3a5c9dbc0e759f8b55a1297a (diff) | |
download | jquery-ui-4dbbd0598a58277816289441f3278a65025515d3.tar.gz jquery-ui-4dbbd0598a58277816289441f3278a65025515d3.zip |
Selectmenu: implement new ARIA spec
-rw-r--r-- | tests/unit/selectmenu/selectmenu_core.js | 40 | ||||
-rw-r--r-- | tests/unit/selectmenu/selectmenu_methods.js | 4 | ||||
-rw-r--r-- | ui/jquery.ui.selectmenu.js | 63 |
3 files changed, 60 insertions, 47 deletions
diff --git a/tests/unit/selectmenu/selectmenu_core.js b/tests/unit/selectmenu/selectmenu_core.js index c8feedee4..d3b2bfa81 100644 --- a/tests/unit/selectmenu/selectmenu_core.js +++ b/tests/unit/selectmenu/selectmenu_core.js @@ -12,22 +12,26 @@ test("accessibility", function () { ul = menu.children("ul"), links = ul.find("li.ui-menu-item a"); - expect(9 + links.length * 2); + expect(13 + links.length * 2); - equals( "true", link.attr("aria-haspopup"), "button link aria-haspopup" ); - equals( "button", link.attr("role"), "button link role" ); - equals( ul.attr("id"), link.attr("aria-owns"), "button link aria-owns" ); - equals( 0, link.attr("tabindex"), "button link tabindex" ); + equals( link.attr("role"), "combobox", "button link role" ); + equals( link.attr("aria-haspopup"), "true", "button link aria-haspopup" ); + equals( link.attr("aria-expanded"), "false", "button link aria-expanded" ); + equals( link.attr("aria-autocomplete"), "list", "button link aria-autocomplete" ); + equals( link.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "button link aria-activedescendant" ); + equals( link.attr("aria-owns"), ul.attr("id"), "button link aria-owns" ); + equals( link.attr("tabindex"), 0, "button link tabindex" ); - equals( "true", ul.attr("aria-hidden"), "menu aria-hidden" ); - equals( link.attr("id"), ul.attr("aria-labelledby"), "menu aria-labelledby" ); - equals( "menubox", ul.attr("role"), "menu role" ); - equals( 0, ul.attr("tabindex"), "menu tabindex" ); - equals( links.eq(element[0].selectedIndex).attr("id"), ul.attr("aria-activedescendant"), "menu aria-activedescendant" ); + equals( ul.attr("role"), "listbox", "menu role" ); + equals( ul.attr("aria-labelledby"), link.attr("id"), "menu aria-labelledby" ); + equals( ul.attr("aria-hidden"), "true", "menu aria-hidden" ); + equals( ul.attr("tabindex"), 0, "menu tabindex" ); + equals( ul.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "menu aria-activedescendant" ); $.each( links, function(index){ - equals( "option", $(this).attr("role"), "menu link #" + index +" role" ); - equals( -1, $(this).attr("tabindex"), "menu link #" + index +" tabindex" ); + equals( $(this).attr("role"), "option", "menu link #" + index +" role" ); + equals( $(this).attr("tabindex"), -1, "menu link #" + index +" tabindex" ); }); + equals( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "selected menu link aria-selected" ); }); @@ -42,23 +46,29 @@ $.each([ } ], function( i, settings ) { test("state synchronization - " + settings.type, function () { - expect(5); + expect(10); var element = $(settings.selector).selectmenu(), widget = element.selectmenu("widget"), button = widget.filter(".ui-selectmenu-button"), menu = widget.filter(".ui-selectmenu-menu"), link = button.find("a"), + ul = menu.children("ul"), + links = ul.find("li.ui-menu-item a"), selected = element.find("option:selected"); - equals( button.text(), selected.text(), "inital button text" ); - link.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + equals( ul.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "after keydown menu aria-activedescendant" ); + equals( link.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "after keydown button link aria-activedescendant" ); + equals( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "after keydown selected menu link aria-selected" ); equals( element.find("option:selected").val(), selected.next("option").val() , "after keydown original select state" ); equals( button.text(), selected.next("option").text(), "after keydown button text" ); link.simulate( "click" ); menu.find("a").last().simulate( "mouseover" ).trigger( "click" ); + equals( ul.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "after click menu aria-activedescendant" ); + equals( link.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "after click button link aria-activedescendant" ); + equals( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "after click selected menu link aria-selected" ); equals( element.find("option:selected").val(), element.find("option").last().val(), "after click original select state" ); equals( button.text(), element.find("option").last().text(), "after click button text" ); }); diff --git a/tests/unit/selectmenu/selectmenu_methods.js b/tests/unit/selectmenu/selectmenu_methods.js index e089bc06f..47e76053d 100644 --- a/tests/unit/selectmenu/selectmenu_methods.js +++ b/tests/unit/selectmenu/selectmenu_methods.js @@ -29,7 +29,7 @@ test( "open / close", function() { test("enable / disable", function () { - expect(12); + expect(14); var element = $('#speed').selectmenu(), widget = element.selectmenu("widget"), @@ -39,6 +39,7 @@ test("enable / disable", function () { element.selectmenu("disable") ok( element.selectmenu("option", "disabled"), "disable: widget option" ); + equals( element.attr("disabled"), "disabled", "disable: native select disabled" ); equals( button.attr("aria-disabled"), "true", "disable: button wrapper ARIA" ); equals( link.attr("aria-disabled"), "true", "disable: button ARIA" ); equals( link.attr("tabindex"), -1, "disable: button tabindex" ); @@ -47,6 +48,7 @@ test("enable / disable", function () { element.selectmenu("enable") ok( !element.selectmenu("option", "disabled"), "enable: widget option" ); + equals( element.attr("disabled"), undefined, "enable: native select disabled" ); equals( button.attr("aria-disabled"), "false", "enable: button wrapper ARIA" ); equals( link.attr("aria-disabled"), "false", "enable: button ARIA" ); equals( link.attr("tabindex"), 0, "enable: button tabindex" ); diff --git a/ui/jquery.ui.selectmenu.js b/ui/jquery.ui.selectmenu.js index 94bdd19a3..f9c8a30af 100644 --- a/ui/jquery.ui.selectmenu.js +++ b/ui/jquery.ui.selectmenu.js @@ -54,6 +54,7 @@ $.widget( "ui.selectmenu", { this._bind( this.button, this._buttonEvents ); this._drawMenu(); + this.refresh(); if ( this.options.disabled ) { this.disable(); @@ -74,15 +75,18 @@ $.widget( "ui.selectmenu", { css: { width: this.element.outerWidth() }, + 'aria-expanded': false, + 'aria-autocomplete': 'list', 'aria-owns': this.ids.menu, 'aria-haspopup': true }) .button({ - label: this.element.find( "option:selected" ).text(), icons: { primary: ( this.options.dropdown ? 'ui-icon-triangle-1-s' : 'ui-icon-triangle-2-n-s' ) } - }); + }) + // change ARIA role + .attr( 'role', 'combobox' ); // wrap and insert new button this.buttonWrap = $( '<span />' ) @@ -122,7 +126,9 @@ $.widget( "ui.selectmenu", { var item = ui.item.data( "item.selectmenu" ), oldIndex = that.element[0].selectedIndex; - that._setIndex( item.index ); + // change native select element + that.element[0].selectedIndex = item.index; + that._setSelected(); that._trigger( "select", event, { item: item } ); if ( item.index != oldIndex ) { @@ -145,7 +151,7 @@ $.widget( "ui.selectmenu", { } }) // change ARIA role - .attr( 'role', 'menubox' ); + .attr( 'role', 'listbox' ); // change menu styles? this._setOption( "dropdown", this.options.dropdown ); @@ -165,38 +171,27 @@ $.widget( "ui.selectmenu", { this._readOptions(); this._renderMenu( this.menu, this.items ); - + this.menu.menu( "refresh" ); - // button option label wont work here - this.button.children( '.ui-button-text' ).text( this.items[ this.element[0].selectedIndex ].label ); // adjust ARIA - this.menu.find( "li" ).not( '.ui-selectmenu-optgroup' ).find( 'a' ).attr( 'role', 'option' ); - this.menu.attr( "aria-activedescendant" , this.menu.find( "li.ui-menu-item a" ).eq( this.element[0].selectedIndex ).attr( "id" ) ); + this._getItems().find( 'a' ).attr( 'role', 'option' ); + this._setSelected(); // set and transfer disabled state this._getCreateOptions(); - if ( this.options.disabled ) { - this.disable(); - } else { - this.enable() - } + this._setOption( "disabled", this.options.disabled ); }, open: function( event ) { if ( !this.options.disabled ) { - // init menu when initial opened - if ( !this.wasOpen ) { - this.refresh(); - this.wasOpen = true; - } - var currentItem = this._getSelectedItem(); this._toggleButtonStyle(); this.menuWrap.addClass( 'ui-selectmenu-open' ); this.menu.attr("aria-hidden", false); + this.button.attr("aria-expanded", true); // needs to be fired after the document click event has closed all other Selectmenus // otherwise the current item is not indicated // TODO check if this should be handled by Menu @@ -236,7 +231,8 @@ $.widget( "ui.selectmenu", { this._toggleButtonStyle(); this.menuWrap.removeClass( 'ui-selectmenu-open' ); - this.menu.attr("aria-hidden", true); + this.menu.attr( "aria-hidden", true ); + this.button.attr( "aria-expanded", false ); this.isOpen = false; if ( focus ) { @@ -282,14 +278,9 @@ $.widget( "ui.selectmenu", { }, _move: function( direction, event ) { - // init menu when not done yet - if ( !this.wasOpen ) { - this.refresh(); - this.wasOpen = true; - } if ( direction == "first" || direction == "last" ) { // set focus manually for first or last item - this.menu.menu( "focus", event, this.menu.find( "li" ).not( '.ui-selectmenu-optgroup' )[ direction ]() ); + this.menu.menu( "focus", event, this._getItems()[ direction ]() ); } else { // if menu is closed we need to focus the element first to indicate correct element if ( !this.isOpen ) { @@ -306,7 +297,11 @@ $.widget( "ui.selectmenu", { }, _getSelectedItem: function() { - return this.menu.find( "li" ).not( '.ui-selectmenu-optgroup' ).eq( this.element[0].selectedIndex ); + return this._getItems().eq( this.element[0].selectedIndex ); + }, + + _getItems: function() { + return this.menu.find( "li" ).not( '.ui-selectmenu-optgroup' ); }, _toggle: function( event ) { @@ -360,6 +355,7 @@ $.widget( "ui.selectmenu", { break; case $.ui.keyCode.HOME: case $.ui.keyCode.PAGE_UP: + console.log("test"); this._move( "first", event ); break; case $.ui.keyCode.END: @@ -376,9 +372,14 @@ $.widget( "ui.selectmenu", { } }, - _setIndex: function( index ) { - this.element[0].selectedIndex = index; - this.button.button( "option", "label", this.items[ index ].label ); + _setSelected: function() { + var item = this._getSelectedItem().find("a"); + // update button text + this.button.button( "option", "label", item.text() ); + // change ARIA attr + this.button.add( this.menu ).attr( "aria-activedescendant" , item.attr( "id" ) ); + this._getItems().find("a").attr( "aria-selected", false ); + item.attr( "aria-selected", true ); }, _setOption: function( key, value ) { |