mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-08 00:42:15 +02:00
Resolve bug 473 (#739)
* Fix #473 * Add tests * Tweak cypress tests * Build
This commit is contained in:
parent
81c44ba8f2
commit
b5b593a62f
|
@ -962,5 +962,41 @@ describe('Choices - select one', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('disabling first choice via options', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||||
|
.find('.choices')
|
||||||
|
.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
let disabledValue;
|
||||||
|
|
||||||
|
it('disables the first choice', () => {
|
||||||
|
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||||
|
.find('.choices__list--dropdown .choices__list')
|
||||||
|
.children()
|
||||||
|
.first()
|
||||||
|
.should('have.class', 'choices__item--disabled')
|
||||||
|
.then($choice => {
|
||||||
|
disabledValue = $choice.val();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('selects the first enabled choice', () => {
|
||||||
|
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||||
|
.find('.choices__input[hidden]')
|
||||||
|
.then($option => {
|
||||||
|
expect($option.text().trim()).to.not.equal(disabledValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||||
|
.find('.choices__item.choices__item--selectable')
|
||||||
|
.first()
|
||||||
|
.should($choice => {
|
||||||
|
expect($choice.text().trim()).to.not.equal(disabledValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1511,9 +1511,10 @@ var cloneObject = function cloneObject(obj) {
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
* Returns an array of keys present on the first but missing on the second object
|
||||||
* @param {object} a
|
* @param {object} a
|
||||||
* @param {object} b
|
* @param {object} b
|
||||||
* @returns {array}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var diff = function diff(a, b) {
|
var diff = function diff(a, b) {
|
||||||
|
@ -2381,7 +2382,7 @@ function () {
|
||||||
this.element.innerHTML = '';
|
this.element.innerHTML = '';
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Element} node
|
* @param {Element | DocumentFragment} node
|
||||||
*/
|
*/
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -3045,12 +3046,13 @@ var TEMPLATES =
|
||||||
/* harmony default export */ var templates = (TEMPLATES);
|
/* harmony default export */ var templates = (TEMPLATES);
|
||||||
// CONCATENATED MODULE: ./src/scripts/actions/choices.js
|
// CONCATENATED MODULE: ./src/scripts/actions/choices.js
|
||||||
/**
|
/**
|
||||||
|
* @typedef {import('redux').Action} Action
|
||||||
* @typedef {import('../../../types/index').Choices.Choice} Choice
|
* @typedef {import('../../../types/index').Choices.Choice} Choice
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @argument {Choice} choice
|
* @argument {Choice} choice
|
||||||
* @returns {{ type: string } & Choice}
|
* @returns {Action & Choice}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var choices_addChoice = function addChoice(_ref) {
|
var choices_addChoice = function addChoice(_ref) {
|
||||||
|
@ -3078,7 +3080,7 @@ var choices_addChoice = function addChoice(_ref) {
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @argument {Choice[]} results
|
* @argument {Choice[]} results
|
||||||
* @returns {{ type: string, results: Choice[] }}
|
* @returns {Action & { results: Choice[] }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var choices_filterChoices = function filterChoices(results) {
|
var choices_filterChoices = function filterChoices(results) {
|
||||||
|
@ -3089,7 +3091,7 @@ var choices_filterChoices = function filterChoices(results) {
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @argument {boolean} active
|
* @argument {boolean} active
|
||||||
* @returns {{ type: string, active: boolean }}
|
* @returns {Action & { active: boolean }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var choices_activateChoices = function activateChoices(active) {
|
var choices_activateChoices = function activateChoices(active) {
|
||||||
|
@ -3103,7 +3105,7 @@ var choices_activateChoices = function activateChoices(active) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @returns {{ type: string }}
|
* @returns {Action}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var choices_clearChoices = function clearChoices() {
|
var choices_clearChoices = function clearChoices() {
|
||||||
|
@ -3114,12 +3116,13 @@ var choices_clearChoices = function clearChoices() {
|
||||||
// CONCATENATED MODULE: ./src/scripts/actions/items.js
|
// CONCATENATED MODULE: ./src/scripts/actions/items.js
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @typedef {import('redux').Action} Action
|
||||||
* @typedef {import('../../../types/index').Choices.Item} Item
|
* @typedef {import('../../../types/index').Choices.Item} Item
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Item} item
|
* @param {Item} item
|
||||||
* @returns {{ type: string } & Item}
|
* @returns {Action & Item}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var items_addItem = function addItem(_ref) {
|
var items_addItem = function addItem(_ref) {
|
||||||
|
@ -3146,7 +3149,7 @@ var items_addItem = function addItem(_ref) {
|
||||||
/**
|
/**
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {string} choiceId
|
* @param {string} choiceId
|
||||||
* @returns {{ type: string, id: string, choiceId: string }}
|
* @returns {Action & { id: string, choiceId: string }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var items_removeItem = function removeItem(id, choiceId) {
|
var items_removeItem = function removeItem(id, choiceId) {
|
||||||
|
@ -3159,7 +3162,7 @@ var items_removeItem = function removeItem(id, choiceId) {
|
||||||
/**
|
/**
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {boolean} highlighted
|
* @param {boolean} highlighted
|
||||||
* @returns {{ type: string, id: string, highlighted: boolean }}
|
* @returns {Action & { id: string, highlighted: boolean }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var items_highlightItem = function highlightItem(id, highlighted) {
|
var items_highlightItem = function highlightItem(id, highlighted) {
|
||||||
|
@ -3172,12 +3175,13 @@ var items_highlightItem = function highlightItem(id, highlighted) {
|
||||||
// CONCATENATED MODULE: ./src/scripts/actions/groups.js
|
// CONCATENATED MODULE: ./src/scripts/actions/groups.js
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @typedef {import('redux').Action} Action
|
||||||
* @typedef {import('../../../types/index').Choices.Group} Group
|
* @typedef {import('../../../types/index').Choices.Group} Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Group} group
|
* @param {Group} group
|
||||||
* @returns {{ type: string } & Group}
|
* @returns {Action & Group}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var groups_addGroup = function addGroup(_ref) {
|
var groups_addGroup = function addGroup(_ref) {
|
||||||
|
@ -3195,7 +3199,11 @@ var groups_addGroup = function addGroup(_ref) {
|
||||||
};
|
};
|
||||||
// CONCATENATED MODULE: ./src/scripts/actions/misc.js
|
// CONCATENATED MODULE: ./src/scripts/actions/misc.js
|
||||||
/**
|
/**
|
||||||
* @returns {{ type: string }}
|
* @typedef {import('redux').Action} Action
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Action}
|
||||||
*/
|
*/
|
||||||
var clearAll = function clearAll() {
|
var clearAll = function clearAll() {
|
||||||
return {
|
return {
|
||||||
|
@ -3204,7 +3212,7 @@ var clearAll = function clearAll() {
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @param {any} state
|
* @param {any} state
|
||||||
* @returns {{ type: string, state: object }}
|
* @returns {Action & { state: object }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var resetTo = function resetTo(state) {
|
var resetTo = function resetTo(state) {
|
||||||
|
@ -3215,7 +3223,7 @@ var resetTo = function resetTo(state) {
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @param {boolean} isLoading
|
* @param {boolean} isLoading
|
||||||
* @returns {{ type: string, isLoading: boolean }}
|
* @returns {Action & { isLoading: boolean }}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var setIsLoading = function setIsLoading(isLoading) {
|
var setIsLoading = function setIsLoading(isLoading) {
|
||||||
|
@ -3297,23 +3305,13 @@ function () {
|
||||||
arrayMerge: function arrayMerge(_, sourceArray) {
|
arrayMerge: function arrayMerge(_, sourceArray) {
|
||||||
return [].concat(sourceArray);
|
return [].concat(sourceArray);
|
||||||
}
|
}
|
||||||
}); // Convert addItemFilter to function
|
});
|
||||||
|
|
||||||
if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {
|
|
||||||
var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);
|
|
||||||
this.config.addItemFilter = re.test.bind(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
var invalidConfigOptions = diff(this.config, DEFAULT_CONFIG);
|
var invalidConfigOptions = diff(this.config, DEFAULT_CONFIG);
|
||||||
|
|
||||||
if (invalidConfigOptions.length) {
|
if (invalidConfigOptions.length) {
|
||||||
console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));
|
console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) {
|
|
||||||
this.config.renderSelectedChoices = 'auto';
|
|
||||||
}
|
|
||||||
|
|
||||||
var passedElement = typeof element === 'string' ? document.querySelector(element) : element;
|
var passedElement = typeof element === 'string' ? document.querySelector(element) : element;
|
||||||
|
|
||||||
if (!(passedElement instanceof HTMLInputElement || passedElement instanceof HTMLSelectElement)) {
|
if (!(passedElement instanceof HTMLInputElement || passedElement instanceof HTMLSelectElement)) {
|
||||||
|
@ -3324,6 +3322,16 @@ function () {
|
||||||
this._isSelectOneElement = passedElement.type === SELECT_ONE_TYPE;
|
this._isSelectOneElement = passedElement.type === SELECT_ONE_TYPE;
|
||||||
this._isSelectMultipleElement = passedElement.type === SELECT_MULTIPLE_TYPE;
|
this._isSelectMultipleElement = passedElement.type === SELECT_MULTIPLE_TYPE;
|
||||||
this._isSelectElement = this._isSelectOneElement || this._isSelectMultipleElement;
|
this._isSelectElement = this._isSelectOneElement || this._isSelectMultipleElement;
|
||||||
|
this.config.searchEnabled = this._isSelectMultipleElement || this.config.searchEnabled;
|
||||||
|
|
||||||
|
if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) {
|
||||||
|
this.config.renderSelectedChoices = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {
|
||||||
|
var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);
|
||||||
|
this.config.addItemFilter = re.test.bind(re);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._isTextElement) {
|
if (this._isTextElement) {
|
||||||
this.passedElement = new WrappedInput({
|
this.passedElement = new WrappedInput({
|
||||||
|
@ -5339,6 +5347,9 @@ function () {
|
||||||
|
|
||||||
var hasSelectedChoice = choices.some(function (choice) {
|
var hasSelectedChoice = choices.some(function (choice) {
|
||||||
return choice.selected;
|
return choice.selected;
|
||||||
|
});
|
||||||
|
var firstEnabledChoiceIndex = choices.findIndex(function (_choice) {
|
||||||
|
return _choice.disabled === undefined || !_choice.disabled;
|
||||||
}); // Add each choice
|
}); // Add each choice
|
||||||
|
|
||||||
choices.forEach(function (choice, index) {
|
choices.forEach(function (choice, index) {
|
||||||
|
@ -5355,12 +5366,15 @@ function () {
|
||||||
id: choice.id || null
|
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
|
* If there is a selected choice already or the choice is not the first in
|
||||||
// Otherwise pre-select the first choice in the array if it's a single select
|
* the array, add each choice normally.
|
||||||
var shouldPreselect = _this22._isSelectOneElement && !hasSelectedChoice && index === 0;
|
*
|
||||||
|
* Otherwise we pre-select the first enabled choice in the array ("select-one" only)
|
||||||
|
*/
|
||||||
|
var shouldPreselect = _this22._isSelectOneElement && !hasSelectedChoice && index === firstEnabledChoiceIndex;
|
||||||
var isSelected = shouldPreselect ? true : choice.selected;
|
var isSelected = shouldPreselect ? true : choice.selected;
|
||||||
var isDisabled = shouldPreselect ? false : choice.disabled;
|
var isDisabled = choice.disabled;
|
||||||
|
|
||||||
_this22._addChoice({
|
_this22._addChoice({
|
||||||
value: value,
|
value: value,
|
||||||
|
|
2
public/assets/scripts/choices.min.js
vendored
2
public/assets/scripts/choices.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -102,6 +102,18 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div data-test-hook="disabled-first-choice-via-options">
|
||||||
|
<label for="choices-disabled-choice-via-options"
|
||||||
|
>Disabled first choice by options</label
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
class="form-control"
|
||||||
|
name="choices-disabled-choice-via-options"
|
||||||
|
id="choices-disabled-choice-via-options"
|
||||||
|
>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div data-test-hook="add-items-disabled">
|
<div data-test-hook="add-items-disabled">
|
||||||
<label for="choices-add-items-disabled">Add items disabled</label>
|
<label for="choices-add-items-disabled">Add items disabled</label>
|
||||||
<select
|
<select
|
||||||
|
@ -373,6 +385,29 @@
|
||||||
removeItemButton: true,
|
removeItemButton: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Choices('#choices-disabled-choice-via-options', {
|
||||||
|
removeItemButton: true,
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
value: 'Choice 1',
|
||||||
|
label: 'Choice 1',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Choice 2',
|
||||||
|
label: 'Choice 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Choice 3',
|
||||||
|
label: 'Choice 3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Choice 4',
|
||||||
|
label: 'Choice 4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
new Choices('#choices-add-items-disabled', {
|
new Choices('#choices-add-items-disabled', {
|
||||||
addItems: false,
|
addItems: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -2115,6 +2115,9 @@ class Choices {
|
||||||
|
|
||||||
// Determine whether there is a selected choice
|
// Determine whether there is a selected choice
|
||||||
const hasSelectedChoice = choices.some(choice => choice.selected);
|
const hasSelectedChoice = choices.some(choice => choice.selected);
|
||||||
|
const firstEnabledChoiceIndex = choices.findIndex(
|
||||||
|
_choice => _choice.disabled === undefined || !_choice.disabled,
|
||||||
|
);
|
||||||
|
|
||||||
// Add each choice
|
// Add each choice
|
||||||
choices.forEach((choice, index) => {
|
choices.forEach((choice, index) => {
|
||||||
|
@ -2128,13 +2131,19 @@ class Choices {
|
||||||
id: choice.id || null,
|
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
|
* If there is a selected choice already or the choice is not the first in
|
||||||
// Otherwise pre-select the first choice in the array if it's a single select
|
* the array, add each choice normally.
|
||||||
|
*
|
||||||
|
* Otherwise we pre-select the first enabled choice in the array ("select-one" only)
|
||||||
|
*/
|
||||||
const shouldPreselect =
|
const shouldPreselect =
|
||||||
this._isSelectOneElement && !hasSelectedChoice && index === 0;
|
this._isSelectOneElement &&
|
||||||
|
!hasSelectedChoice &&
|
||||||
|
index === firstEnabledChoiceIndex;
|
||||||
|
|
||||||
const isSelected = shouldPreselect ? true : choice.selected;
|
const isSelected = shouldPreselect ? true : choice.selected;
|
||||||
const isDisabled = shouldPreselect ? false : choice.disabled;
|
const isDisabled = choice.disabled;
|
||||||
|
|
||||||
this._addChoice({
|
this._addChoice({
|
||||||
value,
|
value,
|
||||||
|
|
Loading…
Reference in a new issue