diff --git a/src/js/_enqueues/lib/nav-menu.js b/src/js/_enqueues/lib/nav-menu.js index d3b9663487..b8dbd40ad6 100644 --- a/src/js/_enqueues/lib/nav-menu.js +++ b/src/js/_enqueues/lib/nav-menu.js @@ -45,6 +45,11 @@ this.attachMenuEditListeners(); + this.attachBulkSelectButtonListeners(); + this.attachMenuCheckBoxListeners(); + this.attachMenuItemDeleteButton(); + this.attachPendingMenuItemsListForDeletion(); + this.attachQuickSearchListeners(); this.attachThemeLocationsListeners(); this.attachMenuSaveSubmitListeners(); @@ -862,6 +867,183 @@ }); }, + /** + * Handle toggling bulk selection checkboxes for menu items. + * + * @since 5.8.0 + */ + attachBulkSelectButtonListeners : function() { + var that = this; + + $('.bulk-select-switcher').on( 'change', function(){ + if( this.checked ){ + $('.bulk-select-switcher').prop('checked',true); + that.enableBulkSelection(); + }else{ + $('.bulk-select-switcher').prop('checked',false); + that.disableBulkSelection(); + } + }); + }, + + /** + * Enable bulk selection checkboxes for menu items. + * + * @since 5.8.0 + */ + enableBulkSelection : function() { + $('#menu-to-edit').addClass('bulk-selection'); + $('#nav-menu-bulk-actions-top').addClass('bulk-selection'); + $('#nav-menu-bulk-actions-bottom').addClass('bulk-selection'); + + var checkbox = $('#menu-to-edit .menu-item-checkbox'); + $.each( checkbox, function(){ + $(this).prop('disabled',false); + }); + }, + + /** + * Disable bulk selection checkboxes for menu items. + * + * @since 5.8.0 + */ + disableBulkSelection : function() { + $('#menu-to-edit').removeClass('bulk-selection'); + $('#nav-menu-bulk-actions-top').removeClass('bulk-selection'); + $('#nav-menu-bulk-actions-bottom').removeClass('bulk-selection'); + + if ( $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ) { + $('.menu-items-delete').removeAttr( 'aria-describedby' ); + } + + var checkbox = $('#menu-to-edit .menu-item-checkbox'); + $.each( checkbox, function(){ + $(this).prop('disabled',true).prop('checked',false); + }); + $('.menu-items-delete').addClass('disabled'); + $('#pending-menu-items-to-delete ul').empty(); + }, + + /** + * Listen for state changes on bulk action checkboxes. + * + * @since 5.8.0 + */ + attachMenuCheckBoxListeners : function() { + var that = this; + + $( '#menu-to-edit' ).on( 'change', '.menu-item-checkbox', function(){ + that.setRemoveSelectedButtonStatus(); + }); + }, + + /** + * Create delete button to remove menu items from collection. + * + * @since 5.8.0 + */ + attachMenuItemDeleteButton : function() { + var that = this; + + $( document ).on('click', '.menu-items-delete', function(e){ + e.preventDefault(); + + if( ! $(this).hasClass('disabled') ){ + $.each( $('.menu-item-checkbox:checked'), function( index, element ) { + $( element ).parents( 'li' ).find( 'a.item-delete' ).trigger( 'click' ); + }); + + $('.menu-items-delete').addClass('disabled'); + $('.bulk-select-switcher').prop('checked',false); + + var itemsPendingDeletion = ''; + var itemsPendingDeletionList = $('#pending-menu-items-to-delete ul li'); + + $.each( itemsPendingDeletionList, function( index, element ) { + var itemName = $( element ).find( '.pending-menu-item-name' ).text(); + var itemSpeech = menus.menuItemDeletion.replace( '%s', itemName ); + itemsPendingDeletion += itemSpeech ; + if( ( index + 1 ) < itemsPendingDeletionList.length ){ + itemsPendingDeletion += ', ' ; + } + }); + + var deletionSpeech = menus.itemsDeleted.replace( '%s', itemsPendingDeletion ); + wp.a11y.speak( deletionSpeech, 'polite' ); + that.disableBulkSelection(); + } + }); + }, + + /** + * List menu items awaiting deletion. + * + * @since 5.8.0 + */ + attachPendingMenuItemsListForDeletion : function(){ + $('#post-body-content').on( 'change', '.menu-item-checkbox', function(){ + + if( ! $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ){ $('.menu-items-delete').attr( 'aria-describedby', 'pending-menu-items-to-delete' ); } + + var menuItemName = $(this).next().text(); + var menuItemType = $(this).parent().next('.item-controls').find('.item-type').text(); + var menuItemID = $(this).attr('data-menu-item-id') ; + + var ListedMenuItem = $('#pending-menu-items-to-delete ul').find('[data-menu-item-id=' + menuItemID + ']') ; + if( ListedMenuItem.length > 0 ){ + ListedMenuItem.remove(); + } + if( this.checked === true ){ + $('#pending-menu-items-to-delete ul').append( '
  • ' + menuItemName + ' (' + menuItemType + ')
  • ' ); + } + + $('#pending-menu-items-to-delete li .separator').html(', '); + $('#pending-menu-items-to-delete li .separator').last().html('.'); + }); + }, + + /** + * Set status of bulk delete checkbox. + * + * @since 5.8.0 + */ + setBulkDeleteCheckboxStatus : function(){ + + var that = this; + var checkbox = $('#menu-to-edit .menu-item-checkbox'); + + $.each( checkbox, function(){ + + if( $(this).prop('disabled') == true ){ + $(this).prop( 'disabled', false ); + }else{ + $(this).prop( 'disabled', true ); + } + + if( $(this).is(':checked')) { + $(this).prop('checked',false); + } + }); + + that.setRemoveSelectedButtonStatus(); + }, + + /** + * Set status of menu items removal button. + * + * @since 5.8.0 + */ + setRemoveSelectedButtonStatus : function(){ + + var button = $('.menu-items-delete'); + + if( $('.menu-item-checkbox:checked').length > 0 ) { + button.removeClass('disabled'); + } else { + button.addClass('disabled'); + } + }, + attachMenuSaveSubmitListeners : function() { /* * When a navigation menu is saved, store a JSON representation of all form data @@ -908,7 +1090,7 @@ searchTimer = setTimeout( function() { api.updateQuickSearchResults( $this ); - }, 500 ); + }, 500 ); }).on( 'blur', '.quick-search', function() { api.lastSearch = ''; }); diff --git a/src/wp-admin/css/nav-menus.css b/src/wp-admin/css/nav-menus.css index ed97188ea5..a6804bccaf 100644 --- a/src/wp-admin/css/nav-menus.css +++ b/src/wp-admin/css/nav-menus.css @@ -97,6 +97,105 @@ ul.add-menu-item-tabs li { margin: 1em 0 10px; } +#nav-menu-bulk-actions-top { + margin: 1em 0; +} + +#nav-menu-bulk-actions-bottom { + margin: 1em 0; + margin: calc( 1em + 9px ) 0 ; +} + +.bulk-actions input.button { + margin-right: 12px; +} + +.bulk-select-button { + position: relative; + display: inline-block; + padding: 0 10px; + font-size: 13px; + line-height: 2.15384615; + height: auto; + min-height: 30px; + background: #f6f7f7; + vertical-align: top; + border: 1px solid #dcdcde; + margin: 0; + cursor: pointer; + border-radius: 3px; + white-space: nowrap; + box-sizing: border-box; +} + +.bulk-selection .bulk-select-button { + color: #2271b1; + border-color: #2271b1; + background: #f6f7f7; + vertical-align: top; +} + +#pending-menu-items-to-delete { + display: none; +} + +.bulk-selection #pending-menu-items-to-delete { + display: block; + margin-top: 1em; +} + +#pending-menu-items-to-delete p { + margin-bottom: 0; +} + +#pending-menu-items-to-delete ul { + margin-top: 0; + list-style: none; +} + +#pending-menu-items-to-delete ul li { + display: inline; +} + +input.bulk-select-switcher + .bulk-select-button-label { + vertical-align: inherit; +} + +label.bulk-select-button:hover, +label.bulk-select-button:active, +label.bulk-select-button:focus-within { + background: #f0f0f1; + border-color: #0a4b78; + color: #0a4b78; +} + +input.bulk-select-switcher:focus + .bulk-select-button-label{ + color: #0a4b78; +} + +.bulk-actions input.menu-items-delete { + -webkit-appearance: none; + appearance: none; + font-size: inherit; + border: 0; + line-height: 2.1em; + background: none; + cursor: pointer; + text-decoration: underline; + color: #b32d2e; +} + +.bulk-actions input.menu-items-delete:hover { + color: #b32d2e; + border: none; +} + +.bulk-actions input.menu-items-delete.disabled { + cursor: default; + color: #a7aaad; + box-shadow: none; +} + .menu-settings { border-top: 1px solid #f0f0f1; margin-top: 2em; @@ -481,6 +580,15 @@ ul.add-menu-item-tabs li { margin-right: 13em; } +.menu-item-handle .menu-item-checkbox { + display: none; +} + +.bulk-selection .menu-item-handle .menu-item-checkbox { + display: inline-block; + margin-right: 6px; +} + .menu-item-handle .menu-item-title.no-title { color: #646970; } diff --git a/src/wp-admin/includes/class-walker-nav-menu-edit.php b/src/wp-admin/includes/class-walker-nav-menu-edit.php index fb9fceb7df..0249149eb3 100644 --- a/src/wp-admin/includes/class-walker-nav-menu-edit.php +++ b/src/wp-admin/includes/class-walker-nav-menu-edit.php @@ -118,7 +118,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {