mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-16 12:45:10 +02:00
replicated PR 525 from main repo
This commit is contained in:
parent
5dbea2825a
commit
04977bae97
10
README.md
10
README.md
|
@ -122,6 +122,7 @@ Or include Choices directly:
|
||||||
choices: [],
|
choices: [],
|
||||||
renderChoiceLimit: -1,
|
renderChoiceLimit: -1,
|
||||||
maxItemCount: -1,
|
maxItemCount: -1,
|
||||||
|
addChoices: false,
|
||||||
addItems: true,
|
addItems: true,
|
||||||
addItemFilter: null,
|
addItemFilter: null,
|
||||||
removeItems: true,
|
removeItems: true,
|
||||||
|
@ -304,6 +305,15 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Usage:** The amount of items a user can input/select ("-1" indicates no limit).
|
**Usage:** The amount of items a user can input/select ("-1" indicates no limit).
|
||||||
|
|
||||||
|
### addChoices
|
||||||
|
**Type**: `Boolean` **Default:** `false`
|
||||||
|
|
||||||
|
**Input types affected:** `select-multiple`, `select-one`
|
||||||
|
|
||||||
|
**Usage:** Whether a user can add choices
|
||||||
|
|
||||||
|
**Note:** `addItems` must also be `true`
|
||||||
|
|
||||||
### addItems
|
### addItems
|
||||||
|
|
||||||
**Type:** `Boolean` **Default:** `true`
|
**Type:** `Boolean` **Default:** `true`
|
||||||
|
|
|
@ -1006,6 +1006,24 @@ describe('Choices - select multiple', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('adding user-created choices', () => {
|
||||||
|
it('allows the user to add choices', () => {
|
||||||
|
const newChoice = 'New Choice';
|
||||||
|
|
||||||
|
cy.get('[data-test-hook=add-choices]')
|
||||||
|
.find('.choices__input--cloned')
|
||||||
|
.type(newChoice)
|
||||||
|
.type('{enter}');
|
||||||
|
|
||||||
|
cy.get('[data-test-hook=add-choices]')
|
||||||
|
.find('.choices__list--multiple')
|
||||||
|
.last()
|
||||||
|
.should($el => {
|
||||||
|
expect($el).to.contain(newChoice);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1145,5 +1145,26 @@ describe('Choices - select one', () => {
|
||||||
.should('have.length', 3);
|
.should('have.length', 3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('adding user-created choices', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.get('[data-test-hook=add-choices]').find('.choices').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows the user to add choices', () => {
|
||||||
|
const newChoice = 'New Choice';
|
||||||
|
|
||||||
|
cy.get('[data-test-hook=add-choices]')
|
||||||
|
.find('.choices__input--cloned')
|
||||||
|
.type(newChoice)
|
||||||
|
.type('{enter}');
|
||||||
|
|
||||||
|
cy.get('[data-test-hook=add-choices]')
|
||||||
|
.find('.choices__list--single .choices__item')
|
||||||
|
.should(($el) => {
|
||||||
|
expect($el).to.contain(newChoice);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -397,6 +397,15 @@
|
||||||
multiple
|
multiple
|
||||||
></select>
|
></select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div data-test-hook="add-choices">
|
||||||
|
<label for="choices-add-choices">Add choices</label>
|
||||||
|
<select class="form-control" name="choices-add-choices" id="choices-add-choices" multiple>
|
||||||
|
<option value="Choice 1">Choice 1</option>
|
||||||
|
<option value="Choice 2">Choice 2</option>
|
||||||
|
<option value="Choice 3">Choice 3</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
@ -622,6 +631,8 @@
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Choices('#choices-add-choices', { addChoices: true });
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -417,6 +417,16 @@
|
||||||
<button class="destroy">Destroy</button>
|
<button class="destroy">Destroy</button>
|
||||||
<button class="init">Init</button>
|
<button class="init">Init</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div data-test-hook="add-choices">
|
||||||
|
<label for="choices-add-choices">Add choices</label>
|
||||||
|
<select class="form-control" name="choices-add-choices" id="choices-add-choices">
|
||||||
|
<option value="Choice 1">Choice 1</option>
|
||||||
|
<option value="Choice 2">Choice 2</option>
|
||||||
|
<option value="Choice 3">Choice 3</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
@ -676,6 +686,8 @@
|
||||||
document.querySelector('button.init').addEventListener('click', () => {
|
document.querySelector('button.init').addEventListener('click', () => {
|
||||||
newDestroyInitChoices.init();
|
newDestroyInitChoices.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Choices('#choices-add-choices', { addChoices: true });
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -825,12 +825,12 @@ class Choices implements Choices {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have choices to show
|
const { activeItems } = this._store; // If we have choices to show
|
||||||
|
|
||||||
if (
|
if (
|
||||||
choiceListFragment.childNodes &&
|
choiceListFragment.childNodes &&
|
||||||
choiceListFragment.childNodes.length > 0
|
choiceListFragment.childNodes.length > 0
|
||||||
) {
|
) {
|
||||||
const { activeItems } = this._store;
|
|
||||||
const canAddItem = this._canAddItem(activeItems, this.input.value);
|
const canAddItem = this._canAddItem(activeItems, this.input.value);
|
||||||
|
|
||||||
// ...and we can select them
|
// ...and we can select them
|
||||||
|
@ -844,18 +844,21 @@ class Choices implements Choices {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise show a notice
|
// Otherwise show a notice
|
||||||
let dropdownItem;
|
const canAddChoice = this._canAddChoice(activeItems, this.input.value);
|
||||||
let notice;
|
|
||||||
|
|
||||||
if (this._isSearching) {
|
let dropdownItem;
|
||||||
notice =
|
|
||||||
|
if (canAddChoice.response) {
|
||||||
|
dropdownItem = this._getTemplate('notice', canAddChoice.notice);
|
||||||
|
} else if (this._isSearching) {
|
||||||
|
const notice =
|
||||||
typeof this.config.noResultsText === 'function'
|
typeof this.config.noResultsText === 'function'
|
||||||
? this.config.noResultsText()
|
? this.config.noResultsText()
|
||||||
: this.config.noResultsText;
|
: this.config.noResultsText;
|
||||||
|
|
||||||
dropdownItem = this._getTemplate('notice', notice, 'no-results');
|
dropdownItem = this._getTemplate('notice', notice, 'no-results');
|
||||||
} else {
|
} else {
|
||||||
notice =
|
const notice =
|
||||||
typeof this.config.noChoicesText === 'function'
|
typeof this.config.noChoicesText === 'function'
|
||||||
? this.config.noChoicesText()
|
? this.config.noChoicesText()
|
||||||
: this.config.noChoicesText;
|
: this.config.noChoicesText;
|
||||||
|
@ -1260,6 +1263,14 @@ class Choices implements Choices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_canAddChoice(activeItems: Item[], value: string): Notice {
|
||||||
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
|
||||||
|
canAddItem.response = this.config.addChoices && canAddItem.response;
|
||||||
|
|
||||||
|
return canAddItem;
|
||||||
|
}
|
||||||
|
|
||||||
_canAddItem(activeItems: Item[], value: string): Notice {
|
_canAddItem(activeItems: Item[], value: string): Notice {
|
||||||
let canAddItem = true;
|
let canAddItem = true;
|
||||||
let notice =
|
let notice =
|
||||||
|
@ -1555,16 +1566,22 @@ class Choices implements Choices {
|
||||||
const { ENTER_KEY: enterKey } = KEY_CODES;
|
const { ENTER_KEY: enterKey } = KEY_CODES;
|
||||||
const targetWasButton =
|
const targetWasButton =
|
||||||
target && (target as HTMLElement).hasAttribute('data-button');
|
target && (target as HTMLElement).hasAttribute('data-button');
|
||||||
|
let addedItem = false;
|
||||||
|
|
||||||
if (this._isTextElement && target && (target as HTMLInputElement).value) {
|
if (target && (target as HTMLInputElement).value) {
|
||||||
const { value } = this.input;
|
const { value } = this.input;
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
const canAddChoice = this._canAddChoice(activeItems, value);
|
||||||
|
|
||||||
if (canAddItem.response) {
|
if (
|
||||||
|
(this._isTextElement && canAddItem.response) ||
|
||||||
|
(!this._isTextElement && canAddChoice.response)
|
||||||
|
) {
|
||||||
this.hideDropdown(true);
|
this.hideDropdown(true);
|
||||||
this._addItem({ value });
|
this._addItem({ value });
|
||||||
this._triggerChange(value);
|
this._triggerChange(value);
|
||||||
this.clearInput();
|
this.clearInput();
|
||||||
|
addedItem = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1579,11 +1596,15 @@ class Choices implements Choices {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (highlightedChoice) {
|
if (highlightedChoice) {
|
||||||
// add enter keyCode value
|
if (addedItem) {
|
||||||
if (activeItems[0]) {
|
this.unhighlightAll();
|
||||||
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
|
} else {
|
||||||
|
if (activeItems[0]) {
|
||||||
|
// add enter keyCode value
|
||||||
|
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
|
||||||
|
}
|
||||||
|
this._handleChoiceAction(activeItems, highlightedChoice);
|
||||||
}
|
}
|
||||||
this._handleChoiceAction(activeItems, highlightedChoice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -37,6 +37,7 @@ export const DEFAULT_CONFIG: Options = {
|
||||||
silent: false,
|
silent: false,
|
||||||
renderChoiceLimit: -1,
|
renderChoiceLimit: -1,
|
||||||
maxItemCount: -1,
|
maxItemCount: -1,
|
||||||
|
addChoices: false,
|
||||||
addItems: true,
|
addItems: true,
|
||||||
addItemFilter: null,
|
addItemFilter: null,
|
||||||
removeItems: true,
|
removeItems: true,
|
||||||
|
|
|
@ -102,6 +102,15 @@ export interface Options {
|
||||||
*/
|
*/
|
||||||
maxItemCount: number;
|
maxItemCount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a user can add choices dynamically.
|
||||||
|
*
|
||||||
|
* **Input types affected:** select-one, select-multiple
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
addChoices: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether a user can add items.
|
* Whether a user can add items.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue