Changeset 46884
- Timestamp:
- 12/11/2019 08:21:08 PM (5 years ago)
- Location:
- branches/5.3
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/5.3
-
branches/5.3/src/js/_enqueues/lib/admin-bar.js
r46875 r46884 4 4 /** 5 5 * Admin bar with Vanilla JS, no external dependencies. 6 * 7 * @since 5.3.1 6 8 * 7 9 * @param {Object} document The document object. … … 11 13 * @return {void} 12 14 */ 13 /* global hoverintent */14 15 ( function( document, window, navigator ) { 15 16 document.addEventListener( 'DOMContentLoaded', function() { 16 17 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', 18 topMenuItems, 19 allMenuItems, 20 adminBarLogout, 21 adminBarSearchForm, 22 shortlink, 23 skipLink, 24 mobileEvent, 25 fontFaceRegex, 24 26 adminBarSearchInput, 25 27 i; 26 28 27 /** 28 * Remove nojs class after the DOM is loaded. 29 */ 30 adminBar.classList.remove( 'nojs' ); 29 if ( ! adminBar || ! ( 'querySelectorAll' in adminBar ) ) { 30 return; 31 } 32 33 topMenuItems = adminBar.querySelectorAll( 'li.menupop' ); 34 allMenuItems = adminBar.querySelectorAll( '.ab-item' ); 35 adminBarLogout = document.getElementById( 'wp-admin-bar-logout' ); 36 adminBarSearchForm = document.getElementById( 'adminbarsearch' ); 37 shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' ); 38 skipLink = adminBar.querySelector( '.screen-reader-shortcut' ); 39 mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click'; 40 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/; 41 42 // Remove nojs class after the DOM is loaded. 43 removeClass( adminBar, 'nojs' ); 31 44 32 45 if ( 'ontouchstart' in window ) { 33 /** 34 * Remove hover class when the user touches outside the menu items. 35 */ 46 // Remove hover class when the user touches outside the menu items. 36 47 document.body.addEventListener( mobileEvent, function( e ) { 37 48 if ( ! getClosest( e.target, 'li.menupop' ) ) { … … 40 51 } ); 41 52 42 /** 43 * Add listener for menu items to toggle hover class by touches. 44 * Remove the callback later for better performance. 45 */ 53 // Add listener for menu items to toggle hover class by touches. 54 // Remove the callback later for better performance. 46 55 adminBar.addEventListener( 'touchstart', function bindMobileEvents() { 47 56 for ( var i = 0; i < topMenuItems.length; i++ ) { … … 53 62 } 54 63 55 /** 56 * Scroll page to top when clicking on the admin bar. 57 */ 64 // Scroll page to top when clicking on the admin bar. 58 65 adminBar.addEventListener( 'click', scrollToTop ); 59 66 60 67 for ( i = 0; i < topMenuItems.length; i++ ) { 61 /** 62 * Adds or removes the hover class based on the hover intent. 63 */ 64 hoverintent( 68 // Adds or removes the hover class based on the hover intent. 69 window.hoverintent( 65 70 topMenuItems[i], 66 add HoverClass.bind( null, topMenuItems[i]),67 remove HoverClass.bind( null, topMenuItems[i])71 addClass.bind( null, topMenuItems[i], 'hover' ), 72 removeClass.bind( null, topMenuItems[i], 'hover' ) 68 73 ).options( { 69 74 timeout: 180 70 75 } ); 71 76 72 /** 73 * Toggle hover class if the enter key is pressed. 74 */ 77 // Toggle hover class if the enter key is pressed. 75 78 topMenuItems[i].addEventListener( 'keydown', toggleHoverIfEnter ); 76 79 } 77 80 78 /** 79 * Remove hover class if the escape key is pressed. 80 */ 81 // Remove hover class if the escape key is pressed. 81 82 for ( i = 0; i < allMenuItems.length; i++ ) { 82 83 allMenuItems[i].addEventListener( 'keydown', removeHoverIfEscape ); … … 86 87 adminBarSearchInput = document.getElementById( 'adminbar-search' ); 87 88 88 /** 89 * Adds the adminbar-focused class on focus. 90 */ 89 // Adds the adminbar-focused class on focus. 91 90 adminBarSearchInput.addEventListener( 'focus', function() { 92 adminBarSearchForm.classList.add( 'adminbar-focused' ); 93 } ); 94 95 /** 96 * Removes the adminbar-focused class on blur. 97 */ 91 addClass( adminBarSearchForm, 'adminbar-focused' ); 92 } ); 93 94 // Removes the adminbar-focused class on blur. 98 95 adminBarSearchInput.addEventListener( 'blur', function() { 99 adminBarSearchForm.classList.remove('adminbar-focused' );100 } ); 101 } 102 103 /**104 *Focus the target of skip link after pressing Enter.105 */106 skipLink.addEventListener( 'keydown', focusTargetAfterEnter );96 removeClass( adminBarSearchForm, 'adminbar-focused' ); 97 } ); 98 } 99 100 if ( skipLink ) { 101 // Focus the target of skip link after pressing Enter. 102 skipLink.addEventListener( 'keydown', focusTargetAfterEnter ); 103 } 107 104 108 105 if ( shortlink ) { … … 110 107 } 111 108 112 /** 113 * Prevents the toolbar from covering up content when a hash is present 114 * in the URL. 115 */ 109 // Prevents the toolbar from covering up content when a hash is present in the URL. 116 110 if ( window.location.hash ) { 117 111 window.scrollBy( 0, -32 ); 118 112 } 119 113 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'; 126 } 127 128 /** 129 * Clear sessionStorage on logging out. 130 */ 131 adminBarLogout.addEventListener( 'click', emptySessionStorage ); 114 // Add no-font-face class to body if needed. 115 if ( 116 navigator.userAgent && 117 fontFaceRegex.test( navigator.userAgent ) && 118 ! hasClass( document.body, 'no-font-face' ) 119 ) { 120 addClass( document.body, 'no-font-face' ); 121 } 122 123 // Clear sessionStorage on logging out. 124 if ( adminBarLogout ) { 125 adminBarLogout.addEventListener( 'click', emptySessionStorage ); 126 } 132 127 } ); 133 128 … … 135 130 * Remove hover class for top level menu item when escape is pressed. 136 131 * 137 * @since 5.3. 0138 * 139 * @param {Event} e The keydown event.140 */ 141 function removeHoverIfEscape( e ) {132 * @since 5.3.1 133 * 134 * @param {Event} event The keydown event. 135 */ 136 function removeHoverIfEscape( event ) { 142 137 var wrapper; 143 138 144 if ( e .which != 27 ) {145 return; 146 } 147 148 wrapper = getClosest( e .target, '.menupop' );139 if ( event.which !== 27 ) { 140 return; 141 } 142 143 wrapper = getClosest( event.target, '.menupop' ); 149 144 150 145 if ( ! wrapper ) { … … 153 148 154 149 wrapper.querySelector( '.menupop > .ab-item' ).focus(); 155 remove HoverClass( wrapper);150 removeClass( wrapper, 'hover' ); 156 151 } 157 152 … … 159 154 * Toggle hover class for top level menu item when enter is pressed. 160 155 * 161 * @since 5.3. 0162 * 163 * @param {Event} e The keydown event.164 */ 165 function toggleHoverIfEnter( e ) {156 * @since 5.3.1 157 * 158 * @param {Event} event The keydown event. 159 */ 160 function toggleHoverIfEnter( event ) { 166 161 var wrapper; 167 162 168 if ( e .which != 13 ) {169 return; 170 } 171 172 if ( !! getClosest( e .target, '.ab-sub-wrapper' ) ) {173 return; 174 } 175 176 wrapper = getClosest( e .target, '.menupop' );163 if ( event.which !== 13 ) { 164 return; 165 } 166 167 if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) { 168 return; 169 } 170 171 wrapper = getClosest( event.target, '.menupop' ); 177 172 178 173 if ( ! wrapper ) { … … 180 175 } 181 176 182 e.preventDefault(); 183 if ( hasHoverClass( wrapper ) ) { 184 removeHoverClass( wrapper ); 177 event.preventDefault(); 178 179 if ( hasClass( wrapper, 'hover' ) ) { 180 removeClass( wrapper, 'hover' ); 185 181 } else { 186 add HoverClass( wrapper);182 addClass( wrapper, 'hover' ); 187 183 } 188 184 } … … 191 187 * Focus the target of skip link after pressing Enter. 192 188 * 193 * @since 5.3. 0194 * 195 * @param {Event} e The keydown event.196 */ 197 function focusTargetAfterEnter( e ) {189 * @since 5.3.1 190 * 191 * @param {Event} event The keydown event. 192 */ 193 function focusTargetAfterEnter( event ) { 198 194 var id, userAgent; 199 195 200 if ( 13 !== e.which) {201 return; 202 } 203 204 id = e .target.getAttribute( 'href' );196 if ( event.which !== 13 ) { 197 return; 198 } 199 200 id = event.target.getAttribute( 'href' ); 205 201 userAgent = navigator.userAgent.toLowerCase(); 206 202 207 if ( userAgent.indexOf( 'applewebkit' ) != -1 && id && id.charAt( 0 )== '#' ) {203 if ( userAgent.indexOf( 'applewebkit' ) > -1 && id && id.charAt( 0 ) === '#' ) { 208 204 setTimeout( function() { 209 205 var target = document.getElementById( id.replace( '#', '' ) ); 210 206 211 target.setAttribute( 'tabIndex', '0' ); 212 target.focus(); 207 if ( target ) { 208 target.setAttribute( 'tabIndex', '0' ); 209 target.focus(); 210 } 213 211 }, 100 ); 214 212 } … … 218 216 * Toogle hover class for mobile devices. 219 217 * 220 * @since 5.3. 0218 * @since 5.3.1 221 219 * 222 220 * @param {NodeList} topMenuItems All menu items. 223 * @param {Event} e The click event.224 */ 225 function mobileHover( topMenuItems, e ) {221 * @param {Event} event The click event. 222 */ 223 function mobileHover( topMenuItems, event ) { 226 224 var wrapper; 227 225 228 if ( !! getClosest( e .target, '.ab-sub-wrapper' ) ) {229 return; 230 } 231 232 e .preventDefault();233 234 wrapper = getClosest( e .target, '.menupop' );226 if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) { 227 return; 228 } 229 230 event.preventDefault(); 231 232 wrapper = getClosest( event.target, '.menupop' ); 235 233 236 234 if ( ! wrapper ) { … … 238 236 } 239 237 240 if ( has HoverClass( wrapper) ) {241 remove HoverClass( wrapper);238 if ( hasClass( wrapper, 'hover' ) ) { 239 removeClass( wrapper, 'hover' ); 242 240 } else { 243 241 removeAllHoverClass( topMenuItems ); 244 add HoverClass( wrapper);242 addClass( wrapper, 'hover' ); 245 243 } 246 244 } … … 250 248 * 251 249 * @since 3.1.0 252 * @since 5.3.0 Use querySelector to clean up the function. 253 * 254 * @param {Event} e The click event. 255 * 250 * @since 5.3.1 Use querySelector to clean up the function. 251 * 252 * @param {Event} event The click event. 256 253 * @return {boolean} Returns false to prevent default click behavior. 257 254 */ 258 function clickShortlink( e ) { 259 var wrapper = e.target.parentNode, 255 function clickShortlink( event ) { 256 var wrapper = event.target.parentNode, 257 input; 258 259 if ( wrapper ) { 260 260 input = wrapper.querySelector( '.shortlink-input' ); 261 262 // IE doesn't support preventDefault, and does support returnValue 263 if ( e.preventDefault ) { 264 e.preventDefault(); 265 } 266 e.returnValue = false; 267 268 wrapper.classList.add( 'selected' ); 261 } 262 263 if ( ! input ) { 264 return; 265 } 266 267 // (Old) IE doesn't support preventDefault, and does support returnValue 268 if ( event.preventDefault ) { 269 event.preventDefault(); 270 } 271 272 event.returnValue = false; 273 274 addClass( wrapper, 'selected' ); 275 269 276 input.focus(); 270 277 input.select(); 271 278 input.onblur = function() { 272 wrapper.classList.remove('selected' );279 removeClass( wrapper, 'selected' ); 273 280 }; 274 281 … … 279 286 * Clear sessionStorage on logging out. 280 287 * 281 * @since 5.3. 0288 * @since 5.3.1 282 289 */ 283 290 function emptySessionStorage() { … … 285 292 try { 286 293 for ( var key in sessionStorage ) { 287 if ( key.indexOf( 'wp-autosave-' ) !=-1 ) {294 if ( key.indexOf( 'wp-autosave-' ) > -1 ) { 288 295 sessionStorage.removeItem( key ); 289 296 } 290 297 } 291 } catch ( e ) {} 292 } 293 } 294 295 /** 296 * Check if menu item has hover class. 297 * 298 * @since 5.3.0 299 * 300 * @param {HTMLElement} item Menu item Element. 301 */ 302 function hasHoverClass( item ) { 303 return item.classList.contains( 'hover' ); 304 } 305 306 /** 307 * Add hover class for menu item. 308 * 309 * @since 5.3.0 310 * 311 * @param {HTMLElement} item Menu item Element. 312 */ 313 function addHoverClass( item ) { 314 item.classList.add( 'hover' ); 315 } 316 317 /** 318 * Remove hover class for menu item. 319 * 320 * @since 5.3.0 321 * 322 * @param {HTMLElement} item Menu item Element. 323 */ 324 function removeHoverClass( item ) { 325 item.classList.remove( 'hover' ); 298 } catch ( er ) {} 299 } 300 } 301 302 /** 303 * Check if element has class. 304 * 305 * @since 5.3.1 306 * 307 * @param {HTMLElement} element The HTML element. 308 * @param {String} className The class name. 309 * @return {bool} Whether the element has the className. 310 */ 311 function hasClass( element, className ) { 312 var classNames; 313 314 if ( ! element ) { 315 return false; 316 } 317 318 if ( element.classList && element.classList.contains ) { 319 return element.classList.contains( className ); 320 } else if ( element.className ) { 321 classNames = element.className.split( ' ' ); 322 return classNames.indexOf( className ) > -1; 323 } 324 325 return false; 326 } 327 328 /** 329 * Add class to an element. 330 * 331 * @since 5.3.1 332 * 333 * @param {HTMLElement} element The HTML element. 334 * @param {String} className The class name. 335 */ 336 function addClass( element, className ) { 337 if ( ! element ) { 338 return; 339 } 340 341 if ( element.classList && element.classList.add ) { 342 element.classList.add( className ); 343 } else if ( ! hasClass( element, className ) ) { 344 if ( element.className ) { 345 element.className += ' '; 346 } 347 348 element.className += className; 349 } 350 } 351 352 /** 353 * Remove class from an element. 354 * 355 * @since 5.3.1 356 * 357 * @param {HTMLElement} element The HTML element. 358 * @param {String} className The class name. 359 */ 360 function removeClass( element, className ) { 361 var testName, 362 classes; 363 364 if ( ! element || ! hasClass( element, className ) ) { 365 return; 366 } 367 368 if ( element.classList && element.classList.remove ) { 369 element.classList.remove( className ); 370 } else { 371 testName = ' ' + className + ' '; 372 classes = ' ' + element.className + ' '; 373 374 while ( classes.indexOf( testName ) > -1 ) { 375 classes = classes.replace( testName, '' ); 376 } 377 378 element.className = classes.replace( /^[\s]+|[\s]+$/g, '' ); 379 } 326 380 } 327 381 … … 329 383 * Remove hover class for all menu items. 330 384 * 331 * @since 5.3. 0385 * @since 5.3.1 332 386 * 333 387 * @param {NodeList} topMenuItems All menu items. 334 388 */ 335 389 function removeAllHoverClass( topMenuItems ) { 336 for ( var i = 0; i < topMenuItems.length; i++) {337 if ( hasHoverClass( topMenuItems[i] )) {338 remove HoverClass( topMenuItems[i]);390 if ( topMenuItems && topMenuItems.length ) { 391 for ( var i = 0; i < topMenuItems.length; i++ ) { 392 removeClass( topMenuItems[i], 'hover' ); 339 393 } 340 394 } … … 346 400 * @since 3.4.0 347 401 * 348 * @param {Event} e The Click event.402 * @param {Event} event The Click event. 349 403 * 350 404 * @return {void} … … 354 408 if ( 355 409 event.target && 356 event.target.id && 357 event.target.id != 'wpadminbar' && 358 event.target.id != 'wp-admin-bar-top-secondary' 410 event.target.id !== 'wpadminbar' && 411 event.target.id !== 'wp-admin-bar-top-secondary' 359 412 ) { 360 413 return; … … 375 428 * Get closest Element. 376 429 * 377 * @since 5.3. 0430 * @since 5.3.1 378 431 * 379 432 * @param {HTMLElement} el Element to get parent. … … 381 434 */ 382 435 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 || 436 if ( ! window.Element.prototype.matches ) { 437 // Polyfill from https://developer.mozilla.org/en-US/docs/Web/API/Element/matches. 438 window.Element.prototype.matches = 439 window.Element.prototype.matchesSelector || 440 window.Element.prototype.mozMatchesSelector || 441 window.Element.prototype.msMatchesSelector || 442 window.Element.prototype.oMatchesSelector || 443 window.Element.prototype.webkitMatchesSelector || 390 444 function( s ) { 391 445 var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ), 392 446 i = matches.length; 447 393 448 while ( --i >= 0 && matches.item( i ) !== this ) { } 449 394 450 return i > -1; 395 451 }; … … 402 458 } 403 459 } 460 404 461 return null; 405 462 } 463 406 464 } )( document, window, navigator );
Note: See TracChangeset
for help on using the changeset viewer.