Ticket #47069: 47069.2.diff
File 47069.2.diff, 29.7 KB (added by , 5 years ago) |
---|
-
src/js/_enqueues/lib/admin-bar.js
1 1 /** 2 2 * @output wp-includes/js/admin-bar.js 3 3 */ 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 * 10 * @return {void} 11 */ 12 (function(document, window) { 4 13 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; 14 document.addEventListener('DOMContentLoaded', function() { 15 var adminBar = document.getElementById('wpadminbar'); 16 var topMenuItems = adminBar.querySelectorAll('li.menupop'); 17 var allMenuItems = adminBar.querySelectorAll('.ab-item'); 18 var adminBarLogout = document.getElementById('wp-admin-bar-logout'); 19 var adminBarSearchForm = document.getElementById('adminbarsearch'); 20 var shortlink = document.getElementById('wp-admin-bar-get-shortlink'); 21 var skipLink = adminBar.querySelector('.screen-reader-shortcut'); 22 var disableHoverIntent = false; 16 23 17 24 /** 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} 25 * Remove nojs class after the DOM is loaded. 28 26 */ 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 }; 27 adminBar.classList.remove('nojs'); 34 28 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'); 62 } 29 if ( 'ontouchstart' in window ) { 30 var mobileEvent = /Mobile\/.+Safari/.test(navigator.userAgent) ? 'touchstart' : 'click'; 31 32 /** 33 * Remove hover class when the user touchs outside the menu items. 34 */ 35 document.body.addEventListener(mobileEvent, function(e) { 36 if (! getClosest(e.target, 'li.menupop')) 37 removeAllHoverClass(topMenuItems); 38 }); 63 39 64 if ( unbind ) { 65 $('li.menupop').off('click.wp-mobile-hover'); 66 disableHoverIntent = false; 40 /** 41 * Disable hover intent on touch devices. 42 * Add listener for menu items to toggle hover class by touchs. 43 * Remove the callback later for better performance. 44 */ 45 adminBar.addEventListener('touchstart', function bindMobileEvents() { 46 disableHoverIntent = disableHoverIntent || true; 47 48 for (var i = 0; i < topMenuItems.length; i++) { 49 topMenuItems[i].addEventListener('click', mobileHover.bind(null, topMenuItems)); 67 50 } 51 52 adminBar.removeEventListener('touchstart', bindMobileEvents); 68 53 }); 69 } ;54 } 70 55 71 56 /** 72 * Removes the hover class if clicked or touched outside the admin bar. 73 * 74 * @since 3.5.0 75 * 76 * @return {void} 57 * Scroll page to top when clicking on the admin bar. 77 58 */ 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'); 59 adminBar.addEventListener('click', scrollToTop); 60 61 for (var i = 0; i < topMenuItems.length; i++) { 62 /** 63 * Adds or removes the hover class based on the hover intent. 64 */ 65 hoverIntent( 66 topMenuItems[i], 67 function() { 68 if (!disableHoverIntent) 69 addHoverClass(this); 70 }, 71 function() { 72 if (!disableHoverIntent) 73 removeHoverClass(this) 74 } 75 ).options({ 76 timeout: 180 84 77 }); 85 };86 78 87 adminbar.removeClass('nojq').removeClass('nojs'); 79 /** 80 * Toggle hover class if the enter key is pressed. 81 */ 82 topMenuItems[i].addEventListener('keydown', toggleHoverWithEnter); 83 } 84 88 85 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 }); 86 for (var i = 0; i < allMenuItems.length; i++) { 87 allMenuItems[i].addEventListener('keydown', removeHoverWithEscape); 88 } 120 89 121 // Prevents the toolbar from covering up content when a hash is present in the 122 // URL. 123 if ( window.location.hash ) 124 window.scrollBy( 0, -32 ); 90 if (adminBarSearchForm) { 91 var adminBarSearchInput = document.getElementById('adminbar-search'); 125 92 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 }); 93 /** 94 * Adds the adminbar-focused class on focus. 95 */ 96 adminBarSearchInput.addEventListener('focus', function() { 97 adminBarSearchForm.classList.add('adminbar-focused'); 98 }) 99 100 /** 101 * Removes the adminbar-focused class on blur. 102 */ 103 adminBarSearchInput.addEventListener('blur', function() { 104 adminBarSearchForm.classList.remove('adminbar-focused'); 105 }) 106 } 142 107 143 108 /** 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} 109 * Focus the target of skip link after pressing Enter. 152 110 */ 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(); 111 skipLink.addEventListener('keydown', focusTargetAfterEnter); 164 112 165 if ( !wrap.length)166 wrap = $('#wpadminbar .quicklinks');113 if (shortlink) 114 shortlink.addEventListener('click', clickShortlink); 167 115 168 wrap.find('.menupop').removeClass('hover'); 116 /** 117 * Prevents the toolbar from covering up content when a hash is present 118 * in the URL. 119 */ 120 if (window.location.hash) 121 window.scrollBy(0, -32); 169 122 170 if ( ! parentHasHover ) { 171 target.parent().toggleClass('hover'); 172 } 123 /** 124 * Add no-font-face class to body if needed. 125 */ 126 if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 && 127 /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 ) ) { 173 128 174 target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh);175 } ).each(refresh);129 document.body.className += ' no-font-face'; 130 } 176 131 177 132 /** 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} 133 * Clear sessionStorage on logging out. 186 134 */ 187 $('#wpadminbar .ab-item').bind('keydown.adminbar', function(e){ 188 // Key code 27 is the escape key. 189 if ( e.which != 27 ) 190 return; 135 adminBarLogout.addEventListener('click', emptySessionStorage); 136 }); 191 137 192 var target = $(e.target); 138 /** 139 * Remove hover class for top level menu item when escape is pressed. 140 * 141 * @since 5.3.0 142 * 143 * @param {Event} e The keydown event. 144 */ 145 function removeHoverWithEscape(e) { 146 var wrapper; 193 147 194 e.stopPropagation();195 e.preventDefault();148 if ( e.which != 27 ) 149 return; 196 150 197 target.closest('.hover').removeClass('hover').children('.ab-item').focus(); 198 target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh); 199 }); 151 wrapper = getClosest(e.target, '.menupop'); 200 152 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 } 153 if (! wrapper) 154 return; 212 155 213 adminbar.find( 'li.menupop.hover' ).removeClass( 'hover' ); 214 $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' ); 215 e.preventDefault(); 216 }); 156 wrapper.querySelector('.menupop > .ab-item').focus(); 157 removeHoverClass(wrapper); 158 } 217 159 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 160 230 if ( 13 != e.which )231 return;232 161 233 id = $( this ).attr( 'href' ); 162 /** 163 * Toggle hover class for top level menu item when enter is pressed. 164 * 165 * @since 5.3.0 166 * 167 * @param {Event} e The keydown event. 168 */ 169 function toggleHoverWithEnter(e) { 170 var wrapper; 234 171 235 ua = navigator.userAgent.toLowerCase(); 172 if ( e.which != 13 ) 173 return; 236 174 237 if ( ua.indexOf('applewebkit') != -1 && id && id.charAt(0) == '#' ) { 238 setTimeout(function () { 239 $(id).focus(); 240 }, 100); 241 } 242 }); 175 if (!! getClosest(e.target, '.ab-sub-wrapper') ) 176 return; 177 178 wrapper = getClosest(e.target, '.menupop'); 179 180 if (! wrapper) 181 return; 182 183 e.preventDefault(); 184 if (hasHoverClass(wrapper)) { 185 removeHoverClass(wrapper); 186 } else { 187 addHoverClass(wrapper); 188 } 189 } 243 190 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 } ); 191 /** 192 * Focus the target of skip link after pressing Enter. 193 * 194 * @since 5.3.0 195 * 196 * @param {Event} e The keydown event. 197 */ 198 function focusTargetAfterEnter(e) { 199 var id, userAgent; 200 201 if (13 !== e.which) 202 return; 203 204 id = e.target.getAttribute('href'); 205 userAgent = navigator.userAgent.toLowerCase(); 206 207 if ( userAgent.indexOf('applewebkit') != -1 && id && id.charAt(0) == '#' ) { 208 setTimeout(function () { 209 var target = document.getElementById(id.replace('#', '')); 210 211 target.setAttribute('tabIndex', '0'); 212 target.focus(); 213 }, 100); 214 } 215 } 216 217 /** 218 * Toogle hover class for mobile devices. 219 * 220 * @since 5.3.0 221 * 222 * @param {NodeList} topMenuItems All menu items. 223 * @param {Event} e The click event. 224 */ 225 function mobileHover(topMenuItems, e) { 226 var wrapper, isSubMenuItem; 227 228 if (!! getClosest(e.target, '.ab-sub-wrapper') ) 229 return; 230 231 e.preventDefault(); 232 233 wrapper = getClosest(e.target, '.menupop'); 234 235 if (! wrapper) 236 return; 237 238 if (hasHoverClass(wrapper)) { 239 removeHoverClass(wrapper); 240 } else { 241 removeAllHoverClass(topMenuItems); 242 addHoverClass(wrapper); 243 } 244 } 245 246 /** 247 * Handles the click on the Shortlink link in the adminbar. 248 * 249 * @since 3.1.0 250 * @since 5.3.0 Use querySelector to clean up the function. 251 * 252 * @param {Event} e The click event. 253 * 254 * @return {boolean} Returns false to prevent default click behavior. 255 */ 256 function clickShortlink(e) { 257 var wrapper = e.target.parentNode, 258 input = wrapper.querySelector('.shortlink-input'); 261 259 260 // IE doesn't support preventDefault, and does support returnValue 261 if ( e.preventDefault ) 262 e.preventDefault(); 263 e.returnValue = false; 264 265 wrapper.classList.add('selected'); 266 input.focus(); 267 input.select(); 268 input.onblur = function() { 269 wrapper.classList.remove('selected'); 270 } 271 272 return false; 273 } 274 275 /** 276 * Clear sessionStorage on logging out. 277 * 278 * @since 5.3.0 279 */ 280 function emptySessionStorage() { 262 281 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 }); 282 try { 283 for ( var key in sessionStorage ) { 284 if ( key.indexOf('wp-autosave-') != -1 ) 285 sessionStorage.removeItem(key); 286 } 287 } catch(e) {} 276 288 } 289 } 277 290 278 if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 && 279 /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 ) ) { 291 /** 292 * Check if menu item has hover class. 293 * 294 * @since 5.3.0 295 * 296 * @param {HTMLElement} item Menu item Element. 297 */ 298 function hasHoverClass(item) { 299 return item.classList.contains('hover') 300 } 280 301 281 document.body.className += ' no-font-face'; 302 /** 303 * Add hover class for menu item. 304 * 305 * @since 5.3.0 306 * 307 * @param {HTMLElement} item Menu item Element. 308 */ 309 function addHoverClass(item) { 310 item.classList.add('hover') 311 } 312 313 /** 314 * Remove hover class for menu item. 315 * 316 * @since 5.3.0 317 * 318 * @param {HTMLElement} item Menu item Element. 319 */ 320 function removeHoverClass(item) { 321 item.classList.remove('hover') 322 } 323 324 /** 325 * Remove hover class for all menu items. 326 * 327 * @since 5.3.0 328 * 329 * @param {NodeList} topMenuItems All menu items. 330 */ 331 function removeAllHoverClass(topMenuItems) { 332 for (var i = 0; i < topMenuItems.length; i++) { 333 if (hasHoverClass(topMenuItems[i])) 334 removeHoverClass(topMenuItems[i]); 282 335 } 283 } );284 } else { 336 } 337 285 338 /** 286 * Wrapper function for the adminbar that's used if jQuery isn't available.339 * Scrolls to the top of the page. 287 340 * 288 * @param {Object} d The document object. 289 * @param {Object} w The window object. 341 * @since 3.4.0 342 * 343 * @param {Event} target The Click event. 290 344 * 291 345 * @return {void} 292 346 */ 293 (function(d, w) { 347 function scrollToTop(e) { 348 var distance, speed, step, steps, timer, speed_step; 349 294 350 /** 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} 351 * Ensure that the #wpadminbar was the target of the click. 304 352 */ 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 }, 353 if ( e.target.id != 'wpadminbar' && e.target.id != 'wp-admin-bar-top-secondary' ) 354 return; 314 355 315 aB, hc = new RegExp('\\bhover\\b', 'g'), q = [], 316 rselected = new RegExp('\\bselected\\b', 'g'), 356 distance = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; 317 357 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 }, 358 if ( distance < 1 ) 359 return; 335 360 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 } 361 speed_step = distance > 800 ? 130 : 100; 362 speed = Math.min( 12, Math.round( distance / speed_step ) ); 363 step = distance > 800 ? Math.round( distance / 30 ) : Math.round( distance / 20 ); 364 steps = []; 365 timer = 0; 362 366 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, '' ) : ''; 372 } 373 } 374 } 367 // Animate scrolling to the top of the page by generating steps to 368 // the top of the page and shifting to each step at a set interval. 369 while ( distance ) { 370 distance -= step; 371 if ( distance < 0 ) 372 distance = 0; 373 steps.push( distance ); 375 374 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 } 375 setTimeout( function() { 376 window.scrollTo( 0, steps.shift() ); 377 }, timer * speed ); 385 378 386 if ( ! inA ) 387 q[i][1].className = q[i][1].className ? q[i][1].className.replace(hc, '') : ''; 388 } 389 }, 379 timer++; 380 } 381 }; 390 382 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 }, 383 /** 384 * Get closest Element. 385 * 386 * @since 5.3.0 387 * 388 * @param {HTMLElement} el Element to get parent. 389 * @param {string} selector CSS selector to match. 390 */ 391 function getClosest(el, selector) { 392 if (!Element.prototype.matches) { 393 Element.prototype.matches = 394 Element.prototype.matchesSelector || 395 Element.prototype.mozMatchesSelector || 396 Element.prototype.msMatchesSelector || 397 Element.prototype.oMatchesSelector || 398 Element.prototype.webkitMatchesSelector || 399 function (s) { 400 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 401 i = matches.length; 402 while (--i >= 0 && matches.item(i) !== this) { } 403 return i > -1; 404 }; 405 } 406 407 // Get the closest matching elent 408 for ( ; el && el !== document; el = el.parentNode ) { 409 if ( el.matches( selector ) ) return el; 410 } 411 return null; 412 } 413 413 414 415 * Handles the click on the Shortlink link in the adminbar.416 *417 * @since 3.1.0418 *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 414 /** 415 * Returns a function, that, as long as it continues to be invoked, will not 416 * be triggered. The function will be called after it stops being called for 417 * N milliseconds. If `immediate` is passed, trigger the function on the 418 * leading edge, instead of the trailing. 419 * 420 * @param {callback} func Function reference. 421 * @param {number} wait Timeout in ms. 422 * @param {boolean} immediate Excute immediately. 423 */ 424 function debounce(func, wait, immediate) { 425 var timeout; 426 return function() { 427 var context = this, args = arguments; 428 var later = function() { 429 timeout = null; 430 if (!immediate) func.apply(context, args); 431 }; 432 var callNow = immediate && !timeout; 433 clearTimeout(timeout); 434 timeout = setTimeout(later, wait); 435 if (callNow) func.apply(context, args); 436 }; 437 } 438 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; 439 /** 440 * Object.assign polyfill. 441 * 442 * @since 5.3.0 443 * 444 * @param {Object} target Target object 445 */ 446 function _extends(target) { 447 for (var i = 1; i < arguments.length; i++) { 448 var source = arguments[i]; 449 450 for (var key in source) { 451 if (Object.prototype.hasOwnProperty.call(source, key)) { 452 target[key] = source[key]; 456 453 } 457 454 } 458 return false; 459 }, 455 } 460 456 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; 457 return target; 458 } 459 460 /** 461 * Vanilla JS HoverIntent. 462 * 463 * @since 5.3.0 464 * 465 * @param {HTMLElement} el Link elent. 466 * @param {callback} onOver Callback when mouse is over the elent. 467 * @param {callback} onOut Callback when mouse leaves the elent. 468 */ 469 function hoverIntent(el, onOver, onOut) { 470 var x, y, pX, pY; 471 var mouseOver = false; 472 var focused = false; 473 var h = {}, 474 state = 0, 475 timer = 0; 472 476 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 ); 477 var options = { 478 sensitivity: 7, 479 interval: 100, 480 timeout: 0, 481 handleFocus: false 482 }; 499 483 500 timer++; 484 function delay(el, e) { 485 if (timer) timer = clearTimeout(timer); 486 state = 0; 487 return focused ? undefined : onOut.call(el, e); 488 } 489 490 function tracker(e) { 491 x = e.clientX; 492 y = e.clientY; 493 } 494 495 function compare(el, e) { 496 if (timer) timer = clearTimeout(timer); 497 if (Math.abs(pX - x) + Math.abs(pY - y) < options.sensitivity) { 498 state = 1; 499 return focused ? undefined : onOver.call(el, e); 500 } else { 501 pX = x; 502 pY = y; 503 timer = setTimeout(function () { 504 compare(el, e); 505 }, options.interval); 506 } 507 } 508 509 // Public methods 510 h.options = function (opt) { 511 var focusOptionChanged = opt.handleFocus !== options.handleFocus; 512 options = _extends({}, options, opt); 513 if (focusOptionChanged) { 514 options.handleFocus ? addFocus() : removeFocus(); 501 515 } 516 return h; 502 517 }; 503 518 504 addEvent(w, 'load', function() { 505 aB = d.getElementById('wpadminbar'); 519 function dispatchOver(e) { 520 mouseOver = true; 521 if (timer) timer = clearTimeout(timer); 522 el.removeEventListener('mousemove', tracker, false); 523 524 if (state !== 1) { 525 pX = e.clientX; 526 pY = e.clientY; 527 528 el.addEventListener('mousemove', tracker, false); 506 529 507 if ( d.body && aB ) { 508 d.body.appendChild( aB ); 530 timer = setTimeout(function () { 531 compare(el, e); 532 }, options.interval); 533 } 509 534 510 if ( aB.className )511 aB.className = aB.className.replace(/nojs/, '');535 return this; 536 } 512 537 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 }); 538 function dispatchOut(e) { 539 mouseOver = false; 540 if (timer) timer = clearTimeout(timer); 541 el.removeEventListener('mousemove', tracker, false); 542 543 if (state === 1) { 544 timer = setTimeout(function () { 545 delay(el, e); 546 }, options.timeout); 537 547 } 538 548 539 if ( w.location.hash )540 w.scrollBy(0,-32);549 return this; 550 } 541 551 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 ) ) { 552 function dispatchFocus(e) { 553 if (!mouseOver) { 554 focused = true; 555 onOver.call(el, e); 556 } 557 } 544 558 545 document.body.className += ' no-font-face'; 559 function dispatchBlur(e) { 560 if (!mouseOver && focused) { 561 focused = false; 562 onOut.call(el, e); 546 563 } 547 }); 548 })(document, window); 564 } 565 566 function addFocus() { 567 el.addEventListener('focus', dispatchFocus, false); 568 el.addEventListener('blur', dispatchBlur, false); 569 } 570 571 function removeFocus() { 572 el.removeEventListener('focus', dispatchFocus, false); 573 el.removeEventListener('blur', dispatchBlur, false); 574 } 575 576 h.remove = function () { 577 if (!el) return; 578 el.removeEventListener('mouseover', dispatchOver, false); 579 el.removeEventListener('mouseout', dispatchOut, false); 580 removeFocus(); 581 }; 549 582 550 } 583 if (el) { 584 el.addEventListener('mouseover', dispatchOver, false); 585 el.addEventListener('mouseout', dispatchOut, false); 586 } 587 588 return h; 589 } 590 })(document, window);