mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-15 20:25:18 +02:00
Integrate dropdown opening with container class
This commit is contained in:
parent
1e40b60c3f
commit
b70f062acd
|
@ -747,36 +747,9 @@ class Choices {
|
|||
* @public
|
||||
*/
|
||||
showDropdown(focusInput = false) {
|
||||
const body = document.body;
|
||||
const html = document.documentElement;
|
||||
const winHeight = Math.max(
|
||||
body.scrollHeight,
|
||||
body.offsetHeight,
|
||||
html.clientHeight,
|
||||
html.scrollHeight,
|
||||
html.offsetHeight,
|
||||
);
|
||||
|
||||
this.containerOuter.element.classList.add(this.config.classNames.openState);
|
||||
this.containerOuter.element.setAttribute('aria-expanded', 'true');
|
||||
this.containerOuter.open(this.dropdown.getPosition());
|
||||
this.dropdown.show();
|
||||
|
||||
const dimensions = this.dropdown.element.getBoundingClientRect();
|
||||
const dropdownPos = Math.ceil(dimensions.top + window.scrollY + this.dropdown.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;
|
||||
}
|
||||
|
||||
if (shouldFlip) {
|
||||
this.containerOuter.element.classList.add(this.config.classNames.flippedState);
|
||||
}
|
||||
|
||||
// Optionally focus the input if we have a search input
|
||||
if (focusInput && this.canSearch && document.activeElement !== this.input) {
|
||||
this.input.focus();
|
||||
|
@ -793,26 +766,15 @@ class Choices {
|
|||
* @public
|
||||
*/
|
||||
hideDropdown(blurInput = false) {
|
||||
// A dropdown flips if it does not have space within the page
|
||||
const isFlipped = this.containerOuter.element.classList.contains(
|
||||
this.config.classNames.flippedState,
|
||||
);
|
||||
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.openState);
|
||||
this.containerOuter.element.setAttribute('aria-expanded', 'false');
|
||||
this.containerOuter.close();
|
||||
this.dropdown.hide();
|
||||
|
||||
if (isFlipped) {
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.flippedState);
|
||||
}
|
||||
|
||||
// Optionally blur the input if we have a search input
|
||||
if (blurInput && this.canSearch && document.activeElement === this.input) {
|
||||
this.input.blur();
|
||||
}
|
||||
|
||||
triggerEvent(this.passedElement, 'hideDropdown', {});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -822,7 +784,12 @@ class Choices {
|
|||
* @public
|
||||
*/
|
||||
toggleDropdown() {
|
||||
this.dropdown.toggle();
|
||||
if (this.dropdown.isActive) {
|
||||
this.hideDropdown();
|
||||
} else {
|
||||
this.showDropdown(true);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1945,7 +1912,7 @@ class Choices {
|
|||
}
|
||||
|
||||
// Remove focus state
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.focusState);
|
||||
this.containerOuter.blur()
|
||||
|
||||
// Close all other dropdowns
|
||||
if (hasActiveDropdown) {
|
||||
|
@ -1962,8 +1929,11 @@ class Choices {
|
|||
*/
|
||||
_onMouseOver(e) {
|
||||
// If the dropdown is either the target or one of its children is the target
|
||||
if (e.target === this.dropdown || this.dropdown.element.contains(e.target)) {
|
||||
if (e.target.hasAttribute('data-choice')) this._highlightChoice(e.target);
|
||||
if (
|
||||
(e.target === this.dropdown || this.dropdown.element.contains(e.target)) &&
|
||||
e.target.hasAttribute('data-choice')
|
||||
) {
|
||||
this._highlightChoice(e.target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1994,11 +1964,11 @@ class Choices {
|
|||
const focusActions = {
|
||||
text: () => {
|
||||
if (target === this.input) {
|
||||
this.containerOuter.element.classList.add(this.config.classNames.focusState);
|
||||
this.containerOuter.focus();
|
||||
}
|
||||
},
|
||||
'select-one': () => {
|
||||
this.containerOuter.element.classList.add(this.config.classNames.focusState);
|
||||
this.containerOuter.focus();
|
||||
if (target === this.input) {
|
||||
// Show dropdown if it isn't already showing
|
||||
if (!hasActiveDropdown) {
|
||||
|
@ -2010,7 +1980,7 @@ class Choices {
|
|||
if (target === this.input) {
|
||||
// If element is a select box, the focused element is the container and the dropdown
|
||||
// isn't already open, focus and show dropdown
|
||||
this.containerOuter.element.classList.add(this.config.classNames.focusState);
|
||||
this.containerOuter.focus();
|
||||
|
||||
if (!hasActiveDropdown) {
|
||||
this.showDropdown(true);
|
||||
|
@ -2040,7 +2010,7 @@ class Choices {
|
|||
text: () => {
|
||||
if (target === this.input) {
|
||||
// Remove the focus state
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.focusState);
|
||||
this.containerOuter.blur();
|
||||
// De-select any highlighted items
|
||||
if (hasHighlightedItems) {
|
||||
this.unhighlightAll();
|
||||
|
@ -2052,7 +2022,7 @@ class Choices {
|
|||
}
|
||||
},
|
||||
'select-one': () => {
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.focusState);
|
||||
this.containerOuter.blur();
|
||||
if (target === this.containerOuter.element) {
|
||||
// Hide dropdown if it is showing
|
||||
if (hasActiveDropdown && !this.canSearch) {
|
||||
|
@ -2067,7 +2037,7 @@ class Choices {
|
|||
'select-multiple': () => {
|
||||
if (target === this.input) {
|
||||
// Remove the focus state
|
||||
this.containerOuter.element.classList.remove(this.config.classNames.focusState);
|
||||
this.containerOuter.blur();
|
||||
// Hide dropdown if it is showing
|
||||
if (hasActiveDropdown) {
|
||||
this.hideDropdown();
|
||||
|
@ -2695,8 +2665,8 @@ class Choices {
|
|||
const input = this._getTemplate('input');
|
||||
const dropdown = this._getTemplate('dropdown');
|
||||
|
||||
this.containerOuter = new Container(this, containerOuter, this.config.classNames);
|
||||
this.containerInner = new Container(this, containerInner, this.config.classNames);
|
||||
this.containerOuter = new Container(this, containerOuter);
|
||||
this.containerInner = new Container(this, containerInner);
|
||||
this.input = input;
|
||||
this.choiceList = choiceList;
|
||||
this.itemList = itemList;
|
||||
|
|
|
@ -2,9 +2,73 @@
|
|||
* Container
|
||||
*/
|
||||
export default class Container {
|
||||
constructor(instance, element, classNames) {
|
||||
constructor(instance, element) {
|
||||
this.instance = instance;
|
||||
this.element = element;
|
||||
this.classNames = classNames;
|
||||
this.config = instance.config;
|
||||
this.classNames = instance.config.classNames;
|
||||
this.isOpen = false;
|
||||
this.isFlipped = false;
|
||||
this.isFocussed = false;
|
||||
}
|
||||
|
||||
shouldFlip(dropdownPos) {
|
||||
if (!dropdownPos) {
|
||||
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;
|
||||
}
|
||||
|
||||
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');
|
||||
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() {
|
||||
this.element.classList.add(this.classNames.focusState);
|
||||
this.isFocussed = true;
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.element.classList.remove(this.classNames.focusState);
|
||||
this.isFocussed = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,15 @@ export default class Dropdown {
|
|||
this.instance = instance;
|
||||
this.element = element;
|
||||
this.classNames = classNames;
|
||||
this.dimensions = null;
|
||||
this.position = null;
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
getPosition() {
|
||||
this.dimensions = this.element.getBoundingClientRect();
|
||||
this.position = Math.ceil(this.dimensions.top + window.scrollY + this.element.offsetHeight);
|
||||
this.isActive = false;
|
||||
return this.position;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue