Index: src/js/_enqueues/lib/admin-bar.js
===================================================================
--- src/js/_enqueues/lib/admin-bar.js	(revision 46879)
+++ src/js/_enqueues/lib/admin-bar.js	(working copy)
@@ -4,45 +4,54 @@
 /**
  * Admin bar with Vanilla JS, no external dependencies.
  *
+ * @since 5.3.1
+ *
  * @param {Object} document  The document object.
  * @param {Object} window    The window object.
  * @param {Object} navigator The navigator object.
  *
  * @return {void}
  */
-/* global hoverintent */
 ( function( document, window, navigator ) {
 	document.addEventListener( 'DOMContentLoaded', function() {
 		var adminBar = document.getElementById( 'wpadminbar' ),
-			topMenuItems = adminBar.querySelectorAll( 'li.menupop' ),
-			allMenuItems = adminBar.querySelectorAll( '.ab-item' ),
-			adminBarLogout = document.getElementById( 'wp-admin-bar-logout' ),
-			adminBarSearchForm = document.getElementById( 'adminbarsearch' ),
-			shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' ),
-			skipLink = adminBar.querySelector( '.screen-reader-shortcut' ),
-			mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click',
+			topMenuItems,
+			allMenuItems,
+			adminBarLogout,
+			adminBarSearchForm,
+			shortlink,
+			skipLink,
+			mobileEvent,
+			fontFaceRegex,
 			adminBarSearchInput,
 			i;
 
-		/**
-		 * Remove nojs class after the DOM is loaded.
-		 */
-		adminBar.classList.remove( 'nojs' );
+		if ( ! adminBar || ! ( 'querySelectorAll' in adminBar ) ) {
+			return;
+		}
+
+		topMenuItems = adminBar.querySelectorAll( 'li.menupop' );
+		allMenuItems = adminBar.querySelectorAll( '.ab-item' );
+		adminBarLogout = document.getElementById( 'wp-admin-bar-logout' );
+		adminBarSearchForm = document.getElementById( 'adminbarsearch' );
+		shortlink = document.getElementById( 'wp-admin-bar-get-shortlink' );
+		skipLink = adminBar.querySelector( '.screen-reader-shortcut' );
+		mobileEvent = /Mobile\/.+Safari/.test( navigator.userAgent ) ? 'touchstart' : 'click';
+		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/;
+
+		// Remove nojs class after the DOM is loaded.
+		removeClass( adminBar, 'nojs' );
 
 		if ( 'ontouchstart' in window ) {
-			/**
-			 * Remove hover class when the user touches outside the menu items.
-			 */
+			// Remove hover class when the user touches outside the menu items.
 			document.body.addEventListener( mobileEvent, function( e ) {
 				if ( ! getClosest( e.target, 'li.menupop' ) ) {
 					removeAllHoverClass( topMenuItems );
 				}
 			} );
 
-			/**
-			 * Add listener for menu items to toggle hover class by touches.
-			 * Remove the callback later for better performance.
-			 */
+			// Add listener for menu items to toggle hover class by touches.
+			// Remove the callback later for better performance.
 			adminBar.addEventListener( 'touchstart', function bindMobileEvents() {
 				for ( var i = 0; i < topMenuItems.length; i++ ) {
 					topMenuItems[i].addEventListener( 'click', mobileHover.bind( null, topMenuItems ) );
@@ -52,32 +61,24 @@
 			} );
 		}
 
-		/**
-		 * Scroll page to top when clicking on the admin bar.
-		 */
+		// Scroll page to top when clicking on the admin bar.
 		adminBar.addEventListener( 'click', scrollToTop );
 
 		for ( i = 0; i < topMenuItems.length; i++ ) {
-			/**
-			 * Adds or removes the hover class based on the hover intent.
-			 */
-			hoverintent(
+			// Adds or removes the hover class based on the hover intent.
+			window.hoverintent(
 				topMenuItems[i],
-				addHoverClass.bind( null, topMenuItems[i] ),
-				removeHoverClass.bind( null, topMenuItems[i] )
+				addClass.bind( null, topMenuItems[i], 'hover' ),
+				removeClass.bind( null, topMenuItems[i], 'hover' )
 			).options( {
 				timeout: 180
 			} );
 
-			/**
-			 * Toggle hover class if the enter key is pressed.
-			 */
+			// Toggle hover class if the enter key is pressed.
 			topMenuItems[i].addEventListener( 'keydown', toggleHoverIfEnter );
 		}
 
-		/**
-		 * Remove hover class if the escape key is pressed.
-		 */
+		// Remove hover class if the escape key is pressed.
 		for ( i = 0; i < allMenuItems.length; i++ ) {
 			allMenuItems[i].addEventListener( 'keydown', removeHoverIfEscape );
 		}
@@ -85,131 +86,128 @@
 		if ( adminBarSearchForm ) {
 			adminBarSearchInput = document.getElementById( 'adminbar-search' );
 
-			/**
-			 * Adds the adminbar-focused class on focus.
-			 */
+			// Adds the adminbar-focused class on focus.
 			adminBarSearchInput.addEventListener( 'focus', function() {
-				adminBarSearchForm.classList.add( 'adminbar-focused' );
+				addClass( adminBarSearchForm, 'adminbar-focused' );
 			} );
 
-			/**
-			 * Removes the adminbar-focused class on blur.
-			 */
+			// Removes the adminbar-focused class on blur.
 			adminBarSearchInput.addEventListener( 'blur', function() {
-				adminBarSearchForm.classList.remove( 'adminbar-focused' );
+				removeClass( adminBarSearchForm, 'adminbar-focused' );
 			} );
 		}
 
-		/**
-		 * Focus the target of skip link after pressing Enter.
-		 */
-		skipLink.addEventListener( 'keydown', focusTargetAfterEnter );
+		if ( skipLink ) {
+			// Focus the target of skip link after pressing Enter.
+			skipLink.addEventListener( 'keydown', focusTargetAfterEnter );
+		}
 
 		if ( shortlink ) {
 			shortlink.addEventListener( 'click', clickShortlink );
 		}
 
-		/**
-		 * Prevents the toolbar from covering up content when a hash is present
-		 * in the URL.
-		 */
+		// Prevents the toolbar from covering up content when a hash is present in the URL.
 		if ( window.location.hash ) {
 			window.scrollBy( 0, -32 );
 		}
 
-		/**
-		 * Add no-font-face class to body if needed.
-		 */
-		if ( navigator.userAgent && document.body.className.indexOf( 'no-font-face' ) === -1 &&
-			/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 ) ) {
-			document.body.className += ' no-font-face';
+		// Add no-font-face class to body if needed.
+		if (
+			navigator.userAgent &&
+			fontFaceRegex.test( navigator.userAgent ) &&
+			! hasClass( document.body, 'no-font-face' )
+		) {
+			addClass( document.body, 'no-font-face' );
 		}
 
-		/**
-		 * Clear sessionStorage on logging out.
-		 */
-		adminBarLogout.addEventListener( 'click', emptySessionStorage );
+		// Clear sessionStorage on logging out.
+		if ( adminBarLogout ) {
+			adminBarLogout.addEventListener( 'click', emptySessionStorage );
+		}
 	} );
 
 	/**
 	 * Remove hover class for top level menu item when escape is pressed.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {Event} e The keydown event.
+	 * @param {Event} event The keydown event.
 	 */
-	function removeHoverIfEscape( e ) {
+	function removeHoverIfEscape( event ) {
 		var wrapper;
 
-		if ( e.which != 27 ) {
+		if ( event.which !== 27 ) {
 			return;
 		}
 
-		wrapper = getClosest( e.target, '.menupop' );
+		wrapper = getClosest( event.target, '.menupop' );
 
 		if ( ! wrapper ) {
 			return;
 		}
 
 		wrapper.querySelector( '.menupop > .ab-item' ).focus();
-		removeHoverClass( wrapper );
+		removeClass( wrapper, 'hover' );
 	}
 
 	/**
 	 * Toggle hover class for top level menu item when enter is pressed.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {Event} e The keydown event.
+	 * @param {Event} event The keydown event.
 	 */
-	function toggleHoverIfEnter( e ) {
+	function toggleHoverIfEnter( event ) {
 		var wrapper;
 
-		if ( e.which != 13 ) {
+		if ( event.which !== 13 ) {
 			return;
 		}
 
-		if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
+		if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) {
 			return;
 		}
 
-		wrapper = getClosest( e.target, '.menupop' );
+		wrapper = getClosest( event.target, '.menupop' );
 
 		if ( ! wrapper ) {
 			return;
 		}
 
-		e.preventDefault();
-		if ( hasHoverClass( wrapper ) ) {
-			removeHoverClass( wrapper );
+		event.preventDefault();
+
+		if ( hasClass( wrapper, 'hover' ) ) {
+			removeClass( wrapper, 'hover' );
 		} else {
-			addHoverClass( wrapper );
+			addClass( wrapper, 'hover' );
 		}
 	}
 
 	/**
 	 * Focus the target of skip link after pressing Enter.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {Event} e The keydown event.
+	 * @param {Event} event The keydown event.
 	 */
-	function focusTargetAfterEnter( e ) {
+	function focusTargetAfterEnter( event ) {
 		var id, userAgent;
 
-		if ( 13 !==	e.which ) {
+		if ( event.which !== 13 ) {
 			return;
 		}
 
-		id = e.target.getAttribute( 'href' );
+		id = event.target.getAttribute( 'href' );
 		userAgent = navigator.userAgent.toLowerCase();
 
-		if ( userAgent.indexOf( 'applewebkit' ) != -1 && id && id.charAt( 0 ) == '#' ) {
+		if ( userAgent.indexOf( 'applewebkit' ) > -1 && id && id.charAt( 0 ) === '#' ) {
 			setTimeout( function() {
 				var target = document.getElementById( id.replace( '#', '' ) );
 
-				target.setAttribute( 'tabIndex', '0' );
-				target.focus();
+				if ( target ) {
+					target.setAttribute( 'tabIndex', '0' );
+					target.focus();
+				}
 			}, 100 );
 		}
 	}
@@ -217,31 +215,31 @@
 	/**
 	 * Toogle hover class for mobile devices.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
 	 * @param {NodeList} topMenuItems All menu items.
-	 * @param {Event} e The click event.
+	 * @param {Event} event The click event.
 	 */
-	function mobileHover( topMenuItems, e ) {
+	function mobileHover( topMenuItems, event ) {
 		var wrapper;
 
-		if ( !! getClosest( e.target, '.ab-sub-wrapper' ) ) {
+		if ( !! getClosest( event.target, '.ab-sub-wrapper' ) ) {
 			return;
 		}
 
-		e.preventDefault();
+		event.preventDefault();
 
-		wrapper = getClosest( e.target, '.menupop' );
+		wrapper = getClosest( event.target, '.menupop' );
 
 		if ( ! wrapper ) {
 			return;
 		}
 
-		if ( hasHoverClass( wrapper ) ) {
-			removeHoverClass( wrapper );
+		if ( hasClass( wrapper, 'hover' ) ) {
+			removeClass( wrapper, 'hover' );
 		} else {
 			removeAllHoverClass( topMenuItems );
-			addHoverClass( wrapper );
+			addClass( wrapper, 'hover' );
 		}
 	}
 
@@ -249,27 +247,36 @@
 	 * Handles the click on the Shortlink link in the adminbar.
 	 *
 	 * @since 3.1.0
-	 * @since 5.3.0 Use querySelector to clean up the function.
-	 *
-	 * @param {Event} e The click event.
+	 * @since 5.3.1 Use querySelector to clean up the function.
 	 *
+	 * @param {Event} event The click event.
 	 * @return {boolean} Returns false to prevent default click behavior.
 	 */
-	function clickShortlink( e ) {
-		var wrapper = e.target.parentNode,
+	function clickShortlink( event ) {
+		var wrapper = event.target.parentNode,
+			input;
+
+		if ( wrapper ) {
 			input = wrapper.querySelector( '.shortlink-input' );
+		}
+
+		if ( ! input ) {
+			return;
+		}
 
-		// IE doesn't support preventDefault, and does support returnValue
-		if ( e.preventDefault ) {
-			e.preventDefault();
+		// (Old) IE doesn't support preventDefault, and does support returnValue
+		if ( event.preventDefault ) {
+			event.preventDefault();
 		}
-		e.returnValue = false;
 
-		wrapper.classList.add( 'selected' );
+		event.returnValue = false;
+
+		addClass( wrapper, 'selected' );
+
 		input.focus();
 		input.select();
 		input.onblur = function() {
-			wrapper.classList.remove( 'selected' );
+			removeClass( wrapper, 'selected' );
 		};
 
 		return false;
@@ -278,64 +285,106 @@
 	/**
 	 * Clear sessionStorage on logging out.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 */
 	function emptySessionStorage() {
 		if ( 'sessionStorage' in window ) {
 			try {
 				for ( var key in sessionStorage ) {
-					if ( key.indexOf( 'wp-autosave-' ) != -1 ) {
+					if ( key.indexOf( 'wp-autosave-' ) > -1 ) {
 						sessionStorage.removeItem( key );
 					}
 				}
-			} catch ( e ) {}
+			} catch ( er ) {}
 		}
 	}
 
 	/**
-	 * Check if menu item has hover class.
+	 * Check if element has class.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {HTMLElement} item Menu item Element.
+	 * @param {HTMLElement} element The HTML element.
+	 * @param {String}      className The class name.
+	 * @return {bool} Whether the element has the className.
 	 */
-	function hasHoverClass( item ) {
-		return item.classList.contains( 'hover' );
+	function hasClass( element, className ) {
+		var classNames;
+
+		if ( element ) {
+			if ( element.classList && element.classList.contains ) {
+				return element.classList.contains( className );
+			} else if ( element.className ) {
+				classNames = element.className.split( ' ' );
+				return classNames.indexOf( className ) > -1;
+			}
+		}
+
+		return false;
 	}
 
 	/**
-	 * Add hover class for menu item.
+	 * Add class to an element.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {HTMLElement} item Menu item Element.
+	 * @param {HTMLElement} element The HTML element.
+	 * @param {String}      className The class name.
 	 */
-	function addHoverClass( item ) {
-		item.classList.add( 'hover' );
+	function addClass( element, className ) {
+		if ( element ) {
+			if ( element.classList && element.classList.add ) {
+				element.classList.add( className );
+			} else if ( ! hasClass( element, className ) ) {
+				if ( element.className ) {
+					element.className += ' ';
+				}
+
+				element.className += className;
+			}
+		}
 	}
 
 	/**
 	 * Remove hover class for menu item.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
-	 * @param {HTMLElement} item Menu item Element.
+	 * @param {HTMLElement} element The HTML element.
+	 * @param {String}      className The class name.
 	 */
-	function removeHoverClass( item ) {
-		item.classList.remove( 'hover' );
+	function removeClass( element, className ) {
+		var testName,
+			classes;
+
+		if ( element && hasClass( element, className ) ) {
+			if ( element.classList && element.classList.remove ) {
+				element.classList.remove( className );
+			} else {
+				testName = ' ' + className + ' ';
+				classes = ' ' + element.className + ' ';
+
+				while ( classes.indexOf( testName ) > -1 ) {
+					classes = classes.replace( testName, '' );
+				}
+
+				element.className = classes.replace( /^[\s]+|[\s]+$/g, '' );
+			}
+		}
+
 	}
 
 	/**
 	 * Remove hover class for all menu items.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
 	 * @param {NodeList} topMenuItems All menu items.
 	 */
 	function removeAllHoverClass( topMenuItems ) {
-		for ( var i = 0; i < topMenuItems.length; i++ ) {
-			if ( hasHoverClass( topMenuItems[i] ) ) {
-				removeHoverClass( topMenuItems[i] );
+		if ( topMenuItems && topMenuItems.length ) {
+			for ( var i = 0; i < topMenuItems.length; i++ ) {
+				removeClass( topMenuItems[i], 'hover' );
 			}
 		}
 	}
@@ -354,8 +403,8 @@
 		if (
 			event.target &&
 			event.target.id &&
-			event.target.id != 'wpadminbar' &&
-			event.target.id != 'wp-admin-bar-top-secondary'
+			event.target.id !== 'wpadminbar' &&
+			event.target.id !== 'wp-admin-bar-top-secondary'
 		) {
 			return;
 		}
@@ -374,33 +423,39 @@
 	/**
 	 * Get closest Element.
 	 *
-	 * @since 5.3.0
+	 * @since 5.3.1
 	 *
 	 * @param {HTMLElement} el Element to get parent.
 	 * @param {string} selector CSS selector to match.
 	 */
 	function getClosest( el, selector ) {
-		if ( ! Element.prototype.matches ) {
-			Element.prototype.matches =
-				Element.prototype.matchesSelector ||
-				Element.prototype.mozMatchesSelector ||
-				Element.prototype.msMatchesSelector ||
-				Element.prototype.oMatchesSelector ||
-				Element.prototype.webkitMatchesSelector ||
-				function( s ) {
-					var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ),
-						i = matches.length;
-					while ( --i >= 0 && matches.item( i ) !== this ) { }
-					return i > -1;
-				};
-		}
-
-		// Get the closest matching elent
-		for ( ; el && el !== document; el = el.parentNode ) {
-			if ( el.matches( selector ) ) {
-				return el;
+		if ( window.Element ) {
+			if ( ! window.Element.prototype.matches ) {
+				// Polyfill from https://developer.mozilla.org/en-US/docs/Web/API/Element/matches.
+				window.Element.prototype.matches =
+					window.Element.prototype.matchesSelector ||
+					window.Element.prototype.mozMatchesSelector ||
+					window.Element.prototype.msMatchesSelector ||
+					window.Element.prototype.oMatchesSelector ||
+					window.Element.prototype.webkitMatchesSelector ||
+					function( s ) {
+						var matches = ( this.document || this.ownerDocument ).querySelectorAll( s ),
+							i = matches.length;
+
+						while ( --i >= 0 && matches.item( i ) !== this ) { }
+
+						return i > -1;
+					};
+			}
+
+			// Get the closest matching elent
+			for ( ; el && el !== document; el = el.parentNode ) {
+				if ( el.matches( selector ) ) {
+					return el;
+				}
 			}
 		}
+
 		return null;
 	}
 } )( document, window, navigator );
