Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve bug 473 #739

Merged
merged 7 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cypress/integration/select-one.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
});
});
72 changes: 43 additions & 29 deletions public/assets/scripts/choices.js
Original file line number Diff line number Diff line change
Expand Up @@ -1511,9 +1511,10 @@ var cloneObject = function cloneObject(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} b
* @returns {array}
* @returns {string[]}
*/

var diff = function diff(a, b) {
Expand Down Expand Up @@ -2381,7 +2382,7 @@ function () {
this.element.innerHTML = '';
}
/**
* @param {Element} node
* @param {Element | DocumentFragment} node
*/
;

Expand Down Expand Up @@ -3045,12 +3046,13 @@ var TEMPLATES =
/* harmony default export */ var templates = (TEMPLATES);
// CONCATENATED MODULE: ./src/scripts/actions/choices.js
/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Choice} Choice
*/

/**
* @argument {Choice} choice
* @returns {{ type: string } & Choice}
* @returns {Action & Choice}
*/

var choices_addChoice = function addChoice(_ref) {
Expand Down Expand Up @@ -3078,7 +3080,7 @@ var choices_addChoice = function addChoice(_ref) {
};
/**
* @argument {Choice[]} results
* @returns {{ type: string, results: Choice[] }}
* @returns {Action & { results: Choice[] }}
*/

var choices_filterChoices = function filterChoices(results) {
Expand All @@ -3089,7 +3091,7 @@ var choices_filterChoices = function filterChoices(results) {
};
/**
* @argument {boolean} active
* @returns {{ type: string, active: boolean }}
* @returns {Action & { active: boolean }}
*/

var choices_activateChoices = function activateChoices(active) {
Expand All @@ -3103,7 +3105,7 @@ var choices_activateChoices = function activateChoices(active) {
};
};
/**
* @returns {{ type: string }}
* @returns {Action}
*/

var choices_clearChoices = function clearChoices() {
Expand All @@ -3114,12 +3116,13 @@ var choices_clearChoices = function clearChoices() {
// CONCATENATED MODULE: ./src/scripts/actions/items.js

/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Item} Item
*/

/**
* @param {Item} item
* @returns {{ type: string } & Item}
* @returns {Action & Item}
*/

var items_addItem = function addItem(_ref) {
Expand All @@ -3146,7 +3149,7 @@ var items_addItem = function addItem(_ref) {
/**
* @param {string} id
* @param {string} choiceId
* @returns {{ type: string, id: string, choiceId: string }}
* @returns {Action & { id: string, choiceId: string }}
*/

var items_removeItem = function removeItem(id, choiceId) {
Expand All @@ -3159,7 +3162,7 @@ var items_removeItem = function removeItem(id, choiceId) {
/**
* @param {string} id
* @param {boolean} highlighted
* @returns {{ type: string, id: string, highlighted: boolean }}
* @returns {Action & { id: string, highlighted: boolean }}
*/

var items_highlightItem = function highlightItem(id, highlighted) {
Expand All @@ -3172,12 +3175,13 @@ var items_highlightItem = function highlightItem(id, highlighted) {
// CONCATENATED MODULE: ./src/scripts/actions/groups.js

/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Group} Group
*/

/**
* @param {Group} group
* @returns {{ type: string } & Group}
* @returns {Action & Group}
*/

var groups_addGroup = function addGroup(_ref) {
Expand All @@ -3195,7 +3199,11 @@ var groups_addGroup = function addGroup(_ref) {
};
// CONCATENATED MODULE: ./src/scripts/actions/misc.js
/**
* @returns {{ type: string }}
* @typedef {import('redux').Action} Action
*/

/**
* @returns {Action}
*/
var clearAll = function clearAll() {
return {
Expand All @@ -3204,7 +3212,7 @@ var clearAll = function clearAll() {
};
/**
* @param {any} state
* @returns {{ type: string, state: object }}
* @returns {Action & { state: object }}
*/

var resetTo = function resetTo(state) {
Expand All @@ -3215,7 +3223,7 @@ var resetTo = function resetTo(state) {
};
/**
* @param {boolean} isLoading
* @returns {{ type: string, isLoading: boolean }}
* @returns {Action & { isLoading: boolean }}
*/

var setIsLoading = function setIsLoading(isLoading) {
Expand Down Expand Up @@ -3297,23 +3305,13 @@ function () {
arrayMerge: function arrayMerge(_, 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);

if (invalidConfigOptions.length) {
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;

if (!(passedElement instanceof HTMLInputElement || passedElement instanceof HTMLSelectElement)) {
Expand All @@ -3324,6 +3322,16 @@ function () {
this._isSelectOneElement = passedElement.type === SELECT_ONE_TYPE;
this._isSelectMultipleElement = passedElement.type === SELECT_MULTIPLE_TYPE;
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) {
this.passedElement = new WrappedInput({
Expand Down Expand Up @@ -5339,6 +5347,9 @@ function () {

var hasSelectedChoice = choices.some(function (choice) {
return choice.selected;
});
var firstEnabledChoiceIndex = choices.findIndex(function (_choice) {
return _choice.disabled === undefined || !_choice.disabled;
}); // Add each choice

choices.forEach(function (choice, index) {
Expand All @@ -5355,12 +5366,15 @@ function () {
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
var shouldPreselect = _this22._isSelectOneElement && !hasSelectedChoice && index === 0;
/**
* If there is a selected choice already or the choice is not the first in
* the array, add each choice normally.
*
* 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 isDisabled = shouldPreselect ? false : choice.disabled;
var isDisabled = choice.disabled;

_this22._addChoice({
value: value,
Expand Down
2 changes: 1 addition & 1 deletion public/assets/scripts/choices.min.js

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions public/test/select-one/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ <h2>Select one inputs</h2>
</select>
</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">
<label for="choices-add-items-disabled">Add items disabled</label>
<select
Expand Down Expand Up @@ -373,6 +385,29 @@ <h2>Select one inputs</h2>
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', {
addItems: false,
});
Expand Down
19 changes: 14 additions & 5 deletions src/scripts/choices.js
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,9 @@ class Choices {

// Determine whether there is a selected choice
const hasSelectedChoice = choices.some(choice => choice.selected);
const firstEnabledChoiceIndex = choices.findIndex(
_choice => _choice.disabled === undefined || !_choice.disabled,
);

// Add each choice
choices.forEach((choice, index) => {
Expand All @@ -2128,13 +2131,19 @@ class Choices {
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
/**
* If there is a selected choice already or the choice is not the first in
* the array, add each choice normally.
*
* Otherwise we pre-select the first enabled choice in the array ("select-one" only)
*/
const shouldPreselect =
this._isSelectOneElement && !hasSelectedChoice && index === 0;
this._isSelectOneElement &&
!hasSelectedChoice &&
index === firstEnabledChoiceIndex;

const isSelected = shouldPreselect ? true : choice.selected;
const isDisabled = shouldPreselect ? false : choice.disabled;
const isDisabled = choice.disabled;

this._addChoice({
value,
Expand Down