mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-01 13:32:23 +02:00
Merge with latest + housekeeping
This commit is contained in:
commit
affd67e542
|
@ -6,7 +6,7 @@ import Input from './components/input';
|
||||||
import List from './components/list';
|
import List from './components/list';
|
||||||
import WrappedInput from './components/wrapped-input';
|
import WrappedInput from './components/wrapped-input';
|
||||||
import WrappedSelect from './components/wrapped-select';
|
import WrappedSelect from './components/wrapped-select';
|
||||||
import { DEFAULT_CONFIG, DEFAULT_CLASSNAMES, EVENTS, KEY_CODES } from './constants';
|
import { DEFAULT_CONFIG, DEFAULT_CLASSNAMES, EVENTS, KEY_CODES, SCROLLING_SPEED } from './constants';
|
||||||
import { TEMPLATES } from './templates';
|
import { TEMPLATES } from './templates';
|
||||||
import { addChoice, filterChoices, activateChoices, clearChoices } from './actions/choices';
|
import { addChoice, filterChoices, activateChoices, clearChoices } from './actions/choices';
|
||||||
import { addItem, removeItem, highlightItem } from './actions/items';
|
import { addItem, removeItem, highlightItem } from './actions/items';
|
||||||
|
@ -24,7 +24,6 @@ import {
|
||||||
sortByAlpha,
|
sortByAlpha,
|
||||||
sortByScore,
|
sortByScore,
|
||||||
generateId,
|
generateId,
|
||||||
triggerEvent,
|
|
||||||
findAncestorByAttrName,
|
findAncestorByAttrName,
|
||||||
regexFilter,
|
regexFilter,
|
||||||
} from './lib/utils';
|
} from './lib/utils';
|
||||||
|
@ -121,9 +120,9 @@ class Choices {
|
||||||
this.presetItems = this.config.items;
|
this.presetItems = this.config.items;
|
||||||
|
|
||||||
// Then add any values passed from attribute
|
// Then add any values passed from attribute
|
||||||
if (this.passedElement.element.value) {
|
if (this.passedElement.getValue()) {
|
||||||
this.presetItems = this.presetItems.concat(
|
this.presetItems = this.presetItems.concat(
|
||||||
this.passedElement.element.value.split(this.config.delimiter),
|
this.passedElement.getValue().split(this.config.delimiter),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,15 +218,7 @@ class Choices {
|
||||||
// Remove all event listeners
|
// Remove all event listeners
|
||||||
this._removeEventListeners();
|
this._removeEventListeners();
|
||||||
this.passedElement.reveal();
|
this.passedElement.reveal();
|
||||||
|
this.containerOuter.revert(this.passedElement.element);
|
||||||
// Move passed element back to original position
|
|
||||||
this.containerOuter.element.parentNode.insertBefore(
|
|
||||||
this.passedElement.element,
|
|
||||||
this.containerOuter.element,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Remove added elements
|
|
||||||
this.containerOuter.element.parentNode.removeChild(this.containerOuter.element);
|
|
||||||
|
|
||||||
// Clear data store
|
// Clear data store
|
||||||
this.clearStore();
|
this.clearStore();
|
||||||
|
@ -292,7 +283,7 @@ class Choices {
|
||||||
(this.isSelectOneElement || !choice.selected) :
|
(this.isSelectOneElement || !choice.selected) :
|
||||||
true;
|
true;
|
||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
const dropdownItem = this._getTemplate('choice', choice);
|
const dropdownItem = this._getTemplate('choice', choice, this.config.itemSelectText);
|
||||||
choicesFragment.appendChild(dropdownItem);
|
choicesFragment.appendChild(dropdownItem);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -359,9 +350,9 @@ class Choices {
|
||||||
// Simplify store data to just values
|
// Simplify store data to just values
|
||||||
const itemsFiltered = this.store.getItemsReducedToValues(items);
|
const itemsFiltered = this.store.getItemsReducedToValues(items);
|
||||||
const itemsFilteredString = itemsFiltered.join(this.config.delimiter);
|
const itemsFilteredString = itemsFiltered.join(this.config.delimiter);
|
||||||
|
|
||||||
// Update the value of the hidden input
|
// Update the value of the hidden input
|
||||||
this.passedElement.element.setAttribute('value', itemsFilteredString);
|
this.passedElement.setValue(itemsFilteredString);
|
||||||
this.passedElement.element.value = itemsFilteredString;
|
|
||||||
} else {
|
} else {
|
||||||
const selectedOptionsFragment = document.createDocumentFragment();
|
const selectedOptionsFragment = document.createDocumentFragment();
|
||||||
const addOptionToFragment = (item) => {
|
const addOptionToFragment = (item) => {
|
||||||
|
@ -373,15 +364,13 @@ class Choices {
|
||||||
|
|
||||||
// Add each list item to list
|
// Add each list item to list
|
||||||
items.forEach(item => addOptionToFragment(item));
|
items.forEach(item => addOptionToFragment(item));
|
||||||
|
// Update the options of the hidden input
|
||||||
// Update selected choices
|
this.passedElement.setOptions(selectedOptionsFragment);
|
||||||
this.passedElement.element.innerHTML = '';
|
|
||||||
this.passedElement.element.appendChild(selectedOptionsFragment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const addItemToFragment = (item) => {
|
const addItemToFragment = (item) => {
|
||||||
// Create new list element
|
// Create new list element
|
||||||
const listItem = this._getTemplate('item', item);
|
const listItem = this._getTemplate('item', item, this.config.removeItemButton);
|
||||||
// Append it to list
|
// Append it to list
|
||||||
itemListFragment.appendChild(listItem);
|
itemListFragment.appendChild(listItem);
|
||||||
};
|
};
|
||||||
|
@ -399,104 +388,104 @@ class Choices {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
this.currentState = this.store.getState();
|
this.currentState = this.store.getState();
|
||||||
|
const stateChanged = (
|
||||||
|
this.currentState.choices !== this.prevState.choices ||
|
||||||
|
this.currentState.groups !== this.prevState.groups ||
|
||||||
|
this.currentState.items !== this.prevState.items
|
||||||
|
);
|
||||||
|
|
||||||
// Only render if our state has actually changed
|
if (!stateChanged) {
|
||||||
if (this.currentState !== this.prevState) {
|
return;
|
||||||
// Choices
|
|
||||||
if (
|
|
||||||
(this.currentState.choices !== this.prevState.choices ||
|
|
||||||
this.currentState.groups !== this.prevState.groups ||
|
|
||||||
this.currentState.items !== this.prevState.items) &&
|
|
||||||
this.isSelectElement
|
|
||||||
) {
|
|
||||||
// Get active groups/choices
|
|
||||||
const activeGroups = this.store.getGroupsFilteredByActive();
|
|
||||||
const activeChoices = this.store.getChoicesFilteredByActive();
|
|
||||||
|
|
||||||
let choiceListFragment = document.createDocumentFragment();
|
|
||||||
|
|
||||||
// Clear choices
|
|
||||||
this.choiceList.clear();
|
|
||||||
|
|
||||||
// Scroll back to top of choices list
|
|
||||||
if (this.config.resetScrollPosition) {
|
|
||||||
this.choiceList.scrollTo(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have grouped options
|
|
||||||
if (activeGroups.length >= 1 && this.isSearching !== true) {
|
|
||||||
// If we have a placeholder choice along with groups
|
|
||||||
const activePlaceholders = activeChoices.filter(
|
|
||||||
activeChoice => activeChoice.placeholder === true && activeChoice.groupId === -1,
|
|
||||||
);
|
|
||||||
if (activePlaceholders.length >= 1) {
|
|
||||||
choiceListFragment = this.renderChoices(activePlaceholders, choiceListFragment);
|
|
||||||
}
|
|
||||||
choiceListFragment = this.renderGroups(activeGroups, activeChoices, choiceListFragment);
|
|
||||||
} else if (activeChoices.length >= 1) {
|
|
||||||
choiceListFragment = this.renderChoices(activeChoices, choiceListFragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
|
||||||
const canAddItem = this._canAddItem(activeItems, this.input.getValue());
|
|
||||||
|
|
||||||
// If we have choices to show
|
|
||||||
if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) {
|
|
||||||
// ...and we can select them
|
|
||||||
if (canAddItem.response) {
|
|
||||||
// ...append them and highlight the first choice
|
|
||||||
this.choiceList.append(choiceListFragment);
|
|
||||||
this._highlightChoice();
|
|
||||||
} else {
|
|
||||||
// ...otherwise show a notice
|
|
||||||
this.choiceList.append(this._getTemplate('notice', canAddItem.notice));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Otherwise show a notice
|
|
||||||
let dropdownItem;
|
|
||||||
let notice;
|
|
||||||
|
|
||||||
if (this.isSearching) {
|
|
||||||
notice = isType('Function', this.config.noResultsText) ?
|
|
||||||
this.config.noResultsText() :
|
|
||||||
this.config.noResultsText;
|
|
||||||
|
|
||||||
dropdownItem = this._getTemplate('notice', notice, 'no-results');
|
|
||||||
} else {
|
|
||||||
notice = isType('Function', this.config.noChoicesText) ?
|
|
||||||
this.config.noChoicesText() :
|
|
||||||
this.config.noChoicesText;
|
|
||||||
|
|
||||||
dropdownItem = this._getTemplate('notice', notice, 'no-choices');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.choiceList.append(dropdownItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Items
|
|
||||||
if (this.currentState.items !== this.prevState.items) {
|
|
||||||
// Get active items (items that can be selected)
|
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
|
||||||
|
|
||||||
// Clear list
|
|
||||||
this.itemList.clear();
|
|
||||||
|
|
||||||
if (activeItems && activeItems.length) {
|
|
||||||
// Create a fragment to store our list items
|
|
||||||
// (so we don't have to update the DOM for each item)
|
|
||||||
const itemListFragment = this.renderItems(activeItems);
|
|
||||||
|
|
||||||
// If we have items to add
|
|
||||||
if (itemListFragment.childNodes) {
|
|
||||||
// Update list
|
|
||||||
this.itemList.append(itemListFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.prevState = this.currentState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Choices */
|
||||||
|
|
||||||
|
if (this.isSelectElement) {
|
||||||
|
// Get active groups/choices
|
||||||
|
const activeGroups = this.store.getGroupsFilteredByActive();
|
||||||
|
const activeChoices = this.store.getChoicesFilteredByActive();
|
||||||
|
|
||||||
|
let choiceListFragment = document.createDocumentFragment();
|
||||||
|
|
||||||
|
// Clear choices
|
||||||
|
this.choiceList.clear();
|
||||||
|
|
||||||
|
// Scroll back to top of choices list
|
||||||
|
if (this.config.resetScrollPosition) {
|
||||||
|
this.choiceList.scrollTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have grouped options
|
||||||
|
if (activeGroups.length >= 1 && !this.isSearching) {
|
||||||
|
// If we have a placeholder choice along with groups
|
||||||
|
const activePlaceholders = activeChoices.filter(
|
||||||
|
activeChoice => activeChoice.placeholder === true && activeChoice.groupId === -1,
|
||||||
|
);
|
||||||
|
if (activePlaceholders.length >= 1) {
|
||||||
|
choiceListFragment = this.renderChoices(activePlaceholders, choiceListFragment);
|
||||||
|
}
|
||||||
|
choiceListFragment = this.renderGroups(activeGroups, activeChoices, choiceListFragment);
|
||||||
|
} else if (activeChoices.length >= 1) {
|
||||||
|
choiceListFragment = this.renderChoices(activeChoices, choiceListFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
|
const canAddItem = this._canAddItem(activeItems, this.input.getValue());
|
||||||
|
|
||||||
|
// If we have choices to show
|
||||||
|
if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) {
|
||||||
|
// ...and we can select them
|
||||||
|
if (canAddItem.response) {
|
||||||
|
// ...append them and highlight the first choice
|
||||||
|
this.choiceList.append(choiceListFragment);
|
||||||
|
this._highlightChoice();
|
||||||
|
} else {
|
||||||
|
// ...otherwise show a notice
|
||||||
|
this.choiceList.append(this._getTemplate('notice', canAddItem.notice));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise show a notice
|
||||||
|
let dropdownItem;
|
||||||
|
let notice;
|
||||||
|
|
||||||
|
if (this.isSearching) {
|
||||||
|
notice = isType('Function', this.config.noResultsText) ?
|
||||||
|
this.config.noResultsText() :
|
||||||
|
this.config.noResultsText;
|
||||||
|
|
||||||
|
dropdownItem = this._getTemplate('notice', notice, 'no-results');
|
||||||
|
} else {
|
||||||
|
notice = isType('Function', this.config.noChoicesText) ?
|
||||||
|
this.config.noChoicesText() :
|
||||||
|
this.config.noChoicesText;
|
||||||
|
|
||||||
|
dropdownItem = this._getTemplate('notice', notice, 'no-choices');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.choiceList.append(dropdownItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Items */
|
||||||
|
|
||||||
|
// Get active items (items that can be selected)
|
||||||
|
const activeItems = this.store.getItemsFilteredByActive() || [];
|
||||||
|
// Clear list
|
||||||
|
this.itemList.clear();
|
||||||
|
|
||||||
|
if (activeItems.length) {
|
||||||
|
// Create a fragment to store our list items
|
||||||
|
// (so we don't have to update the DOM for each item)
|
||||||
|
const itemListFragment = this.renderItems(activeItems);
|
||||||
|
|
||||||
|
// If we have items to add
|
||||||
|
if (itemListFragment.childNodes) {
|
||||||
|
// Update list
|
||||||
|
this.itemList.append(itemListFragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prevState = this.currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -530,7 +519,7 @@ class Choices {
|
||||||
eventResponse.groupValue = group.value;
|
eventResponse.groupValue = group.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerEvent(this.passedElement.element, EVENTS.highlightItem, eventResponse);
|
this.passedElement.triggerEvent(EVENTS.highlightItem, eventResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -560,11 +549,8 @@ class Choices {
|
||||||
eventResponse.groupValue = group.value;
|
eventResponse.groupValue = group.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.store.dispatch(
|
this.store.dispatch(highlightItem(id, false));
|
||||||
highlightItem(id, false),
|
this.passedElement.triggerEvent(EVENTS.highlightItem, eventResponse);
|
||||||
);
|
|
||||||
|
|
||||||
triggerEvent(this.passedElement.element, EVENTS.highlightItem, eventResponse);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -668,8 +654,8 @@ class Choices {
|
||||||
this.containerOuter.open(this.dropdown.getVerticalPos());
|
this.containerOuter.open(this.dropdown.getVerticalPos());
|
||||||
this.dropdown.show();
|
this.dropdown.show();
|
||||||
this.input.activate(focusInput);
|
this.input.activate(focusInput);
|
||||||
|
this.passedElement.triggerEvent(EVENTS.showDropdown, {});
|
||||||
|
|
||||||
triggerEvent(this.passedElement.element, EVENTS.showDropdown, {});
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,8 +672,7 @@ class Choices {
|
||||||
this.containerOuter.close();
|
this.containerOuter.close();
|
||||||
this.dropdown.hide();
|
this.dropdown.hide();
|
||||||
this.input.deactivate(blurInput);
|
this.input.deactivate(blurInput);
|
||||||
|
this.passedElement.triggerEvent(EVENTS.hideDropdown, {});
|
||||||
triggerEvent(this.passedElement.element, EVENTS.hideDropdown, {});
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -922,11 +907,10 @@ class Choices {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.passedElement.element.disabled = false;
|
this.passedElement.enable();
|
||||||
|
|
||||||
if (this.containerOuter.isDisabled) {
|
if (this.containerOuter.isDisabled) {
|
||||||
this._addEventListeners();
|
this._addEventListeners();
|
||||||
this.passedElement.element.removeAttribute('disabled');
|
|
||||||
this.input.enable();
|
this.input.enable();
|
||||||
this.containerOuter.enable();
|
this.containerOuter.enable();
|
||||||
}
|
}
|
||||||
|
@ -944,11 +928,10 @@ class Choices {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.passedElement.element.disabled = true;
|
this.passedElement.disable();
|
||||||
|
|
||||||
if (!this.containerOuter.isDisabled) {
|
if (!this.containerOuter.isDisabled) {
|
||||||
this._removeEventListeners();
|
this._removeEventListeners();
|
||||||
this.passedElement.element.setAttribute('disabled', '');
|
|
||||||
this.input.disable();
|
this.input.disable();
|
||||||
this.containerOuter.disable();
|
this.containerOuter.disable();
|
||||||
}
|
}
|
||||||
|
@ -992,7 +975,7 @@ class Choices {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerEvent(this.passedElement.element, EVENTS.change, {
|
this.passedElement.triggerEvent(EVENTS.change, {
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1102,7 +1085,7 @@ class Choices {
|
||||||
// Update choice keyCode
|
// Update choice keyCode
|
||||||
choice.keyCode = passedKeyCode;
|
choice.keyCode = passedKeyCode;
|
||||||
|
|
||||||
triggerEvent(this.passedElement.element, EVENTS.choice, {
|
this.passedElement.triggerEvent(EVENTS.choice, {
|
||||||
choice,
|
choice,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1155,6 +1138,7 @@ class Choices {
|
||||||
this._triggerChange(lastItem.value);
|
this._triggerChange(lastItem.value);
|
||||||
} else {
|
} else {
|
||||||
if (!hasHighlightedItems) {
|
if (!hasHighlightedItems) {
|
||||||
|
// Highlight last item if none already highlighted
|
||||||
this.highlightItem(lastItem, false);
|
this.highlightItem(lastItem, false);
|
||||||
}
|
}
|
||||||
this.removeHighlightedItems(true);
|
this.removeHighlightedItems(true);
|
||||||
|
@ -1312,26 +1296,26 @@ class Choices {
|
||||||
this.currentValue.trim() :
|
this.currentValue.trim() :
|
||||||
this.currentValue;
|
this.currentValue;
|
||||||
|
|
||||||
// If new value matches the desired length and is not the same as the current value with a space
|
if (newValue.length < 1 && newValue === `${currentValue} `) {
|
||||||
if (newValue.length >= 1 && newValue !== `${currentValue} `) {
|
return 0;
|
||||||
const haystack = this.store.getSearchableChoices();
|
|
||||||
const needle = newValue;
|
|
||||||
const keys = isType('Array', this.config.searchFields) ?
|
|
||||||
this.config.searchFields :
|
|
||||||
[this.config.searchFields];
|
|
||||||
const options = Object.assign(this.config.fuseOptions, { keys });
|
|
||||||
const fuse = new Fuse(haystack, options);
|
|
||||||
const results = fuse.search(needle);
|
|
||||||
|
|
||||||
this.currentValue = newValue;
|
|
||||||
this.highlightPosition = 0;
|
|
||||||
this.isSearching = true;
|
|
||||||
this.store.dispatch(filterChoices(results));
|
|
||||||
|
|
||||||
return results.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
// If new value matches the desired length and is not the same as the current value with a space
|
||||||
|
const haystack = this.store.getSearchableChoices();
|
||||||
|
const needle = newValue;
|
||||||
|
const keys = isType('Array', this.config.searchFields) ?
|
||||||
|
this.config.searchFields :
|
||||||
|
[this.config.searchFields];
|
||||||
|
const options = Object.assign(this.config.fuseOptions, { keys });
|
||||||
|
const fuse = new Fuse(haystack, options);
|
||||||
|
const results = fuse.search(needle);
|
||||||
|
|
||||||
|
this.currentValue = newValue;
|
||||||
|
this.highlightPosition = 0;
|
||||||
|
this.isSearching = true;
|
||||||
|
this.store.dispatch(filterChoices(results));
|
||||||
|
|
||||||
|
return results.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1352,7 +1336,7 @@ class Choices {
|
||||||
if (value && value.length >= this.config.searchFloor) {
|
if (value && value.length >= this.config.searchFloor) {
|
||||||
const resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;
|
const resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;
|
||||||
// Trigger search event
|
// Trigger search event
|
||||||
triggerEvent(this.passedElement.element, EVENTS.search, {
|
this.passedElement.triggerEvent(EVENTS.search, {
|
||||||
value,
|
value,
|
||||||
resultCount,
|
resultCount,
|
||||||
});
|
});
|
||||||
|
@ -1453,7 +1437,7 @@ class Choices {
|
||||||
this.canSearch = false;
|
this.canSearch = false;
|
||||||
if (
|
if (
|
||||||
this.config.removeItems &&
|
this.config.removeItems &&
|
||||||
!this.input.element.value &&
|
!this.input.getValue() &&
|
||||||
this.input.element === document.activeElement
|
this.input.element === document.activeElement
|
||||||
) {
|
) {
|
||||||
// Highlight items
|
// Highlight items
|
||||||
|
@ -1465,7 +1449,7 @@ class Choices {
|
||||||
const onEnterKey = () => {
|
const onEnterKey = () => {
|
||||||
// If enter key is pressed and the input has a value
|
// If enter key is pressed and the input has a value
|
||||||
if (this.isTextElement && target.value) {
|
if (this.isTextElement && target.value) {
|
||||||
const value = this.input.element.value;
|
const value = this.input.getValue();
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
|
||||||
// All is good, add
|
// All is good, add
|
||||||
|
@ -1592,7 +1576,7 @@ class Choices {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = this.input.element.value;
|
const value = this.input.getValue();
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
|
||||||
|
@ -1614,20 +1598,18 @@ class Choices {
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const backKey = 46;
|
const backKey = KEY_CODES.BACK_KEY;
|
||||||
const deleteKey = 8;
|
const deleteKey = KEY_CODES.DELETE_KEY;
|
||||||
|
|
||||||
// If user has removed value...
|
// If user has removed value...
|
||||||
if ((e.keyCode === backKey || e.keyCode === deleteKey) && !e.target.value) {
|
if ((e.keyCode === backKey || e.keyCode === deleteKey) && !e.target.value) {
|
||||||
// ...and it is a multiple select input, activate choices (if searching)
|
// ...and it is a multiple select input, activate choices (if searching)
|
||||||
if (!this.isTextElement && this.isSearching) {
|
if (!this.isTextElement && this.isSearching) {
|
||||||
this.isSearching = false;
|
this.isSearching = false;
|
||||||
this.store.dispatch(
|
this.store.dispatch(activateChoices(true));
|
||||||
activateChoices(true),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if (this.canSearch && canAddItem.response) {
|
} else if (this.canSearch && canAddItem.response) {
|
||||||
this._handleSearch(this.input.element.value);
|
this._handleSearch(this.input.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-establish canSearch value from changes in _onKeyDown
|
// Re-establish canSearch value from changes in _onKeyDown
|
||||||
|
@ -1784,33 +1766,34 @@ class Choices {
|
||||||
*/
|
*/
|
||||||
_onFocus(e) {
|
_onFocus(e) {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
// If target is something that concerns us
|
if (!this.containerOuter.element.contains(target)) {
|
||||||
if (this.containerOuter.element.contains(target)) {
|
return;
|
||||||
const focusActions = {
|
|
||||||
text: () => {
|
|
||||||
if (target === this.input.element) {
|
|
||||||
this.containerOuter.addFocusState();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'select-one': () => {
|
|
||||||
this.containerOuter.addFocusState();
|
|
||||||
if (target === this.input.element) {
|
|
||||||
// Show dropdown if it isn't already showing
|
|
||||||
this.showDropdown();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'select-multiple': () => {
|
|
||||||
if (target === this.input.element) {
|
|
||||||
// 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.addFocusState();
|
|
||||||
this.showDropdown(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
focusActions[this.passedElement.element.type]();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const focusActions = {
|
||||||
|
text: () => {
|
||||||
|
if (target === this.input.element) {
|
||||||
|
this.containerOuter.addFocusState();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'select-one': () => {
|
||||||
|
this.containerOuter.addFocusState();
|
||||||
|
if (target === this.input.element) {
|
||||||
|
// Show dropdown if it isn't already showing
|
||||||
|
this.showDropdown();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'select-multiple': () => {
|
||||||
|
if (target === this.input.element) {
|
||||||
|
// 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.addFocusState();
|
||||||
|
this.showDropdown(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
focusActions[this.passedElement.element.type]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1897,7 +1880,7 @@ class Choices {
|
||||||
choice.offsetTop;
|
choice.offsetTop;
|
||||||
|
|
||||||
const animateScroll = () => {
|
const animateScroll = () => {
|
||||||
const strength = 4;
|
const strength = SCROLLING_SPEED;
|
||||||
const choiceListScrollTop = this.choiceList.scrollPos;
|
const choiceListScrollTop = this.choiceList.scrollPos;
|
||||||
let continueAnimation = false;
|
let continueAnimation = false;
|
||||||
let easing;
|
let easing;
|
||||||
|
@ -2046,7 +2029,7 @@ class Choices {
|
||||||
|
|
||||||
// Trigger change event
|
// Trigger change event
|
||||||
if (group && group.value) {
|
if (group && group.value) {
|
||||||
triggerEvent(this.passedElement.element, EVENTS.addItem, {
|
this.passedElement.triggerEvent(EVENTS.addItem, {
|
||||||
id,
|
id,
|
||||||
value: passedValue,
|
value: passedValue,
|
||||||
label: passedLabel,
|
label: passedLabel,
|
||||||
|
@ -2054,7 +2037,7 @@ class Choices {
|
||||||
keyCode: passedKeyCode,
|
keyCode: passedKeyCode,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
triggerEvent(this.passedElement.element, EVENTS.addItem, {
|
this.passedElement.triggerEvent(EVENTS.addItem, {
|
||||||
id,
|
id,
|
||||||
value: passedValue,
|
value: passedValue,
|
||||||
label: passedLabel,
|
label: passedLabel,
|
||||||
|
@ -2083,19 +2066,17 @@ class Choices {
|
||||||
const groupId = item.groupId;
|
const groupId = item.groupId;
|
||||||
const group = groupId >= 0 ? this.store.getGroupById(groupId) : null;
|
const group = groupId >= 0 ? this.store.getGroupById(groupId) : null;
|
||||||
|
|
||||||
this.store.dispatch(
|
this.store.dispatch(removeItem(id, choiceId));
|
||||||
removeItem(id, choiceId),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (group && group.value) {
|
if (group && group.value) {
|
||||||
triggerEvent(this.passedElement.element, EVENTS.removeItem, {
|
this.passedElement.triggerEvent(EVENTS.removeItem, {
|
||||||
id,
|
id,
|
||||||
value,
|
value,
|
||||||
label,
|
label,
|
||||||
groupValue: group.value,
|
groupValue: group.value,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
triggerEvent(this.passedElement.element, EVENTS.removeItem, {
|
this.passedElement.triggerEvent(EVENTS.removeItem, {
|
||||||
id,
|
id,
|
||||||
value,
|
value,
|
||||||
label,
|
label,
|
||||||
|
@ -2263,10 +2244,16 @@ class Choices {
|
||||||
*/
|
*/
|
||||||
_createInput() {
|
_createInput() {
|
||||||
const direction = this.passedElement.element.getAttribute('dir') || 'ltr';
|
const direction = this.passedElement.element.getAttribute('dir') || 'ltr';
|
||||||
const containerOuter = this._getTemplate('containerOuter', direction);
|
const containerOuter = this._getTemplate('containerOuter',
|
||||||
|
direction,
|
||||||
|
this.isSelectElement,
|
||||||
|
this.isSelectOneElement,
|
||||||
|
this.config.searchEnabled,
|
||||||
|
this.passedElement.element.type,
|
||||||
|
);
|
||||||
const containerInner = this._getTemplate('containerInner');
|
const containerInner = this._getTemplate('containerInner');
|
||||||
const itemList = this._getTemplate('itemList');
|
const itemList = this._getTemplate('itemList', this.isSelectOneElement);
|
||||||
const choiceList = this._getTemplate('choiceList');
|
const choiceList = this._getTemplate('choiceList', this.isSelectOneElement);
|
||||||
const input = this._getTemplate('input');
|
const input = this._getTemplate('input');
|
||||||
const dropdown = this._getTemplate('dropdown');
|
const dropdown = this._getTemplate('dropdown');
|
||||||
|
|
||||||
|
@ -2281,7 +2268,6 @@ class Choices {
|
||||||
|
|
||||||
// Wrap input in container preserving DOM ordering
|
// Wrap input in container preserving DOM ordering
|
||||||
wrap(this.passedElement.element, this.containerInner.element);
|
wrap(this.passedElement.element, this.containerInner.element);
|
||||||
|
|
||||||
// Wrapper inner container with outer container
|
// Wrapper inner container with outer container
|
||||||
wrap(this.containerInner.element, this.containerOuter.element);
|
wrap(this.containerInner.element, this.containerOuter.element);
|
||||||
|
|
||||||
|
@ -2304,21 +2290,21 @@ class Choices {
|
||||||
dropdown.appendChild(choiceList);
|
dropdown.appendChild(choiceList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isSelectMultipleElement || this.isTextElement) {
|
if (!this.isSelectOneElement) {
|
||||||
this.containerInner.element.appendChild(this.input.element);
|
this.containerInner.element.appendChild(this.input.element);
|
||||||
} else if (this.canSearch) {
|
} else if (this.canSearch) {
|
||||||
dropdown.insertBefore(input, dropdown.firstChild);
|
dropdown.insertBefore(input, dropdown.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isSelectElement) {
|
if (this.isSelectElement) {
|
||||||
const passedGroups = Array.from(this.passedElement.element.getElementsByTagName('OPTGROUP'));
|
const passedGroups = this.passedElement.getOptionGroups();
|
||||||
|
|
||||||
this.highlightPosition = 0;
|
this.highlightPosition = 0;
|
||||||
this.isSearching = false;
|
this.isSearching = false;
|
||||||
|
|
||||||
if (passedGroups && passedGroups.length) {
|
if (passedGroups && passedGroups.length) {
|
||||||
// If we have a placeholder option
|
// If we have a placeholder option
|
||||||
const placeholderChoice = this.passedElement.element.querySelector('option[placeholder]');
|
const placeholderChoice = this.passedElement.getPlaceholderOption();
|
||||||
if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') {
|
if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') {
|
||||||
this._addChoice(
|
this._addChoice(
|
||||||
placeholderChoice.value,
|
placeholderChoice.value,
|
||||||
|
@ -2335,7 +2321,7 @@ class Choices {
|
||||||
this._addGroup(group, (group.id || null));
|
this._addGroup(group, (group.id || null));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const passedOptions = Array.from(this.passedElement.element.options);
|
const passedOptions = this.passedElement.getOptions();
|
||||||
const filter = this.config.sortFilter;
|
const filter = this.config.sortFilter;
|
||||||
const allChoices = this.presetChoices;
|
const allChoices = this.presetChoices;
|
||||||
|
|
||||||
|
|
|
@ -32,27 +32,27 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('is defined', () => {
|
||||||
expect(instance).to.not.be.undefined;
|
expect(instance).to.not.be.undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have initialised', () => {
|
it('initialises', () => {
|
||||||
expect(instance.initialised).to.be.true;
|
expect(instance.initialised).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not re-initialise if passed element again', () => {
|
it('does not re-initialise if passed element again', () => {
|
||||||
const reinitialise = new Choices(instance.passedElement.element);
|
const reinitialise = new Choices(instance.passedElement.element);
|
||||||
sinon.spy(reinitialise, '_createTemplates');
|
sinon.spy(reinitialise, '_createTemplates');
|
||||||
expect(reinitialise._createTemplates.callCount).to.equal(0);
|
expect(reinitialise._createTemplates.callCount).to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have a blank state', () => {
|
it('has a blank state', () => {
|
||||||
expect(instance.currentState.items.length).to.equal(0);
|
expect(instance.currentState.items.length).to.equal(0);
|
||||||
expect(instance.currentState.groups.length).to.equal(0);
|
expect(instance.currentState.groups.length).to.equal(0);
|
||||||
expect(instance.currentState.choices.length).to.equal(0);
|
expect(instance.currentState.choices.length).to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have config options', () => {
|
it('has expected config options', () => {
|
||||||
expect(instance.config.silent).to.be.a('boolean');
|
expect(instance.config.silent).to.be.a('boolean');
|
||||||
expect(instance.config.items).to.be.an('array');
|
expect(instance.config.items).to.be.an('array');
|
||||||
expect(instance.config.choices).to.be.an('array');
|
expect(instance.config.choices).to.be.an('array');
|
||||||
|
@ -90,7 +90,7 @@ describe('Choices', () => {
|
||||||
expect(instance.config.callbackOnCreateTemplates).to.be.null;
|
expect(instance.config.callbackOnCreateTemplates).to.be.null;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expose public methods', () => {
|
it('exposes public methods', () => {
|
||||||
expect(instance.init).to.be.a('function');
|
expect(instance.init).to.be.a('function');
|
||||||
expect(instance.destroy).to.be.a('function');
|
expect(instance.destroy).to.be.a('function');
|
||||||
expect(instance.render).to.be.a('function');
|
expect(instance.render).to.be.a('function');
|
||||||
|
@ -118,35 +118,35 @@ describe('Choices', () => {
|
||||||
expect(instance.clearInput).to.be.a('function');
|
expect(instance.clearInput).to.be.a('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hide passed input', () => {
|
it('hides passed input', () => {
|
||||||
expect(instance.passedElement.element.style.display).to.equal('none');
|
expect(instance.passedElement.element.style.display).to.equal('none');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an outer container', () => {
|
it('creates an outer container', () => {
|
||||||
expect(instance.containerOuter).to.be.an.instanceof(Container);
|
expect(instance.containerOuter).to.be.an.instanceof(Container);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an inner container', () => {
|
it('creates an inner container', () => {
|
||||||
expect(instance.containerInner).to.be.an.instanceof(Container);
|
expect(instance.containerInner).to.be.an.instanceof(Container);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a choice list', () => {
|
it('creates a choice list', () => {
|
||||||
expect(instance.choiceList).to.be.an.instanceof(List);
|
expect(instance.choiceList).to.be.an.instanceof(List);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an item list', () => {
|
it('creates an item list', () => {
|
||||||
expect(instance.itemList).to.be.an.instanceof(List);
|
expect(instance.itemList).to.be.an.instanceof(List);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an input', () => {
|
it('creates an input', () => {
|
||||||
expect(instance.input).to.be.an.instanceof(Input);
|
expect(instance.input).to.be.an.instanceof(Input);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a dropdown', () => {
|
it('creates a dropdown', () => {
|
||||||
expect(instance.dropdown).to.be.an.instanceof(Dropdown);
|
expect(instance.dropdown).to.be.an.instanceof(Dropdown);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should backup and recover original styles', () => {
|
it('backs up and recovers original styles', () => {
|
||||||
const origStyle = 'background-color: #ccc; margin: 5px padding: 10px;';
|
const origStyle = 'background-color: #ccc; margin: 5px padding: 10px;';
|
||||||
|
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
|
@ -165,7 +165,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should accept text inputs', () => {
|
describe('text inputs', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -182,12 +182,12 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should wrap passed input', () => {
|
it('wraps passed input', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
expect(instance.passedElement).to.be.an.instanceof(WrappedInput);
|
expect(instance.passedElement).to.be.an.instanceof(WrappedInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should accept a user inputted value', () => {
|
it('accepts a user inputted value', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
|
|
||||||
instance.input.element.focus();
|
instance.input.element.focus();
|
||||||
|
@ -202,13 +202,13 @@ describe('Choices', () => {
|
||||||
expect(instance.currentState.items[0].value).to.include(instance.input.element.value);
|
expect(instance.currentState.items[0].value).to.include(instance.input.element.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should copy the passed placeholder to the cloned input', () => {
|
it('copys the passed placeholder to the cloned input', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
|
|
||||||
expect(instance.input.element.placeholder).to.equal(input.placeholder);
|
expect(instance.input.element.placeholder).to.equal(input.placeholder);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow duplicates if duplicateItems is false', () => {
|
it('doesn\'t allow duplicate items if duplicateItems is false', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
duplicateItems: false,
|
duplicateItems: false,
|
||||||
items: ['test 1'],
|
items: ['test 1'],
|
||||||
|
@ -226,7 +226,7 @@ describe('Choices', () => {
|
||||||
expect(instance.currentState.items[instance.currentState.items.length - 1].value).to.equal(instance.input.element.value);
|
expect(instance.currentState.items[instance.currentState.items.length - 1].value).to.equal(instance.input.element.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter input if regexFilter is passed', () => {
|
it('filters input if regexFilter is passed', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||||||
});
|
});
|
||||||
|
@ -255,7 +255,7 @@ describe('Choices', () => {
|
||||||
expect(lastItem.value).not.to.equal('not an email address');
|
expect(lastItem.value).not.to.equal('not an email address');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prepend and append values if passed', () => {
|
it('prepends and appends values if passed', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
prependValue: 'item-',
|
prependValue: 'item-',
|
||||||
appendValue: '-value',
|
appendValue: '-value',
|
||||||
|
@ -277,7 +277,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should accept single select inputs', () => {
|
describe('single select inputs', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -302,23 +302,23 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should wrap passed input', () => {
|
it('wraps passed input', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
expect(instance.passedElement).to.be.an.instanceof(WrappedSelect);
|
expect(instance.passedElement).to.be.an.instanceof(WrappedSelect);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open the choice list on focusing', () => {
|
it('opens the choice list on focusing', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
instance.input.element.focus();
|
instance.input.element.focus();
|
||||||
expect(instance.dropdown.element.classList.contains(instance.config.classNames.activeState)).to.be.true;
|
expect(instance.dropdown.element.classList.contains(instance.config.classNames.activeState)).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should select the first choice', () => {
|
it('selects the first choice', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
expect(instance.currentState.items[0].value).to.include('Value 1');
|
expect(instance.currentState.items[0].value).to.include('Value 1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should highlight the choices on keydown', () => {
|
it('highlights the choices on keydown', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
renderChoiceLimit: -1,
|
renderChoiceLimit: -1,
|
||||||
});
|
});
|
||||||
|
@ -337,7 +337,7 @@ describe('Choices', () => {
|
||||||
expect(instance.highlightPosition).to.equal(2);
|
expect(instance.highlightPosition).to.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should select choice on enter key press', () => {
|
it('selects choice on enter key press', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
instance.input.element.focus();
|
instance.input.element.focus();
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ describe('Choices', () => {
|
||||||
expect(instance.currentState.items.length).to.equal(2);
|
expect(instance.currentState.items.length).to.equal(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger add/change event on selection', () => {
|
it('triggers add/change event on selection', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
|
|
||||||
const onChangeStub = sinon.stub();
|
const onChangeStub = sinon.stub();
|
||||||
|
@ -394,7 +394,7 @@ describe('Choices', () => {
|
||||||
expect(addSpyStub.callCount).to.equal(1);
|
expect(addSpyStub.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open the dropdown on click', () => {
|
it('opens the dropdown on click', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
const container = instance.containerOuter.element;
|
const container = instance.containerOuter.element;
|
||||||
instance._onClick({
|
instance._onClick({
|
||||||
|
@ -406,7 +406,7 @@ describe('Choices', () => {
|
||||||
expect(document.activeElement === instance.input.element && container.classList.contains('is-open')).to.be.true;
|
expect(document.activeElement === instance.input.element && container.classList.contains('is-open')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close the dropdown on double click', () => {
|
it('closes the dropdown on double click', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
const container = instance.containerOuter.element;
|
const container = instance.containerOuter.element;
|
||||||
const openState = instance.config.classNames.openState;
|
const openState = instance.config.classNames.openState;
|
||||||
|
@ -426,7 +426,7 @@ describe('Choices', () => {
|
||||||
expect(document.activeElement === instance.input.element && container.classList.contains(openState)).to.be.false;
|
expect(document.activeElement === instance.input.element && container.classList.contains(openState)).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger showDropdown on dropdown opening', () => {
|
it('triggers showDropdown on dropdown opening', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
const container = instance.containerOuter.element;
|
const container = instance.containerOuter.element;
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ describe('Choices', () => {
|
||||||
expect(showDropdownStub.callCount).to.equal(1);
|
expect(showDropdownStub.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger hideDropdown on dropdown closing', () => {
|
it('triggers hideDropdown on dropdown closing', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
|
|
||||||
const container = instance.containerOuter.element;
|
const container = instance.containerOuter.element;
|
||||||
|
@ -472,7 +472,7 @@ describe('Choices', () => {
|
||||||
expect(hideDropdownStub.callCount).to.equal(1);
|
expect(hideDropdownStub.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter choices when searching', () => {
|
it('filters choices when searching', () => {
|
||||||
instance = new Choices(input);
|
instance = new Choices(input);
|
||||||
|
|
||||||
const onSearchStub = sinon.spy();
|
const onSearchStub = sinon.spy();
|
||||||
|
@ -496,7 +496,7 @@ describe('Choices', () => {
|
||||||
expect(onSearchStub.callCount).to.equal(1);
|
expect(onSearchStub.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shouldn\'t filter choices when searching', () => {
|
it('doesn\'t filter choices when searching', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
searchChoices: false,
|
searchChoices: false,
|
||||||
});
|
});
|
||||||
|
@ -524,7 +524,7 @@ describe('Choices', () => {
|
||||||
expect(onSearchStub.callCount).to.equal(1);
|
expect(onSearchStub.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shouldn\'t sort choices if shouldSort is false', () => {
|
it('doesn\'t sort choices if shouldSort is false', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
shouldSort: false,
|
shouldSort: false,
|
||||||
choices: [
|
choices: [
|
||||||
|
@ -544,7 +544,7 @@ describe('Choices', () => {
|
||||||
expect(instance.currentState.choices[0].value).to.equal('Value 5');
|
expect(instance.currentState.choices[0].value).to.equal('Value 5');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sort choices if shouldSort is true', () => {
|
it('sorts choices if shouldSort is true', () => {
|
||||||
instance = new Choices(input, {
|
instance = new Choices(input, {
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
choices: [
|
choices: [
|
||||||
|
@ -565,7 +565,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should accept multiple select inputs', () => {
|
describe('multiple select inputs', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -613,24 +613,24 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should wrap passed input', () => {
|
it('wraps passed input', () => {
|
||||||
expect(instance.passedElement).to.be.an.instanceof(WrappedSelect);
|
expect(instance.passedElement).to.be.an.instanceof(WrappedSelect);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add any pre-defined values', () => {
|
it('adds any pre-defined values', () => {
|
||||||
expect(instance.currentState.items.length).to.be.above(1);
|
expect(instance.currentState.items.length).to.be.above(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add options defined in the config + pre-defined options', () => {
|
it('adds options defined in the config + pre-defined options', () => {
|
||||||
expect(instance.currentState.choices.length).to.equal(6);
|
expect(instance.currentState.choices.length).to.equal(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a placeholder defined in the config to the search input', () => {
|
it('adds a placeholder defined in the config to the search input', () => {
|
||||||
expect(instance.input.element.placeholder).to.equal('Placeholder text');
|
expect(instance.input.element.placeholder).to.equal('Placeholder text');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should handle public methods on select input types', () => {
|
describe('handles public methods on select input types', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -661,7 +661,7 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle highlightItem()', () => {
|
it('handles highlightItem()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
const randomItem = items[Math.floor(Math.random() * items.length)];
|
const randomItem = items[Math.floor(Math.random() * items.length)];
|
||||||
|
|
||||||
|
@ -670,7 +670,7 @@ describe('Choices', () => {
|
||||||
expect(randomItem.highlighted).to.be.true;
|
expect(randomItem.highlighted).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle unhighlightItem()', () => {
|
it('handles unhighlightItem()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
const randomItem = items[Math.floor(Math.random() * items.length)];
|
const randomItem = items[Math.floor(Math.random() * items.length)];
|
||||||
|
|
||||||
|
@ -679,7 +679,7 @@ describe('Choices', () => {
|
||||||
expect(randomItem.highlighted).to.be.false;
|
expect(randomItem.highlighted).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle highlightAll()', () => {
|
it('handles highlightAll()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
|
|
||||||
instance.highlightAll();
|
instance.highlightAll();
|
||||||
|
@ -689,7 +689,7 @@ describe('Choices', () => {
|
||||||
expect(unhighlightedItems).to.be.false;
|
expect(unhighlightedItems).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle unhighlightAll()', () => {
|
it('handles unhighlightAll()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
|
|
||||||
instance.unhighlightAll();
|
instance.unhighlightAll();
|
||||||
|
@ -699,7 +699,7 @@ describe('Choices', () => {
|
||||||
expect(highlightedItems).to.be.false;
|
expect(highlightedItems).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle removeHighlightedItems()', () => {
|
it('handles removeHighlightedItems()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
instance.highlightAll();
|
instance.highlightAll();
|
||||||
instance.removeHighlightedItems();
|
instance.removeHighlightedItems();
|
||||||
|
@ -709,7 +709,7 @@ describe('Choices', () => {
|
||||||
expect(activeItems).to.be.false;
|
expect(activeItems).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle showDropdown()', () => {
|
it('handles showDropdown()', () => {
|
||||||
instance.showDropdown();
|
instance.showDropdown();
|
||||||
|
|
||||||
const hasOpenState = instance.containerOuter.element.classList.contains(instance.config.classNames.openState);
|
const hasOpenState = instance.containerOuter.element.classList.contains(instance.config.classNames.openState);
|
||||||
|
@ -719,7 +719,7 @@ describe('Choices', () => {
|
||||||
expect(hasOpenState && hasAttr && hasActiveState).to.be.true;
|
expect(hasOpenState && hasAttr && hasActiveState).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle hideDropdown()', () => {
|
it('handles hideDropdown()', () => {
|
||||||
instance.showDropdown();
|
instance.showDropdown();
|
||||||
instance.hideDropdown();
|
instance.hideDropdown();
|
||||||
|
|
||||||
|
@ -731,14 +731,14 @@ describe('Choices', () => {
|
||||||
expect(hasOpenState && hasAttr && hasActiveState).to.be.false;
|
expect(hasOpenState && hasAttr && hasActiveState).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle toggleDropdown()', () => {
|
it('handles toggleDropdown()', () => {
|
||||||
sinon.spy(instance, 'hideDropdown');
|
sinon.spy(instance, 'hideDropdown');
|
||||||
instance.showDropdown();
|
instance.showDropdown();
|
||||||
instance.toggleDropdown();
|
instance.toggleDropdown();
|
||||||
expect(instance.hideDropdown.callCount).to.equal(1);
|
expect(instance.hideDropdown.callCount).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle getValue()', () => {
|
it('handles getValue()', () => {
|
||||||
const valueObjects = instance.getValue();
|
const valueObjects = instance.getValue();
|
||||||
const valueStrings = instance.getValue(true);
|
const valueStrings = instance.getValue(true);
|
||||||
|
|
||||||
|
@ -748,7 +748,7 @@ describe('Choices', () => {
|
||||||
expect(valueObjects.length).to.equal(5);
|
expect(valueObjects.length).to.equal(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle setValue()', () => {
|
it('handles setValue()', () => {
|
||||||
instance.setValue(['Set value 1', 'Set value 2', 'Set value 3']);
|
instance.setValue(['Set value 1', 'Set value 2', 'Set value 3']);
|
||||||
const valueStrings = instance.getValue(true);
|
const valueStrings = instance.getValue(true);
|
||||||
|
|
||||||
|
@ -757,7 +757,7 @@ describe('Choices', () => {
|
||||||
expect(valueStrings[valueStrings.length - 3]).to.equal('Set value 1');
|
expect(valueStrings[valueStrings.length - 3]).to.equal('Set value 1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle setValueByChoice()', () => {
|
it('handles setValueByChoice()', () => {
|
||||||
const choices = instance.store.getChoicesFilteredByActive();
|
const choices = instance.store.getChoicesFilteredByActive();
|
||||||
const randomChoice = choices[Math.floor(Math.random() * choices.length)];
|
const randomChoice = choices[Math.floor(Math.random() * choices.length)];
|
||||||
|
|
||||||
|
@ -770,7 +770,7 @@ describe('Choices', () => {
|
||||||
expect(value[0]).to.equal(randomChoice.value);
|
expect(value[0]).to.equal(randomChoice.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle setChoices()', () => {
|
it('handles setChoices()', () => {
|
||||||
instance.setChoices([{
|
instance.setChoices([{
|
||||||
label: 'Group one',
|
label: 'Group one',
|
||||||
id: 1,
|
id: 1,
|
||||||
|
@ -818,7 +818,7 @@ describe('Choices', () => {
|
||||||
expect(choices[choices.length - 2].value).to.equal('Child Five');
|
expect(choices[choices.length - 2].value).to.equal('Child Five');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle setChoices() with blank values', () => {
|
it('handles setChoices() with blank values', () => {
|
||||||
instance.setChoices([{
|
instance.setChoices([{
|
||||||
label: 'Choice one',
|
label: 'Choice one',
|
||||||
value: 'one',
|
value: 'one',
|
||||||
|
@ -833,7 +833,7 @@ describe('Choices', () => {
|
||||||
expect(choices[1].value).to.equal('');
|
expect(choices[1].value).to.equal('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle clearStore()', () => {
|
it('handles clearStore()', () => {
|
||||||
instance.clearStore();
|
instance.clearStore();
|
||||||
|
|
||||||
expect(instance.currentState.items).to.have.lengthOf(0);
|
expect(instance.currentState.items).to.have.lengthOf(0);
|
||||||
|
@ -841,7 +841,7 @@ describe('Choices', () => {
|
||||||
expect(instance.currentState.groups).to.have.lengthOf(0);
|
expect(instance.currentState.groups).to.have.lengthOf(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle disable()', () => {
|
it('handles disable()', () => {
|
||||||
instance.disable();
|
instance.disable();
|
||||||
|
|
||||||
expect(instance.input.element.disabled).to.be.true;
|
expect(instance.input.element.disabled).to.be.true;
|
||||||
|
@ -853,7 +853,7 @@ describe('Choices', () => {
|
||||||
expect(instance.containerOuter.element.getAttribute('aria-disabled')).to.equal('true');
|
expect(instance.containerOuter.element.getAttribute('aria-disabled')).to.equal('true');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle enable()', () => {
|
it('handles enable()', () => {
|
||||||
instance.enable();
|
instance.enable();
|
||||||
|
|
||||||
expect(instance.input.element.disabled).to.be.false;
|
expect(instance.input.element.disabled).to.be.false;
|
||||||
|
@ -865,7 +865,7 @@ describe('Choices', () => {
|
||||||
expect(instance.containerOuter.element.hasAttribute('aria-disabled')).to.be.false;
|
expect(instance.containerOuter.element.hasAttribute('aria-disabled')).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle ajax()', () => {
|
it('handles ajax()', () => {
|
||||||
const dummyFn = sinon.spy();
|
const dummyFn = sinon.spy();
|
||||||
|
|
||||||
instance.ajax(dummyFn);
|
instance.ajax(dummyFn);
|
||||||
|
@ -874,7 +874,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should handle public methods on select-one input types', () => {
|
describe('handles public methods on select-one input types', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -904,20 +904,20 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle disable()', () => {
|
it('handles disable()', () => {
|
||||||
instance.disable();
|
instance.disable();
|
||||||
|
|
||||||
expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('-1');
|
expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle enable()', () => {
|
it('handles enable()', () => {
|
||||||
instance.enable();
|
instance.enable();
|
||||||
|
|
||||||
expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('0');
|
expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('0');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should handle public methods on text input types', () => {
|
describe('handles public methods on text input types', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -935,12 +935,12 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle clearInput()', () => {
|
it('handles clearInput()', () => {
|
||||||
instance.clearInput();
|
instance.clearInput();
|
||||||
expect(instance.input.element.value).to.equal('');
|
expect(instance.input.element.value).to.equal('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle removeItemsByValue()', () => {
|
it('handles removeItemsByValue()', () => {
|
||||||
const items = instance.currentState.items;
|
const items = instance.currentState.items;
|
||||||
const randomItem = items[Math.floor(Math.random() * items.length)];
|
const randomItem = items[Math.floor(Math.random() * items.length)];
|
||||||
|
|
||||||
|
@ -949,7 +949,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should react to config options', () => {
|
describe('reacts to config options', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -1056,7 +1056,7 @@ describe('Choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should allow custom properties provided by the user on items or choices', () => {
|
describe('allows custom properties provided by the user on items or choices', () => {
|
||||||
let input;
|
let input;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
|
@ -1072,7 +1072,7 @@ describe('Choices', () => {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow the user to supply custom properties for a choice that will be inherited by the item when the user selects the choice', () => {
|
it('allows the user to supply custom properties for a choice that will be inherited by the item when the user selects the choice', () => {
|
||||||
const expectedCustomProperties = {
|
const expectedCustomProperties = {
|
||||||
isBestOptionEver: true,
|
isBestOptionEver: true,
|
||||||
};
|
};
|
||||||
|
@ -1093,7 +1093,7 @@ describe('Choices', () => {
|
||||||
expect(selectedItems[0].customProperties).to.equal(expectedCustomProperties);
|
expect(selectedItems[0].customProperties).to.equal(expectedCustomProperties);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow the user to supply custom properties when directly creating a selected item', () => {
|
it('allows the user to supply custom properties when directly creating a selected item', () => {
|
||||||
const expectedCustomProperties = {
|
const expectedCustomProperties = {
|
||||||
isBestOptionEver: true,
|
isBestOptionEver: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,10 @@ export default class Container {
|
||||||
this.onBlur = this.onBlur.bind(this);
|
this.onBlur = this.onBlur.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add event listeners
|
* Add event listeners
|
||||||
*/
|
*/
|
||||||
|
@ -155,6 +159,16 @@ export default class Container {
|
||||||
this.isDisabled = true;
|
this.isDisabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
revert(originalElement) {
|
||||||
|
// Move passed element back to original position
|
||||||
|
this.element.parentNode.insertBefore(
|
||||||
|
originalElement,
|
||||||
|
this.element,
|
||||||
|
);
|
||||||
|
// Remove container
|
||||||
|
this.element.parentNode.removeChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add loading state to element
|
* Add loading state to element
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,6 +8,10 @@ export default class Dropdown {
|
||||||
this.isActive = false;
|
this.isActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine how far the top of our element is from
|
* Determine how far the top of our element is from
|
||||||
* the top of the window
|
* the top of the window
|
||||||
|
|
|
@ -15,6 +15,10 @@ export default class Input {
|
||||||
this.onBlur = this.onBlur.bind(this);
|
this.onBlur = this.onBlur.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
addEventListeners() {
|
addEventListeners() {
|
||||||
this.element.addEventListener('input', this.onInput);
|
this.element.addEventListener('input', this.onInput);
|
||||||
this.element.addEventListener('paste', this.onPaste);
|
this.element.addEventListener('paste', this.onPaste);
|
||||||
|
|
|
@ -8,6 +8,10 @@ export default class List {
|
||||||
this.hasChildren = !!this.element.children;
|
this.hasChildren = !!this.element.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear List contents
|
* Clear List contents
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
|
import { dispatchEvent } from '../lib/utils';
|
||||||
|
|
||||||
export default class WrappedElement {
|
export default class WrappedElement {
|
||||||
constructor(instance, element, classNames) {
|
constructor(instance, element, classNames) {
|
||||||
this.parentInstance = instance;
|
this.parentInstance = instance;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.classNames = classNames;
|
this.classNames = classNames;
|
||||||
|
this.isDisabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.element.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
conceal() {
|
conceal() {
|
||||||
|
@ -50,4 +61,20 @@ export default class WrappedElement {
|
||||||
// Re-assign values - this is weird, I know
|
// Re-assign values - this is weird, I know
|
||||||
this.element.value = this.element.value;
|
this.element.value = this.element.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
this.element.removeAttribute('disabled');
|
||||||
|
this.element.disabled = false;
|
||||||
|
this.isDisabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
this.element.setAttribute('disabled', '');
|
||||||
|
this.element.disabled = true;
|
||||||
|
this.isDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEvent(eventType, data) {
|
||||||
|
dispatchEvent(this.element, eventType, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ export default class WrappedInput extends WrappedElement {
|
||||||
this.classNames = classNames;
|
this.classNames = classNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
super.getElement();
|
||||||
|
}
|
||||||
|
|
||||||
conceal() {
|
conceal() {
|
||||||
super.conceal();
|
super.conceal();
|
||||||
}
|
}
|
||||||
|
@ -15,4 +19,17 @@ export default class WrappedInput extends WrappedElement {
|
||||||
reveal() {
|
reveal() {
|
||||||
super.reveal();
|
super.reveal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
super.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
super.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(value) {
|
||||||
|
this.element.setAttribute('value', value);
|
||||||
|
this.element.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ export default class WrappedSelect extends WrappedElement {
|
||||||
this.classNames = classNames;
|
this.classNames = classNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getElement() {
|
||||||
|
super.getElement();
|
||||||
|
}
|
||||||
|
|
||||||
conceal() {
|
conceal() {
|
||||||
super.conceal();
|
super.conceal();
|
||||||
}
|
}
|
||||||
|
@ -15,4 +19,29 @@ export default class WrappedSelect extends WrappedElement {
|
||||||
reveal() {
|
reveal() {
|
||||||
super.reveal();
|
super.reveal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
super.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
super.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptions(options) {
|
||||||
|
this.element.innerHTML = '';
|
||||||
|
this.element.appendChild(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlaceholderOption() {
|
||||||
|
return this.element.querySelector('option[placeholder]');
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions() {
|
||||||
|
return Array.from(this.element.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptionGroups() {
|
||||||
|
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,3 +103,5 @@ export const KEY_CODES = {
|
||||||
PAGE_UP_KEY: 33,
|
PAGE_UP_KEY: 33,
|
||||||
PAGE_DOWN_KEY: 34,
|
PAGE_DOWN_KEY: 34,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SCROLLING_SPEED = 4;
|
||||||
|
|
|
@ -552,13 +552,13 @@ export const sortByAlpha = (a, b) => {
|
||||||
export const sortByScore = (a, b) => a.score - b.score;
|
export const sortByScore = (a, b) => a.score - b.score;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger native event
|
* Dispatch native event
|
||||||
* @param {NodeElement} element Element to trigger event on
|
* @param {NodeElement} element Element to trigger event on
|
||||||
* @param {String} type Type of event to trigger
|
* @param {String} type Type of event to trigger
|
||||||
* @param {Object} customArgs Data to pass with event
|
* @param {Object} customArgs Data to pass with event
|
||||||
* @return {Object} Triggered event
|
* @return {Object} Triggered event
|
||||||
*/
|
*/
|
||||||
export const triggerEvent = (element, type, customArgs = null) => {
|
export const dispatchEvent = (element, type, customArgs = null) => {
|
||||||
const event = new CustomEvent(type, {
|
const event = new CustomEvent(type, {
|
||||||
detail: customArgs,
|
detail: customArgs,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
|
|
|
@ -2,12 +2,19 @@ import classNames from 'classnames';
|
||||||
import { strToEl } from './lib/utils';
|
import { strToEl } from './lib/utils';
|
||||||
|
|
||||||
export const TEMPLATES = {
|
export const TEMPLATES = {
|
||||||
containerOuter(globalClasses, direction) {
|
containerOuter(
|
||||||
const tabIndex = this.isSelectOneElement ? 'tabindex="0"' : '';
|
globalClasses,
|
||||||
let role = this.isSelectElement ? 'role="listbox"' : '';
|
direction,
|
||||||
|
isSelectElement,
|
||||||
|
isSelectOneElement,
|
||||||
|
searchEnabled,
|
||||||
|
passedElementType,
|
||||||
|
) {
|
||||||
|
const tabIndex = isSelectOneElement ? 'tabindex="0"' : '';
|
||||||
|
let role = isSelectElement ? 'role="listbox"' : '';
|
||||||
let ariaAutoComplete = '';
|
let ariaAutoComplete = '';
|
||||||
|
|
||||||
if (this.isSelectElement && this.config.searchEnabled) {
|
if (isSelectElement && searchEnabled) {
|
||||||
role = 'role="combobox"';
|
role = 'role="combobox"';
|
||||||
ariaAutoComplete = 'aria-autocomplete="list"';
|
ariaAutoComplete = 'aria-autocomplete="list"';
|
||||||
}
|
}
|
||||||
|
@ -15,7 +22,7 @@ export const TEMPLATES = {
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
<div
|
<div
|
||||||
class="${globalClasses.containerOuter}"
|
class="${globalClasses.containerOuter}"
|
||||||
data-type="${this.passedElement.element.type}"
|
data-type="${passedElementType}"
|
||||||
${role}
|
${role}
|
||||||
${tabIndex}
|
${tabIndex}
|
||||||
${ariaAutoComplete}
|
${ariaAutoComplete}
|
||||||
|
@ -31,11 +38,11 @@ export const TEMPLATES = {
|
||||||
<div class="${globalClasses.containerInner}"></div>
|
<div class="${globalClasses.containerInner}"></div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
itemList(globalClasses) {
|
itemList(globalClasses, isSelectOneElement) {
|
||||||
const localClasses = classNames(
|
const localClasses = classNames(
|
||||||
globalClasses.list, {
|
globalClasses.list, {
|
||||||
[globalClasses.listSingle]: (this.isSelectOneElement),
|
[globalClasses.listSingle]: (isSelectOneElement),
|
||||||
[globalClasses.listItems]: (!this.isSelectOneElement),
|
[globalClasses.listItems]: (!isSelectOneElement),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -50,7 +57,7 @@ export const TEMPLATES = {
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
item(globalClasses, data) {
|
item(globalClasses, data, removeItemButton) {
|
||||||
const ariaSelected = data.active ? 'aria-selected="true"' : '';
|
const ariaSelected = data.active ? 'aria-selected="true"' : '';
|
||||||
const ariaDisabled = data.disabled ? 'aria-disabled="true"' : '';
|
const ariaDisabled = data.disabled ? 'aria-disabled="true"' : '';
|
||||||
|
|
||||||
|
@ -62,7 +69,7 @@ export const TEMPLATES = {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.config.removeItemButton) {
|
if (removeItemButton) {
|
||||||
localClasses = classNames(
|
localClasses = classNames(
|
||||||
globalClasses.item, {
|
globalClasses.item, {
|
||||||
[globalClasses.highlightedState]: data.highlighted,
|
[globalClasses.highlightedState]: data.highlighted,
|
||||||
|
@ -107,8 +114,8 @@ export const TEMPLATES = {
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
choiceList(globalClasses) {
|
choiceList(globalClasses, isSelectOneElement) {
|
||||||
const ariaMultiSelectable = !this.isSelectOneElement ?
|
const ariaMultiSelectable = !isSelectOneElement ?
|
||||||
'aria-multiselectable="true"' :
|
'aria-multiselectable="true"' :
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@ -143,7 +150,7 @@ export const TEMPLATES = {
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
choice(globalClasses, data) {
|
choice(globalClasses, data, itemSelectText) {
|
||||||
const role = data.groupId > 0 ? 'role="treeitem"' : 'role="option"';
|
const role = data.groupId > 0 ? 'role="treeitem"' : 'role="option"';
|
||||||
const localClasses = classNames(
|
const localClasses = classNames(
|
||||||
globalClasses.item,
|
globalClasses.item,
|
||||||
|
@ -157,7 +164,7 @@ export const TEMPLATES = {
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
<div
|
<div
|
||||||
class="${localClasses}"
|
class="${localClasses}"
|
||||||
data-select-text="${this.config.itemSelectText}"
|
data-select-text="${itemSelectText}"
|
||||||
data-choice
|
data-choice
|
||||||
data-id="${data.id}"
|
data-id="${data.id}"
|
||||||
data-value="${data.value}"
|
data-value="${data.value}"
|
||||||
|
|
Loading…
Reference in a new issue