Make WordPress Core

Changeset 46872


Ignore:
Timestamp:
12/10/2019 01:01:35 AM (5 years ago)
Author:
azaozz
Message:

Fix the admin toolbar js when jQuery is not present and replace the jQuery based hoverIntent.js with a native implementation. Introduces the "hoverintent" (no dependencies) package.

Props dinhtungdu, audrasjb, azaozz.
Fixes #47069.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Gruntfile.js

    r46638 r46872  
    163163                        [ WORKING_DIR + 'wp-includes/js/clipboard.js' ]: [ './node_modules/clipboard/dist/clipboard.js' ],
    164164                        [ WORKING_DIR + 'wp-includes/js/hoverIntent.js' ]: [ './node_modules/jquery-hoverintent/jquery.hoverIntent.js' ],
     165
     166                        // Renamed to avoid conflict with jQuery hoverIntent.min.js (after minifying)
     167                        [ WORKING_DIR + 'wp-includes/js/hoverintent-js.min.js' ]: [ './node_modules/hoverintent/dist/hoverintent.min.js' ],
    165168                        [ WORKING_DIR + 'wp-includes/js/imagesloaded.min.js' ]: [ './node_modules/imagesloaded/imagesloaded.pkgd.min.js' ],
    166169                        [ WORKING_DIR + 'wp-includes/js/jquery/jquery-migrate.js' ]: [ './node_modules/jquery-migrate/dist/jquery-migrate.js' ],
  • trunk/package-lock.json

    r46870 r46872  
    1321813218            }
    1321913219        },
     13220        "hoverintent": {
     13221            "version": "2.2.1",
     13222            "resolved": "https://registry.npmjs.org/hoverintent/-/hoverintent-2.2.1.tgz",
     13223            "integrity": "sha512-VyU54L1xW5rSqpsv/LJ6ecymGXsXXeGs9iVEKot4kKBCq5UodSAuy3DqX686LZxEpaMEfeCHPu4LndsMX5Q9eQ=="
     13224        },
    1322013225        "jquery-hoverintent": {
    1322113226            "version": "1.8.3",
  • trunk/package.json

    r46860 r46872  
    121121        "jquery-color": "https://github.com/jquery/jquery-color/archive/2.1.2.tar.gz",
    122122        "jquery-form": "4.2.1",
     123        "jquery-ui": "https://github.com/jquery/jquery-ui/archive/1.11.4.tar.gz",
    123124        "jquery-hoverintent": "1.8.3",
    124         "jquery-ui": "https://github.com/jquery/jquery-ui/archive/1.11.4.tar.gz",
     125        "hoverintent": "2.2.1",
    125126        "lodash": "4.17.15",
    126127        "masonry-layout": "3.3.2",
  • trunk/src/js/_enqueues/lib/admin-bar.js

    r43556 r46872  
    22 * @output wp-includes/js/admin-bar.js
    33 */
    4 
    5 /* jshint loopfunc: true */
    6 // use jQuery and hoverIntent if loaded
    7 if ( typeof(jQuery) != 'undefined' ) {
    8     if ( typeof(jQuery.fn.hoverIntent) == 'undefined' ) {
    9         /* jshint ignore:start */
    10         // hoverIntent v1.8.1 - Copy of wp-includes/js/hoverIntent.min.js
    11         !function(a){a.fn.hoverIntent=function(b,c,d){var e={interval:100,sensitivity:6,timeout:0};e="object"==typeof b?a.extend(e,b):a.isFunction(c)?a.extend(e,{over:b,out:c,selector:d}):a.extend(e,{over:b,out:b,selector:c});var f,g,h,i,j=function(a){f=a.pageX,g=a.pageY},k=function(b,c){return c.hoverIntent_t=clearTimeout(c.hoverIntent_t),Math.sqrt((h-f)*(h-f)+(i-g)*(i-g))<e.sensitivity?(a(c).off("mousemove.hoverIntent",j),c.hoverIntent_s=!0,e.over.apply(c,[b])):(h=f,i=g,c.hoverIntent_t=setTimeout(function(){k(b,c)},e.interval),void 0)},l=function(a,b){return b.hoverIntent_t=clearTimeout(b.hoverIntent_t),b.hoverIntent_s=!1,e.out.apply(b,[a])},m=function(b){var c=a.extend({},b),d=this;d.hoverIntent_t&&(d.hoverIntent_t=clearTimeout(d.hoverIntent_t)),"mouseenter"===b.type?(h=c.pageX,i=c.pageY,a(d).on("mousemove.hoverIntent",j),d.hoverIntent_s||(d.hoverIntent_t=setTimeout(function(){k(c,d)},e.interval))):(a(d).off("mousemove.hoverIntent",j),d.hoverIntent_s&&(d.hoverIntent_t=setTimeout(function(){l(c,d)},e.timeout)))};return this.on({"mouseenter.hoverIntent":m,"mouseleave.hoverIntent":m},e.selector)}}(jQuery);
    12         /* jshint ignore:end */
    13     }
    14     jQuery(document).ready(function($){
    15         var adminbar = $('#wpadminbar'), refresh, touchOpen, touchClose, disableHoverIntent = false;
    16 
    17         /**
    18          * Forces the browser to refresh the tabbing index.
    19          *
    20          * @since 3.3.0
    21          *
    22          * @param {number}      i  The index of the HTML element to remove the tab index
    23          *                         from. This parameter is necessary because we use this
    24          *                         function in .each calls.
    25          * @param {HTMLElement} el The HTML element to remove the tab index from.
    26          *
    27          * @return {void}
    28          */
    29         refresh = function(i, el){
    30             var node = $(el), tab = node.attr('tabindex');
    31             if ( tab )
    32                 node.attr('tabindex', '0').attr('tabindex', tab);
    33         };
    34 
    35         /**
    36          * Adds or removes the hover class on touch.
    37          *
    38          * @since 3.5.0
    39          *
    40          * @param {boolean} unbind If true removes the wp-mobile-hover class.
    41          *
    42          * @return {void}
    43          */
    44         touchOpen = function(unbind) {
    45             adminbar.find('li.menupop').on('click.wp-mobile-hover', function(e) {
    46                 var el = $(this);
    47 
    48                 if ( el.parent().is('#wp-admin-bar-root-default') && !el.hasClass('hover') ) {
    49                     e.preventDefault();
    50                     adminbar.find('li.menupop.hover').removeClass('hover');
    51                     el.addClass('hover');
    52                 } else if ( !el.hasClass('hover') ) {
    53                     e.stopPropagation();
    54                     e.preventDefault();
    55                     el.addClass('hover');
    56                 } else if ( ! $( e.target ).closest( 'div' ).hasClass( 'ab-sub-wrapper' ) ) {
    57                     // We're dealing with an already-touch-opened menu genericon (we know el.hasClass('hover')),
    58                     // so close it on a second tap and prevent propag and defaults. See #29906
    59                     e.stopPropagation();
    60                     e.preventDefault();
    61                     el.removeClass('hover');
     4/**
     5 * Admin bar with Vanilla JS, no external dependencies.
     6 *
     7 * @param {Object} document  The document object.
     8 * @param {Object} window    The window object.
     9 * @param {Object} navigator The navigator object.
     10 *
     11 * @return {void}
     12 */
     13( function( document, window, navigator ) {
     14    document.addEventListener( 'DOMContentLoaded', function() {
     15        var adminBar = document.getElementById( 'wpadminbar' ),
     16            topMenuItems = adminBar.querySelectorAll( 'li.menupop' ),
     17            allMenuItems = adminBar.querySelectorAll( '.ab-item' ),
     18            adminBarLogout = document.getElementById( 'wp-admin-bar-logout' ),
     19            adminBarSearchForm = document.getElementById( 'adminbarsearch' ),
     20            shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' ),
     21            skipLink = adminBar.querySelector( '.screen-reader-shortcut' ),
     22            mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click',
     23            adminBarSearchInput,
     24            i;
     25
     26        /**
     27         * Remove nojs class after the DOM is loaded.
     28         */
     29        adminBar.classList.remove( 'nojs' );
     30
     31        if ( 'ontouchstart' in window ) {
     32            /**
     33             * Remove hover class when the user touches outside the menu items.
     34             */
     35            document.body.addEventListener( mobileEvent, function( e ) {
     36                if ( ! getClosest( e.target, 'li.menupop' ) ) {
     37                    removeAllHoverClass( topMenuItems );
    6238                }
    63 
    64                 if ( unbind ) {
    65                     $('li.menupop').off('click.wp-mobile-hover');
    66                     disableHoverIntent = false;
     39            } );
     40
     41            /**
     42             * Add listener for menu items to toggle hover class by touches.
     43             * Remove the callback later for better performance.
     44             */
     45            adminBar.addEventListener( 'touchstart', function bindMobileEvents() {
     46                for ( var i = 0; i < topMenuItems.length; i++ ) {
     47                    topMenuItems[i].addEventListener( 'click', mobileHover.bind( null, topMenuItems ) );
    6748                }
    68             });
    69         };
    70 
    71         /**
    72          * Removes the hover class if clicked or touched outside the admin bar.
    73          *
    74          * @since 3.5.0
    75          *
    76          * @return {void}
    77          */
    78         touchClose = function() {
    79             var mobileEvent = /Mobile\/.+Safari/.test(navigator.userAgent) ? 'touchstart' : 'click';
    80             // close any open drop-downs when the click/touch is not on the toolbar
    81             $(document.body).on( mobileEvent+'.wp-mobile-hover', function(e) {
    82                 if ( !$(e.target).closest('#wpadminbar').length )
    83                     adminbar.find('li.menupop.hover').removeClass('hover');
    84             });
    85         };
    86 
    87         adminbar.removeClass('nojq').removeClass('nojs');
    88 
    89         // If clicked on the adminbar add the hoverclass, if clicked outside it remove
    90         // it.
    91         if ( 'ontouchstart' in window ) {
    92             adminbar.on('touchstart', function(){
    93                 touchOpen(true);
    94                 disableHoverIntent = true;
    95             });
    96             touchClose();
    97         } else if ( /IEMobile\/[1-9]/.test(navigator.userAgent) ) {
    98             touchOpen();
    99             touchClose();
    100         }
    101 
    102         // Adds or removes the hover class based on the hover intent.
    103         adminbar.find('li.menupop').hoverIntent({
    104             over: function() {
    105                 if ( disableHoverIntent )
    106                     return;
    107 
    108                 $(this).addClass('hover');
    109             },
    110             out: function() {
    111                 if ( disableHoverIntent )
    112                     return;
    113 
    114                 $(this).removeClass('hover');
    115             },
    116             timeout: 180,
    117             sensitivity: 7,
    118             interval: 100
    119         });
    120 
    121         // Prevents the toolbar from covering up content when a hash is present in the
    122         // URL.
    123         if ( window.location.hash )
     49
     50                adminBar.removeEventListener( 'touchstart', bindMobileEvents );
     51            } );
     52        }
     53
     54        /**
     55         * Scroll page to top when clicking on the admin bar.
     56         */
     57        adminBar.addEventListener( 'click', scrollToTop );
     58
     59        for ( i = 0; i < topMenuItems.length; i++ ) {
     60            /**
     61             * Adds or removes the hover class based on the hover intent.
     62             */
     63            hoverintent(
     64                topMenuItems[i],
     65                addHoverClass.bind( null, topMenuItems[i] ),
     66                removeHoverClass.bind( null, topMenuItems[i] )
     67            ).options( {
     68                timeout: 180,
     69            } );
     70
     71            /**
     72             * Toggle hover class if the enter key is pressed.
     73             */
     74            topMenuItems[i].addEventListener( 'keydown', toggleHoverIfEnter );
     75        }
     76
     77        /**
     78         * Remove hover class if the escape key is pressed.
     79         */
     80        for ( i = 0; i < allMenuItems.length; i++ ) {
     81            allMenuItems[i].addEventListener( 'keydown', removeHoverIfEscape );
     82        }
     83
     84        if ( adminBarSearchForm ) {
     85            adminBarSearchInput = document.getElementById( 'adminbar-search' );
     86
     87            /**
     88             * Adds the adminbar-focused class on focus.
     89             */
     90            adminBarSearchInput.addEventListener( 'focus', function() {
     91                adminBarSearchForm.classList.add( 'adminbar-focused' );
     92            } );
     93
     94            /**
     95             * Removes the adminbar-focused class on blur.
     96             */
     97            adminBarSearchInput.addEventListener( 'blur', function() {
     98                adminBarSearchForm.classList.remove( 'adminbar-focused' );
     99            } );
     100        }
     101
     102        /**
     103         * Focus the target of skip link after pressing Enter.
     104         */
     105        skipLink.addEventListener( 'keydown', focusTargetAfterEnter );
     106
     107        if ( shortlink ) {
     108            shortlink.addEventListener( 'click', clickShortlink );
     109        }
     110
     111        /**
     112         * Prevents the toolbar from covering up content when a hash is present
     113         * in the URL.
     114         */
     115        if ( window.location.hash ) {
    124116            window.scrollBy( 0, -32 );
    125 
    126         /**
    127          * Handles the selected state of the Shortlink link.
    128          *
    129          * When the input is visible the link should be selected, when the input is
    130          * unfocused the link should be unselected.
    131          *
    132          * @param {Object} e The click event.
    133          *
    134          * @return {void}
    135          **/
    136         $('#wp-admin-bar-get-shortlink').click(function(e){
    137             e.preventDefault();
    138             $(this).addClass('selected').children('.shortlink-input').blur(function(){
    139                 $(this).parents('#wp-admin-bar-get-shortlink').removeClass('selected');
    140             }).focus().select();
    141         });
    142 
    143         /**
    144          * Removes the hoverclass if the enter key is pressed.
    145          *
    146          * Makes sure the tab index is refreshed by refreshing each ab-item
    147          * and its children.
    148          *
    149          * @param {Object} e The keydown event.
    150          *
    151          * @return {void}
    152          */
    153         $('#wpadminbar li.menupop > .ab-item').bind('keydown.adminbar', function(e){
    154             // Key code 13 is the enter key.
    155             if ( e.which != 13 )
    156                 return;
    157 
    158             var target = $(e.target),
    159                 wrap = target.closest('.ab-sub-wrapper'),
    160                 parentHasHover = target.parent().hasClass('hover');
    161 
    162             e.stopPropagation();
    163             e.preventDefault();
    164 
    165             if ( !wrap.length )
    166                 wrap = $('#wpadminbar .quicklinks');
    167 
    168             wrap.find('.menupop').removeClass('hover');
    169 
    170             if ( ! parentHasHover ) {
    171                 target.parent().toggleClass('hover');
    172             }
    173 
    174             target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh);
    175         }).each(refresh);
    176 
    177         /**
    178          * Removes the hover class when the escape key is pressed.
    179          *
    180          * Makes sure the tab index is refreshed by refreshing each ab-item
    181          * and its children.
    182          *
    183          * @param {Object} e The keydown event.
    184          *
    185          * @return {void}
    186          */
    187         $('#wpadminbar .ab-item').bind('keydown.adminbar', function(e){
    188             // Key code 27 is the escape key.
    189             if ( e.which != 27 )
    190                 return;
    191 
    192             var target = $(e.target);
    193 
    194             e.stopPropagation();
    195             e.preventDefault();
    196 
    197             target.closest('.hover').removeClass('hover').children('.ab-item').focus();
    198             target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh);
    199         });
    200 
    201         /**
    202          * Scrolls to top of page by clicking the adminbar.
    203          *
    204          * @param {Object} e The click event.
    205          *
    206          * @return {void}
    207          */
    208         adminbar.click( function(e) {
    209             if ( e.target.id != 'wpadminbar' && e.target.id != 'wp-admin-bar-top-secondary' ) {
    210                 return;
    211             }
    212 
    213             adminbar.find( 'li.menupop.hover' ).removeClass( 'hover' );
    214             $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' );
    215             e.preventDefault();
    216         });
    217 
    218         /**
    219          * Sets the focus on an element with a href attribute.
    220          *
    221          * The timeout is used to fix a focus bug in WebKit.
    222          *
    223          * @param {Object} e The keydown event.
    224          *
    225          * @return {void}
    226          */
    227         $('.screen-reader-shortcut').keydown( function(e) {
    228             var id, ua;
    229 
    230             if ( 13 != e.which )
    231                 return;
    232 
    233             id = $( this ).attr( 'href' );
    234 
    235             ua = navigator.userAgent.toLowerCase();
    236 
    237             if ( ua.indexOf('applewebkit') != -1 && id && id.charAt(0) == '#' ) {
    238                 setTimeout(function () {
    239                     $(id).focus();
    240                 }, 100);
    241             }
    242         });
    243 
    244         $( '#adminbar-search' ).on({
    245             /**
    246              * Adds the adminbar-focused class on focus.
    247              *
    248              * @return {void}
    249              */
    250             focus: function() {
    251                 $( '#adminbarsearch' ).addClass( 'adminbar-focused' );
    252             /**
    253              * Removes the adminbar-focused class on blur.
    254              *
    255              * @return {void}
    256              */
    257             }, blur: function() {
    258                 $( '#adminbarsearch' ).removeClass( 'adminbar-focused' );
    259             }
    260         } );
    261 
    262         if ( 'sessionStorage' in window ) {
    263             /**
    264              * Empties sessionStorage on logging out.
    265              *
    266              * @return {void}
    267              */
    268             $('#wp-admin-bar-logout a').click( function() {
    269                 try {
    270                     for ( var key in sessionStorage ) {
    271                         if ( key.indexOf('wp-autosave-') != -1 )
    272                             sessionStorage.removeItem(key);
    273                     }
    274                 } catch(e) {}
    275             });
    276         }
    277 
     117        }
     118
     119        /**
     120         * Add no-font-face class to body if needed.
     121         */
    278122        if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 &&
    279123            /Android (1.0|1.1|1.5|1.6|2.0|2.1)|Nokia|Opera Mini|w(eb)?OSBrowser|webOS|UCWEB|Windows Phone OS 7|XBLWP7|ZuneWP7|MSIE 7/.test( navigator.userAgent ) ) {
    280 
    281124            document.body.className += ' no-font-face';
    282125        }
    283     });
    284 } else {
    285     /**
    286      * Wrapper function for the adminbar that's used if jQuery isn't available.
    287      *
    288      * @param {Object} d The document object.
    289      * @param {Object} w The window object.
    290      *
    291      * @return {void}
    292      */
    293     (function(d, w) {
    294         /**
    295          * Adds an event listener to an object.
    296          *
    297          * @since 3.1.0
    298          *
    299          * @param {Object}   obj  The object to add the event listener to.
    300          * @param {string}   type The type of event.
    301          * @param {function} fn   The function to bind to the event listener.
    302          *
    303          * @return {void}
    304          */
    305         var addEvent = function( obj, type, fn ) {
    306             if ( obj && typeof obj.addEventListener === 'function' ) {
    307                 obj.addEventListener( type, fn, false );
    308             } else if ( obj && typeof obj.attachEvent === 'function' ) {
    309                 obj.attachEvent( 'on' + type, function() {
    310                     return fn.call( obj, window.event );
    311                 } );
    312             }
    313         },
    314 
    315         aB, hc = new RegExp('\\bhover\\b', 'g'), q = [],
    316         rselected = new RegExp('\\bselected\\b', 'g'),
    317 
    318         /**
    319          * Gets the timeout ID of the given element.
    320          *
    321          * @since 3.1.0
    322          *
    323          * @param {HTMLElement} el The HTML element.
    324          *
    325          * @return {number|boolean} The ID value of the timer that is set or false.
    326          */
    327         getTOID = function(el) {
    328             var i = q.length;
    329             while ( i-- ) {
    330                 if ( q[i] && el == q[i][1] )
    331                     return q[i][0];
    332             }
    333             return false;
    334         },
    335 
    336         /**
    337          * Adds the hoverclass to menu items.
    338          *
    339          * @since 3.1.0
    340          *
    341          * @param {HTMLElement} t The HTML element.
    342          *
    343          * @return {void}
    344          */
    345         addHoverClass = function(t) {
    346             var i, id, inA, hovering, ul, li,
    347                 ancestors = [],
    348                 ancestorLength = 0;
    349 
    350             // aB is adminbar. d is document.
    351             while ( t && t != aB && t != d ) {
    352                 if ( 'LI' == t.nodeName.toUpperCase() ) {
    353                     ancestors[ ancestors.length ] = t;
    354                     id = getTOID(t);
    355                     if ( id )
    356                         clearTimeout( id );
    357                     t.className = t.className ? ( t.className.replace(hc, '') + ' hover' ) : 'hover';
    358                     hovering = t;
    359                 }
    360                 t = t.parentNode;
    361             }
    362 
    363             // Removes any selected classes.
    364             if ( hovering && hovering.parentNode ) {
    365                 ul = hovering.parentNode;
    366                 if ( ul && 'UL' == ul.nodeName.toUpperCase() ) {
    367                     i = ul.childNodes.length;
    368                     while ( i-- ) {
    369                         li = ul.childNodes[i];
    370                         if ( li != hovering )
    371                             li.className = li.className ? li.className.replace( rselected, '' ) : '';
     126
     127        /**
     128         * Clear sessionStorage on logging out.
     129         */
     130        adminBarLogout.addEventListener( 'click', emptySessionStorage );
     131    } );
     132
     133    /**
     134     * Remove hover class for top level menu item when escape is pressed.
     135     *
     136     * @since 5.3.0
     137     *
     138     * @param {Event} e The keydown event.
     139     */
     140    function removeHoverIfEscape( e ) {
     141        var wrapper;
     142
     143        if ( e.which != 27 ) {
     144            return;
     145        }
     146
     147        wrapper = getClosest( e.target, '.menupop' );
     148
     149        if ( ! wrapper ) {
     150            return;
     151        }
     152
     153        wrapper.querySelector( '.menupop > .ab-item' ).focus();
     154        removeHoverClass( wrapper );
     155    }
     156
     157    /**
     158     * Toggle hover class for top level menu item when enter is pressed.
     159     *
     160     * @since 5.3.0
     161     *
     162     * @param {Event} e The keydown event.
     163     */
     164    function toggleHoverIfEnter( e ) {
     165        var wrapper;
     166
     167        if ( e.which != 13 ) {
     168            return;
     169        }
     170
     171        if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
     172            return;
     173        }
     174
     175        wrapper = getClosest( e.target, '.menupop' );
     176
     177        if ( ! wrapper ) {
     178            return;
     179        }
     180
     181        e.preventDefault();
     182        if ( hasHoverClass( wrapper ) ) {
     183            removeHoverClass( wrapper );
     184        } else {
     185            addHoverClass( wrapper );
     186        }
     187    }
     188
     189    /**
     190     * Focus the target of skip link after pressing Enter.
     191     *
     192     * @since 5.3.0
     193     *
     194     * @param {Event} e The keydown event.
     195     */
     196    function focusTargetAfterEnter( e ) {
     197        var id, userAgent;
     198
     199        if ( 13 !== e.which ) {
     200            return;
     201        }
     202
     203        id = e.target.getAttribute( 'href' );
     204        userAgent = navigator.userAgent.toLowerCase();
     205
     206        if ( userAgent.indexOf( 'applewebkit' ) != -1 && id && id.charAt( 0 ) == '#' ) {
     207            setTimeout( function() {
     208                var target = document.getElementById( id.replace( '#', '' ) );
     209
     210                target.setAttribute( 'tabIndex', '0' );
     211                target.focus();
     212            }, 100 );
     213        }
     214    }
     215
     216    /**
     217     * Toogle hover class for mobile devices.
     218     *
     219     * @since 5.3.0
     220     *
     221     * @param {NodeList} topMenuItems All menu items.
     222     * @param {Event} e The click event.
     223     */
     224    function mobileHover( topMenuItems, e ) {
     225        var wrapper;
     226
     227        if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
     228            return;
     229        }
     230
     231        e.preventDefault();
     232
     233        wrapper = getClosest( e.target, '.menupop' );
     234
     235        if ( ! wrapper ) {
     236            return;
     237        }
     238
     239        if ( hasHoverClass( wrapper ) ) {
     240            removeHoverClass( wrapper );
     241        } else {
     242            removeAllHoverClass( topMenuItems );
     243            addHoverClass( wrapper );
     244        }
     245    }
     246
     247    /**
     248     * Handles the click on the Shortlink link in the adminbar.
     249     *
     250     * @since 3.1.0
     251     * @since 5.3.0 Use querySelector to clean up the function.
     252     *
     253     * @param {Event} e The click event.
     254     *
     255     * @return {boolean} Returns false to prevent default click behavior.
     256     */
     257    function clickShortlink( e ) {
     258        var wrapper = e.target.parentNode,
     259            input = wrapper.querySelector( '.shortlink-input' );
     260
     261        // IE doesn't support preventDefault, and does support returnValue
     262        if ( e.preventDefault ) {
     263            e.preventDefault();
     264        }
     265        e.returnValue = false;
     266
     267        wrapper.classList.add( 'selected' );
     268        input.focus();
     269        input.select();
     270        input.onblur = function() {
     271            wrapper.classList.remove( 'selected' );
     272        };
     273
     274        return false;
     275    }
     276
     277    /**
     278     * Clear sessionStorage on logging out.
     279     *
     280     * @since 5.3.0
     281     */
     282    function emptySessionStorage() {
     283        if ( 'sessionStorage' in window ) {
     284            try {
     285                for ( var key in sessionStorage ) {
     286                    if ( key.indexOf( 'wp-autosave-' ) != -1 ) {
     287                        sessionStorage.removeItem( key );
    372288                    }
    373289                }
     290            } catch ( e ) {}
     291        }
     292    }
     293
     294    /**
     295     * Check if menu item has hover class.
     296     *
     297     * @since 5.3.0
     298     *
     299     * @param {HTMLElement} item Menu item Element.
     300     */
     301    function hasHoverClass( item ) {
     302        return item.classList.contains( 'hover' );
     303    }
     304
     305    /**
     306     * Add hover class for menu item.
     307     *
     308     * @since 5.3.0
     309     *
     310     * @param {HTMLElement} item Menu item Element.
     311     */
     312    function addHoverClass( item ) {
     313        item.classList.add( 'hover' );
     314    }
     315
     316    /**
     317     * Remove hover class for menu item.
     318     *
     319     * @since 5.3.0
     320     *
     321     * @param {HTMLElement} item Menu item Element.
     322     */
     323    function removeHoverClass( item ) {
     324        item.classList.remove( 'hover' );
     325    }
     326
     327    /**
     328     * Remove hover class for all menu items.
     329     *
     330     * @since 5.3.0
     331     *
     332     * @param {NodeList} topMenuItems All menu items.
     333     */
     334    function removeAllHoverClass( topMenuItems ) {
     335        for ( var i = 0; i < topMenuItems.length; i++ ) {
     336            if ( hasHoverClass( topMenuItems[i] ) ) {
     337                removeHoverClass( topMenuItems[i] );
    374338            }
    375 
    376             // Removes the hover class for any objects not in the immediate element's ancestry.
    377             i = q.length;
    378             while ( i-- ) {
    379                 inA = false;
    380                 ancestorLength = ancestors.length;
    381                 while( ancestorLength-- ) {
    382                     if ( ancestors[ ancestorLength ] == q[i][1] )
    383                         inA = true;
    384                 }
    385 
    386                 if ( ! inA )
    387                     q[i][1].className = q[i][1].className ? q[i][1].className.replace(hc, '') : '';
     339        }
     340    }
     341
     342    /**
     343     * Scrolls to the top of the page.
     344     *
     345     * @since 3.4.0
     346     *
     347     * @param {Event} e The Click event.
     348     *
     349     * @return {void}
     350     */
     351    function scrollToTop( event ) {
     352        // Only scroll when clicking on the wpadminbar, not on menus or submenus.
     353        if (
     354            event.target &&
     355            event.target.id &&
     356            event.target.id != 'wpadminbar' &&
     357            event.target.id != 'wp-admin-bar-top-secondary'
     358        ) {
     359            return;
     360        }
     361
     362        try {
     363            window.scrollTo( {
     364                top: -32,
     365                left: 0,
     366                behavior: 'smooth'
     367            } );
     368        } catch ( er ) {
     369            window.scrollTo( 0, -32 );
     370        }
     371    }
     372
     373    /**
     374     * Get closest Element.
     375     *
     376     * @since 5.3.0
     377     *
     378     * @param {HTMLElement} el Element to get parent.
     379     * @param {string} selector CSS selector to match.
     380     */
     381    function getClosest( el, selector ) {
     382        if ( ! Element.prototype.matches ) {
     383            Element.prototype.matches =
     384                Element.prototype.matchesSelector ||
     385                Element.prototype.mozMatchesSelector ||
     386                Element.prototype.msMatchesSelector ||
     387                Element.prototype.oMatchesSelector ||
     388                Element.prototype.webkitMatchesSelector ||
     389                function( s ) {
     390                    var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ),
     391                        i = matches.length;
     392                    while ( --i >= 0 && matches.item( i ) !== this ) { }
     393                    return i > -1;
     394                };
     395        }
     396
     397        // Get the closest matching elent
     398        for ( ; el && el !== document; el = el.parentNode ) {
     399            if ( el.matches( selector ) ) {
     400                return el;
    388401            }
    389         },
    390 
    391         /**
    392          * Removes the hoverclass from menu items.
    393          *
    394          * @since 3.1.0
    395          *
    396          * @param {HTMLElement} t The HTML element.
    397          *
    398          * @return {void}
    399          */
    400         removeHoverClass = function(t) {
    401             while ( t && t != aB && t != d ) {
    402                 if ( 'LI' == t.nodeName.toUpperCase() ) {
    403                     (function(t) {
    404                         var to = setTimeout(function() {
    405                             t.className = t.className ? t.className.replace(hc, '') : '';
    406                         }, 500);
    407                         q[q.length] = [to, t];
    408                     })(t);
    409                 }
    410                 t = t.parentNode;
    411             }
    412         },
    413 
    414         /**
    415          * Handles the click on the Shortlink link in the adminbar.
    416          *
    417          * @since 3.1.0
    418          *
    419          * @param {Object} e The click event.
    420          *
    421          * @return {boolean} Returns false to prevent default click behavior.
    422          */
    423         clickShortlink = function(e) {
    424             var i, l, node,
    425                 t = e.target || e.srcElement;
    426 
    427             // Make t the shortlink menu item, or return.
    428             while ( true ) {
    429                 // Check if we've gone past the shortlink node,
    430                 // or if the user is clicking on the input.
    431                 if ( ! t || t == d || t == aB )
    432                     return;
    433                 // Check if we've found the shortlink node.
    434                 if ( t.id && t.id == 'wp-admin-bar-get-shortlink' )
    435                     break;
    436                 t = t.parentNode;
    437             }
    438 
    439             // IE doesn't support preventDefault, and does support returnValue
    440             if ( e.preventDefault )
    441                 e.preventDefault();
    442             e.returnValue = false;
    443 
    444             if ( -1 == t.className.indexOf('selected') )
    445                 t.className += ' selected';
    446 
    447             for ( i = 0, l = t.childNodes.length; i < l; i++ ) {
    448                 node = t.childNodes[i];
    449                 if ( node.className && -1 != node.className.indexOf('shortlink-input') ) {
    450                     node.focus();
    451                     node.select();
    452                     node.onblur = function() {
    453                         t.className = t.className ? t.className.replace( rselected, '' ) : '';
    454                     };
    455                     break;
    456                 }
    457             }
    458             return false;
    459         },
    460 
    461         /**
    462          * Scrolls to the top of the page.
    463          *
    464          * @since 3.4.0
    465          *
    466          * @param {HTMLElement} t The HTML element.
    467          *
    468          * @return {void}
    469          */
    470         scrollToTop = function(t) {
    471             var distance, speed, step, steps, timer, speed_step;
    472 
    473             // Ensure that the #wpadminbar was the target of the click.
    474             if ( t.id != 'wpadminbar' && t.id != 'wp-admin-bar-top-secondary' )
    475                 return;
    476 
    477             distance    = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
    478 
    479             if ( distance < 1 )
    480                 return;
    481 
    482             speed_step = distance > 800 ? 130 : 100;
    483             speed     = Math.min( 12, Math.round( distance / speed_step ) );
    484             step      = distance > 800 ? Math.round( distance / 30  ) : Math.round( distance / 20  );
    485             steps     = [];
    486             timer     = 0;
    487 
    488             // Animate scrolling to the top of the page by generating steps to
    489             // the top of the page and shifting to each step at a set interval.
    490             while ( distance ) {
    491                 distance -= step;
    492                 if ( distance < 0 )
    493                     distance = 0;
    494                 steps.push( distance );
    495 
    496                 setTimeout( function() {
    497                     window.scrollTo( 0, steps.shift() );
    498                 }, timer * speed );
    499 
    500                 timer++;
    501             }
    502         };
    503 
    504         addEvent(w, 'load', function() {
    505             aB = d.getElementById('wpadminbar');
    506 
    507             if ( d.body && aB ) {
    508                 d.body.appendChild( aB );
    509 
    510                 if ( aB.className )
    511                     aB.className = aB.className.replace(/nojs/, '');
    512 
    513                 addEvent(aB, 'mouseover', function(e) {
    514                     addHoverClass( e.target || e.srcElement );
    515                 });
    516 
    517                 addEvent(aB, 'mouseout', function(e) {
    518                     removeHoverClass( e.target || e.srcElement );
    519                 });
    520 
    521                 addEvent(aB, 'click', clickShortlink );
    522 
    523                 addEvent(aB, 'click', function(e) {
    524                     scrollToTop( e.target || e.srcElement );
    525                 });
    526 
    527                 addEvent( document.getElementById('wp-admin-bar-logout'), 'click', function() {
    528                     if ( 'sessionStorage' in window ) {
    529                         try {
    530                             for ( var key in sessionStorage ) {
    531                                 if ( key.indexOf('wp-autosave-') != -1 )
    532                                     sessionStorage.removeItem(key);
    533                             }
    534                         } catch(e) {}
    535                     }
    536                 });
    537             }
    538 
    539             if ( w.location.hash )
    540                 w.scrollBy(0,-32);
    541 
    542             if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 &&
    543                 /Android (1.0|1.1|1.5|1.6|2.0|2.1)|Nokia|Opera Mini|w(eb)?OSBrowser|webOS|UCWEB|Windows Phone OS 7|XBLWP7|ZuneWP7|MSIE 7/.test( navigator.userAgent ) ) {
    544 
    545                 document.body.className += ' no-font-face';
    546             }
    547         });
    548     })(document, window);
    549 
    550 }
     402        }
     403        return null;
     404    }
     405} )( document, window, navigator );
  • trunk/src/wp-includes/script-loader.php

    r46860 r46872  
    14911491    $scripts->add( 'user-suggest', "/wp-admin/js/user-suggest$suffix.js", array( 'jquery-ui-autocomplete' ), false, 1 );
    14921492
    1493     $scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array(), false, 1 );
     1493    $scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array( 'hoverintent-js' ), false, 1 );
    14941494
    14951495    $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
     
    15151515
    15161516    $scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array( 'jquery' ), '1.8.1', 1 );
     1517
     1518    // JS-only version of hoverintent (no dependencies).
     1519    $scripts->add( 'hoverintent-js', "/wp-includes/js/hoverintent-js.min.js", array(), '2.2.1', 1 );
    15171520
    15181521    $scripts->add( 'customize-base', "/wp-includes/js/customize-base$suffix.js", array( 'jquery', 'json2', 'underscore' ), false, 1 );
Note: See TracChangeset for help on using the changeset viewer.