UNPKG

@randstad-design/orbit-multitheme

Version:

multitheme Front-end code based on Randstad Human Forward components

204 lines (181 loc) 5.02 kB
/** * selector.js * script to toggle dropdown content by selector + set pointer position */ import ElementHelpers from '../helpers/element-helpers'; import trapFocus from '../helpers/trapFocus'; /** * Declare constants */ const attributeBase = 'data-rs-selector'; export class Selector { constructor(element) { this.element = element; this.dropdown = ElementHelpers.getElementByAttributeWithinElement( this.element, this.attributes.dropdown ); this.content = ElementHelpers.getElementByAttributeWithinElement( this.element, this.attributes.content ); this.pointer = ElementHelpers.getElementByAttributeWithinElement( this.element, this.attributes.pointer ); this.overlay = ElementHelpers.getElementByAttribute( this.attributes.overlay ); this.keystroke = 0; this.elementIsOpen; this.addEventHandlers(); } /** * Declare attribute constants */ get attributes() { return { content: `${attributeBase}-content`, dropdown: `${attributeBase}-dropdown`, overlay: `${attributeBase}-overlay`, pointer: `${attributeBase}-pointer` }; } /** * Declare classes */ get classes() { return { selectorDropDownActive: 'selector__dropdown--active', selectorContentActive: 'selector-box--active', modalOverlayActive: 'modal__overlay--active' }; } /** * Add event handlers */ addEventHandlers() { this.dropdown.addEventListener('click', (clickEvent) => { clickEvent.preventDefault(); if ( this.dropdown.classList.contains(this.classes.selectorDropDownActive) ) { this.closeContent(); } else { this.openContent(); } }); // if page contains overlay, on click, close content if (this.overlay !== null) { this.overlay.addEventListener('click', () => { this.closeContent(); }); } window.addEventListener('resize', () => { if ( this.dropdown.classList.contains(this.classes.selectorDropDownActive) ) { this.setPointer(); } }); document.addEventListener('keydown', (keydownEvent) => { this.handleButtonKeys(keydownEvent); }); } /** * Handle button keys - handle key presses escape * * @param {Event} event - event triggered */ handleButtonKeys(event) { if (event != null) { switch (ElementHelpers.getKeyCodeOnKeyDownEvent(event)) { case 'Tab': trapFocus(event, this.content, this.elementIsOpen, this.keystroke); if (this.elementIsOpen) { this.keystroke++; } break; case 'Escape': case 'Backspace': if (this.elementIsOpen) { this.closeContent(); this.dropdown.focus(); } } } } /** * Close content */ closeContent() { this.elementIsOpen = false; this.dropdown.classList.remove(this.classes.selectorDropDownActive); this.content.classList.remove(this.classes.selectorContentActive); // set aria attributes this.dropdown.setAttribute('aria-expanded', 'false'); this.content.setAttribute('aria-hidden', 'true'); if (this.overlay !== null) { this.overlay.classList.remove(this.classes.modalOverlayActive); } this.keystroke = 0; } /** * Open content */ openContent() { this.elementIsOpen = true; this.dropdown.classList.add(this.classes.selectorDropDownActive); this.content.classList.add(this.classes.selectorContentActive); this.setPointer(); // set aria attributes this.dropdown.setAttribute('aria-expanded', 'true'); this.content.setAttribute('aria-hidden', 'false'); if (this.overlay !== null) { this.overlay.classList.add(this.classes.modalOverlayActive); } } /** * Set pointer - defines position of pointer attribute on dropdown content */ setPointer() { const paddingRight = Math.round( window .getComputedStyle(this.dropdown, null) .getPropertyValue('padding-right') .replace('px', '') ); const childNodes = this.dropdown.childNodes; let iconWidth; for (let i = 0; i < childNodes.length; i++) { if ( childNodes[i].classList != null && childNodes[i].classList.contains('icon') ) { const visibleIcon = getComputedStyle(childNodes[i]).getPropertyValue('display') !== 'none' ? childNodes[i] : null; if (visibleIcon) { iconWidth = getComputedStyle(childNodes[i]) .getPropertyValue('width') .replace('px', ''); } } } this.pointer.style.left = `${ this.dropdown.offsetWidth - paddingRight - this.pointer.getBoundingClientRect().width / 2 + this.dropdown.offsetLeft - iconWidth / 3 + 1 }px`; } /** * Get selector */ static getSelector() { return `[${attributeBase}]`; } }