Untitled
unknown
javascript
2 years ago
8.5 kB
11
Indexable
/* 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();
Editor is loading...