Accessibility revamp for nav menus.

props lessbloat. fixes #14045

git-svn-id: http://core.svn.wordpress.org/trunk@23727 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Mark Jaquith 2013-03-16 04:47:19 +00:00
parent 46baddba34
commit 9bd740f616
5 changed files with 265 additions and 89 deletions

View File

@ -1789,10 +1789,6 @@ div.widgets-sortables,
background: #fbfbfb; background: #fbfbfb;
} }
.menu-settings {
border-top: 1px solid #eeeeee;
}
.theme-location-set { .theme-location-set {
color: #999999; color: #999999;
} }

View File

@ -7305,9 +7305,12 @@ a.rsswidget {
margin: .3em 0 .6em; margin: .3em 0 .6em;
} }
.menu-edit #post-body-content h3 {
margin: 0 0 10px;
}
.menu-settings { .menu-settings {
margin-top: 2em; margin-top: 2em;
padding-top: 16px;
overflow: hidden; overflow: hidden;
} }
@ -7801,6 +7804,11 @@ body.menu-max-depth-11 { min-width: 1280px !important; }
border-bottom-right-radius: 3px; border-bottom-right-radius: 3px;
} }
.menu-item-settings .field-move a {
display: none;
margin: 0 2px;
}
.menu-item-edit-active .menu-item-settings { .menu-item-edit-active .menu-item-settings {
display: block; display: block;
} }

View File

@ -89,7 +89,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
<li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>"> <li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
<dl class="menu-item-bar"> <dl class="menu-item-bar">
<dt class="menu-item-handle"> <dt class="menu-item-handle">
<span class="item-title"><?php echo esc_html( $title ); ?> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span> <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>
<span class="item-controls"> <span class="item-controls">
<span class="item-type"><?php echo esc_html( $item->type_label ); ?></span> <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
<span class="item-order hide-if-js"> <span class="item-order hide-if-js">
@ -173,6 +173,17 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
</label> </label>
</p> </p>
<p class="field-move description description-wide">
<label>
<?php _e( 'Move' ); ?>
<a href="#" class="menus-move-up"><?php _e( 'Up one' ); ?></a>
<a href="#" class="menus-move-down"><?php _e( 'Down one' ); ?></a>
<a href="#" class="menus-move-left"></a>
<a href="#" class="menus-move-right"></a>
<a href="#" class="menus-move-top"><?php _e( 'To the top' ); ?></a>
</label>
</p>
<div class="menu-item-actions description-wide submitbox"> <div class="menu-item-actions description-wide submitbox">
<?php if( 'custom' != $item->type && $original_title !== false ) : ?> <?php if( 'custom' != $item->type && $original_title !== false ) : ?>
<p class="link-to-original"> <p class="link-to-original">

View File

@ -45,7 +45,7 @@ var wpNavMenu;
if( api.menuList.length ) if( api.menuList.length )
this.initSortables(); this.initSortables();
if( oneThemeLocationNoMenus ) if( menu.oneThemeLocationNoMenus )
$( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom ); $( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom );
this.initAccessibility(); this.initAccessibility();
@ -162,7 +162,7 @@ var wpNavMenu;
return this.each(function() { return this.each(function() {
var t = $(this), menuItems = {}, var t = $(this), menuItems = {},
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'), 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'),
re = new RegExp('menu-item\\[(\[^\\]\]*)'); re = new RegExp('menu-item\\[(\[^\\]\]*)');
processMethod = processMethod || api.addMenuItemToBottom; processMethod = processMethod || api.addMenuItemToBottom;
@ -271,9 +271,226 @@ var wpNavMenu;
accordionOptions.filter(':visible').first().addClass( 'open' ); accordionOptions.filter(':visible').first().addClass( 'open' );
}, },
countMenuItems : function( depth ) {
return $( '.menu-item-depth-' + depth ).length;
},
moveMenuItem : function( $this, dir ) {
var menuItems = $('#menu-to-edit li');
menuItemsCount = menuItems.length,
thisItem = $this.parents( 'li.menu-item' ),
thisItemChildren = thisItem.childMenuItems(),
thisItemData = thisItem.getItemData(),
thisItemDepth = parseInt( thisItem.menuItemDepth() ),
thisItemPosition = parseInt( thisItem.index() ),
nextItem = thisItem.next(),
nextItemChildren = nextItem.childMenuItems(),
nextItemDepth = parseInt( nextItem.menuItemDepth() ) + 1,
prevItem = thisItem.prev(),
prevItemDepth = parseInt( prevItem.menuItemDepth() ),
prevItemId = prevItem.getItemData()['menu-item-db-id'];
switch ( dir ) {
case 'up':
var newItemPosition = thisItemPosition - 1;
// Already at top
if ( 0 === thisItemPosition )
break;
// If a sub item is moved to top, shift it to 0 depth
if ( 0 === newItemPosition && 0 !== thisItemDepth )
thisItem.moveHorizontally( 0, thisItemDepth );
// If prev item is sub item, shift to match depth
if ( 0 !== prevItemDepth )
thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
// Does this item have sub items?
if ( thisItemChildren ) {
var items = thisItem.add( thisItemChildren );
// Move the entire block
items.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
} else {
thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
}
break;
case 'down':
// Does this item have sub items?
if ( thisItemChildren ) {
var items = thisItem.add( thisItemChildren ),
nextItem = menuItems.eq( items.length + thisItemPosition ),
nextItemChildren = 0 !== nextItem.childMenuItems().length;
if ( nextItemChildren ) {
var newDepth = parseInt( nextItem.menuItemDepth() ) + 1;
thisItem.moveHorizontally( newDepth, thisItemDepth );
}
// Have we reached the bottom?
if ( menuItemsCount === thisItemPosition + items.length )
break;
items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) ).updateParentMenuItemDBId();
} else {
// If next item has sub items, shift depth
if ( 0 !== nextItemChildren.length )
thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
// Have we reached the bottom
if ( menuItemsCount === thisItemPosition + 1 )
break;
thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) ).updateParentMenuItemDBId();
}
break;
case 'top':
// Already at top
if ( 0 === thisItemPosition )
break;
// Does this item have sub items?
if ( thisItemChildren ) {
var items = thisItem.add( thisItemChildren );
// Move the entire block
items.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
} else {
thisItem.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
}
break;
case 'left':
// As far left as possible
if ( 0 === thisItemDepth )
break;
thisItem.shiftHorizontally( -1 );
break;
case 'right':
// Can't be sub item at top
if ( 0 === thisItemPosition )
break;
// Already sub item of prevItem
if ( thisItemData['menu-item-parent-id'] === prevItemId )
break;
thisItem.shiftHorizontally( 1 );
break;
}
$this.focus();
api.registerChange();
api.refreshKeyboardAccessibility();
api.refreshAdvancedAccessibility();
},
initAccessibility : function() { initAccessibility : function() {
api.refreshKeyboardAccessibility();
api.refreshAdvancedAccessibility();
// Events
$( '.menus-move-up' ).on( 'click', function ( e ) {
api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'up' );
e.preventDefault();
});
$( '.menus-move-down' ).on( 'click', function ( e ) {
api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'down' );
e.preventDefault();
});
$( '.menus-move-top' ).on( 'click', function ( e ) {
api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'top' );
e.preventDefault();
});
$( '.menus-move-left' ).on( 'click', function ( e ) {
api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'left' );
e.preventDefault();
});
$( '.menus-move-right' ).on( 'click', function ( e ) {
api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'right' );
e.preventDefault();
});
},
refreshAdvancedAccessibility : function() {
// Hide all links by default
$( '.menu-item-settings .field-move a' ).hide();
$( '.item-edit' ).each( function() {
var $this = $(this),
movement = [],
availableMovement = '',
menuItem = $this.parents( 'li.menu-item' ).first(),
depth = menuItem.menuItemDepth(),
isPrimaryMenuItem = ( 0 === depth ),
itemName = $this.parents( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
position = parseInt( menuItem.index() ),
prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1 ),
prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
totalMenuItems = $('#menu-to-edit li').length,
hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
// Where can they move this menu item?
if ( 0 !== position ) {
var thisLink = menuItem.find( '.menus-move-up' ),
thisLinkText = thisLink.text();
thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
}
if ( 0 !== position && isPrimaryMenuItem ) {
var thisLink = menuItem.find( '.menus-move-top' ),
thisLinkText = thisLink.text();
thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
}
if ( position + 1 !== totalMenuItems && 0 !== position ) {
var thisLink = menuItem.find( '.menus-move-down' ),
thisLinkText = thisLink.text();
thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
}
if ( 0 === position && 0 !== hasSameDepthSibling ) {
var thisLink = menuItem.find( '.menus-move-down' ),
thisLinkText = thisLink.text();
thisLink.prop('title', menus.move + ' ' + thisLinkText).show();
}
if ( ! isPrimaryMenuItem ) {
var thisLink = menuItem.find( '.menus-move-left' ),
thisLinkText = menus.outFrom + ' ' + prevItemNameLeft;
thisLink.prop('title', menus.move + ' ' + thisLinkText).html(thisLinkText).show();
}
if ( 0 !== position ) {
if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
var thisLink = menuItem.find( '.menus-move-right' ),
thisLinkText = menus.under + ' ' + prevItemNameRight;
thisLink.prop('title', menus.move + ' ' + thisLinkText).html(thisLinkText).show();
}
}
if ( isPrimaryMenuItem ) {
var primaryItems = $( '.menu-item-depth-0' ),
itemPosition = primaryItems.index( menuItem ) + 1,
totalMenuItems = primaryItems.length,
// String together help text for primary menu items
title = itemName + '. ' + menus.menuFocus.replace('%d', itemPosition).replace('%d', totalMenuItems) + '.';
} else {
var parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1 ) ).first(),
parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
parentItemName = parentItem.find( '.menu-item-title' ).text(),
subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
itemPosition = $(subItems.parents('.menu-item').get().reverse()).index( menuItem ) + 1;
// String together help text for sub menu items
title = itemName + '. ' + menus.subMenuFocus.replace('%d', itemPosition) + parentItemName + '.';
}
$this.prop('title', title).html( title );
});
},
refreshKeyboardAccessibility : function() {
$( '.item-edit' ).off( 'focus' ).on( 'focus', function(){ $( '.item-edit' ).off( 'focus' ).on( 'focus', function(){
$(this).on( 'keydown', function(e){ $(this).off( 'keydown' ).on( 'keydown', function(e){
var $this = $(this); var $this = $(this);
@ -284,22 +501,8 @@ var wpNavMenu;
// Avoid multiple keydown events // Avoid multiple keydown events
$this.off('keydown'); $this.off('keydown');
var menuItems = $('#menu-to-edit li');
menuItemsCount = menuItems.length,
thisItem = $this.parents( 'li.menu-item' ),
thisItemChildren = thisItem.childMenuItems(),
thisItemData = thisItem.getItemData(),
thisItemDepth = parseInt( thisItem.menuItemDepth() ),
thisItemPosition = parseInt( thisItem.index() ),
nextItem = thisItem.next(),
nextItemChildren = nextItem.childMenuItems(),
nextItemDepth = parseInt( nextItem.menuItemDepth() ) + 1,
prevItem = thisItem.prev(),
prevItemDepth = parseInt( prevItem.menuItemDepth() ),
prevItemId = prevItem.getItemData()['menu-item-db-id'];
// Bail if there is only one menu item // Bail if there is only one menu item
if ( 1 === menuItemsCount ) if ( 1 === $('#menu-to-edit li').length )
return; return;
// If RTL, swap left/right arrows // If RTL, swap left/right arrows
@ -309,80 +512,22 @@ var wpNavMenu;
switch ( arrows[e.which] ) { switch ( arrows[e.which] ) {
case 'up': case 'up':
var newItemPosition = thisItemPosition - 1; api.moveMenuItem( $this, 'up' );
// Already at top
if ( 0 === thisItemPosition )
break;
// If a sub item is moved to top, shift it to 0 depth
if ( 0 === newItemPosition && 0 !== thisItemDepth )
thisItem.moveHorizontally( 0, thisItemDepth );
// If prev item is sub item, shift to match depth
if ( 0 !== prevItemDepth )
thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
// Does this item have sub items?
if ( thisItemChildren ) {
var items = thisItem.add( thisItemChildren );
// Move the entire block
items.detach().insertBefore( menuItems.eq( newItemPosition ) );
} else {
thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) );
}
break; break;
case 'down': case 'down':
// Does this item have sub items? api.moveMenuItem( $this, 'down' );
if ( thisItemChildren ) {
var items = thisItem.add( thisItemChildren ),
nextItem = menuItems.eq( items.length + thisItemPosition ),
nextItemChildren = 0 !== nextItem.childMenuItems().length;
if ( nextItemChildren ) {
var newDepth = parseInt( nextItem.menuItemDepth() ) + 1;
thisItem.moveHorizontally( newDepth, thisItemDepth );
}
// Have we reached the bottom?
if ( menuItemsCount === thisItemPosition + items.length )
break;
items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) );
} else {
// If next item has sub items, shift depth
if ( 0 !== nextItemChildren.length )
thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
// Have we reached the bottom
if ( menuItemsCount === thisItemPosition + 1 )
break;
thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) );
}
break; break;
case 'left': case 'left':
// As far left as possible api.moveMenuItem( $this, 'left' );
if ( 0 === thisItemDepth )
break;
thisItem.shiftHorizontally( -1 );
break; break;
case 'right': case 'right':
// Can't be sub item at top api.moveMenuItem( $this, 'right' );
if ( 0 === thisItemPosition )
break;
// Already sub item of prevItem
if ( thisItemData['menu-item-parent-id'] === prevItemId )
break;
thisItem.shiftHorizontally( 1 );
break; break;
} }
api.registerChange();
// Put focus back on same menu item // Put focus back on same menu item
$( '#edit-' + thisItemData['menu-item-db-id'] ).focus(); $( '#edit-' + thisItemData['menu-item-db-id'] ).focus();
return false; return false;
}); });
}).blur(function () {
$(this).off( 'keydown' );
}); });
}, },
@ -512,6 +657,9 @@ var wpNavMenu;
ui.item[0].style.left = 'auto'; ui.item[0].style.left = 'auto';
ui.item[0].style.right = 0; ui.item[0].style.right = 0;
} }
api.refreshKeyboardAccessibility();
api.refreshAdvancedAccessibility();
}, },
change: function(e, ui) { change: function(e, ui) {
// Make sure the placeholder is inside the menu. // Make sure the placeholder is inside the menu.
@ -773,12 +921,14 @@ var wpNavMenu;
*/ */
addMenuItemToBottom : function( menuMarkup, req ) { addMenuItemToBottom : function( menuMarkup, req ) {
$(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList ); $(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList );
api.initAccessibility(); api.refreshKeyboardAccessibility();
api.refreshAdvancedAccessibility();
}, },
addMenuItemToTop : function( menuMarkup, req ) { addMenuItemToTop : function( menuMarkup, req ) {
$(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList ); $(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList );
api.initAccessibility(); api.refreshKeyboardAccessibility();
api.refreshAdvancedAccessibility();
}, },
attachUnsavedChangesListener : function() { attachUnsavedChangesListener : function() {

View File

@ -354,6 +354,16 @@ $add_new_screen = ( isset( $_GET['menu'] ) && 0 == $_GET['menu'] ) ? true : fals
$page_count = wp_count_posts( 'page' ); $page_count = wp_count_posts( 'page' );
$one_theme_location_no_menus = ( 1 == count( get_registered_nav_menus() ) && ! $add_new_screen && empty( $nav_menus ) && ! empty( $page_count->publish ) ) ? true : false; $one_theme_location_no_menus = ( 1 == count( get_registered_nav_menus() ) && ! $add_new_screen && empty( $nav_menus ) && ! empty( $page_count->publish ) ) ? true : false;
$l10n = array(
"oneThemeLocationNoMenus" => ( $one_theme_location_no_menus ) ? 'true' : 'false',
"move" => __( 'Move' ),
"menuFocus" => __( 'Menu item %d of %d' ),
"subMenuFocus" => __( 'Sub item number %d under' ),
"under" => __( 'Under' ),
"outFrom" => __( 'Out from under' )
);
wp_localize_script( 'nav-menu', 'menus', $l10n );
// Redirect to add screen if there are no menus and this users has either zero, or more than 1 theme locations // Redirect to add screen if there are no menus and this users has either zero, or more than 1 theme locations
if ( 0 == $menu_count && ! $add_new_screen && ! $one_theme_location_no_menus ) if ( 0 == $menu_count && ! $add_new_screen && ! $one_theme_location_no_menus )
wp_redirect( admin_url( 'nav-menus.php?action=edit&menu=0' ) ); wp_redirect( admin_url( 'nav-menus.php?action=edit&menu=0' ) );
@ -543,6 +553,7 @@ require_once( './admin-header.php' );
<div id="post-body"> <div id="post-body">
<div id="post-body-content"> <div id="post-body-content">
<?php if ( ! $add_new_screen ) : ?> <?php if ( ! $add_new_screen ) : ?>
<h3><?php _e( 'Menu Structure' ); ?></h3>
<?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.' ); ?> <?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.' ); ?>
<div class="drag-instructions post-body-plain" <?php if ( isset( $menu_items ) && 0 == count( $menu_items ) ) { ?>style="display: none;"<?php } ?>> <div class="drag-instructions post-body-plain" <?php if ( isset( $menu_items ) && 0 == count( $menu_items ) ) { ?>style="display: none;"<?php } ?>>
<p><?php echo $starter_copy; ?></p> <p><?php echo $starter_copy; ?></p>
@ -559,6 +570,7 @@ require_once( './admin-header.php' );
<p class="post-body-plain"><?php _e( 'Give your menu a name above, then click Create Menu.' ); ?></p> <p class="post-body-plain"><?php _e( 'Give your menu a name above, then click Create Menu.' ); ?></p>
<?php endif; ?> <?php endif; ?>
<div class="menu-settings" <?php if ( $one_theme_location_no_menus ) { ?>style="display: none;"<?php } ?>> <div class="menu-settings" <?php if ( $one_theme_location_no_menus ) { ?>style="display: none;"<?php } ?>>
<h3><?php _e( 'Menu Settings' ); ?></h3>
<?php <?php
if ( ! isset( $auto_add ) ) { if ( ! isset( $auto_add ) ) {
$auto_add = get_option( 'nav_menu_options' ); $auto_add = get_option( 'nav_menu_options' );
@ -612,5 +624,4 @@ require_once( './admin-header.php' );
</div><!-- /#menu-management-liquid --> </div><!-- /#menu-management-liquid -->
</div><!-- /#nav-menus-frame --> </div><!-- /#nav-menus-frame -->
</div><!-- /.wrap--> </div><!-- /.wrap-->
<script type="text/javascript">var oneThemeLocationNoMenus = <?php if ( $one_theme_location_no_menus ) echo 'true'; else echo 'false'; ?>;</script>
<?php include( './admin-footer.php' ); ?> <?php include( './admin-footer.php' ); ?>