Untitled
unknown
javascript
a year ago
8.5 kB
4
Indexable
Never
/* eslint no-console: ["error", { allow: ["warn", "error", "log"] }] */ // import Logger from '../legacy-core/logger'; const navActiveClass = 'nav--active'; const navButtonClass = 'nav--button--active'; const navBodyClass = 'overlay-lock'; const OVERLAY_CLASSES = ['search--active', 'property-finder--active', 'login--active']; class Navigation { /** * Navigation Constructor */ constructor() { this.menuActive = false; this.searchToggles = document.querySelectorAll('.js-search-toggle'); this.propertyFinderToggles = document.querySelectorAll('.js-property-finder-toggle'); this.loginToggles = document.querySelectorAll('.js-login-toggle'); this.body = document.querySelector('body'); this.navMain = document.querySelector('.js-nav-main'); this.navToggle = document.querySelector('.js-nav-toggle'); this.hasChildren = this.navMain.querySelectorAll('.has-children'); this.navButtons = document.querySelectorAll('.js-btn-nav'); this.navBackButtons = document.querySelectorAll('.js-btn-nav-back'); this.attachEventListeners(); window.addEventListener('resize', () => this.toggleNavigationOff()); } /** * Attaches event listeners to the corresponding elements in the DOM. * @returns {undefined} */ attachEventListeners() { // Nav toggle this.navToggle.addEventListener('click', (event) => this.navToggleClick(event)); // Search toggles this.searchToggles.forEach((searchToggle) => { searchToggle.addEventListener('click', () => this.overlayToggleClick('search')); }); // Login toggles this.loginToggles.forEach((loginToggle) => { loginToggle.addEventListener('click', () => this.overlayToggleClick('login')); }); // Property finder toggles this.propertyFinderToggles.forEach((propertyFinderToggle) => { propertyFinderToggle.addEventListener('click', ({ target }) => { this.updatePropertyFinderDisplay(target); this.overlayToggleClick('property-finder'); }); }); // Nav buttons this.navButtons.forEach((navButton) => { navButton.addEventListener('click', ({ target }) => this.navButtonClick(target)); }); // Nav back buttons this.navBackButtons.forEach((navBackButton) => { navBackButton.addEventListener('click', ({ target }) => this.navBackButtonClick(target)); }); } /** * Toggles the navigation off by setting the menuActive property to false, * adding the navBodyClass to the body element, and removing all active * classes from navigation elements and buttons * @return {void} - No return value */ toggleNavigationOff() { this.menuActive = false; this.body.classList.add(navBodyClass); this.removeAllNavActiveClasses(); this.removeAllButtonActiveClasses(); } /** * Toggles the navigation menu on by setting the required classes * @method toggleNavigationOn * * @return {void} - Does not return any value */ toggleNavigationOn() { this.menuActive = true; this.navToggle.classList.add(navActiveClass); this.body.classList.remove(navBodyClass); this.navMain.classList.add(navActiveClass); } /** * Removes specified classes from the document body. * * @param {Array} classes - An array of classes to remove from the document body. */ removeClassesFromBody(classes) { classes.forEach((classToRemove) => { if (this.body.classList.contains(classToRemove)) { this.body.classList.remove(classToRemove); } }); } /** * Removes the "navActiveClass" from all elements that have it. * * @returns {void} */ removeAllNavActiveClasses() { document.querySelectorAll(`.${navActiveClass}`).forEach((elem) => elem.classList.remove(navActiveClass)); } /** * Removes the "active" classes from all buttons with a specific class. * * @param {string} navButtonClass - The class name of the buttons to remove the "active" class from. * @returns {void} */ removeAllButtonActiveClasses() { document.querySelectorAll(`.${navButtonClass}`).forEach((elem) => elem.classList.remove(navButtonClass)); } /** * Toggles the overlay of a given type. * * @param {string} type - The type of the overlay to toggle. * @return {void} */ overlayToggleClick(type) { const activeClassForOverlayType = `${type}--active`; // Remove all overlay body classes apart from the one for this overlay type this.removeClassesFromBody(OVERLAY_CLASSES.filter((x) => x !== activeClassForOverlayType)); // Toggle off navigation this.toggleNavigationOff(); this.body.classList.toggle(`${type}--active`); } /** * Handles click event of the navigation toggle button. * * @param {Event} event - The click event. */ navToggleClick(event) { event.stopPropagation(); this.removeClassesFromBody(OVERLAY_CLASSES); // eslint-disable-next-line no-unused-expressions this.menuActive ? this.toggleNavigationOff() : this.toggleNavigationOn(); } /** * Removes the active class for all grandchild elements of the navigation container * @function removeAllGrandchildActiveClasses * @returns {void} */ removeAllGrandchildActiveClasses() { document.querySelectorAll('.js-nav-grandchild') .forEach((grandchild) => grandchild.classList.remove(navActiveClass)); } /** * Removes the active class from all child elements with the class 'js-nav-child'. * * @returns {void} */ removeAllChildActiveClasses() { document.querySelectorAll('.js-nav-child') .forEach((child) => child.classList.remove(navActiveClass)); } /** * Handles clicks on a navigation button * * @param {HTMLElement} clickedButton - The button element that was clicked. */ navButtonClick(clickedButton) { const isChildItem = clickedButton.classList.contains('nav--item__child'); const isActiveItem = clickedButton.classList.contains(navButtonClass); this.removeClassesFromBody(OVERLAY_CLASSES); let container; if (isChildItem) { container = clickedButton.closest('.has-grandchildren'); this.removeAllGrandchildActiveClasses(); if (!isActiveItem) { container.querySelector('.js-nav-grandchild').classList.add(navActiveClass); } } else { // Is top level item container = clickedButton.closest('.has-children'); this.removeAllChildActiveClasses(); if (!isActiveItem) { container.querySelector('.js-nav-child').classList.add(navActiveClass); } } this.navButtons.forEach((button) => { button.classList.remove(navButtonClass); }); if (isActiveItem) { clickedButton.classList.remove(navButtonClass); } else { clickedButton.classList.add(navButtonClass); } } /** * Handles the click event of the back buttons * Removes the "navActiveClass" from the closest ancestor element containing the clickedButton. * * @param {HTMLElement} clickedButton - The element representing the navigation back button that was clicked. * @return {undefined} */ navBackButtonClick(clickedButton) { clickedButton.closest(`.${navActiveClass}`).classList.remove(navActiveClass); } /** * Updates the property finder display based on the clicked button. * * @param {Element} clickedButton - The button element that was clicked. */ updatePropertyFinderDisplay(clickedButton) { const buttonElem = clickedButton.classList.contains('js-property-finder-toggle') ? clickedButton : clickedButton.closest('button'); const finderHeading = buttonElem.getAttribute('data-property-finder-title'); const finderDefaultType = buttonElem.getAttribute('data-property-finder-default-property-type'); const finderButtonText = buttonElem.getAttribute('data-property-finder-button-text'); document.getElementById('property-finder-heading').innerText = finderHeading; const searchTypeInput = document.querySelector('.property-finder--overlay .js-property-search-type'); searchTypeInput.value = finderDefaultType; document.querySelector('#property-finder-overlay-form .js-submit-btn').value = finderButtonText; } } export default new Navigation();