angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

admin-bar.js (10762B)


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