diff --git a/README.md b/README.md index cc48afd..fd027a0 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ will be returned. If you target one element, that instance will be returned. renderChoiceLimit: -1, maxItemCount: -1, addItems: true, - addItemFilterFn: null, + addItemFilter: null, removeItems: true, removeItemButton: false, editItems: false, @@ -370,23 +370,29 @@ Pass an array of objects: **Usage:** Whether the scroll position should reset after adding an item. -### addItemFilterFn +### addItemFilter -**Type:** `Function` **Default:** `null` +**Type:** `string | RegExp | Function` **Default:** `null` **Input types affected:** `text` -**Usage:** A filter function that will need to return `true` for a user to successfully add an item. +**Usage:** A RegExp or string (will be passed to RegExp constructor internally) or 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, { - addItemFilterFn: (value) => { - return (value !== 'test'); + addItemFilter: (value) => { + return ['orange', 'apple', 'banana'].includes(value); }; }); + +// only items ending to `-red` +new Choices(element, { + addItemFilter: '-red$'; +}); + ``` ### shouldSort diff --git a/public/index.html b/public/index.html index 579ebfe..c943526 100644 --- a/public/index.html +++ b/public/index.html @@ -1,590 +1,935 @@ + + + + Choices + + + + + + + + + - - - - Choices - - - - - - - - - + + + - - - + + + - - - + + + + - - - - - - - + - -
-
- -

Choices.js is a lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without - the jQuery dependency.

-

For all config options, visit the GitHub repo.

- -
-

- Interested in writing your own ES6 JavaScript plugins? Check out ES6.io for great tutorials! 💪🏼 + +

+
+ +

+ Choices.js is a lightweight, configurable select box/text input + plugin. Similar to Select2 and Selectize but without the jQuery + dependency. +

+

+ For all config options, visit the + GitHub repo.

-
-

Text inputs

- - +
+

+ Interested in writing your own ES6 JavaScript plugins? Check out + ES6.io for great + tutorials! 💪🏼 +

+
- - +

Text inputs

+ + - - + + - - + + - - + + - - + + - - + + - - + + -
+ + -

Multiple select input

- - +
- - - - - - -

If the following example do not load, the Discogs rate limit has probably been reached. Try again later!

- - - - - - - - -

- -
- -

Single select input

- - - -

If the following two examples do not load, the Discogs rate limit has probably been reached. Try again later!

- - - - - - - - - - - - - - - - - - - - -

Try searching for 'fantastic', "Label 3" should display

- - - -

Try searching for 'fantastic', "Label 3" should display

- - - - - - - - -

Below is an example of how you could have two select inputs depend on eachother. 'Tube stations' will only be enabled if - the value of 'Cities' is 'London'

- - - - - - -
-

Form interaction

-

Change the values and press reset to restore to initial state.

-
- - - - - - -
+ + + + + + +

+ If the following example do not load, the Discogs rate limit has + probably been reached. Try again later! +

+ + + + + + + + +

+ +
+ +

Single select input

+ + + +

+ If the following two examples do not load, the Discogs rate limit + has probably been reached. Try again later! +

+ + + + + + + + + + + + + + + + + + + + +

+ Try searching for 'fantastic', "Label 3" should display +

+ + + +

+ Try searching for 'fantastic', "Label 3" should display +

+ + + + + + + + +

+ Below is an example of how you could have two select inputs depend on + eachother. 'Tube stations' will only be enabled if the value of + 'Cities' is 'London' +

+ + + + + + +
+

Form interaction

+

Change the values and press reset to restore to initial state.

+
+ + + + + + + +
+
-
- - var resetSimple = new Choices(document.getElementById('reset-simple')); - - var resetMultiple = new Choices('#reset-multiple', { - removeItemButton: true, - }); - }); - - - - - - - - + + + + + diff --git a/public/test/text.html b/public/test/text.html index f2e8003..1040403 100644 --- a/public/test/text.html +++ b/public/test/text.html @@ -1,28 +1,58 @@ + + + + Choices + + + + + + + + + - - - - Choices - - - - - - - - - + + + - - - - - - - - + + + + @@ -31,63 +61,76 @@

Text inputs

- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
@@ -114,8 +157,8 @@ 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,}))$/ + addItemFilter: 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); }, @@ -133,13 +176,16 @@ }); new Choices('#choices-prepopulated', { - items: ['Josh Johnson', { - value: 'joe@bloggs.co.uk', - label: 'Joe Bloggs', - customProperties: { - description: 'Joe Blogg is such a generic name', - } - }], + items: [ + 'Josh Johnson', + { + value: 'joe@bloggs.co.uk', + label: 'Joe Bloggs', + customProperties: { + description: 'Joe Blogg is such a generic name', + }, + }, + ], }); new Choices('#choices-placeholder', { @@ -151,4 +197,4 @@ }); - + diff --git a/src/scripts/choices.js b/src/scripts/choices.js index e09e346..5eee61b 100644 --- a/src/scripts/choices.js +++ b/src/scripts/choices.js @@ -79,6 +79,18 @@ class Choices { { arrayMerge: (destinationArray, sourceArray) => [...sourceArray] }, ); + // Convert addItemFilter to function + if ( + userConfig.addItemFilter && + typeof userConfig.addItemFilter !== 'function' + ) { + const re = + userConfig.addItemFilter instanceof RegExp + ? userConfig.addItemFilter + : new RegExp(userConfig.addItemFilter); + this.config.addItemFilter = re.test.bind(re); + } + const invalidConfigOptions = diff(this.config, DEFAULT_CONFIG); if (invalidConfigOptions.length) { console.warn( @@ -1026,13 +1038,14 @@ class Choices { this._isTextElement && this.config.addItems && canAddItem && - isType('Function', this.config.addItemFilterFn) && - !this.config.addItemFilterFn(value) + typeof this.config.addItemFilter === 'function' && + !this.config.addItemFilter(value) ) { canAddItem = false; - notice = isType('Function', this.config.customAddItemText) - ? this.config.customAddItemText(value) - : this.config.customAddItemText; + notice = + typeof this.config.customAddItemText === 'function' + ? this.config.customAddItemText(value) + : this.config.customAddItemText; } } diff --git a/src/scripts/constants.js b/src/scripts/constants.js index dd8192c..4699361 100644 --- a/src/scripts/constants.js +++ b/src/scripts/constants.js @@ -35,7 +35,7 @@ export const DEFAULT_CONFIG = { renderChoiceLimit: -1, maxItemCount: -1, addItems: true, - addItemFilterFn: null, + addItemFilter: null, removeItems: true, removeItemButton: false, editItems: false, diff --git a/src/scripts/constants.test.js b/src/scripts/constants.test.js index 9061f20..1accbcd 100644 --- a/src/scripts/constants.test.js +++ b/src/scripts/constants.test.js @@ -55,7 +55,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.addItemFilter).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'); diff --git a/types/index.d.ts b/types/index.d.ts index 478c429..d992528 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -18,6 +18,7 @@ declare namespace Choices { type stringFunction = () => string; type noticeStringFunction = (value: string) => string; type noticeLimitFunction = (maxItemCount: number) => string; + type filterFunction = (value: string) => boolean; } interface Choice { @@ -403,7 +404,7 @@ declare namespace Choices { * * @default null */ - addItemFilterFn: (value: string) => boolean; + addItemFilter: string | RegExp | Choices.Types.filterFunction; /** * The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.