Ticket #47069: 47069.12.diff
File 47069.12.diff, 15.5 KB (added by , 3 years ago) |
---|
-
src/js/_enqueues/lib/admin-bar.js
10 10 * 11 11 * @return {void} 12 12 */ 13 /* global hoverintent */14 13 ( function( document, window, navigator ) { 15 14 document.addEventListener( 'DOMContentLoaded', function() { 16 15 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, 24 24 adminBarSearchInput, 25 25 i; 26 26 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 } 31 30 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 32 43 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. 36 45 document.body.addEventListener( mobileEvent, function( e ) { 37 46 if ( ! getClosest( e.target, 'li.menupop' ) ) { 38 47 removeAllHoverClass( topMenuItems ); … … 39 48 } 40 49 } ); 41 50 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. 46 53 adminBar.addEventListener( 'touchstart', function bindMobileEvents() { 47 54 for ( var i = 0; i < topMenuItems.length; i++ ) { 48 55 topMenuItems[i].addEventListener( 'click', mobileHover.bind( null, topMenuItems ) ); … … 52 59 } ); 53 60 } 54 61 55 /** 56 * Scroll page to top when clicking on the admin bar. 57 */ 62 // Scroll page to top when clicking on the admin bar. 58 63 adminBar.addEventListener( 'click', scrollToTop ); 59 64 60 65 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( 65 68 topMenuItems[i], 66 add HoverClass.bind( null, topMenuItems[i]),67 remove HoverClass.bind( null, topMenuItems[i])69 addClass.bind( null, topMenuItems[i], 'hover' ), 70 removeClass.bind( null, topMenuItems[i], 'hover' ) 68 71 ).options( { 69 72 timeout: 180 70 73 } ); 71 74 72 /** 73 * Toggle hover class if the enter key is pressed. 74 */ 75 // Toggle hover class if the enter key is pressed. 75 76 topMenuItems[i].addEventListener( 'keydown', toggleHoverIfEnter ); 76 77 } 77 78 78 /** 79 * Remove hover class if the escape key is pressed. 80 */ 79 // Remove hover class if the escape key is pressed. 81 80 for ( i = 0; i < allMenuItems.length; i++ ) { 82 81 allMenuItems[i].addEventListener( 'keydown', removeHoverIfEscape ); 83 82 } … … 85 84 if ( adminBarSearchForm ) { 86 85 adminBarSearchInput = document.getElementById( 'adminbar-search' ); 87 86 88 /** 89 * Adds the adminbar-focused class on focus. 90 */ 87 // Adds the adminbar-focused class on focus. 91 88 adminBarSearchInput.addEventListener( 'focus', function() { 92 ad minBarSearchForm.classList.add('adminbar-focused' );89 addClass( adminBarSearchForm, 'adminbar-focused' ); 93 90 } ); 94 91 95 /** 96 * Removes the adminbar-focused class on blur. 97 */ 92 // Removes the adminbar-focused class on blur. 98 93 adminBarSearchInput.addEventListener( 'blur', function() { 99 adminBarSearchForm.classList.remove('adminbar-focused' );94 removeClass( adminBarSearchForm, 'adminbar-focused' ); 100 95 } ); 101 96 } 102 97 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 } 107 102 108 103 if ( shortlink ) { 109 104 shortlink.addEventListener( 'click', clickShortlink ); 110 105 } 111 106 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. 116 108 if ( window.location.hash ) { 117 109 window.scrollBy( 0, -32 ); 118 110 } 119 111 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' ); 126 119 } 127 120 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 } 132 125 } ); 133 126 134 127 /** … … 136 129 * 137 130 * @since 5.3.0 138 131 * 139 * @param {Event} e The keydown event.132 * @param {Event} event The keydown event. 140 133 */ 141 function removeHoverIfEscape( e ) {134 function removeHoverIfEscape( event ) { 142 135 var wrapper; 143 136 144 if ( e .which != 27 ) {137 if ( event.which !== 27 ) { 145 138 return; 146 139 } 147 140 148 wrapper = getClosest( e .target, '.menupop' );141 wrapper = getClosest( event.target, '.menupop' ); 149 142 150 143 if ( ! wrapper ) { 151 144 return; … … 152 145 } 153 146 154 147 wrapper.querySelector( '.menupop > .ab-item' ).focus(); 155 remove HoverClass( wrapper);148 removeClass( wrapper, 'hover' ); 156 149 } 157 150 158 151 /** … … 160 153 * 161 154 * @since 5.3.0 162 155 * 163 * @param {Event} e The keydown event.156 * @param {Event} event The keydown event. 164 157 */ 165 function toggleHoverIfEnter( e ) {158 function toggleHoverIfEnter( event ) { 166 159 var wrapper; 167 160 168 if ( e .which != 13 ) {161 if ( event.which !== 13 ) { 169 162 return; 170 163 } 171 164 172 if ( !! getClosest( e .target, '.ab-sub-wrapper' ) ) {165 if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) { 173 166 return; 174 167 } 175 168 176 wrapper = getClosest( e .target, '.menupop' );169 wrapper = getClosest( event.target, '.menupop' ); 177 170 178 171 if ( ! wrapper ) { 179 172 return; 180 173 } 181 174 182 e.preventDefault(); 183 if ( hasHoverClass( wrapper ) ) { 184 removeHoverClass( wrapper ); 175 event.preventDefault(); 176 177 if ( hasClass( wrapper, 'hover' ) ) { 178 removeClass( wrapper, 'hover' ); 185 179 } else { 186 add HoverClass( wrapper);180 addClass( wrapper, 'hover' ); 187 181 } 188 182 } 189 183 … … 192 186 * 193 187 * @since 5.3.0 194 188 * 195 * @param {Event} e The keydown event.189 * @param {Event} event The keydown event. 196 190 */ 197 function focusTargetAfterEnter( e ) {191 function focusTargetAfterEnter( event ) { 198 192 var id, userAgent; 199 193 200 if ( 13 !== e.which) {194 if ( event.which !== 13 ) { 201 195 return; 202 196 } 203 197 204 id = e .target.getAttribute( 'href' );198 id = event.target.getAttribute( 'href' ); 205 199 userAgent = navigator.userAgent.toLowerCase(); 206 200 207 if ( userAgent.indexOf( 'applewebkit' ) != -1 && id && id.charAt( 0 )== '#' ) {201 if ( userAgent.indexOf( 'applewebkit' ) > -1 && id && id.charAt( 0 ) === '#' ) { 208 202 setTimeout( function() { 209 203 var target = document.getElementById( id.replace( '#', '' ) ); 210 204 211 target.setAttribute( 'tabIndex', '0' ); 212 target.focus(); 205 if ( target ) { 206 target.setAttribute( 'tabIndex', '0' ); 207 target.focus(); 208 } 213 209 }, 100 ); 214 210 } 215 211 } … … 220 216 * @since 5.3.0 221 217 * 222 218 * @param {NodeList} topMenuItems All menu items. 223 * @param {Event} e The click event.219 * @param {Event} event The click event. 224 220 */ 225 function mobileHover( topMenuItems, e ) {221 function mobileHover( topMenuItems, event ) { 226 222 var wrapper; 227 223 228 if ( !! getClosest( e .target, '.ab-sub-wrapper' ) ) {224 if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) { 229 225 return; 230 226 } 231 227 232 e .preventDefault();228 event.preventDefault(); 233 229 234 wrapper = getClosest( e .target, '.menupop' );230 wrapper = getClosest( event.target, '.menupop' ); 235 231 236 232 if ( ! wrapper ) { 237 233 return; 238 234 } 239 235 240 if ( has HoverClass( wrapper) ) {241 remove HoverClass( wrapper);236 if ( hasClass( wrapper, 'hover' ) ) { 237 removeClass( wrapper, 'hover' ); 242 238 } else { 243 239 removeAllHoverClass( topMenuItems ); 244 add HoverClass( wrapper);240 addClass( wrapper, 'hover' ); 245 241 } 246 242 } 247 243 … … 251 247 * @since 3.1.0 252 248 * @since 5.3.0 Use querySelector to clean up the function. 253 249 * 254 * @param {Event} e The click event. 255 * 250 * @param {Event} event The click event. 256 251 * @return {boolean} Returns false to prevent default click behavior. 257 252 */ 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 ) { 260 258 input = wrapper.querySelector( '.shortlink-input' ); 259 } 261 260 262 // IE doesn't support preventDefault, and does support returnValue 263 if ( e.preventDefault ) { 264 e.preventDefault(); 261 if ( ! input ) { 262 return; 265 263 } 266 e.returnValue = false;267 264 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 269 274 input.focus(); 270 275 input.select(); 271 276 input.onblur = function() { 272 wrapper.classList.remove('selected' );277 removeClass( wrapper, 'selected' ); 273 278 }; 274 279 275 280 return false; … … 284 289 if ( 'sessionStorage' in window ) { 285 290 try { 286 291 for ( var key in sessionStorage ) { 287 if ( key.indexOf( 'wp-autosave-' ) !=-1 ) {292 if ( key.indexOf( 'wp-autosave-' ) > -1 ) { 288 293 sessionStorage.removeItem( key ); 289 294 } 290 295 } 291 } catch ( e ) {}296 } catch ( er ) {} 292 297 } 293 298 } 294 299 … … 297 302 * 298 303 * @since 5.3.0 299 304 * 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. 301 308 */ 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; 304 322 } 305 323 306 324 /** 307 * Add hover class for menu item.325 * Add class to an element. 308 326 * 309 327 * @since 5.3.0 310 328 * 311 * @param {HTMLElement} item Menu item Element. 329 * @param {HTMLElement} element The HTML element. 330 * @param {String} className The class name. 312 331 */ 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 } 315 344 } 316 345 317 346 /** … … 319 348 * 320 349 * @since 5.3.0 321 350 * 322 * @param {HTMLElement} item Menu item Element. 351 * @param {HTMLElement} element The HTML element. 352 * @param {String} className The class name. 323 353 */ 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 326 373 } 327 374 328 375 /** … … 333 380 * @param {NodeList} topMenuItems All menu items. 334 381 */ 335 382 function removeAllHoverClass( topMenuItems ) { 336 for ( var i = 0; i < topMenuItems.length; i++) {337 if ( hasHoverClass( topMenuItems[i] )) {338 remove HoverClass( topMenuItems[i]);383 if ( topMenuItems && topMenuItems.length ) { 384 for ( var i = 0; i < topMenuItems.length; i++ ) { 385 removeClass( topMenuItems[i], 'hover' ); 339 386 } 340 387 } 341 388 } … … 354 401 if ( 355 402 event.target && 356 403 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' 359 406 ) { 360 407 return; 361 408 } … … 380 427 * @param {string} selector CSS selector to match. 381 428 */ 382 429 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; 397 442 398 // Get the closest matching elent399 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 }; 402 447 } 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 } 403 455 } 456 404 457 return null; 405 458 } 406 459 } )( document, window, navigator );