WordPress.org

Make WordPress Core

Ticket #47069: 47069.12.diff

File 47069.12.diff, 15.5 KB (added by azaozz, 18 months ago)
  • src/js/_enqueues/lib/admin-bar.js

     
    1010 *
    1111 * @return {void}
    1212 */
    13 /* global hoverintent */
    1413( function( document, window, navigator ) {
    1514        document.addEventListener( 'DOMContentLoaded', function() {
    1615                var adminBar = document.getElementById( 'wpadminbar' ),
    17                         topMenuItems = adminBar.querySelectorAll( 'li.menupop' ),
    18                         allMenuItems = adminBar.querySelectorAll( '.ab-item' ),
    19                         adminBarLogout = document.getElementById( 'wp-admin-bar-logout' ),
    20                         adminBarSearchForm = document.getElementById( 'adminbarsearch' ),
    21                         shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' ),
    22                         skipLink = adminBar.querySelector( '.screen-reader-shortcut' ),
    23                         mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click',
     16                        topMenuItems,
     17                        allMenuItems,
     18                        adminBarLogout,
     19                        adminBarSearchForm,
     20                        shortlink,
     21                        skipLink,
     22                        mobileEvent,
     23                        fontFaceRegex,
    2424                        adminBarSearchInput,
    2525                        i;
    2626
    27                 /**
    28                  * Remove nojs class after the DOM is loaded.
    29                  */
    30                 adminBar.classList.remove( 'nojs' );
     27                if ( ! adminBar || ! ( 'querySelectorAll' in adminBar ) ) {
     28                        return;
     29                }
    3130
     31                topMenuItems = adminBar.querySelectorAll( 'li.menupop' );
     32                allMenuItems = adminBar.querySelectorAll( '.ab-item' );
     33                adminBarLogout = document.getElementById( 'wp-admin-bar-logout' );
     34                adminBarSearchForm = document.getElementById( 'adminbarsearch' );
     35                shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' );
     36                skipLink = adminBar.querySelector( '.screen-reader-shortcut' );
     37                mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click';
     38                fontFaceRegex = /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/;
     39
     40                // Remove nojs class after the DOM is loaded.
     41                removeClass( adminBar, 'nojs' );
     42
    3243                if ( 'ontouchstart' in window ) {
    33                         /**
    34                          * Remove hover class when the user touches outside the menu items.
    35                          */
     44                        // Remove hover class when the user touches outside the menu items.
    3645                        document.body.addEventListener( mobileEvent, function( e ) {
    3746                                if ( ! getClosest( e.target, 'li.menupop' ) ) {
    3847                                        removeAllHoverClass( topMenuItems );
     
    3948                                }
    4049                        } );
    4150
    42                         /**
    43                          * Add listener for menu items to toggle hover class by touches.
    44                          * Remove the callback later for better performance.
    45                          */
     51                        // Add listener for menu items to toggle hover class by touches.
     52                        // Remove the callback later for better performance.
    4653                        adminBar.addEventListener( 'touchstart', function bindMobileEvents() {
    4754                                for ( var i = 0; i < topMenuItems.length; i++ ) {
    4855                                        topMenuItems[i].addEventListener( 'click', mobileHover.bind( null, topMenuItems ) );
     
    5259                        } );
    5360                }
    5461
    55                 /**
    56                  * Scroll page to top when clicking on the admin bar.
    57                  */
     62                // Scroll page to top when clicking on the admin bar.
    5863                adminBar.addEventListener( 'click', scrollToTop );
    5964
    6065                for ( i = 0; i < topMenuItems.length; i++ ) {
    61                         /**
    62                          * Adds or removes the hover class based on the hover intent.
    63                          */
    64                         hoverintent(
     66                        // Adds or removes the hover class based on the hover intent.
     67                        window.hoverintent(
    6568                                topMenuItems[i],
    66                                 addHoverClass.bind( null, topMenuItems[i] ),
    67                                 removeHoverClass.bind( null, topMenuItems[i] )
     69                                addClass.bind( null, topMenuItems[i], 'hover' ),
     70                                removeClass.bind( null, topMenuItems[i], 'hover' )
    6871                        ).options( {
    6972                                timeout: 180
    7073                        } );
    7174
    72                         /**
    73                          * Toggle hover class if the enter key is pressed.
    74                          */
     75                        // Toggle hover class if the enter key is pressed.
    7576                        topMenuItems[i].addEventListener( 'keydown', toggleHoverIfEnter );
    7677                }
    7778
    78                 /**
    79                  * Remove hover class if the escape key is pressed.
    80                  */
     79                // Remove hover class if the escape key is pressed.
    8180                for ( i = 0; i < allMenuItems.length; i++ ) {
    8281                        allMenuItems[i].addEventListener( 'keydown', removeHoverIfEscape );
    8382                }
     
    8584                if ( adminBarSearchForm ) {
    8685                        adminBarSearchInput = document.getElementById( 'adminbar-search' );
    8786
    88                         /**
    89                          * Adds the adminbar-focused class on focus.
    90                          */
     87                        // Adds the adminbar-focused class on focus.
    9188                        adminBarSearchInput.addEventListener( 'focus', function() {
    92                                 adminBarSearchForm.classList.add( 'adminbar-focused' );
     89                                addClass( adminBarSearchForm, 'adminbar-focused' );
    9390                        } );
    9491
    95                         /**
    96                          * Removes the adminbar-focused class on blur.
    97                          */
     92                        // Removes the adminbar-focused class on blur.
    9893                        adminBarSearchInput.addEventListener( 'blur', function() {
    99                                 adminBarSearchForm.classList.remove( 'adminbar-focused' );
     94                                removeClass( adminBarSearchForm, 'adminbar-focused' );
    10095                        } );
    10196                }
    10297
    103                 /**
    104                  * Focus the target of skip link after pressing Enter.
    105                  */
    106                 skipLink.addEventListener( 'keydown', focusTargetAfterEnter );
     98                if ( skipLink ) {
     99                        // Focus the target of skip link after pressing Enter.
     100                        skipLink.addEventListener( 'keydown', focusTargetAfterEnter );
     101                }
    107102
    108103                if ( shortlink ) {
    109104                        shortlink.addEventListener( 'click', clickShortlink );
    110105                }
    111106
    112                 /**
    113                  * Prevents the toolbar from covering up content when a hash is present
    114                  * in the URL.
    115                  */
     107                // Prevents the toolbar from covering up content when a hash is present in the URL.
    116108                if ( window.location.hash ) {
    117109                        window.scrollBy( 0, -32 );
    118110                }
    119111
    120                 /**
    121                  * Add no-font-face class to body if needed.
    122                  */
    123                 if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 &&
    124                         /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 ) ) {
    125                         document.body.className += ' no-font-face';
     112                // Add no-font-face class to body if needed.
     113                if (
     114                        navigator.userAgent &&
     115                        fontFaceRegex.test( navigator.userAgent ) &&
     116                        ! hasClass( document.body, 'no-font-face' )
     117                ) {
     118                        addClass( document.body, 'no-font-face' );
    126119                }
    127120
    128                 /**
    129                  * Clear sessionStorage on logging out.
    130                  */
    131                 adminBarLogout.addEventListener( 'click', emptySessionStorage );
     121                // Clear sessionStorage on logging out.
     122                if ( adminBarLogout ) {
     123                        adminBarLogout.addEventListener( 'click', emptySessionStorage );
     124                }
    132125        } );
    133126
    134127        /**
     
    136129         *
    137130         * @since 5.3.0
    138131         *
    139          * @param {Event} e The keydown event.
     132         * @param {Event} event The keydown event.
    140133         */
    141         function removeHoverIfEscape( e ) {
     134        function removeHoverIfEscape( event ) {
    142135                var wrapper;
    143136
    144                 if ( e.which != 27 ) {
     137                if ( event.which !== 27 ) {
    145138                        return;
    146139                }
    147140
    148                 wrapper = getClosest( e.target, '.menupop' );
     141                wrapper = getClosest( event.target, '.menupop' );
    149142
    150143                if ( ! wrapper ) {
    151144                        return;
     
    152145                }
    153146
    154147                wrapper.querySelector( '.menupop > .ab-item' ).focus();
    155                 removeHoverClass( wrapper );
     148                removeClass( wrapper, 'hover' );
    156149        }
    157150
    158151        /**
     
    160153         *
    161154         * @since 5.3.0
    162155         *
    163          * @param {Event} e The keydown event.
     156         * @param {Event} event The keydown event.
    164157         */
    165         function toggleHoverIfEnter( e ) {
     158        function toggleHoverIfEnter( event ) {
    166159                var wrapper;
    167160
    168                 if ( e.which != 13 ) {
     161                if ( event.which !== 13 ) {
    169162                        return;
    170163                }
    171164
    172                 if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
     165                if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) {
    173166                        return;
    174167                }
    175168
    176                 wrapper = getClosest( e.target, '.menupop' );
     169                wrapper = getClosest( event.target, '.menupop' );
    177170
    178171                if ( ! wrapper ) {
    179172                        return;
    180173                }
    181174
    182                 e.preventDefault();
    183                 if ( hasHoverClass( wrapper ) ) {
    184                         removeHoverClass( wrapper );
     175                event.preventDefault();
     176
     177                if ( hasClass( wrapper, 'hover' ) ) {
     178                        removeClass( wrapper, 'hover' );
    185179                } else {
    186                         addHoverClass( wrapper );
     180                        addClass( wrapper, 'hover' );
    187181                }
    188182        }
    189183
     
    192186         *
    193187         * @since 5.3.0
    194188         *
    195          * @param {Event} e The keydown event.
     189         * @param {Event} event The keydown event.
    196190         */
    197         function focusTargetAfterEnter( e ) {
     191        function focusTargetAfterEnter( event ) {
    198192                var id, userAgent;
    199193
    200                 if ( 13 !==     e.which ) {
     194                if ( event.which !== 13 ) {
    201195                        return;
    202196                }
    203197
    204                 id = e.target.getAttribute( 'href' );
     198                id = event.target.getAttribute( 'href' );
    205199                userAgent = navigator.userAgent.toLowerCase();
    206200
    207                 if ( userAgent.indexOf( 'applewebkit' ) != -1 && id && id.charAt( 0 ) == '#' ) {
     201                if ( userAgent.indexOf( 'applewebkit' ) > -1 && id && id.charAt( 0 ) === '#' ) {
    208202                        setTimeout( function() {
    209203                                var target = document.getElementById( id.replace( '#', '' ) );
    210204
    211                                 target.setAttribute( 'tabIndex', '0' );
    212                                 target.focus();
     205                                if ( target ) {
     206                                        target.setAttribute( 'tabIndex', '0' );
     207                                        target.focus();
     208                                }
    213209                        }, 100 );
    214210                }
    215211        }
     
    220216         * @since 5.3.0
    221217         *
    222218         * @param {NodeList} topMenuItems All menu items.
    223          * @param {Event} e The click event.
     219         * @param {Event} event The click event.
    224220         */
    225         function mobileHover( topMenuItems, e ) {
     221        function mobileHover( topMenuItems, event ) {
    226222                var wrapper;
    227223
    228                 if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
     224                if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) {
    229225                        return;
    230226                }
    231227
    232                 e.preventDefault();
     228                event.preventDefault();
    233229
    234                 wrapper = getClosest( e.target, '.menupop' );
     230                wrapper = getClosest( event.target, '.menupop' );
    235231
    236232                if ( ! wrapper ) {
    237233                        return;
    238234                }
    239235
    240                 if ( hasHoverClass( wrapper ) ) {
    241                         removeHoverClass( wrapper );
     236                if ( hasClass( wrapper, 'hover' ) ) {
     237                        removeClass( wrapper, 'hover' );
    242238                } else {
    243239                        removeAllHoverClass( topMenuItems );
    244                         addHoverClass( wrapper );
     240                        addClass( wrapper, 'hover' );
    245241                }
    246242        }
    247243
     
    251247         * @since 3.1.0
    252248         * @since 5.3.0 Use querySelector to clean up the function.
    253249         *
    254          * @param {Event} e The click event.
    255          *
     250         * @param {Event} event The click event.
    256251         * @return {boolean} Returns false to prevent default click behavior.
    257252         */
    258         function clickShortlink( e ) {
    259                 var wrapper = e.target.parentNode,
     253        function clickShortlink( event ) {
     254                var wrapper = event.target.parentNode,
     255                        input;
     256
     257                if ( wrapper ) {
    260258                        input = wrapper.querySelector( '.shortlink-input' );
     259                }
    261260
    262                 // IE doesn't support preventDefault, and does support returnValue
    263                 if ( e.preventDefault ) {
    264                         e.preventDefault();
     261                if ( ! input ) {
     262                        return;
    265263                }
    266                 e.returnValue = false;
    267264
    268                 wrapper.classList.add( 'selected' );
     265                // (Old) IE doesn't support preventDefault, and does support returnValue
     266                if ( event.preventDefault ) {
     267                        event.preventDefault();
     268                }
     269
     270                event.returnValue = false;
     271
     272                addClass( wrapper, 'selected' );
     273
    269274                input.focus();
    270275                input.select();
    271276                input.onblur = function() {
    272                         wrapper.classList.remove( 'selected' );
     277                        removeClass( wrapper, 'selected' );
    273278                };
    274279
    275280                return false;
     
    284289                if ( 'sessionStorage' in window ) {
    285290                        try {
    286291                                for ( var key in sessionStorage ) {
    287                                         if ( key.indexOf( 'wp-autosave-' ) != -1 ) {
     292                                        if ( key.indexOf( 'wp-autosave-' ) > -1 ) {
    288293                                                sessionStorage.removeItem( key );
    289294                                        }
    290295                                }
    291                         } catch ( e ) {}
     296                        } catch ( er ) {}
    292297                }
    293298        }
    294299
     
    297302         *
    298303         * @since 5.3.0
    299304         *
    300          * @param {HTMLElement} item Menu item Element.
     305         * @param {HTMLElement} element The HTML element.
     306         * @param {String}      className The class name.
     307         * @return {bool} Whether the element has the className.
    301308         */
    302         function hasHoverClass( item ) {
    303                 return item.classList.contains( 'hover' );
     309        function hasClass( element, className ) {
     310                var classNames;
     311
     312                if ( element ) {
     313                        if ( element.classList && element.classList.contains ) {
     314                                return element.classList.contains( className );
     315                        } else if ( element.className ) {
     316                                classNames = element.className.split( ' ' );
     317                                return classNames.indexOf( className ) > -1;
     318                        }
     319                }
     320
     321                return false;
    304322        }
    305323
    306324        /**
    307          * Add hover class for menu item.
     325         * Add class to an element.
    308326         *
    309327         * @since 5.3.0
    310328         *
    311          * @param {HTMLElement} item Menu item Element.
     329         * @param {HTMLElement} element The HTML element.
     330         * @param {String}      className The class name.
    312331         */
    313         function addHoverClass( item ) {
    314                 item.classList.add( 'hover' );
     332        function addClass( element, className ) {
     333                if ( element ) {
     334                        if ( element.classList && element.classList.add ) {
     335                                element.classList.add( className );
     336                        } else if ( ! hasClass( element, className ) ) {
     337                                if ( element.className ) {
     338                                        element.className += ' ';
     339                                }
     340
     341                                element.className += className;
     342                        }
     343                }
    315344        }
    316345
    317346        /**
     
    319348         *
    320349         * @since 5.3.0
    321350         *
    322          * @param {HTMLElement} item Menu item Element.
     351         * @param {HTMLElement} element The HTML element.
     352         * @param {String}      className The class name.
    323353         */
    324         function removeHoverClass( item ) {
    325                 item.classList.remove( 'hover' );
     354        function removeClass( element, className ) {
     355                var testName,
     356                        classes;
     357
     358                if ( element && hasClass( element, className ) ) {
     359                        if ( element.classList && element.classList.remove ) {
     360                                element.classList.remove( className );
     361                        } else {
     362                                testName = ' ' + className + ' ';
     363                                classes = ' ' + element.className + ' ';
     364
     365                                while ( classes.indexOf( testName ) > -1 ) {
     366                                        classes = classes.replace( testName, '' );
     367                                }
     368
     369                                element.className = classes.replace( /^[\s]+|[\s]+$/g, '' );
     370                        }
     371                }
     372
    326373        }
    327374
    328375        /**
     
    333380         * @param {NodeList} topMenuItems All menu items.
    334381         */
    335382        function removeAllHoverClass( topMenuItems ) {
    336                 for ( var i = 0; i < topMenuItems.length; i++ ) {
    337                         if ( hasHoverClass( topMenuItems[i] ) ) {
    338                                 removeHoverClass( topMenuItems[i] );
     383                if ( topMenuItems && topMenuItems.length ) {
     384                        for ( var i = 0; i < topMenuItems.length; i++ ) {
     385                                removeClass( topMenuItems[i], 'hover' );
    339386                        }
    340387                }
    341388        }
     
    354401                if (
    355402                        event.target &&
    356403                        event.target.id &&
    357                         event.target.id != 'wpadminbar' &&
    358                         event.target.id != 'wp-admin-bar-top-secondary'
     404                        event.target.id !== 'wpadminbar' &&
     405                        event.target.id !== 'wp-admin-bar-top-secondary'
    359406                ) {
    360407                        return;
    361408                }
     
    380427         * @param {string} selector CSS selector to match.
    381428         */
    382429        function getClosest( el, selector ) {
    383                 if ( ! Element.prototype.matches ) {
    384                         Element.prototype.matches =
    385                                 Element.prototype.matchesSelector ||
    386                                 Element.prototype.mozMatchesSelector ||
    387                                 Element.prototype.msMatchesSelector ||
    388                                 Element.prototype.oMatchesSelector ||
    389                                 Element.prototype.webkitMatchesSelector ||
    390                                 function( s ) {
    391                                         var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ),
    392                                                 i = matches.length;
    393                                         while ( --i >= 0 && matches.item( i ) !== this ) { }
    394                                         return i > -1;
    395                                 };
    396                 }
     430                if ( window.Element ) {
     431                        if ( ! window.Element.prototype.matches ) {
     432                                // Polyfill from https://developer.mozilla.org/en-US/docs/Web/API/Element/matches.
     433                                window.Element.prototype.matches =
     434                                        window.Element.prototype.matchesSelector ||
     435                                        window.Element.prototype.mozMatchesSelector ||
     436                                        window.Element.prototype.msMatchesSelector ||
     437                                        window.Element.prototype.oMatchesSelector ||
     438                                        window.Element.prototype.webkitMatchesSelector ||
     439                                        function( s ) {
     440                                                var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ),
     441                                                        i = matches.length;
    397442
    398                 // Get the closest matching elent
    399                 for ( ; el && el !== document; el = el.parentNode ) {
    400                         if ( el.matches( selector ) ) {
    401                                 return el;
     443                                                while ( --i >= 0 && matches.item( i ) !== this ) { }
     444
     445                                                return i > -1;
     446                                        };
    402447                        }
     448
     449                        // Get the closest matching elent
     450                        for ( ; el && el !== document; el = el.parentNode ) {
     451                                if ( el.matches( selector ) ) {
     452                                        return el;
     453                                }
     454                        }
    403455                }
     456
    404457                return null;
    405458        }
    406459} )( document, window, navigator );