@randstad-design/orbit-multitheme
Version:
multitheme Front-end code based on Randstad Human Forward components
204 lines (181 loc) • 5.02 kB
JavaScript
/**
* 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}]`;
}
}