Refactor adding predefined groups/items/choices

This commit is contained in:
Josh Johnson 2019-11-03 15:54:24 +00:00
parent c68d1ad610
commit 43c020edd1

View file

@ -45,6 +45,8 @@ import {
/** /**
* @typedef {import('../../types/index').Choices.Choice} Choice * @typedef {import('../../types/index').Choices.Choice} Choice
* @typedef {import('../../types/index').Choices.Item} Item
* @typedef {import('../../types/index').Choices.Group} Group
* @typedef {import('../../types/index').Choices.Options} Options * @typedef {import('../../types/index').Choices.Options} Options
*/ */
@ -174,16 +176,31 @@ class Choices {
this._idNames = { this._idNames = {
itemChoice: 'item-choice', itemChoice: 'item-choice',
}; };
// Assign preset groups from passed element
this._presetGroups = this.passedElement.optionGroups;
// Assign preset choices from passed object // Assign preset choices from passed object
this._presetChoices = this.config.choices; this._presetChoices = this.config.choices;
// Assign preset items from passed object first // Assign preset items from passed object first
this._presetItems = this.config.items; this._presetItems = this.config.items;
// Then add any values passed from attribute // Add any values passed from attribute
if (this.passedElement.value) { if (this.passedElement.value) {
this._presetItems = this._presetItems.concat( this._presetItems = this._presetItems.concat(
this.passedElement.value.split(this.config.delimiter), this.passedElement.value.split(this.config.delimiter),
); );
} }
// Create array of choices from option elements
if (this.passedElement.options) {
this.passedElement.options.forEach(o => {
this._presetChoices.push({
value: o.value,
label: o.innerHTML,
selected: o.selected,
disabled: o.disabled || o.parentNode.disabled,
placeholder: o.value === '' || o.hasAttribute('placeholder'),
customProperties: o.getAttribute('data-custom-properties'),
});
});
}
this._render = this._render.bind(this); this._render = this._render.bind(this);
this._onFocus = this._onFocus.bind(this); this._onFocus = this._onFocus.bind(this);
@ -2024,7 +2041,7 @@ class Choices {
this.input.placeholder = this.config.searchPlaceholderValue || ''; this.input.placeholder = this.config.searchPlaceholderValue || '';
} else if (this._placeholderValue) { } else if (this._placeholderValue) {
this.input.placeholder = this._placeholderValue; this.input.placeholder = this._placeholderValue;
this.input.setWidth(true); this.input.setWidth();
} }
this.containerOuter.element.appendChild(this.containerInner.element); this.containerOuter.element.appendChild(this.containerInner.element);
@ -2045,116 +2062,105 @@ class Choices {
} }
if (this._isSelectElement) { if (this._isSelectElement) {
this._addPredefinedChoices(); this._highlightPosition = 0;
} else if (this._isTextElement) { this._isSearching = false;
this._addPredefinedItems(); this._setLoading(true);
if (this._presetGroups.length) {
this._addPredefinedGroups(this._presetGroups);
} else {
this._addPredefinedChoices(this._presetChoices);
}
this._setLoading(false);
}
if (this._isTextElement) {
this._addPredefinedItems(this._presetItems);
} }
} }
_addPredefinedChoices() { _addPredefinedGroups(groups) {
const passedGroups = this.passedElement.optionGroups; // If we have a placeholder option
const placeholderChoice = this.passedElement.placeholderOption;
this._highlightPosition = 0; if (
this._isSearching = false; placeholderChoice &&
this._setLoading(true); placeholderChoice.parentNode.tagName === 'SELECT'
) {
if (passedGroups && passedGroups.length) { this._addChoice({
// If we have a placeholder option value: placeholderChoice.value,
const placeholderChoice = this.passedElement.placeholderOption; label: placeholderChoice.innerHTML,
if ( isSelected: placeholderChoice.selected,
placeholderChoice && isDisabled: placeholderChoice.disabled,
placeholderChoice.parentNode.tagName === 'SELECT' placeholder: true,
) {
this._addChoice({
value: placeholderChoice.value,
label: placeholderChoice.innerHTML,
isSelected: placeholderChoice.selected,
isDisabled: placeholderChoice.disabled,
placeholder: true,
});
}
passedGroups.forEach(group =>
this._addGroup({
group,
id: group.id || null,
}),
);
} else {
const passedOptions = this.passedElement.options;
const filter = this.config.sorter;
const allChoices = this._presetChoices;
// Create array of options from option elements
passedOptions.forEach(o => {
allChoices.push({
value: o.value,
label: o.innerHTML,
selected: o.selected,
disabled: o.disabled || o.parentNode.disabled,
placeholder: o.value === '' || o.hasAttribute('placeholder'),
customProperties: o.getAttribute('data-custom-properties'),
});
}); });
}
// If sorting is enabled or the user is searching, filter choices groups.forEach(group =>
if (this.config.shouldSort) { this._addGroup({
allChoices.sort(filter); group,
} id: group.id || null,
}),
);
}
// Determine whether there is a selected choice _addPredefinedChoices(choices) {
const hasSelectedChoice = allChoices.some(choice => choice.selected); // If sorting is enabled or the user is searching, filter choices
const handleChoice = (choice, index) => { if (this.config.shouldSort) {
const { value, label, customProperties, placeholder } = choice; choices.sort(this.config.sorter);
}
if (this._isSelectElement) { // Determine whether there is a selected choice
// If the choice is actually a group const hasSelectedChoice = choices.some(choice => choice.selected);
if (choice.choices) {
this._addGroup({
group: choice,
id: choice.id || null,
});
} else {
// If there is a selected choice already or the choice is not
// the first in the array, add each choice normally
// Otherwise pre-select the first choice in the array if it's a single select
const shouldPreselect =
this._isSelectOneElement && !hasSelectedChoice && index === 0;
const isSelected = shouldPreselect ? true : choice.selected;
const isDisabled = shouldPreselect ? false : choice.disabled;
this._addChoice({ // Add each choice
value, choices.forEach((choice, index) => {
label, const { value, label, customProperties, placeholder } = choice;
isSelected,
isDisabled, if (this._isSelectElement) {
customProperties, // If the choice is actually a group
placeholder, if (choice.choices) {
}); this._addGroup({
} group: choice,
id: choice.id || null,
});
} else { } else {
// If there is a selected choice already or the choice is not
// the first in the array, add each choice normally
// Otherwise pre-select the first choice in the array if it's a single select
const shouldPreselect =
this._isSelectOneElement && !hasSelectedChoice && index === 0;
const isSelected = shouldPreselect ? true : choice.selected;
const isDisabled = shouldPreselect ? false : choice.disabled;
this._addChoice({ this._addChoice({
value, value,
label, label,
isSelected: choice.selected, isSelected,
isDisabled: choice.disabled, isDisabled,
customProperties, customProperties,
placeholder, placeholder,
}); });
} }
}; } else {
this._addChoice({
// Add each choice value,
allChoices.forEach((choice, index) => handleChoice(choice, index)); label,
} isSelected: choice.selected,
isDisabled: choice.disabled,
this._setLoading(false); customProperties,
placeholder,
});
}
});
} }
_addPredefinedItems() { /**
const handlePresetItem = item => { * @param {Item[]} items
const itemType = getType(item); */
if (itemType === 'Object' && item.value) { _addPredefinedItems(items) {
items.forEach(item => {
if (typeof item === 'object' && item.value) {
this._addItem({ this._addItem({
value: item.value, value: item.value,
label: item.label, label: item.label,
@ -2162,14 +2168,14 @@ class Choices {
customProperties: item.customProperties, customProperties: item.customProperties,
placeholder: item.placeholder, placeholder: item.placeholder,
}); });
} else if (itemType === 'String') { }
if (typeof item === 'string') {
this._addItem({ this._addItem({
value: item, value: item,
}); });
} }
}; });
this._presetItems.forEach(item => handlePresetItem(item));
} }
_setChoiceOrItem(item) { _setChoiceOrItem(item) {