Make WordPress Core

Changeset 31604


Ignore:
Timestamp:
03/03/2015 09:13:37 PM (10 years ago)
Author:
helen
Message:

Nav menus: Better JS performance on initial load of edit screen.

The accessibility helpers previously processed all items when editing a menu, which was quite slow to the point of being unresponsive for large menus. They now only process items when they are expanded or a user comes near them in some way, such as hover or focus.

Also simplifies a redundant set of click event handlers down to one, which further enhances performance.

props atimmer, sevenspark.
fixes #25698.

Location:
trunk/src/wp-admin
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/nav-menu.php

    r30982 r31604  
    187187                    <label>
    188188                        <span><?php _e( 'Move' ); ?></span>
    189                         <a href="#" class="menus-move-up"><?php _e( 'Up one' ); ?></a>
    190                         <a href="#" class="menus-move-down"><?php _e( 'Down one' ); ?></a>
    191                         <a href="#" class="menus-move-left"></a>
    192                         <a href="#" class="menus-move-right"></a>
    193                         <a href="#" class="menus-move-top"><?php _e( 'To the top' ); ?></a>
     189                        <a href="#" class="menus-move menus-move-up" data-dir="up"><?php _e( 'Up one' ); ?></a>
     190                        <a href="#" class="menus-move menus-move-down" data-dir="down"><?php _e( 'Down one' ); ?></a>
     191                        <a href="#" class="menus-move menus-move-left" data-dir="left"></a>
     192                        <a href="#" class="menus-move menus-move-right" data-dir="right"></a>
     193                        <a href="#" class="menus-move menus-move-top" data-dir="top"><?php _e( 'To the top' ); ?></a>
    194194                    </label>
    195195                </p>
  • trunk/src/wp-admin/js/nav-menu.js

    r31320 r31604  
    387387            api.refreshAdvancedAccessibility();
    388388
    389             // Events
    390             menu.on( 'click', '.menus-move-up', function ( e ) {
    391                 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'up' );
     389            // Refresh the accessibility when the user comes close to the item in any way
     390            menu.on( 'mouseenter.refreshAccessibility focus.refreshAccessibility touchstart.refreshAccessibility' , '.menu-item' , function(){
     391                api.refreshAdvancedAccessibilityOfItem( $( this ).find( '.item-edit' ) );
     392            } );
     393
     394            // We have to update on click aswell because we might hover first, change the item and then click.
     395            menu.on( 'click', '.item-edit', function() {
     396                api.refreshAdvancedAccessibilityOfItem( $( this ) );
     397            } );
     398
     399            // Links for moving items
     400            menu.on( 'click', '.menus-move', function ( e ) {
     401                var $this = $( this ),
     402                    dir = $this.data( 'dir' );
     403
     404                if ( 'undefined' !== typeof dir ) {
     405                    api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), dir );
     406                }
    392407                e.preventDefault();
    393408            });
    394             menu.on( 'click', '.menus-move-down', function ( e ) {
    395                 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'down' );
    396                 e.preventDefault();
    397             });
    398             menu.on( 'click', '.menus-move-top', function ( e ) {
    399                 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'top' );
    400                 e.preventDefault();
    401             });
    402             menu.on( 'click', '.menus-move-left', function ( e ) {
    403                 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'left' );
    404                 e.preventDefault();
    405             });
    406             menu.on( 'click', '.menus-move-right', function ( e ) {
    407                 api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'right' );
    408                 e.preventDefault();
    409             });
    410         },
    411 
     409        },
     410
     411        /**
     412         * refreshAdvancedAccessibilityOfItem( [itemToRefresh] )
     413         *
     414         * Refreshes advanced accessibility buttons for one menu item.
     415         * Shows or hides buttons based on the location of the menu item.
     416         *
     417         * @param  {object} itemToRefresh The menu item that might need it's advanced accessibility buttons refreshed
     418         */
     419        refreshAdvancedAccessibilityOfItem : function( itemToRefresh ) {
     420
     421            // Only refresh accessibility when necessary
     422            if ( true !== $( itemToRefresh ).data( 'needs_accessibility_refresh' ) ) {
     423                return;
     424            }
     425
     426            var thisLink, thisLinkText, primaryItems, itemPosition, title,
     427                parentItem, parentItemId, parentItemName, subItems,
     428                $this = $( itemToRefresh ),
     429                menuItem = $this.closest( 'li.menu-item' ).first(),
     430                depth = menuItem.menuItemDepth(),
     431                isPrimaryMenuItem = ( 0 === depth ),
     432                itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
     433                position = parseInt( menuItem.index(), 10 ),
     434                prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1, 10 ),
     435                prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
     436                prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
     437                totalMenuItems = $('#menu-to-edit li').length,
     438                hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
     439
     440                menuItem.find( '.field-move' ).toggle( totalMenuItems > 1 );
     441
     442            // Where can they move this menu item?
     443            if ( 0 !== position ) {
     444                thisLink = menuItem.find( '.menus-move-up' );
     445                thisLink.prop( 'title', menus.moveUp ).css( 'display', 'inline' );
     446            }
     447
     448            if ( 0 !== position && isPrimaryMenuItem ) {
     449                thisLink = menuItem.find( '.menus-move-top' );
     450                thisLink.prop( 'title', menus.moveToTop ).css( 'display', 'inline' );
     451            }
     452
     453            if ( position + 1 !== totalMenuItems && 0 !== position ) {
     454                thisLink = menuItem.find( '.menus-move-down' );
     455                thisLink.prop( 'title', menus.moveDown ).css( 'display', 'inline' );
     456            }
     457
     458            if ( 0 === position && 0 !== hasSameDepthSibling ) {
     459                thisLink = menuItem.find( '.menus-move-down' );
     460                thisLink.prop( 'title', menus.moveDown ).css( 'display', 'inline' );
     461            }
     462
     463            if ( ! isPrimaryMenuItem ) {
     464                thisLink = menuItem.find( '.menus-move-left' ),
     465                thisLinkText = menus.outFrom.replace( '%s', prevItemNameLeft );
     466                thisLink.prop( 'title', menus.moveOutFrom.replace( '%s', prevItemNameLeft ) ).html( thisLinkText ).css( 'display', 'inline' );
     467            }
     468
     469            if ( 0 !== position ) {
     470                if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
     471                    thisLink = menuItem.find( '.menus-move-right' ),
     472                    thisLinkText = menus.under.replace( '%s', prevItemNameRight );
     473                    thisLink.prop( 'title', menus.moveUnder.replace( '%s', prevItemNameRight ) ).html( thisLinkText ).css( 'display', 'inline' );
     474                }
     475            }
     476
     477            if ( isPrimaryMenuItem ) {
     478                primaryItems = $( '.menu-item-depth-0' ),
     479                itemPosition = primaryItems.index( menuItem ) + 1,
     480                totalMenuItems = primaryItems.length,
     481
     482                // String together help text for primary menu items
     483                title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems );
     484            } else {
     485                parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
     486                parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
     487                parentItemName = parentItem.find( '.menu-item-title' ).text(),
     488                subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
     489                itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1;
     490
     491                // String together help text for sub menu items
     492                title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName );
     493            }
     494
     495            $this.prop('title', title).html( title );
     496
     497            // Mark this item's accessibility as refreshed
     498            $this.data( 'needs_accessibility_refresh', false );
     499        },
     500
     501        /**
     502         * refreshAdvancedAccessibility
     503         *
     504         * Hides all advanced accessibility buttons and marks them for refreshing.
     505         */
    412506        refreshAdvancedAccessibility : function() {
    413507
    414508            // Hide all links by default
    415             $( '.menu-item-settings .field-move a' ).css( 'display', 'none' );
    416 
    417             $( '.item-edit' ).each( function() {
    418                 var thisLink, thisLinkText, primaryItems, itemPosition, title,
    419                     parentItem, parentItemId, parentItemName, subItems,
    420                     $this = $(this),
    421                     menuItem = $this.closest( 'li.menu-item' ).first(),
    422                     depth = menuItem.menuItemDepth(),
    423                     isPrimaryMenuItem = ( 0 === depth ),
    424                     itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
    425                     position = parseInt( menuItem.index(), 10 ),
    426                     prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1, 10 ),
    427                     prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
    428                     prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
    429                     totalMenuItems = $('#menu-to-edit li').length,
    430                     hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
    431 
    432                 menuItem.find( '.field-move' ).toggle( totalMenuItems > 1 );
    433 
    434                 // Where can they move this menu item?
    435                 if ( 0 !== position ) {
    436                     thisLink = menuItem.find( '.menus-move-up' );
    437                     thisLink.prop( 'title', menus.moveUp ).css( 'display', 'inline' );
    438                 }
    439 
    440                 if ( 0 !== position && isPrimaryMenuItem ) {
    441                     thisLink = menuItem.find( '.menus-move-top' );
    442                     thisLink.prop( 'title', menus.moveToTop ).css( 'display', 'inline' );
    443                 }
    444 
    445                 if ( position + 1 !== totalMenuItems && 0 !== position ) {
    446                     thisLink = menuItem.find( '.menus-move-down' );
    447                     thisLink.prop( 'title', menus.moveDown ).css( 'display', 'inline' );
    448                 }
    449 
    450                 if ( 0 === position && 0 !== hasSameDepthSibling ) {
    451                     thisLink = menuItem.find( '.menus-move-down' );
    452                     thisLink.prop( 'title', menus.moveDown ).css( 'display', 'inline' );
    453                 }
    454 
    455                 if ( ! isPrimaryMenuItem ) {
    456                     thisLink = menuItem.find( '.menus-move-left' ),
    457                     thisLinkText = menus.outFrom.replace( '%s', prevItemNameLeft );
    458                     thisLink.prop( 'title', menus.moveOutFrom.replace( '%s', prevItemNameLeft ) ).html( thisLinkText ).css( 'display', 'inline' );
    459                 }
    460 
    461                 if ( 0 !== position ) {
    462                     if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
    463                         thisLink = menuItem.find( '.menus-move-right' ),
    464                         thisLinkText = menus.under.replace( '%s', prevItemNameRight );
    465                         thisLink.prop( 'title', menus.moveUnder.replace( '%s', prevItemNameRight ) ).html( thisLinkText ).css( 'display', 'inline' );
    466                     }
    467                 }
    468 
    469                 if ( isPrimaryMenuItem ) {
    470                     primaryItems = $( '.menu-item-depth-0' ),
    471                     itemPosition = primaryItems.index( menuItem ) + 1,
    472                     totalMenuItems = primaryItems.length,
    473 
    474                     // String together help text for primary menu items
    475                     title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems );
    476                 } else {
    477                     parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
    478                     parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
    479                     parentItemName = parentItem.find( '.menu-item-title' ).text(),
    480                     subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
    481                     itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1;
    482 
    483                     // String together help text for sub menu items
    484                     title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName );
    485                 }
    486 
    487                 $this.prop('title', title).html( title );
    488             });
     509            $( '.menu-item-settings .field-move a' ).hide();
     510
     511            // Mark all menu items as unprocessed
     512            $( '.item-edit' ).data( 'needs_accessibility_refresh', true );
     513
     514            // All open items have to be refreshed or they will show no links
     515            $( '.menu-item-edit-active .item-edit' ).each( function() {
     516                api.refreshAdvancedAccessibilityOfItem( this );
     517            } );
    489518        },
    490519
Note: See TracChangeset for help on using the changeset viewer.