Choices/src/scripts/src/components/container.js

181 lines
4.2 KiB
JavaScript
Raw Normal View History

2017-12-11 15:40:38 +01:00
import { getWindowHeight, wrap } from '../lib/utils';
2017-12-10 19:00:57 +01:00
2017-08-16 17:31:47 +02:00
export default class Container {
2018-05-21 18:01:03 +02:00
constructor({ element, type, classNames, position }) {
Object.assign(this, { element, classNames, type, position });
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;
2018-05-21 18:01:03 +02:00
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-29 13:56:54 +02:00
/**
* Determine whether container should be flipped
* based on passed dropdown position
* @param {Number} dropdownPos
* @returns
*/
2017-12-10 19:00:57 +01:00
shouldFlip(dropdownPos, windowHeight = getWindowHeight()) {
2017-09-29 14:26:47 +02:00
if (dropdownPos === undefined) {
return false;
}
2018-05-21 18:01:03 +02:00
// If flip is enabled and the dropdown bottom position is
// greater than the window height flip the dropdown.
let shouldFlip = false;
2018-05-21 18:01:03 +02:00
if (this.position === 'auto') {
2017-12-10 19:00:57 +01:00
shouldFlip = dropdownPos >= windowHeight;
2018-05-21 18:01:03 +02:00
} else if (this.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
*/
setActiveDescendant(activeDescendantID) {
this.element.setAttribute('aria-activedescendant', activeDescendantID);
2017-08-27 14:49:35 +02:00
}
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');
}
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();
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() {
this.element.classList.add(this.classNames.focusState);
}
2017-08-27 14:49:35 +02:00
removeFocusState() {
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() {
2017-12-10 19:13:13 +01:00
this.element.classList.remove(this.classNames.disabledState);
2017-08-17 14:50:14 +02:00
this.element.removeAttribute('aria-disabled');
2018-05-21 18:01:03 +02:00
if (this.type === 'select-one') {
2017-08-17 14:50:14 +02:00
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() {
2017-12-10 19:13:13 +01:00
this.element.classList.add(this.classNames.disabledState);
2017-08-17 14:50:14 +02:00
this.element.setAttribute('aria-disabled', 'true');
2018-05-21 18:01:03 +02:00
if (this.type === 'select-one') {
2017-08-17 14:50:14 +02:00
this.element.setAttribute('tabindex', '-1');
}
this.isDisabled = true;
}
2017-08-27 14:49:35 +02:00
2017-12-11 15:40:38 +01:00
wrap(element) {
wrap(element, this.element);
2017-12-11 15:40:38 +01:00
}
unwrap(element) {
// Move passed element outside this element
2017-10-18 14:05:07 +02:00
this.element.parentNode.insertBefore(
element,
2017-10-18 14:05:07 +02:00
this.element,
);
// Remove this element
2017-10-18 14:05:07 +02:00
this.element.parentNode.removeChild(this.element);
}
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
}