Make WordPress Core

Changeset 23727


Ignore:
Timestamp:
03/16/2013 04:47:19 AM (12 years ago)
Author:
markjaquith
Message:

Accessibility revamp for nav menus.

props lessbloat. fixes #14045

Location:
trunk/wp-admin
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/css/colors-fresh.css

    r23638 r23727  
    17881788    border: 1px solid #eeeeee;
    17891789    background: #fbfbfb;
    1790 }
    1791 
    1792 .menu-settings {
    1793     border-top: 1px solid #eeeeee;
    17941790}
    17951791
  • trunk/wp-admin/css/wp-admin.css

    r23725 r23727  
    73067306}
    73077307
     7308.menu-edit #post-body-content h3 {
     7309    margin: 0 0 10px;
     7310}
     7311
    73087312.menu-settings {
    73097313    margin-top: 2em;
    7310     padding-top: 16px;
    73117314    overflow: hidden;
    73127315}
     
    78007803    border-bottom-left-radius: 3px;
    78017804    border-bottom-right-radius: 3px;
     7805}
     7806
     7807.menu-item-settings .field-move a {
     7808    display: none;
     7809    margin: 0 2px;
    78027810}
    78037811
  • trunk/wp-admin/includes/nav-menu.php

    r23712 r23727  
    9090            <dl class="menu-item-bar">
    9191                <dt class="menu-item-handle">
    92                     <span class="item-title"><?php echo esc_html( $title ); ?> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
     92                    <span class="item-title"><span class="menu-item-title"><?php echo esc_html( $title ); ?></span> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
    9393                    <span class="item-controls">
    9494                        <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
     
    171171                        <textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
    172172                        <span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
     173                    </label>
     174                </p>
     175
     176                <p class="field-move description description-wide">
     177                    <label>
     178                        <?php _e( 'Move' ); ?>
     179                        <a href="#" class="menus-move-up"><?php _e( 'Up one' ); ?></a>
     180                        <a href="#" class="menus-move-down"><?php _e( 'Down one' ); ?></a>
     181                        <a href="#" class="menus-move-left"></a>
     182                        <a href="#" class="menus-move-right"></a>
     183                        <a href="#" class="menus-move-top"><?php _e( 'To the top' ); ?></a>
    173184                    </label>
    174185                </p>
  • trunk/wp-admin/js/nav-menu.js

    r23707 r23727  
    4646                this.initSortables();
    4747
    48             if( oneThemeLocationNoMenus )
     48            if( menu.oneThemeLocationNoMenus )
    4949                $( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom );
    5050
     
    163163                    return this.each(function() {
    164164                        var t = $(this), menuItems = {},
    165                             checkboxes = ( oneThemeLocationNoMenus && 0 == t.find('.tabs-panel-active .categorychecklist li input:checked').length ) ? t.find('#page-all li input[type="checkbox"]') : t.find('.tabs-panel-active .categorychecklist li input:checked'),
     165                            checkboxes = ( menu.oneThemeLocationNoMenus && 0 == t.find('.tabs-panel-active .categorychecklist li input:checked').length ) ? t.find('#page-all li input[type="checkbox"]') : t.find('.tabs-panel-active .categorychecklist li input:checked'),
    166166                            re = new RegExp('menu-item\\[(\[^\\]\]*)');
    167167
     
    272272        },
    273273
     274        countMenuItems : function( depth ) {
     275            return $( '.menu-item-depth-' + depth ).length;
     276        },
     277
     278        moveMenuItem : function( $this, dir ) {
     279
     280            var menuItems = $('#menu-to-edit li');
     281                menuItemsCount = menuItems.length,
     282                thisItem = $this.parents( 'li.menu-item' ),
     283                thisItemChildren = thisItem.childMenuItems(),
     284                thisItemData = thisItem.getItemData(),
     285                thisItemDepth = parseInt( thisItem.menuItemDepth() ),
     286                thisItemPosition = parseInt( thisItem.index() ),
     287                nextItem = thisItem.next(),
     288                nextItemChildren = nextItem.childMenuItems(),
     289                nextItemDepth = parseInt( nextItem.menuItemDepth() ) + 1,
     290                prevItem = thisItem.prev(),
     291                prevItemDepth = parseInt( prevItem.menuItemDepth() ),
     292                prevItemId = prevItem.getItemData()['menu-item-db-id'];
     293
     294            switch ( dir ) {
     295            case 'up':
     296                var newItemPosition = thisItemPosition - 1;
     297
     298                // Already at top
     299                if ( 0 === thisItemPosition )
     300                    break;
     301
     302                // If a sub item is moved to top, shift it to 0 depth
     303                if ( 0 === newItemPosition && 0 !== thisItemDepth )
     304                    thisItem.moveHorizontally( 0, thisItemDepth );
     305
     306                // If prev item is sub item, shift to match depth
     307                if ( 0 !== prevItemDepth )
     308                    thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
     309
     310                // Does this item have sub items?
     311                if ( thisItemChildren ) {
     312                    var items = thisItem.add( thisItemChildren );
     313                    // Move the entire block
     314                    items.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
     315                } else {
     316                    thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
     317                }
     318                break;
     319            case 'down':
     320                // Does this item have sub items?
     321                if ( thisItemChildren ) {
     322                    var items = thisItem.add( thisItemChildren ),
     323                        nextItem = menuItems.eq( items.length + thisItemPosition ),
     324                        nextItemChildren = 0 !== nextItem.childMenuItems().length;
     325
     326                    if ( nextItemChildren ) {
     327                        var newDepth = parseInt( nextItem.menuItemDepth() ) + 1;
     328                        thisItem.moveHorizontally( newDepth, thisItemDepth );
     329                    }
     330
     331                    // Have we reached the bottom?
     332                    if ( menuItemsCount === thisItemPosition + items.length )
     333                        break;
     334
     335                    items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) ).updateParentMenuItemDBId();
     336                } else {
     337                    // If next item has sub items, shift depth
     338                    if ( 0 !== nextItemChildren.length )
     339                        thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
     340
     341                    // Have we reached the bottom
     342                    if ( menuItemsCount === thisItemPosition + 1 )
     343                        break;
     344                    thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) ).updateParentMenuItemDBId();
     345                }
     346                break;
     347            case 'top':
     348                // Already at top
     349                if ( 0 === thisItemPosition )
     350                    break;
     351                // Does this item have sub items?
     352                if ( thisItemChildren ) {
     353                    var items = thisItem.add( thisItemChildren );
     354                    // Move the entire block
     355                    items.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
     356                } else {
     357                    thisItem.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
     358                }
     359                break;
     360            case 'left':
     361                // As far left as possible
     362                if ( 0 === thisItemDepth )
     363                    break;
     364                thisItem.shiftHorizontally( -1 );
     365                break;
     366            case 'right':
     367                // Can't be sub item at top
     368                if ( 0 === thisItemPosition )
     369                    break;
     370                // Already sub item of prevItem
     371                if ( thisItemData['menu-item-parent-id'] === prevItemId )
     372                    break;
     373                thisItem.shiftHorizontally( 1 );
     374                break;
     375            }
     376            $this.focus();
     377            api.registerChange();
     378            api.refreshKeyboardAccessibility();
     379            api.refreshAdvancedAccessibility();
     380        },
     381
    274382        initAccessibility : function() {
     383            api.refreshKeyboardAccessibility();
     384            api.refreshAdvancedAccessibility();
     385
     386            // Events
     387            $( '.menus-move-up' ).on( 'click', function ( e ) {
     388                api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'up' );
     389                e.preventDefault();
     390            });
     391            $( '.menus-move-down' ).on( 'click', function ( e ) {
     392                api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'down' );
     393                e.preventDefault();
     394            });
     395            $( '.menus-move-top' ).on( 'click', function ( e ) {
     396                api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'top' );
     397                e.preventDefault();
     398            });
     399            $( '.menus-move-left' ).on( 'click', function ( e ) {
     400                api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'left' );
     401                e.preventDefault();
     402            });
     403            $( '.menus-move-right' ).on( 'click', function ( e ) {
     404                api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'right' );
     405                e.preventDefault();
     406            });
     407        },
     408
     409        refreshAdvancedAccessibility : function() {
     410
     411            // Hide all links by default
     412            $( '.menu-item-settings .field-move a' ).hide();
     413
     414            $( '.item-edit' ).each( function() {
     415                var $this = $(this),
     416                    movement = [],
     417                    availableMovement = '',
     418                    menuItem = $this.parents( 'li.menu-item' ).first(),
     419                    depth = menuItem.menuItemDepth(),
     420                    isPrimaryMenuItem = ( 0 === depth ),
     421                    itemName = $this.parents( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
     422                    position = parseInt( menuItem.index() ),
     423                    prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1 ),
     424                    prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
     425                    prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
     426                    totalMenuItems = $('#menu-to-edit li').length,
     427                    hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
     428
     429                // Where can they move this menu item?
     430                if ( 0 !== position ) {
     431                    var thisLink = menuItem.find( '.menus-move-up' ),
     432                        thisLinkText = thisLink.text();
     433                    thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
     434                }
     435
     436                if ( 0 !== position && isPrimaryMenuItem ) {
     437                    var thisLink = menuItem.find( '.menus-move-top' ),
     438                        thisLinkText = thisLink.text();
     439                    thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
     440                }
     441
     442                if ( position + 1 !== totalMenuItems && 0 !== position ) {
     443                    var thisLink = menuItem.find( '.menus-move-down' ),
     444                        thisLinkText = thisLink.text();
     445                    thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
     446                }
     447
     448                if ( 0 === position && 0 !== hasSameDepthSibling ) {
     449                    var thisLink = menuItem.find( '.menus-move-down' ),
     450                        thisLinkText = thisLink.text();
     451                    thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
     452                }
     453
     454                if ( ! isPrimaryMenuItem ) {
     455                    var thisLink = menuItem.find( '.menus-move-left' ),
     456                        thisLinkText = menus.outFrom + ' ' + prevItemNameLeft;
     457                    thisLink.prop('title', menus.move + ' ' + thisLinkText).html(thisLinkText).show();
     458                }
     459
     460                if ( 0 !== position ) {
     461                    if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
     462                        var thisLink = menuItem.find( '.menus-move-right' ),
     463                            thisLinkText = menus.under + ' ' + prevItemNameRight;
     464                        thisLink.prop('title', menus.move + ' ' + thisLinkText).html(thisLinkText).show();
     465                    }
     466                }
     467
     468                if ( isPrimaryMenuItem ) {
     469                    var primaryItems = $( '.menu-item-depth-0' ),
     470                        itemPosition = primaryItems.index( menuItem ) + 1,
     471                        totalMenuItems = primaryItems.length,
     472
     473                        // String together help text for primary menu items
     474                        title = itemName + '. ' + menus.menuFocus.replace('%d', itemPosition).replace('%d', totalMenuItems) + '.';
     475                } else {
     476                    var parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1 ) ).first(),
     477                        parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
     478                        parentItemName = parentItem.find( '.menu-item-title' ).text(),
     479                        subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
     480                        itemPosition = $(subItems.parents('.menu-item').get().reverse()).index( menuItem ) + 1;
     481
     482                        // String together help text for sub menu items
     483
     484                        title = itemName + '. ' + menus.subMenuFocus.replace('%d', itemPosition) + parentItemName + '.';
     485                }
     486
     487                $this.prop('title', title).html( title );
     488            });
     489        },
     490
     491        refreshKeyboardAccessibility : function() {
    275492            $( '.item-edit' ).off( 'focus' ).on( 'focus', function(){
    276                 $(this).on( 'keydown', function(e){
     493                $(this).off( 'keydown' ).on( 'keydown', function(e){
    277494
    278495                    var $this = $(this);
     
    285502                    $this.off('keydown');
    286503
    287                     var menuItems = $('#menu-to-edit li');
    288                         menuItemsCount = menuItems.length,
    289                         thisItem = $this.parents( 'li.menu-item' ),
    290                         thisItemChildren = thisItem.childMenuItems(),
    291                         thisItemData = thisItem.getItemData(),
    292                         thisItemDepth = parseInt( thisItem.menuItemDepth() ),
    293                         thisItemPosition = parseInt( thisItem.index() ),
    294                         nextItem = thisItem.next(),
    295                         nextItemChildren = nextItem.childMenuItems(),
    296                         nextItemDepth = parseInt( nextItem.menuItemDepth() ) + 1,
    297                         prevItem = thisItem.prev(),
    298                         prevItemDepth = parseInt( prevItem.menuItemDepth() ),
    299                         prevItemId = prevItem.getItemData()['menu-item-db-id'];
    300 
    301504                    // Bail if there is only one menu item
    302                     if ( 1 === menuItemsCount )
     505                    if ( 1 === $('#menu-to-edit li').length )
    303506                        return;
    304507
     
    310513                    switch ( arrows[e.which] ) {
    311514                    case 'up':
    312                         var newItemPosition = thisItemPosition - 1;
    313 
    314                         // Already at top
    315                         if ( 0 === thisItemPosition )
    316                             break;
    317 
    318                         // If a sub item is moved to top, shift it to 0 depth
    319                         if ( 0 === newItemPosition && 0 !== thisItemDepth )
    320                             thisItem.moveHorizontally( 0, thisItemDepth );
    321 
    322                         // If prev item is sub item, shift to match depth
    323                         if ( 0 !== prevItemDepth )
    324                             thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
    325 
    326                         // Does this item have sub items?
    327                         if ( thisItemChildren ) {
    328                             var items = thisItem.add( thisItemChildren );
    329                             // Move the entire block
    330                             items.detach().insertBefore( menuItems.eq( newItemPosition ) );
    331                         } else {
    332                             thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) );
    333                         }
     515                        api.moveMenuItem( $this, 'up' );
    334516                        break;
    335517                    case 'down':
    336                         // Does this item have sub items?
    337                         if ( thisItemChildren ) {
    338                             var items = thisItem.add( thisItemChildren ),
    339                                 nextItem = menuItems.eq( items.length + thisItemPosition ),
    340                                 nextItemChildren = 0 !== nextItem.childMenuItems().length;
    341 
    342                             if ( nextItemChildren ) {
    343                                 var newDepth = parseInt( nextItem.menuItemDepth() ) + 1;
    344                                 thisItem.moveHorizontally( newDepth, thisItemDepth );
    345                             }
    346 
    347                             // Have we reached the bottom?
    348                             if ( menuItemsCount === thisItemPosition + items.length )
    349                                 break;
    350 
    351                             items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) );
    352                         } else {
    353                             // If next item has sub items, shift depth
    354                             if ( 0 !== nextItemChildren.length )
    355                                 thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
    356 
    357                             // Have we reached the bottom
    358                             if ( menuItemsCount === thisItemPosition + 1 )
    359                                 break;
    360                             thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) );
    361                         }
     518                        api.moveMenuItem( $this, 'down' );
    362519                        break;
    363520                    case 'left':
    364                         // As far left as possible
    365                         if ( 0 === thisItemDepth )
    366                             break;
    367                         thisItem.shiftHorizontally( -1 );
     521                        api.moveMenuItem( $this, 'left' );
    368522                        break;
    369523                    case 'right':
    370                         // Can't be sub item at top
    371                         if ( 0 === thisItemPosition )
    372                             break;
    373                         // Already sub item of prevItem
    374                         if ( thisItemData['menu-item-parent-id'] === prevItemId )
    375                             break;
    376                         thisItem.shiftHorizontally( 1 );
     524                        api.moveMenuItem( $this, 'right' );
    377525                        break;
    378526                    }
    379                     api.registerChange();
    380527                    // Put focus back on same menu item
    381528                    $( '#edit-' + thisItemData['menu-item-db-id'] ).focus();
    382529                    return false;
    383530                });
    384             }).blur(function () {
    385                 $(this).off( 'keydown' );
    386531            });
    387532        },
     
    513658                        ui.item[0].style.right = 0;
    514659                    }
     660
     661                    api.refreshKeyboardAccessibility();
     662                    api.refreshAdvancedAccessibility();
    515663                },
    516664                change: function(e, ui) {
     
    774922        addMenuItemToBottom : function( menuMarkup, req ) {
    775923            $(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList );
    776             api.initAccessibility();
     924            api.refreshKeyboardAccessibility();
     925            api.refreshAdvancedAccessibility();
    777926        },
    778927
    779928        addMenuItemToTop : function( menuMarkup, req ) {
    780929            $(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList );
    781             api.initAccessibility();
     930            api.refreshKeyboardAccessibility();
     931            api.refreshAdvancedAccessibility();
    782932        },
    783933
  • trunk/wp-admin/nav-menus.php

    r23707 r23727  
    354354$page_count = wp_count_posts( 'page' );
    355355$one_theme_location_no_menus = ( 1 == count( get_registered_nav_menus() ) && ! $add_new_screen && empty( $nav_menus ) && ! empty( $page_count->publish ) ) ? true : false;
     356
     357$l10n = array(
     358    "oneThemeLocationNoMenus" => ( $one_theme_location_no_menus ) ? 'true' : 'false',
     359    "move" => __( 'Move' ),
     360    "menuFocus" => __( 'Menu item %d of %d' ),
     361    "subMenuFocus" => __( 'Sub item number %d under' ),
     362    "under" => __( 'Under' ),
     363    "outFrom" => __( 'Out from under' )
     364);
     365wp_localize_script( 'nav-menu', 'menus', $l10n );
    356366
    357367// Redirect to add screen if there are no menus and this users has either zero, or more than 1 theme locations
     
    544554                        <div id="post-body-content">
    545555                            <?php if ( ! $add_new_screen ) : ?>
     556                            <h3><?php _e( 'Menu Structure' ); ?></h3>
    546557                            <?php $starter_copy = ( $one_theme_location_no_menus ) ? __( 'Edit your default menu by adding or removing items. Drag each item into the order you prefer. Click Create Menu to save your changes.' ) : __( 'Drag each item into the order you prefer. Click an item to reveal additional configuration options.' ); ?>
    547558                            <div class="drag-instructions post-body-plain" <?php if ( isset( $menu_items ) && 0 == count( $menu_items ) ) { ?>style="display: none;"<?php } ?>>
     
    560571                            <?php endif; ?>
    561572                            <div class="menu-settings" <?php if ( $one_theme_location_no_menus ) { ?>style="display: none;"<?php } ?>>
     573                                <h3><?php _e( 'Menu Settings' ); ?></h3>
    562574                                <?php
    563575                                if ( ! isset( $auto_add ) ) {
     
    613625    </div><!-- /#nav-menus-frame -->
    614626</div><!-- /.wrap-->
    615 <script type="text/javascript">var oneThemeLocationNoMenus = <?php if ( $one_theme_location_no_menus ) echo 'true'; else echo 'false'; ?>;</script>
    616627<?php include( './admin-footer.php' ); ?>
Note: See TracChangeset for help on using the changeset viewer.