Make WordPress Core

Changeset 31604


Ignore:
Timestamp:
03/03/2015 09:13:37 PM (12 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.