2017-08-16 17:31:47 +02:00
|
|
|
export default class Container {
|
2017-10-10 13:56:36 +02:00
|
|
|
constructor(instance, element, classNames) {
|
2017-08-16 17:31:47 +02:00
|
|
|
this.instance = instance;
|
|
|
|
this.element = element;
|
2017-10-10 13:56:36 +02:00
|
|
|
this.classNames = classNames;
|
2017-08-16 17:59:10 +02:00
|
|
|
this.config = instance.config;
|
|
|
|
this.isOpen = false;
|
|
|
|
this.isFlipped = false;
|
|
|
|
this.isFocussed = false;
|
2017-08-17 14:50:14 +02:00
|
|
|
this.isDisabled = false;
|
2017-08-29 13:56:54 +02:00
|
|
|
this.isLoading = false;
|
2017-08-27 14:49:35 +02:00
|
|
|
this.onFocus = this.onFocus.bind(this);
|
|
|
|
this.onBlur = this.onBlur.bind(this);
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Add event listeners
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
addEventListeners() {
|
|
|
|
this.element.addEventListener('focus', this.onFocus);
|
|
|
|
this.element.addEventListener('blur', this.onBlur);
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Remove event listeners
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** */
|
2017-08-27 14:49:35 +02:00
|
|
|
removeEventListeners() {
|
|
|
|
this.element.removeEventListener('focus', this.onFocus);
|
|
|
|
this.element.removeEventListener('blur', this.onBlur);
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Set focussed state
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
onFocus() {
|
|
|
|
this.isFocussed = true;
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Remove blurred state
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
onBlur() {
|
|
|
|
this.isFocussed = false;
|
2017-08-16 17:59:10 +02:00
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Determine whether container should be flipped
|
|
|
|
* based on passed dropdown position
|
|
|
|
* @param {Number} dropdownPos
|
|
|
|
* @returns
|
|
|
|
*/
|
2017-08-16 17:59:10 +02:00
|
|
|
shouldFlip(dropdownPos) {
|
2017-09-29 14:26:47 +02:00
|
|
|
if (dropdownPos === undefined) {
|
2017-08-16 17:59:10 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const body = document.body;
|
|
|
|
const html = document.documentElement;
|
|
|
|
const winHeight = Math.max(
|
|
|
|
body.scrollHeight,
|
|
|
|
body.offsetHeight,
|
|
|
|
html.clientHeight,
|
|
|
|
html.scrollHeight,
|
|
|
|
html.offsetHeight,
|
|
|
|
);
|
|
|
|
|
|
|
|
// If flip is enabled and the dropdown bottom position is
|
|
|
|
// greater than the window height flip the dropdown.
|
|
|
|
let shouldFlip = false;
|
|
|
|
if (this.config.position === 'auto') {
|
|
|
|
shouldFlip = dropdownPos >= winHeight;
|
|
|
|
} else if (this.config.position === 'top') {
|
|
|
|
shouldFlip = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shouldFlip;
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Set active descendant attribute
|
|
|
|
* @param {Number} activeDescendant ID of active descendant
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
setActiveDescendant(activeDescendant) {
|
|
|
|
this.element.setAttribute('aria-activedescendant', activeDescendant);
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Remove active descendant attribute
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
removeActiveDescendant() {
|
|
|
|
this.element.removeAttribute('aria-activedescendant');
|
|
|
|
}
|
|
|
|
|
2017-08-16 17:59:10 +02:00
|
|
|
open(dropdownPos) {
|
|
|
|
this.element.classList.add(this.classNames.openState);
|
|
|
|
this.element.setAttribute('aria-expanded', 'true');
|
|
|
|
this.isOpen = true;
|
|
|
|
|
|
|
|
if (this.shouldFlip(dropdownPos)) {
|
|
|
|
this.element.classList.add(this.classNames.flippedState);
|
|
|
|
this.isFlipped = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close() {
|
|
|
|
this.element.classList.remove(this.classNames.openState);
|
|
|
|
this.element.setAttribute('aria-expanded', 'false');
|
2017-08-27 14:49:35 +02:00
|
|
|
this.removeActiveDescendant();
|
2017-08-16 17:59:10 +02:00
|
|
|
this.isOpen = false;
|
|
|
|
|
|
|
|
// A dropdown flips if it does not have space within the page
|
|
|
|
if (this.isFlipped) {
|
|
|
|
this.element.classList.remove(this.classNames.flippedState);
|
|
|
|
this.isFlipped = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
focus() {
|
2017-08-27 14:49:35 +02:00
|
|
|
if (!this.isFocussed) {
|
|
|
|
this.element.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addFocusState() {
|
2017-08-16 17:59:10 +02:00
|
|
|
this.element.classList.add(this.classNames.focusState);
|
|
|
|
}
|
|
|
|
|
2017-08-27 14:49:35 +02:00
|
|
|
removeFocusState() {
|
2017-08-16 17:59:10 +02:00
|
|
|
this.element.classList.remove(this.classNames.focusState);
|
2017-08-16 17:31:47 +02:00
|
|
|
}
|
2017-08-17 14:50:14 +02:00
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Remove disabled state
|
|
|
|
*/
|
2017-08-17 14:50:14 +02:00
|
|
|
enable() {
|
|
|
|
this.element.classList.remove(this.config.classNames.disabledState);
|
|
|
|
this.element.removeAttribute('aria-disabled');
|
|
|
|
if (this.instance.isSelectOneElement) {
|
|
|
|
this.element.setAttribute('tabindex', '0');
|
|
|
|
}
|
|
|
|
this.isDisabled = false;
|
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Set disabled state
|
|
|
|
*/
|
2017-08-17 14:50:14 +02:00
|
|
|
disable() {
|
|
|
|
this.element.classList.add(this.config.classNames.disabledState);
|
|
|
|
this.element.setAttribute('aria-disabled', 'true');
|
|
|
|
if (this.instance.isSelectOneElement) {
|
|
|
|
this.element.setAttribute('tabindex', '-1');
|
|
|
|
}
|
|
|
|
this.isDisabled = true;
|
|
|
|
}
|
2017-08-27 14:49:35 +02:00
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Add loading state to element
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
addLoadingState() {
|
|
|
|
this.element.classList.add(this.classNames.loadingState);
|
|
|
|
this.element.setAttribute('aria-busy', 'true');
|
2017-08-29 13:56:54 +02:00
|
|
|
this.isLoading = true;
|
2017-08-27 14:49:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-29 13:56:54 +02:00
|
|
|
/**
|
|
|
|
* Remove loading state from element
|
|
|
|
*/
|
2017-08-27 14:49:35 +02:00
|
|
|
removeLoadingState() {
|
|
|
|
this.element.classList.remove(this.classNames.loadingState);
|
|
|
|
this.element.removeAttribute('aria-busy');
|
2017-08-29 13:56:54 +02:00
|
|
|
this.isLoading = false;
|
2017-08-27 14:49:35 +02:00
|
|
|
}
|
2017-08-16 17:31:47 +02:00
|
|
|
}
|