mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-12 02:26:35 +02:00
Api changes (#515)
* Combine regexFilter and addItemFilter + minor tweaks * Update tests to accomodate fixed dropdown notice * Remove broken `toggleDropdown` method * Unskip dropdown interaction tests * Remove reference to removed method
This commit is contained in:
parent
55b356ec69
commit
8540d5aabd
26
README.md
26
README.md
|
@ -78,6 +78,7 @@ will be returned. If you target one element, that instance will be returned.
|
||||||
renderChoiceLimit: -1,
|
renderChoiceLimit: -1,
|
||||||
maxItemCount: -1,
|
maxItemCount: -1,
|
||||||
addItems: true,
|
addItems: true,
|
||||||
|
addItemFilterFn: null,
|
||||||
removeItems: true,
|
removeItems: true,
|
||||||
removeItemButton: false,
|
removeItemButton: false,
|
||||||
editItems: false,
|
editItems: false,
|
||||||
|
@ -91,8 +92,6 @@ will be returned. If you target one element, that instance will be returned.
|
||||||
searchFields: ['label', 'value'],
|
searchFields: ['label', 'value'],
|
||||||
position: 'auto',
|
position: 'auto',
|
||||||
resetScrollPosition: true,
|
resetScrollPosition: true,
|
||||||
regexFilter: null,
|
|
||||||
addItemFilter: null,
|
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
shouldSortItems: false,
|
shouldSortItems: false,
|
||||||
sortFn: () => {...},
|
sortFn: () => {...},
|
||||||
|
@ -340,31 +339,24 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Usage:** Whether the scroll position should reset after adding an item.
|
**Usage:** Whether the scroll position should reset after adding an item.
|
||||||
|
|
||||||
### addItemFilter
|
### addItemFilterFn
|
||||||
**Type:** `Function` **Default:** `null`
|
**Type:** `Function` **Default:** `null`
|
||||||
|
|
||||||
**Input types affected:** `text`
|
**Input types affected:** `text`
|
||||||
|
|
||||||
**Usage:** A callback function that will need to return `true` for a user to successfully add an item.
|
**Usage:** A filter function that will need to return `true` for a user to successfully add an item.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Only adds items matching the text test
|
// Only adds items matching the text test
|
||||||
new Choices(element, {
|
new Choices(element, {
|
||||||
addItemFilter: function (value) {
|
addItemFilterFn: (value) => {
|
||||||
return (value !== 'test')
|
return (value !== 'test');
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### regexFilter
|
|
||||||
**Type:** `Regex` **Default:** `null`
|
|
||||||
|
|
||||||
**Input types affected:** `text`
|
|
||||||
|
|
||||||
**Usage:** A filter that will need to pass for a user to successfully add an item.
|
|
||||||
|
|
||||||
### shouldSort
|
### shouldSort
|
||||||
**Type:** `Boolean` **Default:** `true`
|
**Type:** `Boolean` **Default:** `true`
|
||||||
|
|
||||||
|
@ -752,12 +744,6 @@ choices.disable();
|
||||||
|
|
||||||
**Usage:** Hide option list dropdown (only affects select inputs).
|
**Usage:** Hide option list dropdown (only affects select inputs).
|
||||||
|
|
||||||
|
|
||||||
### toggleDropdown();
|
|
||||||
**Input types affected:** `text`, `select-multiple`
|
|
||||||
|
|
||||||
**Usage:** Toggle dropdown between showing/hidden.
|
|
||||||
|
|
||||||
### setChoices(choices, value, label, replaceChoices);
|
### setChoices(choices, value, label, replaceChoices);
|
||||||
**Input types affected:** `select-one`, `select-multiple`
|
**Input types affected:** `select-one`, `select-multiple`
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,7 @@ describe('Choices - select multiple', () => {
|
||||||
|
|
||||||
@todo Investigate why
|
@todo Investigate why
|
||||||
*/
|
*/
|
||||||
describe.skip('interacting with dropdown', () => {
|
describe('interacting with dropdown', () => {
|
||||||
describe('opening dropdown', () => {
|
describe('opening dropdown', () => {
|
||||||
it('opens dropdown', () => {
|
it('opens dropdown', () => {
|
||||||
cy.get('[data-test-hook=basic]')
|
cy.get('[data-test-hook=basic]')
|
||||||
|
@ -247,44 +247,6 @@ describe('Choices - select multiple', () => {
|
||||||
.should('not.be.visible');
|
.should('not.be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toggling dropdown', () => {
|
|
||||||
describe('when open', () => {
|
|
||||||
it('closes dropdown', () => {
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.open-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.toggle-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('.choices__list--dropdown')
|
|
||||||
.should('not.be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when closed', () => {
|
|
||||||
it('opens dropdown', () => {
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.close-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.toggle-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('.choices__list--dropdown')
|
|
||||||
.should('be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('disabling', () => {
|
describe('disabling', () => {
|
||||||
|
|
|
@ -134,7 +134,7 @@ describe('Choices - select one', () => {
|
||||||
|
|
||||||
@todo Investigate why
|
@todo Investigate why
|
||||||
*/
|
*/
|
||||||
describe.skip('interacting with dropdown', () => {
|
describe('interacting with dropdown', () => {
|
||||||
describe('opening dropdown', () => {
|
describe('opening dropdown', () => {
|
||||||
it('opens dropdown', () => {
|
it('opens dropdown', () => {
|
||||||
cy.get('[data-test-hook=basic]')
|
cy.get('[data-test-hook=basic]')
|
||||||
|
@ -165,44 +165,6 @@ describe('Choices - select one', () => {
|
||||||
.should('not.be.visible');
|
.should('not.be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toggling dropdown', () => {
|
|
||||||
describe('when open', () => {
|
|
||||||
it('closes dropdown', () => {
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.open-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.toggle-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('.choices__list--dropdown')
|
|
||||||
.should('not.be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when closed', () => {
|
|
||||||
it('opens dropdown', () => {
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.close-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('button.toggle-dropdown')
|
|
||||||
.focus()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=basic]')
|
|
||||||
.find('.choices__list--dropdown')
|
|
||||||
.should('be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('disabling', () => {
|
describe('disabling', () => {
|
||||||
|
|
|
@ -197,8 +197,9 @@ describe('Choices - text element', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('input limit', () => {
|
describe('input limit', () => {
|
||||||
|
const inputLimit = 5;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
for (let index = 0; index < 6; index++) {
|
for (let index = 0; index < inputLimit + 1; index++) {
|
||||||
cy.get('[data-test-hook=input-limit]')
|
cy.get('[data-test-hook=input-limit]')
|
||||||
.find('.choices__input--cloned')
|
.find('.choices__input--cloned')
|
||||||
.type(`${textInput} + ${index}`)
|
.type(`${textInput} + ${index}`)
|
||||||
|
@ -212,29 +213,36 @@ describe('Choices - text element', () => {
|
||||||
.first()
|
.first()
|
||||||
.children()
|
.children()
|
||||||
.should($items => {
|
.should($items => {
|
||||||
expect($items.length).to.equal(5);
|
expect($items.length).to.equal(inputLimit);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides dropdown prompt once limit has been reached', () => {
|
describe('reaching input limit', () => {
|
||||||
cy.wait(500); // allow for animation frame
|
it('displays dropdown prompt', () => {
|
||||||
cy.get('[data-test-hook=input-limit]')
|
cy.get('[data-test-hook=input-limit]')
|
||||||
.find('.choices__list--dropdown')
|
.find('.choices__list--dropdown')
|
||||||
.should('not.be.visible');
|
.should('be.visible')
|
||||||
|
.should($dropdown => {
|
||||||
|
const dropdownText = $dropdown.text().trim();
|
||||||
|
expect(dropdownText).to.equal(
|
||||||
|
`Only ${inputLimit} values can be added`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('regex filter', () => {
|
describe('add item filter', () => {
|
||||||
describe('inputting a value that satisfies the regex', () => {
|
describe('inputting a value that satisfies the filter', () => {
|
||||||
const input = 'joe@bloggs.com';
|
const input = 'joe@bloggs.com';
|
||||||
|
|
||||||
it('allows me to add choice', () => {
|
it('allows me to add choice', () => {
|
||||||
cy.get('[data-test-hook=regex-filter]')
|
cy.get('[data-test-hook=add-item-filter]')
|
||||||
.find('.choices__input--cloned')
|
.find('.choices__input--cloned')
|
||||||
.type(input)
|
.type(input)
|
||||||
.type('{enter}');
|
.type('{enter}');
|
||||||
|
|
||||||
cy.get('[data-test-hook=regex-filter]')
|
cy.get('[data-test-hook=add-item-filter]')
|
||||||
.find('.choices__list--multiple .choices__item')
|
.find('.choices__list--multiple .choices__item')
|
||||||
.last()
|
.last()
|
||||||
.should($choice => {
|
.should($choice => {
|
||||||
|
@ -245,14 +253,20 @@ describe('Choices - text element', () => {
|
||||||
|
|
||||||
describe('inputting a value that does not satisfy the regex', () => {
|
describe('inputting a value that does not satisfy the regex', () => {
|
||||||
it('displays dropdown prompt', () => {
|
it('displays dropdown prompt', () => {
|
||||||
cy.get('[data-test-hook=regex-filter]')
|
cy.get('[data-test-hook=add-item-filter]')
|
||||||
.find('.choices__input--cloned')
|
.find('.choices__input--cloned')
|
||||||
.type(`this is not an email address`)
|
.type(`this is not an email address`)
|
||||||
.type('{enter}');
|
.type('{enter}');
|
||||||
|
|
||||||
cy.get('[data-test-hook=regex-filter]')
|
cy.get('[data-test-hook=add-item-filter]')
|
||||||
.find('.choices__list--dropdown')
|
.find('.choices__list--dropdown')
|
||||||
.should('not.be.visible');
|
.should('be.visible')
|
||||||
|
.should($dropdown => {
|
||||||
|
const dropdownText = $dropdown.text().trim();
|
||||||
|
expect(dropdownText).to.equal(
|
||||||
|
'Only values matching specific conditions can be added',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -293,39 +307,6 @@ describe('Choices - text element', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('custom add item callback', () => {
|
|
||||||
describe('inputting a value that satisfies the addItemFilter', () => {
|
|
||||||
const input = 'test';
|
|
||||||
|
|
||||||
it('allows me to add choice', () => {
|
|
||||||
cy.get('[data-test-hook=add-item-callback]')
|
|
||||||
.find('.choices__input--cloned')
|
|
||||||
.type(input)
|
|
||||||
.type('{enter}');
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=add-item-callback]')
|
|
||||||
.find('.choices__list--multiple .choices__item')
|
|
||||||
.last()
|
|
||||||
.should($choice => {
|
|
||||||
expect($choice.text().trim()).to.equal(input);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('inputting a value that does not satisfy the callback', () => {
|
|
||||||
it('displays dropdown prompt', () => {
|
|
||||||
cy.get('[data-test-hook=add-item-callback]')
|
|
||||||
.find('.choices__input--cloned')
|
|
||||||
.type(`this is not the allowed text`)
|
|
||||||
.type('{enter}');
|
|
||||||
|
|
||||||
cy.get('[data-test-hook=add-item-callback]')
|
|
||||||
.find('.choices__list--dropdown')
|
|
||||||
.should('not.be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('disabled via attribute', () => {
|
describe('disabled via attribute', () => {
|
||||||
it('does not allow me to input data', () => {
|
it('does not allow me to input data', () => {
|
||||||
cy.get('[data-test-hook=disabled-via-attr]')
|
cy.get('[data-test-hook=disabled-via-attr]')
|
||||||
|
|
|
@ -344,7 +344,15 @@
|
||||||
|
|
||||||
var textEmailFilter = new Choices('#choices-text-email-filter', {
|
var textEmailFilter = new Choices('#choices-text-email-filter', {
|
||||||
editItems: true,
|
editItems: true,
|
||||||
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,}))$/,
|
addItemFilterFn: (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const regex = /^(([^<>()\[\]\\.,;:\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,}))$/
|
||||||
|
const expression = new RegExp(regex.source, 'i');
|
||||||
|
return expression.test(value);
|
||||||
|
},
|
||||||
}).setValue(['joe@bloggs.com']);
|
}).setValue(['joe@bloggs.com']);
|
||||||
|
|
||||||
var textDisabled = new Choices('#choices-text-disabled', {
|
var textDisabled = new Choices('#choices-text-disabled', {
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
<label for="choices-basic">Basic</label>
|
<label for="choices-basic">Basic</label>
|
||||||
<button class="open-dropdown push-bottom">Open dropdown</button>
|
<button class="open-dropdown push-bottom">Open dropdown</button>
|
||||||
<button class="close-dropdown push-bottom">Close dropdown</button>
|
<button class="close-dropdown push-bottom">Close dropdown</button>
|
||||||
<button class="toggle-dropdown push-bottom">Toggle dropdown</button>
|
|
||||||
<button class="disable push-bottom">Disable</button>
|
<button class="disable push-bottom">Disable</button>
|
||||||
<button class="enable push-bottom">Enable</button>
|
<button class="enable push-bottom">Enable</button>
|
||||||
<select class="form-control" name="choices-basic" id="choices-basic" multiple>
|
<select class="form-control" name="choices-basic" id="choices-basic" multiple>
|
||||||
|
@ -216,10 +215,6 @@
|
||||||
choicesBasic.hideDropdown();
|
choicesBasic.hideDropdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('button.toggle-dropdown').addEventListener('click', () => {
|
|
||||||
choicesBasic.toggleDropdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelector('button.disable').addEventListener('click', () => {
|
document.querySelector('button.disable').addEventListener('click', () => {
|
||||||
choicesBasic.disable();
|
choicesBasic.disable();
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
<label for="choices-basic">Basic</label>
|
<label for="choices-basic">Basic</label>
|
||||||
<button class="open-dropdown push-bottom">Open dropdown</button>
|
<button class="open-dropdown push-bottom">Open dropdown</button>
|
||||||
<button class="close-dropdown push-bottom">Close dropdown</button>
|
<button class="close-dropdown push-bottom">Close dropdown</button>
|
||||||
<button class="toggle-dropdown push-bottom">Toggle dropdown</button>
|
|
||||||
<button class="disable push-bottom">Disable</button>
|
<button class="disable push-bottom">Disable</button>
|
||||||
<button class="enable push-bottom">Enable</button>
|
<button class="enable push-bottom">Enable</button>
|
||||||
<select class="form-control" name="choices-basic" id="choices-basic">
|
<select class="form-control" name="choices-basic" id="choices-basic">
|
||||||
|
@ -220,10 +219,6 @@
|
||||||
choicesBasic.hideDropdown();
|
choicesBasic.hideDropdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('button.toggle-dropdown').addEventListener('click', () => {
|
|
||||||
choicesBasic.toggleDropdown(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelector('button.disable').addEventListener('click', () => {
|
document.querySelector('button.disable').addEventListener('click', () => {
|
||||||
choicesBasic.disable();
|
choicesBasic.disable();
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,9 +54,9 @@
|
||||||
<input class="form-control" id="choices-input-limit" type="text">
|
<input class="form-control" id="choices-input-limit" type="text">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-test-hook="regex-filter">
|
<div data-test-hook="add-item-filter">
|
||||||
<label for="choices-regex-filter">Regex filter</label>
|
<label for="choices-add-item-filter">Add item filter</label>
|
||||||
<input class="form-control" id="choices-regex-filter" type="text">
|
<input class="form-control" id="choices-add-item-filter" type="text">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-test-hook="adding-items-disabled">
|
<div data-test-hook="adding-items-disabled">
|
||||||
|
@ -64,11 +64,6 @@
|
||||||
<input class="form-control" id="choices-adding-items-disabled" type="text">
|
<input class="form-control" id="choices-adding-items-disabled" type="text">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-test-hook="add-item-callback">
|
|
||||||
<label for="choices-add-item-callback">Callback on Add Item</label>
|
|
||||||
<input class="form-control" id="choices-add-item-callback" type="text">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-test-hook="disabled-via-attr">
|
<div data-test-hook="disabled-via-attr">
|
||||||
<label for="choices-disabled-via-attr">Disabled via attribute</label>
|
<label for="choices-disabled-via-attr">Disabled via attribute</label>
|
||||||
<input class="form-control" id="choices-disabled-via-attr" type="text" disabled>
|
<input class="form-control" id="choices-disabled-via-attr" type="text" disabled>
|
||||||
|
@ -117,20 +112,19 @@
|
||||||
maxItemCount: 5,
|
maxItemCount: 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
new Choices('#choices-regex-filter', {
|
new Choices('#choices-add-item-filter', {
|
||||||
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,}))$/,
|
addItems: true,
|
||||||
|
addItemFilterFn: (value) => {
|
||||||
|
const regex = /^(([^<>()\[\]\\.,;:\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,}))$/
|
||||||
|
const expression = new RegExp(regex.source, 'i');
|
||||||
|
return expression.test(value);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
new Choices('#choices-adding-items-disabled', {
|
new Choices('#choices-adding-items-disabled', {
|
||||||
addItems: false,
|
addItems: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
new Choices('#choices-add-item-callback', {
|
|
||||||
addItemFilter: function (value) {
|
|
||||||
return (value !== 'test')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Choices('#choices-disabled-via-attr');
|
new Choices('#choices-disabled-via-attr');
|
||||||
|
|
||||||
new Choices('#choices-prepend-append', {
|
new Choices('#choices-prepend-append', {
|
||||||
|
|
|
@ -33,12 +33,11 @@ import {
|
||||||
sortByScore,
|
sortByScore,
|
||||||
generateId,
|
generateId,
|
||||||
findAncestorByAttrName,
|
findAncestorByAttrName,
|
||||||
regexFilter,
|
|
||||||
fetchFromObject,
|
fetchFromObject,
|
||||||
isIE11,
|
isIE11,
|
||||||
existsInArray,
|
existsInArray,
|
||||||
cloneObject,
|
cloneObject,
|
||||||
doKeysMatch,
|
diff,
|
||||||
} from './lib/utils';
|
} from './lib/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,8 +63,12 @@ class Choices {
|
||||||
{ arrayMerge: (destinationArray, sourceArray) => [...sourceArray] },
|
{ arrayMerge: (destinationArray, sourceArray) => [...sourceArray] },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!doKeysMatch(this.config, DEFAULT_CONFIG)) {
|
const invalidConfigOptions = diff(this.config, DEFAULT_CONFIG);
|
||||||
console.warn('Unknown config option(s) passed');
|
if (invalidConfigOptions.length) {
|
||||||
|
console.warn(
|
||||||
|
'Unknown config option(s) passed',
|
||||||
|
invalidConfigOptions.join(', '),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) {
|
if (!['auto', 'always'].includes(this.config.renderSelectedChoices)) {
|
||||||
|
@ -375,11 +378,6 @@ class Choices {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDropdown() {
|
|
||||||
this.dropdown.isActive ? this.hideDropdown() : this.showDropdown();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getValue(valueOnly = false) {
|
getValue(valueOnly = false) {
|
||||||
const values = this._store.activeItems.reduce((selectedItems, item) => {
|
const values = this._store.activeItems.reduce((selectedItems, item) => {
|
||||||
const itemValue = valueOnly ? item.value : item;
|
const itemValue = valueOnly ? item.value : item;
|
||||||
|
@ -965,18 +963,6 @@ class Choices {
|
||||||
: this.config.maxItemText;
|
: this.config.maxItemText;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
this.config.regexFilter &&
|
|
||||||
this._isTextElement &&
|
|
||||||
this.config.addItems &&
|
|
||||||
canAddItem
|
|
||||||
) {
|
|
||||||
// If a user has supplied a regular expression filter
|
|
||||||
// determine whether we can update based on whether
|
|
||||||
// our regular expression passes
|
|
||||||
canAddItem = regexFilter(value, this.config.regexFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.config.duplicateItemsAllowed &&
|
!this.config.duplicateItemsAllowed &&
|
||||||
isDuplicateValue &&
|
isDuplicateValue &&
|
||||||
|
@ -989,11 +975,11 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isType('Function', this.config.addItemFilter) &&
|
|
||||||
this.config.addItemFilter(value) &&
|
|
||||||
this._isTextElement &&
|
this._isTextElement &&
|
||||||
this.config.addItems &&
|
this.config.addItems &&
|
||||||
canAddItem
|
canAddItem &&
|
||||||
|
isType('Function', this.config.addItemFilterFn) &&
|
||||||
|
!this.config.addItemFilterFn(value)
|
||||||
) {
|
) {
|
||||||
canAddItem = false;
|
canAddItem = false;
|
||||||
notice = isType('Function', this.config.customAddItemText)
|
notice = isType('Function', this.config.customAddItemText)
|
||||||
|
@ -1202,35 +1188,29 @@ class Choices {
|
||||||
const value = this.input.value;
|
const value = this.input.value;
|
||||||
const activeItems = this._store.activeItems;
|
const activeItems = this._store.activeItems;
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
const { BACK_KEY: backKey, DELETE_KEY: deleteKey } = KEY_CODES;
|
||||||
|
|
||||||
// We are typing into a text input and have a value, we want to show a dropdown
|
// We are typing into a text input and have a value, we want to show a dropdown
|
||||||
// notice. Otherwise hide the dropdown
|
// notice. Otherwise hide the dropdown
|
||||||
if (this._isTextElement) {
|
if (this._isTextElement) {
|
||||||
if (value) {
|
const canShowDropdownNotice = canAddItem.notice && value;
|
||||||
if (canAddItem.notice) {
|
if (canShowDropdownNotice) {
|
||||||
const dropdownItem = this._getTemplate('notice', canAddItem.notice);
|
const dropdownItem = this._getTemplate('notice', canAddItem.notice);
|
||||||
this.dropdown.element.innerHTML = dropdownItem.outerHTML;
|
this.dropdown.element.innerHTML = dropdownItem.outerHTML;
|
||||||
}
|
this.showDropdown(true);
|
||||||
|
|
||||||
if (canAddItem.response === true) {
|
|
||||||
this.showDropdown(true);
|
|
||||||
} else if (!canAddItem.notice) {
|
|
||||||
this.hideDropdown(true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.hideDropdown(true);
|
this.hideDropdown(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const backKey = KEY_CODES.BACK_KEY;
|
const userHasRemovedValue =
|
||||||
const deleteKey = KEY_CODES.DELETE_KEY;
|
(keyCode === backKey || keyCode === deleteKey) && !target.value;
|
||||||
|
const canReactivateChoices = !this._isTextElement && this._isSearching;
|
||||||
|
const canSearch = this._canSearch && canAddItem.response;
|
||||||
|
|
||||||
// If user has removed value...
|
if (userHasRemovedValue && canReactivateChoices) {
|
||||||
if ((keyCode === backKey || keyCode === deleteKey) && !target.value) {
|
this._isSearching = false;
|
||||||
if (!this._isTextElement && this._isSearching) {
|
this._store.dispatch(activateChoices(true));
|
||||||
this._isSearching = false;
|
} else if (canSearch) {
|
||||||
this._store.dispatch(activateChoices(true));
|
|
||||||
}
|
|
||||||
} else if (this._canSearch && canAddItem.response) {
|
|
||||||
this._handleSearch(this.input.value);
|
this._handleSearch(this.input.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1242,12 +1222,13 @@ class Choices {
|
||||||
// If CTRL + A or CMD + A have been pressed and there are items to select
|
// If CTRL + A or CMD + A have been pressed and there are items to select
|
||||||
if (hasCtrlDownKeyPressed && hasItems) {
|
if (hasCtrlDownKeyPressed && hasItems) {
|
||||||
this._canSearch = false;
|
this._canSearch = false;
|
||||||
if (
|
|
||||||
|
const shouldHightlightAll =
|
||||||
this.config.removeItems &&
|
this.config.removeItems &&
|
||||||
!this.input.value &&
|
!this.input.value &&
|
||||||
this.input.element === document.activeElement
|
this.input.element === document.activeElement;
|
||||||
) {
|
|
||||||
// Highlight items
|
if (shouldHightlightAll) {
|
||||||
this.highlightAll();
|
this.highlightAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1255,12 +1236,12 @@ class Choices {
|
||||||
|
|
||||||
_onEnterKey({ event, target, activeItems, hasActiveDropdown }) {
|
_onEnterKey({ event, target, activeItems, hasActiveDropdown }) {
|
||||||
const { ENTER_KEY: enterKey } = KEY_CODES;
|
const { ENTER_KEY: enterKey } = KEY_CODES;
|
||||||
// If enter key is pressed and the input has a value
|
const targetWasButton = target.hasAttribute('data-button');
|
||||||
|
|
||||||
if (this._isTextElement && target.value) {
|
if (this._isTextElement && target.value) {
|
||||||
const value = this.input.value;
|
const value = this.input.value;
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
|
||||||
// All is good, add
|
|
||||||
if (canAddItem.response) {
|
if (canAddItem.response) {
|
||||||
this.hideDropdown(true);
|
this.hideDropdown(true);
|
||||||
this._addItem({ value });
|
this._addItem({ value });
|
||||||
|
@ -1269,28 +1250,26 @@ class Choices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.hasAttribute('data-button')) {
|
if (targetWasButton) {
|
||||||
this._handleButtonAction(activeItems, target);
|
this._handleButtonAction(activeItems, target);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasActiveDropdown) {
|
if (hasActiveDropdown) {
|
||||||
const highlighted = this.dropdown.getChild(
|
const highlightedChoice = this.dropdown.getChild(
|
||||||
`.${this.config.classNames.highlightedState}`,
|
`.${this.config.classNames.highlightedState}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we have a highlighted choice
|
if (highlightedChoice) {
|
||||||
if (highlighted) {
|
|
||||||
// add enter keyCode value
|
// add enter keyCode value
|
||||||
if (activeItems[0]) {
|
if (activeItems[0]) {
|
||||||
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
|
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
this._handleChoiceAction(activeItems, highlighted);
|
this._handleChoiceAction(activeItems, highlightedChoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (this._isSelectOneElement) {
|
} else if (this._isSelectOneElement) {
|
||||||
// Open single select dropdown if it's not active
|
|
||||||
this.showDropdown();
|
this.showDropdown();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
@ -1375,31 +1354,29 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchMove() {
|
_onTouchMove() {
|
||||||
if (this._wasTap === true) {
|
if (this._wasTap) {
|
||||||
this._wasTap = false;
|
this._wasTap = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchEnd(event) {
|
_onTouchEnd(event) {
|
||||||
const target = event.target || event.touches[0].target;
|
const { target } = event || event.touches[0];
|
||||||
|
const touchWasWithinContainer =
|
||||||
|
this._wasTap && this.containerOuter.element.contains(target);
|
||||||
|
|
||||||
// If a user tapped within our container...
|
if (touchWasWithinContainer) {
|
||||||
if (this._wasTap === true && this.containerOuter.element.contains(target)) {
|
const containerWasExactTarget =
|
||||||
// ...and we aren't dealing with a single select box, show dropdown/focus input
|
|
||||||
|
|
||||||
const containerWasTarget =
|
|
||||||
target === this.containerOuter.element ||
|
target === this.containerOuter.element ||
|
||||||
target === this.containerInner.element;
|
target === this.containerInner.element;
|
||||||
|
|
||||||
if (containerWasTarget && !this._isSelectOneElement) {
|
if (containerWasExactTarget) {
|
||||||
if (this._isTextElement) {
|
if (this._isTextElement) {
|
||||||
// If text element, we only want to focus the input
|
|
||||||
this.input.focus();
|
this.input.focus();
|
||||||
} else {
|
} else if (this._isSelectMultipleElement) {
|
||||||
// If a select box, we want to show the dropdown
|
|
||||||
this.showDropdown();
|
this.showDropdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevents focus event firing
|
// Prevents focus event firing
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
@ -1423,7 +1400,6 @@ class Choices {
|
||||||
|
|
||||||
const activeItems = this._store.activeItems;
|
const activeItems = this._store.activeItems;
|
||||||
const hasShiftKey = shiftKey;
|
const hasShiftKey = shiftKey;
|
||||||
|
|
||||||
const buttonTarget = findAncestorByAttrName(target, 'data-button');
|
const buttonTarget = findAncestorByAttrName(target, 'data-button');
|
||||||
const itemTarget = findAncestorByAttrName(target, 'data-item');
|
const itemTarget = findAncestorByAttrName(target, 'data-item');
|
||||||
const choiceTarget = findAncestorByAttrName(target, 'data-choice');
|
const choiceTarget = findAncestorByAttrName(target, 'data-choice');
|
||||||
|
@ -1451,7 +1427,11 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClick({ target }) {
|
_onClick({ target }) {
|
||||||
if (this.containerOuter.element.contains(target)) {
|
const clickWasWithinContainer = this.containerOuter.element.contains(
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (clickWasWithinContainer) {
|
||||||
if (!this.dropdown.isActive && !this.containerOuter.isDisabled) {
|
if (!this.dropdown.isActive && !this.containerOuter.isDisabled) {
|
||||||
if (this._isTextElement) {
|
if (this._isTextElement) {
|
||||||
if (document.activeElement !== this.input.element) {
|
if (document.activeElement !== this.input.element) {
|
||||||
|
@ -1481,7 +1461,11 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onFocus({ target }) {
|
_onFocus({ target }) {
|
||||||
if (!this.containerOuter.element.contains(target)) {
|
const focusWasWithinContainer = this.containerOuter.element.contains(
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!focusWasWithinContainer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1511,11 +1495,9 @@ class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onBlur({ target }) {
|
_onBlur({ target }) {
|
||||||
// If target is something that concerns us
|
const blurWasWithinContainer = this.containerOuter.element.contains(target);
|
||||||
if (
|
|
||||||
this.containerOuter.element.contains(target) &&
|
if (blurWasWithinContainer && !this._isScrollingOnIe) {
|
||||||
!this._isScrollingOnIe
|
|
||||||
) {
|
|
||||||
const activeItems = this._store.activeItems;
|
const activeItems = this._store.activeItems;
|
||||||
const hasHighlightedItems = activeItems.some(item => item.highlighted);
|
const hasHighlightedItems = activeItems.some(item => item.highlighted);
|
||||||
const blurActions = {
|
const blurActions = {
|
||||||
|
|
|
@ -491,50 +491,6 @@ describe('choices', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toggleDropdown', () => {
|
|
||||||
let hideDropdownStub;
|
|
||||||
let showDropdownStub;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
hideDropdownStub = stub();
|
|
||||||
showDropdownStub = stub();
|
|
||||||
|
|
||||||
instance.hideDropdown = hideDropdownStub;
|
|
||||||
instance.showDropdown = showDropdownStub;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
instance.hideDropdown.reset();
|
|
||||||
instance.showDropdown.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dropdown active', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
instance.dropdown.isActive = true;
|
|
||||||
output = instance.toggleDropdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('hides dropdown', () => {
|
|
||||||
expect(hideDropdownStub.called).to.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
returnsInstance(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dropdown inactive', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
instance.dropdown.isActive = false;
|
|
||||||
output = instance.toggleDropdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shows dropdown', () => {
|
|
||||||
expect(showDropdownStub.called).to.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
returnsInstance(output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('highlightItem', () => {
|
describe('highlightItem', () => {
|
||||||
let passedElementTriggerEventStub;
|
let passedElementTriggerEventStub;
|
||||||
let storeDispatchSpy;
|
let storeDispatchSpy;
|
||||||
|
|
|
@ -36,6 +36,7 @@ export const DEFAULT_CONFIG = {
|
||||||
renderChoiceLimit: -1,
|
renderChoiceLimit: -1,
|
||||||
maxItemCount: -1,
|
maxItemCount: -1,
|
||||||
addItems: true,
|
addItems: true,
|
||||||
|
addItemFilterFn: null,
|
||||||
removeItems: true,
|
removeItems: true,
|
||||||
removeItemButton: false,
|
removeItemButton: false,
|
||||||
editItems: false,
|
editItems: false,
|
||||||
|
@ -49,7 +50,6 @@ export const DEFAULT_CONFIG = {
|
||||||
searchFields: ['label', 'value'],
|
searchFields: ['label', 'value'],
|
||||||
position: 'auto',
|
position: 'auto',
|
||||||
resetScrollPosition: true,
|
resetScrollPosition: true,
|
||||||
regexFilter: null,
|
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
shouldSortItems: false,
|
shouldSortItems: false,
|
||||||
sortFn: sortByAlpha,
|
sortFn: sortByAlpha,
|
||||||
|
@ -64,7 +64,7 @@ export const DEFAULT_CONFIG = {
|
||||||
noChoicesText: 'No choices to choose from',
|
noChoicesText: 'No choices to choose from',
|
||||||
itemSelectText: 'Press to select',
|
itemSelectText: 'Press to select',
|
||||||
uniqueItemText: 'Only unique values can be added',
|
uniqueItemText: 'Only unique values can be added',
|
||||||
customAddItemText: 'Only values matching specific conditions can be added.',
|
customAddItemText: 'Only values matching specific conditions can be added',
|
||||||
addItemText: value => `Press Enter to add <b>"${stripHTML(value)}"</b>`,
|
addItemText: value => `Press Enter to add <b>"${stripHTML(value)}"</b>`,
|
||||||
maxItemText: maxItemCount => `Only ${maxItemCount} values can be added`,
|
maxItemText: maxItemCount => `Only ${maxItemCount} values can be added`,
|
||||||
itemComparer: (choice, item) => choice === item,
|
itemComparer: (choice, item) => choice === item,
|
||||||
|
@ -72,7 +72,6 @@ export const DEFAULT_CONFIG = {
|
||||||
includeScore: true,
|
includeScore: true,
|
||||||
},
|
},
|
||||||
callbackOnInit: null,
|
callbackOnInit: null,
|
||||||
addItemFilter: null,
|
|
||||||
callbackOnCreateTemplates: null,
|
callbackOnCreateTemplates: null,
|
||||||
classNames: DEFAULT_CLASSNAMES,
|
classNames: DEFAULT_CLASSNAMES,
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,6 +56,7 @@ describe('constants', () => {
|
||||||
expect(DEFAULT_CONFIG.renderChoiceLimit).to.be.a('number');
|
expect(DEFAULT_CONFIG.renderChoiceLimit).to.be.a('number');
|
||||||
expect(DEFAULT_CONFIG.maxItemCount).to.be.a('number');
|
expect(DEFAULT_CONFIG.maxItemCount).to.be.a('number');
|
||||||
expect(DEFAULT_CONFIG.addItems).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.addItems).to.be.a('boolean');
|
||||||
|
expect(DEFAULT_CONFIG.addItemFilterFn).to.equal(null);
|
||||||
expect(DEFAULT_CONFIG.removeItems).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.removeItems).to.be.a('boolean');
|
||||||
expect(DEFAULT_CONFIG.removeItemButton).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.removeItemButton).to.be.a('boolean');
|
||||||
expect(DEFAULT_CONFIG.editItems).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.editItems).to.be.a('boolean');
|
||||||
|
@ -68,7 +69,6 @@ describe('constants', () => {
|
||||||
expect(DEFAULT_CONFIG.searchResultLimit).to.be.a('number');
|
expect(DEFAULT_CONFIG.searchResultLimit).to.be.a('number');
|
||||||
expect(DEFAULT_CONFIG.searchFields).to.be.an('array');
|
expect(DEFAULT_CONFIG.searchFields).to.be.an('array');
|
||||||
expect(DEFAULT_CONFIG.position).to.be.a('string');
|
expect(DEFAULT_CONFIG.position).to.be.a('string');
|
||||||
expect(DEFAULT_CONFIG.regexFilter).to.equal(null);
|
|
||||||
expect(DEFAULT_CONFIG.shouldSort).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.shouldSort).to.be.a('boolean');
|
||||||
expect(DEFAULT_CONFIG.shouldSortItems).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.shouldSortItems).to.be.a('boolean');
|
||||||
expect(DEFAULT_CONFIG.placeholder).to.be.a('boolean');
|
expect(DEFAULT_CONFIG.placeholder).to.be.a('boolean');
|
||||||
|
@ -86,7 +86,6 @@ describe('constants', () => {
|
||||||
expect(DEFAULT_CONFIG.addItemText).to.be.a('function');
|
expect(DEFAULT_CONFIG.addItemText).to.be.a('function');
|
||||||
expect(DEFAULT_CONFIG.maxItemText).to.be.a('function');
|
expect(DEFAULT_CONFIG.maxItemText).to.be.a('function');
|
||||||
expect(DEFAULT_CONFIG.fuseOptions).to.be.an('object');
|
expect(DEFAULT_CONFIG.fuseOptions).to.be.an('object');
|
||||||
expect(DEFAULT_CONFIG.addItemFilter).to.equal(null);
|
|
||||||
expect(DEFAULT_CONFIG.callbackOnInit).to.equal(null);
|
expect(DEFAULT_CONFIG.callbackOnInit).to.equal(null);
|
||||||
expect(DEFAULT_CONFIG.callbackOnCreateTemplates).to.equal(null);
|
expect(DEFAULT_CONFIG.callbackOnCreateTemplates).to.equal(null);
|
||||||
});
|
});
|
||||||
|
|
|
@ -229,15 +229,6 @@ export const dispatchEvent = (element, type, customArgs = null) => {
|
||||||
return element.dispatchEvent(event);
|
return element.dispatchEvent(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const regexFilter = (value, regex) => {
|
|
||||||
if (!value || !regex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const expression = new RegExp(regex.source, 'i');
|
|
||||||
return expression.test(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getWindowHeight = () => {
|
export const getWindowHeight = () => {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
const html = document.documentElement;
|
const html = document.documentElement;
|
||||||
|
@ -289,8 +280,11 @@ export const existsInArray = (array, value, key = 'value') =>
|
||||||
|
|
||||||
export const cloneObject = obj => JSON.parse(JSON.stringify(obj));
|
export const cloneObject = obj => JSON.parse(JSON.stringify(obj));
|
||||||
|
|
||||||
export const doKeysMatch = (a, b) => {
|
export const diff = (a, b) => {
|
||||||
const aKeys = Object.keys(a).sort();
|
const aKeys = Object.keys(a).sort();
|
||||||
const bKeys = Object.keys(b).sort();
|
const bKeys = Object.keys(b).sort();
|
||||||
return JSON.stringify(aKeys) === JSON.stringify(bKeys);
|
|
||||||
|
return aKeys.filter((i) => {
|
||||||
|
return bKeys.indexOf(i) < 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {
|
||||||
fetchFromObject,
|
fetchFromObject,
|
||||||
existsInArray,
|
existsInArray,
|
||||||
cloneObject,
|
cloneObject,
|
||||||
regexFilter,
|
|
||||||
dispatchEvent,
|
dispatchEvent,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
@ -248,17 +247,6 @@ describe('utils', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('regexFilter', () => {
|
|
||||||
it('tests given regex against given value', () => {
|
|
||||||
// An email address regex
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const regex = /^(([^<>()\[\]\\.,;:\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,}))$/;
|
|
||||||
|
|
||||||
expect(regexFilter('joe@bloggs.com', regex)).to.equal(true);
|
|
||||||
expect(regexFilter('joe bloggs', regex)).to.equal(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('reduceToValues', () => {
|
describe('reduceToValues', () => {
|
||||||
it('reduces an array of objects to an array of values using given key', () => {
|
it('reduces an array of objects to an array of values using given key', () => {
|
||||||
const values = [
|
const values = [
|
||||||
|
|
25
types/index.d.ts
vendored
25
types/index.d.ts
vendored
|
@ -29,6 +29,15 @@ declare namespace Choices {
|
||||||
*/
|
*/
|
||||||
"addItem": CustomEvent;
|
"addItem": CustomEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filter that will need to pass for a user to successfully add an item.
|
||||||
|
*
|
||||||
|
* **Input types affected:** text
|
||||||
|
*
|
||||||
|
* @default null
|
||||||
|
*/
|
||||||
|
addItemFilterFn?: () => any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered each time an item is removed (programmatically or by the user).
|
* Triggered each time an item is removed (programmatically or by the user).
|
||||||
*
|
*
|
||||||
|
@ -405,15 +414,6 @@ declare namespace Choices {
|
||||||
*/
|
*/
|
||||||
resetScrollPosition?: boolean;
|
resetScrollPosition?: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* A filter that will need to pass for a user to successfully add an item.
|
|
||||||
*
|
|
||||||
* **Input types affected:** text
|
|
||||||
*
|
|
||||||
* @default null
|
|
||||||
*/
|
|
||||||
regexFilter?: RegExp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.
|
* Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.
|
||||||
*
|
*
|
||||||
|
@ -764,13 +764,6 @@ export default class Choices {
|
||||||
*/
|
*/
|
||||||
hideDropdown(blurInput?: boolean): this;
|
hideDropdown(blurInput?: boolean): this;
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle dropdown between showing/hidden.
|
|
||||||
*
|
|
||||||
* **Input types affected:** text, select-multiple
|
|
||||||
*/
|
|
||||||
toggleDropdown(): this;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value(s) of input (i.e. inputted items (text) or selected choices (select)). Optionally pass an argument of `true` to only return values rather than value objects.
|
* Get value(s) of input (i.e. inputted items (text) or selected choices (select)). Optionally pass an argument of `true` to only return values rather than value objects.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue