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:
Josh Johnson 2019-02-12 18:35:46 +00:00 committed by GitHub
parent 55b356ec69
commit 8540d5aabd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 129 additions and 335 deletions

View file

@ -78,6 +78,7 @@ will be returned. If you target one element, that instance will be returned.
renderChoiceLimit: -1,
maxItemCount: -1,
addItems: true,
addItemFilterFn: null,
removeItems: true,
removeItemButton: false,
editItems: false,
@ -91,8 +92,6 @@ will be returned. If you target one element, that instance will be returned.
searchFields: ['label', 'value'],
position: 'auto',
resetScrollPosition: true,
regexFilter: null,
addItemFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFn: () => {...},
@ -340,31 +339,24 @@ Pass an array of objects:
**Usage:** Whether the scroll position should reset after adding an item.
### addItemFilter
### addItemFilterFn
**Type:** `Function` **Default:** `null`
**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:**
```js
// Only adds items matching the text test
new Choices(element, {
addItemFilter: function (value) {
return (value !== 'test')
}
addItemFilterFn: (value) => {
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
**Type:** `Boolean` **Default:** `true`
@ -752,12 +744,6 @@ choices.disable();
**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);
**Input types affected:** `select-one`, `select-multiple`

View file

@ -216,7 +216,7 @@ describe('Choices - select multiple', () => {
@todo Investigate why
*/
describe.skip('interacting with dropdown', () => {
describe('interacting with dropdown', () => {
describe('opening dropdown', () => {
it('opens dropdown', () => {
cy.get('[data-test-hook=basic]')
@ -247,44 +247,6 @@ describe('Choices - select multiple', () => {
.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', () => {

View file

@ -134,7 +134,7 @@ describe('Choices - select one', () => {
@todo Investigate why
*/
describe.skip('interacting with dropdown', () => {
describe('interacting with dropdown', () => {
describe('opening dropdown', () => {
it('opens dropdown', () => {
cy.get('[data-test-hook=basic]')
@ -165,44 +165,6 @@ describe('Choices - select one', () => {
.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', () => {

View file

@ -197,8 +197,9 @@ describe('Choices - text element', () => {
});
describe('input limit', () => {
const inputLimit = 5;
beforeEach(() => {
for (let index = 0; index < 6; index++) {
for (let index = 0; index < inputLimit + 1; index++) {
cy.get('[data-test-hook=input-limit]')
.find('.choices__input--cloned')
.type(`${textInput} + ${index}`)
@ -212,29 +213,36 @@ describe('Choices - text element', () => {
.first()
.children()
.should($items => {
expect($items.length).to.equal(5);
expect($items.length).to.equal(inputLimit);
});
});
it('hides dropdown prompt once limit has been reached', () => {
cy.wait(500); // allow for animation frame
cy.get('[data-test-hook=input-limit]')
.find('.choices__list--dropdown')
.should('not.be.visible');
describe('reaching input limit', () => {
it('displays dropdown prompt', () => {
cy.get('[data-test-hook=input-limit]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Only ${inputLimit} values can be added`,
);
});
});
});
});
describe('regex filter', () => {
describe('inputting a value that satisfies the regex', () => {
describe('add item filter', () => {
describe('inputting a value that satisfies the filter', () => {
const input = 'joe@bloggs.com';
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')
.type(input)
.type('{enter}');
cy.get('[data-test-hook=regex-filter]')
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
@ -245,14 +253,20 @@ describe('Choices - text element', () => {
describe('inputting a value that does not satisfy the regex', () => {
it('displays dropdown prompt', () => {
cy.get('[data-test-hook=regex-filter]')
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__input--cloned')
.type(`this is not an email address`)
.type('{enter}');
cy.get('[data-test-hook=regex-filter]')
cy.get('[data-test-hook=add-item-filter]')
.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', () => {
it('does not allow me to input data', () => {
cy.get('[data-test-hook=disabled-via-attr]')

View file

@ -344,7 +344,15 @@
var textEmailFilter = new Choices('#choices-text-email-filter', {
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']);
var textDisabled = new Choices('#choices-text-disabled', {

View file

@ -33,7 +33,6 @@
<label for="choices-basic">Basic</label>
<button class="open-dropdown push-bottom">Open 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="enable push-bottom">Enable</button>
<select class="form-control" name="choices-basic" id="choices-basic" multiple>
@ -216,10 +215,6 @@
choicesBasic.hideDropdown();
});
document.querySelector('button.toggle-dropdown').addEventListener('click', () => {
choicesBasic.toggleDropdown();
});
document.querySelector('button.disable').addEventListener('click', () => {
choicesBasic.disable();
});

View file

@ -33,7 +33,6 @@
<label for="choices-basic">Basic</label>
<button class="open-dropdown push-bottom">Open 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="enable push-bottom">Enable</button>
<select class="form-control" name="choices-basic" id="choices-basic">
@ -220,10 +219,6 @@
choicesBasic.hideDropdown();
});
document.querySelector('button.toggle-dropdown').addEventListener('click', () => {
choicesBasic.toggleDropdown(true);
});
document.querySelector('button.disable').addEventListener('click', () => {
choicesBasic.disable();
});

View file

@ -54,9 +54,9 @@
<input class="form-control" id="choices-input-limit" type="text">
</div>
<div data-test-hook="regex-filter">
<label for="choices-regex-filter">Regex filter</label>
<input class="form-control" id="choices-regex-filter" type="text">
<div data-test-hook="add-item-filter">
<label for="choices-add-item-filter">Add item filter</label>
<input class="form-control" id="choices-add-item-filter" type="text">
</div>
<div data-test-hook="adding-items-disabled">
@ -64,11 +64,6 @@
<input class="form-control" id="choices-adding-items-disabled" type="text">
</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">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<input class="form-control" id="choices-disabled-via-attr" type="text" disabled>
@ -117,20 +112,19 @@
maxItemCount: 5,
});
new Choices('#choices-regex-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,}))$/,
new Choices('#choices-add-item-filter', {
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', {
addItems: false,
});
new Choices('#choices-add-item-callback', {
addItemFilter: function (value) {
return (value !== 'test')
}
});
new Choices('#choices-disabled-via-attr');
new Choices('#choices-prepend-append', {

View file

@ -33,12 +33,11 @@ import {
sortByScore,
generateId,
findAncestorByAttrName,
regexFilter,
fetchFromObject,
isIE11,
existsInArray,
cloneObject,
doKeysMatch,
diff,
} from './lib/utils';
/**
@ -64,8 +63,12 @@ class Choices {
{ arrayMerge: (destinationArray, sourceArray) => [...sourceArray] },
);
if (!doKeysMatch(this.config, DEFAULT_CONFIG)) {
console.warn('Unknown config option(s) passed');
const 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)) {
@ -375,11 +378,6 @@ class Choices {
return this;
}
toggleDropdown() {
this.dropdown.isActive ? this.hideDropdown() : this.showDropdown();
return this;
}
getValue(valueOnly = false) {
const values = this._store.activeItems.reduce((selectedItems, item) => {
const itemValue = valueOnly ? item.value : item;
@ -965,18 +963,6 @@ class Choices {
: 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 (
!this.config.duplicateItemsAllowed &&
isDuplicateValue &&
@ -989,11 +975,11 @@ class Choices {
}
if (
isType('Function', this.config.addItemFilter) &&
this.config.addItemFilter(value) &&
this._isTextElement &&
this.config.addItems &&
canAddItem
canAddItem &&
isType('Function', this.config.addItemFilterFn) &&
!this.config.addItemFilterFn(value)
) {
canAddItem = false;
notice = isType('Function', this.config.customAddItemText)
@ -1202,35 +1188,29 @@ class Choices {
const value = this.input.value;
const activeItems = this._store.activeItems;
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
// notice. Otherwise hide the dropdown
if (this._isTextElement) {
if (value) {
if (canAddItem.notice) {
const dropdownItem = this._getTemplate('notice', canAddItem.notice);
this.dropdown.element.innerHTML = dropdownItem.outerHTML;
}
if (canAddItem.response === true) {
this.showDropdown(true);
} else if (!canAddItem.notice) {
this.hideDropdown(true);
}
const canShowDropdownNotice = canAddItem.notice && value;
if (canShowDropdownNotice) {
const dropdownItem = this._getTemplate('notice', canAddItem.notice);
this.dropdown.element.innerHTML = dropdownItem.outerHTML;
this.showDropdown(true);
} else {
this.hideDropdown(true);
}
} else {
const backKey = KEY_CODES.BACK_KEY;
const deleteKey = KEY_CODES.DELETE_KEY;
const userHasRemovedValue =
(keyCode === backKey || keyCode === deleteKey) && !target.value;
const canReactivateChoices = !this._isTextElement && this._isSearching;
const canSearch = this._canSearch && canAddItem.response;
// If user has removed value...
if ((keyCode === backKey || keyCode === deleteKey) && !target.value) {
if (!this._isTextElement && this._isSearching) {
this._isSearching = false;
this._store.dispatch(activateChoices(true));
}
} else if (this._canSearch && canAddItem.response) {
if (userHasRemovedValue && canReactivateChoices) {
this._isSearching = false;
this._store.dispatch(activateChoices(true));
} else if (canSearch) {
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 (hasCtrlDownKeyPressed && hasItems) {
this._canSearch = false;
if (
const shouldHightlightAll =
this.config.removeItems &&
!this.input.value &&
this.input.element === document.activeElement
) {
// Highlight items
this.input.element === document.activeElement;
if (shouldHightlightAll) {
this.highlightAll();
}
}
@ -1255,12 +1236,12 @@ class Choices {
_onEnterKey({ event, target, activeItems, hasActiveDropdown }) {
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) {
const value = this.input.value;
const canAddItem = this._canAddItem(activeItems, value);
// All is good, add
if (canAddItem.response) {
this.hideDropdown(true);
this._addItem({ value });
@ -1269,28 +1250,26 @@ class Choices {
}
}
if (target.hasAttribute('data-button')) {
if (targetWasButton) {
this._handleButtonAction(activeItems, target);
event.preventDefault();
}
if (hasActiveDropdown) {
const highlighted = this.dropdown.getChild(
const highlightedChoice = this.dropdown.getChild(
`.${this.config.classNames.highlightedState}`,
);
// If we have a highlighted choice
if (highlighted) {
if (highlightedChoice) {
// add enter keyCode value
if (activeItems[0]) {
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
}
this._handleChoiceAction(activeItems, highlighted);
this._handleChoiceAction(activeItems, highlightedChoice);
}
event.preventDefault();
} else if (this._isSelectOneElement) {
// Open single select dropdown if it's not active
this.showDropdown();
event.preventDefault();
}
@ -1375,31 +1354,29 @@ class Choices {
}
_onTouchMove() {
if (this._wasTap === true) {
if (this._wasTap) {
this._wasTap = false;
}
}
_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 (this._wasTap === true && this.containerOuter.element.contains(target)) {
// ...and we aren't dealing with a single select box, show dropdown/focus input
const containerWasTarget =
if (touchWasWithinContainer) {
const containerWasExactTarget =
target === this.containerOuter.element ||
target === this.containerInner.element;
if (containerWasTarget && !this._isSelectOneElement) {
if (containerWasExactTarget) {
if (this._isTextElement) {
// If text element, we only want to focus the input
this.input.focus();
} else {
// If a select box, we want to show the dropdown
} else if (this._isSelectMultipleElement) {
this.showDropdown();
}
}
// Prevents focus event firing
event.stopPropagation();
}
@ -1423,7 +1400,6 @@ class Choices {
const activeItems = this._store.activeItems;
const hasShiftKey = shiftKey;
const buttonTarget = findAncestorByAttrName(target, 'data-button');
const itemTarget = findAncestorByAttrName(target, 'data-item');
const choiceTarget = findAncestorByAttrName(target, 'data-choice');
@ -1451,7 +1427,11 @@ class Choices {
}
_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._isTextElement) {
if (document.activeElement !== this.input.element) {
@ -1481,7 +1461,11 @@ class Choices {
}
_onFocus({ target }) {
if (!this.containerOuter.element.contains(target)) {
const focusWasWithinContainer = this.containerOuter.element.contains(
target,
);
if (!focusWasWithinContainer) {
return;
}
@ -1511,11 +1495,9 @@ class Choices {
}
_onBlur({ target }) {
// If target is something that concerns us
if (
this.containerOuter.element.contains(target) &&
!this._isScrollingOnIe
) {
const blurWasWithinContainer = this.containerOuter.element.contains(target);
if (blurWasWithinContainer && !this._isScrollingOnIe) {
const activeItems = this._store.activeItems;
const hasHighlightedItems = activeItems.some(item => item.highlighted);
const blurActions = {

View file

@ -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', () => {
let passedElementTriggerEventStub;
let storeDispatchSpy;

View file

@ -36,6 +36,7 @@ export const DEFAULT_CONFIG = {
renderChoiceLimit: -1,
maxItemCount: -1,
addItems: true,
addItemFilterFn: null,
removeItems: true,
removeItemButton: false,
editItems: false,
@ -49,7 +50,6 @@ export const DEFAULT_CONFIG = {
searchFields: ['label', 'value'],
position: 'auto',
resetScrollPosition: true,
regexFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFn: sortByAlpha,
@ -64,7 +64,7 @@ export const DEFAULT_CONFIG = {
noChoicesText: 'No choices to choose from',
itemSelectText: 'Press to select',
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>`,
maxItemText: maxItemCount => `Only ${maxItemCount} values can be added`,
itemComparer: (choice, item) => choice === item,
@ -72,7 +72,6 @@ export const DEFAULT_CONFIG = {
includeScore: true,
},
callbackOnInit: null,
addItemFilter: null,
callbackOnCreateTemplates: null,
classNames: DEFAULT_CLASSNAMES,
};

View file

@ -56,6 +56,7 @@ describe('constants', () => {
expect(DEFAULT_CONFIG.renderChoiceLimit).to.be.a('number');
expect(DEFAULT_CONFIG.maxItemCount).to.be.a('number');
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.removeItemButton).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.searchFields).to.be.an('array');
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.shouldSortItems).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.maxItemText).to.be.a('function');
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.callbackOnCreateTemplates).to.equal(null);
});

View file

@ -229,15 +229,6 @@ export const dispatchEvent = (element, type, customArgs = null) => {
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 = () => {
const body = document.body;
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 doKeysMatch = (a, b) => {
export const diff = (a, b) => {
const aKeys = Object.keys(a).sort();
const bKeys = Object.keys(b).sort();
return JSON.stringify(aKeys) === JSON.stringify(bKeys);
return aKeys.filter((i) => {
return bKeys.indexOf(i) < 0;
});
}

View file

@ -14,7 +14,6 @@ import {
fetchFromObject,
existsInArray,
cloneObject,
regexFilter,
dispatchEvent,
} 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', () => {
it('reduces an array of objects to an array of values using given key', () => {
const values = [

25
types/index.d.ts vendored
View file

@ -29,6 +29,15 @@ declare namespace Choices {
*/
"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).
*
@ -405,15 +414,6 @@ declare namespace Choices {
*/
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.
*
@ -764,13 +764,6 @@ export default class Choices {
*/
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.
*