'use strict';

/**
 * File navigation.js.
 *
 * Handles toggling the navigation menu for small screens and enables TAB key
 * navigation support for dropdown menus.
 */

var SITENAV = document.querySelector('.main-navigation'),
    KEYMAP = {
	TAB: 9
};

// Initiate the menus when the DOM loads.
document.addEventListener('DOMContentLoaded', function () {
	initMainNavigation();
	initMenuToggle();
});

/**
 * Initiate the main navigation script.
 */
function initMainNavigation() {

	// No point if no site nav.
	if (!SITENAV) {
		return;
	}

	// Get the submenus.
	var SUBMENUS = SITENAV.querySelectorAll('.menu ul');

	// No point if no submenus.
	if (!SUBMENUS.length) {
		return;
	}

	// Create the dropdown button.
	var dropdownButton = getDropdownButton();

	SUBMENUS.forEach(function (submenu) {
		var parentMenuItem = submenu.parentNode;
		var dropdown = parentMenuItem.querySelector('.dropdown');

		// If no dropdown, create one.
		if (!dropdown) {

			// Create dropdown.
			dropdown = document.createElement('span');
			dropdown.classList.add('dropdown');

			var dropdownSymbol = document.createElement('i');
			dropdownSymbol.classList.add('dropdown-symbol');
			dropdown.appendChild(dropdownSymbol);

			// Add before submenu.
			submenu.parentNode.insertBefore(dropdown, submenu);
		}

		// Convert dropdown to button.
		var thisDropdownButton = dropdownButton.cloneNode(true);

		// Copy contents of dropdown into button.
		thisDropdownButton.innerHTML = dropdown.innerHTML;

		// Replace dropdown with toggle button.
		dropdown.parentNode.replaceChild(thisDropdownButton, dropdown);

		// Toggle the submenu when we click the dropdown button.
		thisDropdownButton.addEventListener('click', function (event) {
			toggleSubMenu(this.parentNode);
		});

		// Clean up the toggle if a mouse takes over from keyboard.
		parentMenuItem.addEventListener('mouseleave', function (event) {
			toggleSubMenu(this, false);
		});

		// When we focus on a menu link, make sure all siblings are closed.
		parentMenuItem.querySelector('a').addEventListener('focus', function (event) {
			this.parentNode.parentNode.querySelectorAll('li.toggled-on').forEach(function (item) {
				toggleSubMenu(item, false);
			});
		});

		// Handle keyboard accessibility for traversing menu.
		submenu.addEventListener('keydown', function (event) {

			// These specific selectors help us only select items that are visible.
			var focusSelector = 'ul.toggle-show > li > a, ul.toggle-show > li > button';

			if (KEYMAP.TAB === event.keyCode) {
				if (event.shiftKey) {

					// Means we're tabbing out of the beginning of the submenu.
					if (isfirstFocusableElement(this, document.activeElement, focusSelector)) {
						toggleSubMenu(this.parentNode, false);
					}
				} else {

					// Means we're tabbing out of the end of the submenu.
					if (islastFocusableElement(this, document.activeElement, focusSelector)) {
						toggleSubMenu(this.parentNode, false);
					}
				}
			}
		});
	});

	SITENAV.classList.add('has-dropdown-toggle');
}

/**
 * Initiate the mobile menu toggle button.
 */
function initMenuToggle() {
	var MENUTOGGLE = SITENAV.querySelector('.menu-toggle');

	// Return early if MENUTOGGLE is missing.
	if (!MENUTOGGLE) {
		return;
	}

	// Add an initial values for the attribute.
	MENUTOGGLE.setAttribute('aria-expanded', 'false');

	MENUTOGGLE.addEventListener('click', function () {
		SITENAV.classList.toggle('toggled-on');
		this.setAttribute('aria-expanded', 'false' === this.getAttribute('aria-expanded') ? 'true' : 'false');
	}, false);
}

/**
 * Toggle submenus open and closed, and tell screen readers what's going on.
 */
function toggleSubMenu(parentMenuItem, forceToggle) {
	var toggleButton = parentMenuItem.querySelector('.dropdown-toggle'),
	    subMenu = parentMenuItem.querySelector('ul');
	var parentMenuItemToggled = parentMenuItem.classList.contains('toggled-on');

	// Will be true if we want to force the toggle on, false if force toggle close.
	if (undefined !== forceToggle && 'boolean' == typeof forceToggle) {
		parentMenuItemToggled = !forceToggle;
	}

	// Toggle aria-expanded status.
	toggleButton.setAttribute('aria-expanded', (!parentMenuItemToggled).toString());

	/*
  * Steps to handle during toggle:
  * - Let the parent menu item know we're toggled on/off.
  * - Toggle the ARIA label to let screen readers know will expand or collapse.
  */
	if (parentMenuItemToggled) {

		// Toggle "off" the submenu.
		parentMenuItem.classList.remove('toggled-on');
		subMenu.classList.remove('toggle-show');
		toggleButton.setAttribute('aria-label', wprigScreenReaderText.expand);

		// Make sure all children are closed.
		parentMenuItem.querySelectorAll('.toggled-on').forEach(function (item) {
			toggleSubMenu(item, false);
		});
	} else {

		// Make sure siblings are closed.
		parentMenuItem.parentNode.querySelectorAll('li.toggled-on').forEach(function (item) {
			toggleSubMenu(item, false);
		});

		// Toggle "on" the submenu.
		parentMenuItem.classList.add('toggled-on');
		subMenu.classList.add('toggle-show');
		toggleButton.setAttribute('aria-label', wprigScreenReaderText.collapse);
	}
}

/**
 * Returns the dropdown button
 * element needed for the menu.
 */
function getDropdownButton() {
	var dropdownButton = document.createElement('button');
	dropdownButton.classList.add('dropdown-toggle');
	dropdownButton.setAttribute('aria-expanded', 'false');
	dropdownButton.setAttribute('aria-label', wprigScreenReaderText.expand);
	return dropdownButton;
}

/**
 * Returns true if element is the
 * first focusable element in the container.
 */
function isfirstFocusableElement(container, element, focusSelector) {
	var focusableElements = container.querySelectorAll(focusSelector);
	if (0 < focusableElements.length) {
		return element === focusableElements[0];
	}
	return false;
}

/**
 * Returns true if element is the
 * last focusable element in the container.
 */
function islastFocusableElement(container, element, focusSelector) {
	var focusableElements = container.querySelectorAll(focusSelector);
	if (0 < focusableElements.length) {
		return element === focusableElements[focusableElements.length - 1];
	}
	return false;
}