]> source.dussan.org Git - jquery-ui.git/commitdiff
Menu: Add classes option
authorAlexander Schmitz <arschmitz@gmail.com>
Wed, 3 Dec 2014 16:24:44 +0000 (11:24 -0500)
committerAlexander Schmitz <arschmitz@gmail.com>
Wed, 11 Mar 2015 20:04:42 +0000 (16:04 -0400)
Ref #7053
Ref gh-1411

tests/unit/menu/menu.html
tests/unit/menu/menu_core.js
ui/menu.js

index 56115c3343ce70f7fd20d7d7b65d8e6d3aba308a..114382587c5e3253790cff7072d94d964c05a491 100644 (file)
@@ -9,6 +9,7 @@
        <script src="../../../external/qunit/qunit.js"></script>
        <script src="../../../external/jquery-simulate/jquery.simulate.js"></script>
        <script src="../testsuite.js"></script>
+       <script src="../../../external/qunit-assert-classes/qunit-assert-classes.js"></script>
        <script>
        TestHelpers.loadResources({
                css: [ "core", "menu" ],
@@ -52,7 +53,7 @@
 <div id="qunit-fixture">
 
 <ul class="foo" id="menu1">
-       <li class="foo"><div>Aberdeen</div></li>
+       <li class="foo"><div>Aberdeen</div>
        <li class="foo"><div>Ada</div></li>
        <li class="foo"><div>Adamsville</div></li>
        <li class="foo"><div id="testID1">Addyston</div></li>
        <li class="foo"><div>-Saarland</div></li>
 </ul>
 
+<ul class="foo" id="menu9">
+       <li class="foo">
+               <div>Aberdeen</div>
+               <ul>
+                       <li class="foo"><div>Ada</div></li>
+               </ul>
+       </li>
+       <li class="foo"><div>Ada</div></li>
+       <li class="foo"><div>Adamsville</div></li>
+       <li class="foo"><div>Addyston</div></li>
+       <li class="foo"><div>Adelphi</div></li>
+</ul>
 </div>
 </body>
 </html>
index 5be717a669162e4cb0a35848d0b39234b9cf5fb4..955424477ff6071c75bd12156d5f38dd98afd7d8 100644 (file)
@@ -2,13 +2,23 @@
 
 module( "menu: core" );
 
-test( "markup structure", function() {
-       expect( 6 );
-       var element = $( "#menu1" ).menu();
-       ok( element.hasClass( "ui-menu" ), "main element is .ui-menu" );
-       element.children().each(function( index ) {
-               ok( $( this ).hasClass( "ui-menu-item" ), "child " + index + " is .ui-menu-item" );
-       });
+test( "markup structure", function( assert ) {
+       expect( 11 );
+       var element = $( "#menu9" ).menu(),
+               items = element.children(),
+               firstItemChildren = items.eq( 0 ).children();
+
+       assert.hasClasses( element, "ui-menu ui-widget ui-widget-content" );
+       assert.hasClasses( items[ 0 ], "ui-menu-item" );
+       equal( items.eq( 0 ).children().length, 2, "Item has exactly 2 children when it has a sub menu" );
+       assert.hasClasses( firstItemChildren[ 0 ], "ui-menu-item-wrapper" );
+       assert.hasClasses( firstItemChildren[ 1 ], "ui-menu ui-widget ui-widget-content" );
+       assert.hasClasses( firstItemChildren.eq( 1 ).children()[ 0 ], "ui-menu-item" );
+       assert.hasClasses( firstItemChildren.eq( 1 ).children().eq( 0 ).children(), "ui-menu-item-wrapper" );
+       assert.hasClasses( items[ 1 ], "ui-menu-item" );
+       equal( items.eq( 1 ).children().length, 1, "Item has exactly 1 child when it does not have a sub menu" );
+       assert.hasClasses( items[ 2 ], "ui-menu-item" );
+       equal( items.eq( 2 ).children().length, 1, "Item has exactly 1 child when it does not have a sub menu" );
 });
 
 test( "accessibility", function () {
index 353368cf959f8d4ca73f852dedbf4f52c23c912d..6c09e336f5fce454a76d75a27fba403cd9acd14c 100644 (file)
@@ -38,6 +38,7 @@ return $.widget( "ui.menu", {
        defaultElement: "<ul>",
        delay: 300,
        options: {
+               classes: {},
                icons: {
                        submenu: "ui-icon-caret-1-e"
                },
@@ -63,20 +64,19 @@ return $.widget( "ui.menu", {
                this.mouseHandled = false;
                this.element
                        .uniqueId()
-                       .addClass( "ui-menu ui-widget ui-widget-content" )
-                       .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
                        .attr({
                                role: this.options.role,
                                tabIndex: 0
                        });
 
                if ( this.options.disabled ) {
-                       this.element
-                               .addClass( "ui-state-disabled" )
-                               .attr( "aria-disabled", "true" );
+                       this._addClass( null, "ui-state-disabled" );
+                       this.element.attr( "aria-disabled", "true" );
                }
 
+               this._addClass( "ui-menu", "ui-widget ui-widget-content" );
                this._on({
+
                        // Prevent focus from sticking to links inside menu after clicking
                        // them (focus should always stay on UL during navigation).
                        "mousedown .ui-menu-item": function( event ) {
@@ -118,8 +118,8 @@ return $.widget( "ui.menu", {
                                var target = $( event.currentTarget );
                                // Remove ui-state-active class from siblings of the newly focused menu item
                                // to avoid a jump caused by adjacent elements both having a class with a border
-                               target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
-
+                               this._removeClass( target.siblings().children( ".ui-state-active" ),
+                                       null, "ui-state-active" );
                                this.focus( event, target );
                        },
                        mouseleave: "collapseAll",
@@ -159,11 +159,19 @@ return $.widget( "ui.menu", {
        },
 
        _destroy: function() {
+               var items = this.element.find( ".ui-menu-item" )
+                               .removeAttr( "role" )
+                               .removeAttr( "aria-disabled" ),
+                       submenus = items.children( ".ui-menu-item-wrapper" )
+                               .removeUniqueId()
+                               .removeAttr( "tabIndex" )
+                               .removeAttr( "role" )
+                               .removeAttr( "aria-haspopup" );
+
                // Destroy (sub)menus
                this.element
                        .removeAttr( "aria-activedescendant" )
                        .find( ".ui-menu" ).addBack()
-                               .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
                                .removeAttr( "role" )
                                .removeAttr( "tabIndex" )
                                .removeAttr( "aria-labelledby" )
@@ -173,26 +181,12 @@ return $.widget( "ui.menu", {
                                .removeUniqueId()
                                .show();
 
-               // Destroy menu items
-               this.element.find( ".ui-menu-item" )
-                       .removeClass( "ui-menu-item" )
-                       .removeAttr( "role" )
-                       .removeAttr( "aria-disabled" )
-                       .children( ".ui-menu-item-wrapper" )
-                               .removeUniqueId()
-                               .removeClass( "ui-menu-item-wrapper ui-state-hover" )
-                               .removeAttr( "tabIndex" )
-                               .removeAttr( "role" )
-                               .removeAttr( "aria-haspopup" )
-                               .children().each(function() {
-                                       var elem = $( this );
-                                       if ( elem.data( "ui-menu-submenu-caret" ) ) {
-                                               elem.remove();
-                                       }
-                               });
-
-               // Destroy menu dividers
-               this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+               submenus.children().each(function() {
+                       var elem = $( this );
+                       if ( elem.data( "ui-menu-submenu-caret" ) ) {
+                               elem.remove();
+                       }
+               });
        },
 
        _keydown: function( event ) {
@@ -286,16 +280,15 @@ return $.widget( "ui.menu", {
        },
 
        refresh: function() {
-               var menus, items,
+               var menus, items, newSubmenus, newItems, newWrappers,
                        that = this,
                        icon = this.options.icons.submenu,
                        submenus = this.element.find( this.options.menus );
 
-               this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
+               this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
 
                // Initialize nested menus
-               submenus.filter( ":not(.ui-menu)" )
-                       .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
+               newSubmenus = submenus.filter( ":not(.ui-menu)" )
                        .hide()
                        .attr({
                                role: this.options.role,
@@ -305,16 +298,17 @@ return $.widget( "ui.menu", {
                        .each(function() {
                                var menu = $( this ),
                                        item = menu.prev(),
-                                       submenuCaret = $( "<span>" )
-                                               .addClass( "ui-menu-icon ui-icon " + icon )
-                                               .data( "ui-menu-submenu-caret", true );
+                                       submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
 
+                               that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
                                item
                                        .attr( "aria-haspopup", "true" )
                                        .prepend( submenuCaret );
                                menu.attr( "aria-labelledby", item.attr( "id" ) );
                        });
 
+               this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
+
                menus = submenus.add( this.element );
                items = menus.find( this.options.items );
 
@@ -322,21 +316,21 @@ return $.widget( "ui.menu", {
                items.not( ".ui-menu-item" ).each(function() {
                        var item = $( this );
                        if ( that._isDivider( item ) ) {
-                               item.addClass( "ui-widget-content ui-menu-divider" );
+                               that._addClass( item, "ui-menu-divider", "ui-widget-content" );
                        }
                });
 
                // Don't refresh list items that are already adapted
-               items.not( ".ui-menu-item, .ui-menu-divider" )
-                       .addClass( "ui-menu-item" )
-                       .children()
-                               .not( ".ui-menu" )
-                                       .addClass( "ui-menu-item-wrapper" )
-                                       .uniqueId()
-                                       .attr({
-                                               tabIndex: -1,
-                                               role: this._itemRole()
-                                       });
+               newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
+               newWrappers = newItems.children()
+                       .not( ".ui-menu" )
+                               .uniqueId()
+                               .attr({
+                                       tabIndex: -1,
+                                       role: this._itemRole()
+                               });
+               this._addClass( newItems, "ui-menu-item" )
+                       ._addClass( newWrappers, "ui-menu-item-wrapper" );
 
                // Add aria-disabled attribute to any disabled menu item
                items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
@@ -356,26 +350,27 @@ return $.widget( "ui.menu", {
 
        _setOption: function( key, value ) {
                if ( key === "icons" ) {
-                       this.element.find( ".ui-menu-icon" )
-                               .removeClass( this.options.icons.submenu )
-                               .addClass( value.submenu );
+                       var icons = this.element.find( ".ui-menu-icon" );
+                       this._removeClass( icons, null, this.options.icons.submenu )
+                               ._addClass( icons, null, value.submenu );
                }
                if ( key === "disabled" ) {
-                       this.element
-                               .toggleClass( "ui-state-disabled", !!value )
-                               .attr( "aria-disabled", value );
+                       this.element.attr( "aria-disabled", value );
+                       this._toggleClass( null, "ui-state-disabled", !!value );
                }
                this._super( key, value );
        },
 
        focus: function( event, item ) {
-               var nested, focused;
+               var nested, focused, activeParent;
                this.blur( event, event && event.type === "focus" );
 
                this._scrollIntoView( item );
 
                this.active = item.first();
-               focused = this.active.children( ".ui-menu-item-wrapper" ).addClass( "ui-state-active" );
+
+               focused = this.active.children( ".ui-menu-item-wrapper" );
+               this._addClass( focused, null, "ui-state-active" );
 
                // Only update aria-activedescendant if there's a role
                // otherwise we assume focus is managed elsewhere
@@ -384,11 +379,11 @@ return $.widget( "ui.menu", {
                }
 
                // Highlight active parent menu item, if any
-               this.active
+               activeParent = this.active
                        .parent()
                                .closest( ".ui-menu-item" )
-                                       .children( ".ui-menu-item-wrapper" )
-                                               .addClass( "ui-state-active" );
+                                       .children( ".ui-menu-item-wrapper" );
+               this._addClass( activeParent, null, "ui-state-active" );
 
                if ( event && event.type === "keydown" ) {
                        this._close();
@@ -434,7 +429,8 @@ return $.widget( "ui.menu", {
                        return;
                }
 
-               this.active.children( ".ui-menu-item-wrapper" ).removeClass( "ui-state-active" );
+               this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
+                       null, "ui-state-active" );
                this.active = null;
 
                this._trigger( "blur", event, { item: this.active } );
@@ -498,14 +494,14 @@ return $.widget( "ui.menu", {
                        startMenu = this.active ? this.active.parent() : this.element;
                }
 
-               startMenu
+               var active = startMenu
                        .find( ".ui-menu" )
                                .hide()
                                .attr( "aria-hidden", "true" )
                                .attr( "aria-expanded", "false" )
                        .end()
-                       .find( ".ui-state-active" ).not( ".ui-menu-item-wrapper" )
-                               .removeClass( "ui-state-active" );
+                       .find( ".ui-state-active" ).not( ".ui-menu-item-wrapper" );
+               this._removeClass( active, null, "ui-state-active" );
        },
 
        _closeOnDocumentClick: function( event ) {