mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-10 09:36:35 +02:00
Add option to remove search filter choices but emit the search event.
This commit is contained in:
parent
c1327c9f55
commit
7ec1e5310c
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
tests/reports
|
tests/reports
|
||||||
|
|
50
README.md
50
README.md
|
@ -3,7 +3,7 @@ A vanilla, lightweight (~15kb gzipped 🎉), configurable select box/text input
|
||||||
|
|
||||||
[Demo](https://joshuajohnson.co.uk/Choices/)
|
[Demo](https://joshuajohnson.co.uk/Choices/)
|
||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
* Lightweight
|
* Lightweight
|
||||||
* No jQuery dependency
|
* No jQuery dependency
|
||||||
* Configurable sorting
|
* Configurable sorting
|
||||||
|
@ -14,7 +14,7 @@ A vanilla, lightweight (~15kb gzipped 🎉), configurable select box/text input
|
||||||
* Custom templates
|
* Custom templates
|
||||||
|
|
||||||
----
|
----
|
||||||
### Interested in writing your own ES6 JavaScript plugins? Check out [ES6.io](https://ES6.io/friend/JOHNSON) for great tutorials! 💪🏼
|
### Interested in writing your own ES6 JavaScript plugins? Check out [ES6.io](https://ES6.io/friend/JOHNSON) for great tutorials! 💪🏼
|
||||||
----
|
----
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
@ -43,17 +43,17 @@ Or include Choices directly:
|
||||||
```js
|
```js
|
||||||
// Pass multiple elements:
|
// Pass multiple elements:
|
||||||
const choices = new Choices(elements);
|
const choices = new Choices(elements);
|
||||||
|
|
||||||
// Pass single element:
|
// Pass single element:
|
||||||
const choices = new Choices(element);
|
const choices = new Choices(element);
|
||||||
|
|
||||||
// Pass reference
|
// Pass reference
|
||||||
const choices = new Choices('[data-trigger']);
|
const choices = new Choices('[data-trigger']);
|
||||||
const choices = new Choices('.js-choice');
|
const choices = new Choices('.js-choice');
|
||||||
|
|
||||||
// Pass jQuery element
|
// Pass jQuery element
|
||||||
const choices = new Choices($('.js-choice')[0]);
|
const choices = new Choices($('.js-choice')[0]);
|
||||||
|
|
||||||
// Passing options (with default options)
|
// Passing options (with default options)
|
||||||
const choices = new Choices(elements, {
|
const choices = new Choices(elements, {
|
||||||
items: [],
|
items: [],
|
||||||
|
@ -67,6 +67,7 @@ Or include Choices directly:
|
||||||
delimiter: ',',
|
delimiter: ',',
|
||||||
paste: true,
|
paste: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchChoices: true,
|
||||||
searchFloor: 1,
|
searchFloor: 1,
|
||||||
position: 'auto',
|
position: 'auto',
|
||||||
resetScrollPosition: true,
|
resetScrollPosition: true,
|
||||||
|
@ -137,23 +138,23 @@ Or include Choices directly:
|
||||||
|
|
||||||
**Input types affected:** `text`
|
**Input types affected:** `text`
|
||||||
|
|
||||||
**Usage:** Add pre-selected items (see terminology) to text input.
|
**Usage:** Add pre-selected items (see terminology) to text input.
|
||||||
|
|
||||||
Pass an array of strings:
|
Pass an array of strings:
|
||||||
|
|
||||||
`['value 1', 'value 2', 'value 3']`
|
`['value 1', 'value 2', 'value 3']`
|
||||||
|
|
||||||
Pass an array of objects:
|
Pass an array of objects:
|
||||||
|
|
||||||
```
|
```
|
||||||
[{
|
[{
|
||||||
value: 'Value 1',
|
value: 'Value 1',
|
||||||
label: 'Label 1',
|
label: 'Label 1',
|
||||||
id: 1
|
id: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'Value 2',
|
value: 'Value 2',
|
||||||
label: 'Label 2',
|
label: 'Label 2',
|
||||||
id: 2
|
id: 2
|
||||||
}]
|
}]
|
||||||
```
|
```
|
||||||
|
@ -163,7 +164,7 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Input types affected:** `select-one`, `select-multiple`
|
**Input types affected:** `select-one`, `select-multiple`
|
||||||
|
|
||||||
**Usage:** Add choices (see terminology) to select input.
|
**Usage:** Add choices (see terminology) to select input.
|
||||||
|
|
||||||
Pass an array of objects:
|
Pass an array of objects:
|
||||||
|
|
||||||
|
@ -245,6 +246,13 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Usage:** Whether a user should be allowed to search avaiable choices. Note that multiple select boxes will always show search inputs.
|
**Usage:** Whether a user should be allowed to search avaiable choices. Note that multiple select boxes will always show search inputs.
|
||||||
|
|
||||||
|
### searchChoices
|
||||||
|
**Type:** `Boolean` **Default:** `true`
|
||||||
|
|
||||||
|
**Input types affected:** `select-one`
|
||||||
|
|
||||||
|
**Usage:** Whether the plugin should filter the choices by input or not. If `false` the search event will be emited.
|
||||||
|
|
||||||
### searchFloor
|
### searchFloor
|
||||||
**Type:** `Number` **Default:** `1`
|
**Type:** `Number` **Default:** `1`
|
||||||
|
|
||||||
|
@ -257,7 +265,7 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Input types affected:** `select-one`, `select-multiple`
|
**Input types affected:** `select-one`, `select-multiple`
|
||||||
|
|
||||||
**Usage:** Whether the dropdown should appear above (`top`) or below (`bottom`) the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.
|
**Usage:** Whether the dropdown should appear above (`top`) or below (`bottom`) the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.
|
||||||
|
|
||||||
### resetScrollPosition
|
### resetScrollPosition
|
||||||
**Type:** `Boolean` **Default:** `true`
|
**Type:** `Boolean` **Default:** `true`
|
||||||
|
@ -278,7 +286,7 @@ Pass an array of objects:
|
||||||
|
|
||||||
**Input types affected:** `select-one`, `select-multiple`
|
**Input types affected:** `select-one`, `select-multiple`
|
||||||
|
|
||||||
**Usage:** Whether choices should be sorted. If false, choices will appear in the order they were given.
|
**Usage:** Whether choices should be sorted. If false, choices will appear in the order they were given.
|
||||||
|
|
||||||
### sortFilter
|
### sortFilter
|
||||||
**Type:** `Function` **Default:** sortByAlpha
|
**Type:** `Function` **Default:** sortByAlpha
|
||||||
|
@ -303,7 +311,7 @@ const example = new Choices(element, {
|
||||||
|
|
||||||
**Input types affected:**`select-one`, `select-multiple`
|
**Input types affected:**`select-one`, `select-multiple`
|
||||||
|
|
||||||
**Usage:** Specify which fields should be used for sorting when a user is searching. If a user is not searching and sorting is enabled, only the choice's label will be sorted.
|
**Usage:** Specify which fields should be used for sorting when a user is searching. If a user is not searching and sorting is enabled, only the choice's label will be sorted.
|
||||||
|
|
||||||
### placeholder
|
### placeholder
|
||||||
**Type:** `Boolean` **Default:** `true`
|
**Type:** `Boolean` **Default:** `true`
|
||||||
|
@ -454,7 +462,7 @@ const example = new Choices(element, {
|
||||||
```
|
```
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
**Note:** Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object.
|
**Note:** Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
|
@ -470,7 +478,7 @@ element.addEventListener('addItem', function(event) {
|
||||||
console.log(event.detail.groupValue);
|
console.log(event.detail.groupValue);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
// or
|
// or
|
||||||
const example = new Choices(document.getElementById('example'));
|
const example = new Choices(document.getElementById('example'));
|
||||||
|
|
||||||
example.passedElement.addEventListener('addItem', function(event) {
|
example.passedElement.addEventListener('addItem', function(event) {
|
||||||
|
@ -570,7 +578,7 @@ choices.disable();
|
||||||
|
|
||||||
**Usage:** Creates a new instance of Choices, adds event listeners, creates templates and renders a Choices element to the DOM.
|
**Usage:** Creates a new instance of Choices, adds event listeners, creates templates and renders a Choices element to the DOM.
|
||||||
|
|
||||||
**Note:** This is called implicitly when a new instance of Choices is created. This would be used after a Choices instance had already been destroyed (using `destroy()`).
|
**Note:** This is called implicitly when a new instance of Choices is created. This would be used after a Choices instance had already been destroyed (using `destroy()`).
|
||||||
|
|
||||||
### highlightAll();
|
### highlightAll();
|
||||||
**Input types affected:** `text`, `select-multiple`
|
**Input types affected:** `text`, `select-multiple`
|
||||||
|
@ -650,7 +658,7 @@ example.setChoices([{
|
||||||
{value: 'Child Two', label: 'Child Two', disabled: true},
|
{value: 'Child Two', label: 'Child Two', disabled: true},
|
||||||
{value: 'Child Three', label: 'Child Three'},
|
{value: 'Child Three', label: 'Child Three'},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Group two',
|
label: 'Group two',
|
||||||
id: 2,
|
id: 2,
|
||||||
|
@ -800,7 +808,7 @@ To setup a local environment: clone this repo, navigate into it's directory in a
|
||||||
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using npm scripts...bla bla bla
|
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using npm scripts...bla bla bla
|
||||||
|
|
||||||
## License
|
## License
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
Thanks to [@mikefrancis](https://github.com/mikefrancis/) for [sending me on a hunt](https://twitter.com/_mikefrancis/status/701797835826667520) for a non-jQuery solution for select boxes that eventually led to this being built!
|
Thanks to [@mikefrancis](https://github.com/mikefrancis/) for [sending me on a hunt](https://twitter.com/_mikefrancis/status/701797835826667520) for a non-jQuery solution for select boxes that eventually led to this being built!
|
||||||
|
|
19
assets/scripts/dist/choices.js
vendored
19
assets/scripts/dist/choices.js
vendored
|
@ -124,6 +124,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
delimiter: ',',
|
delimiter: ',',
|
||||||
paste: true,
|
paste: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchChoices: true,
|
||||||
searchFloor: 1,
|
searchFloor: 1,
|
||||||
position: 'auto',
|
position: 'auto',
|
||||||
resetScrollPosition: true,
|
resetScrollPosition: true,
|
||||||
|
@ -1045,6 +1046,9 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
this.input.removeAttribute('disabled');
|
this.input.removeAttribute('disabled');
|
||||||
this.containerOuter.classList.remove(this.config.classNames.disabledState);
|
this.containerOuter.classList.remove(this.config.classNames.disabledState);
|
||||||
this.containerOuter.removeAttribute('aria-disabled');
|
this.containerOuter.removeAttribute('aria-disabled');
|
||||||
|
if (this.passedElement.type === 'select-one') {
|
||||||
|
this.containerOuter.setAttribute('tabindex', '0');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1066,6 +1070,9 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
this.input.setAttribute('disabled', '');
|
this.input.setAttribute('disabled', '');
|
||||||
this.containerOuter.classList.add(this.config.classNames.disabledState);
|
this.containerOuter.classList.add(this.config.classNames.disabledState);
|
||||||
this.containerOuter.setAttribute('aria-disabled', 'true');
|
this.containerOuter.setAttribute('aria-disabled', 'true');
|
||||||
|
if (this.passedElement.type === 'select-one') {
|
||||||
|
this.containerOuter.setAttribute('tabindex', '-1');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1434,8 +1441,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
if (this.input === document.activeElement) {
|
if (this.input === document.activeElement) {
|
||||||
// Check that we have a value to search and the input was an alphanumeric character
|
// Check that we have a value to search and the input was an alphanumeric character
|
||||||
if (value && value.length > this.config.searchFloor) {
|
if (value && value.length > this.config.searchFloor) {
|
||||||
// Filter available choices
|
// Check flag to filter search input
|
||||||
this._searchChoices(value);
|
if (this.config.searchChoices) {
|
||||||
|
// Filter available choices
|
||||||
|
this._searchChoices(value);
|
||||||
|
}
|
||||||
// Trigger search event
|
// Trigger search event
|
||||||
(0, _utils.triggerEvent)(this.passedElement, 'search', {
|
(0, _utils.triggerEvent)(this.passedElement, 'search', {
|
||||||
value: value
|
value: value
|
||||||
|
@ -2679,10 +2689,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
* @param {!Object<string, *>} options
|
* @param {!Object<string, *>} options
|
||||||
*/
|
*/
|
||||||
function Fuse (list, options) {
|
function Fuse (list, options) {
|
||||||
var i
|
|
||||||
var len
|
|
||||||
var key
|
var key
|
||||||
var keys
|
|
||||||
|
|
||||||
this.list = list
|
this.list = list
|
||||||
this.options = options = options || {}
|
this.options = options = options || {}
|
||||||
|
@ -2701,7 +2708,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Fuse.VERSION = '2.6.0'
|
Fuse.VERSION = '2.6.2'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new list for Fuse to match against.
|
* Sets a new list for Fuse to match against.
|
||||||
|
|
2
assets/scripts/dist/choices.js.map
vendored
2
assets/scripts/dist/choices.js.map
vendored
File diff suppressed because one or more lines are too long
4
assets/scripts/dist/choices.min.js
vendored
4
assets/scripts/dist/choices.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -60,6 +60,7 @@ class Choices {
|
||||||
delimiter: ',',
|
delimiter: ',',
|
||||||
paste: true,
|
paste: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchChoices: true,
|
||||||
searchFloor: 1,
|
searchFloor: 1,
|
||||||
position: 'auto',
|
position: 'auto',
|
||||||
resetScrollPosition: true,
|
resetScrollPosition: true,
|
||||||
|
@ -1225,8 +1226,11 @@ class Choices {
|
||||||
if (this.input === document.activeElement) {
|
if (this.input === document.activeElement) {
|
||||||
// Check that we have a value to search and the input was an alphanumeric character
|
// Check that we have a value to search and the input was an alphanumeric character
|
||||||
if (value && value.length > this.config.searchFloor) {
|
if (value && value.length > this.config.searchFloor) {
|
||||||
// Filter available choices
|
// Check flag to filter search input
|
||||||
this._searchChoices(value);
|
if (this.config.searchChoices) {
|
||||||
|
// Filter available choices
|
||||||
|
this._searchChoices(value);
|
||||||
|
}
|
||||||
// Trigger search event
|
// Trigger search event
|
||||||
triggerEvent(this.passedElement, 'search', {
|
triggerEvent(this.passedElement, 'search', {
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -389,7 +389,7 @@ describe('Choices', () => {
|
||||||
it('should trigger showDropdown on dropdown opening', function() {
|
it('should trigger showDropdown on dropdown opening', function() {
|
||||||
this.choices = new Choices(this.input);
|
this.choices = new Choices(this.input);
|
||||||
const container = this.choices.containerOuter;
|
const container = this.choices.containerOuter;
|
||||||
|
|
||||||
const showDropdownSpy = jasmine.createSpy('showDropdownSpy');
|
const showDropdownSpy = jasmine.createSpy('showDropdownSpy');
|
||||||
const passedElement = this.choices.passedElement;
|
const passedElement = this.choices.passedElement;
|
||||||
|
|
||||||
|
@ -406,10 +406,10 @@ describe('Choices', () => {
|
||||||
expect(showDropdownSpy).toHaveBeenCalled();
|
expect(showDropdownSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger hideDropdown on dropdown closing', function() {
|
it('should trigger hideDropdown on dropdown closing', function() {
|
||||||
this.choices = new Choices(this.input);
|
this.choices = new Choices(this.input);
|
||||||
const container = this.choices.containerOuter;
|
const container = this.choices.containerOuter;
|
||||||
|
|
||||||
const hideDropdownSpy = jasmine.createSpy('hideDropdownSpy');
|
const hideDropdownSpy = jasmine.createSpy('hideDropdownSpy');
|
||||||
const passedElement = this.choices.passedElement;
|
const passedElement = this.choices.passedElement;
|
||||||
|
|
||||||
|
@ -441,7 +441,7 @@ it('should trigger hideDropdown on dropdown closing', function() {
|
||||||
passedElement.addEventListener('search', searchSpy);
|
passedElement.addEventListener('search', searchSpy);
|
||||||
|
|
||||||
this.choices.input.focus();
|
this.choices.input.focus();
|
||||||
this.choices.input.value = 'Value 3';
|
this.choices.input.value = '3 ';
|
||||||
|
|
||||||
// Key down to search
|
// Key down to search
|
||||||
this.choices._onKeyUp({
|
this.choices._onKeyUp({
|
||||||
|
@ -450,9 +450,41 @@ it('should trigger hideDropdown on dropdown closing', function() {
|
||||||
ctrlKey: false
|
ctrlKey: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const mostAccurateResult = this.choices.currentState.choices[0];
|
const mostAccurateResult = this.choices.currentState.choices.filter(function (choice) {
|
||||||
|
return choice.active;
|
||||||
|
});
|
||||||
|
|
||||||
expect(this.choices.isSearching && mostAccurateResult.value === 'Value 3').toBeTruthy;
|
expect(this.choices.isSearching && mostAccurateResult[0].value === 'Value 3').toBe(true);
|
||||||
|
expect(searchSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shouldn\'t filter choices when searching', function() {
|
||||||
|
this.choices = new Choices(this.input, {
|
||||||
|
searchChoices: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.choices.setValue(['Javascript', 'HTML', 'Jasmine']);
|
||||||
|
|
||||||
|
const searchSpy = jasmine.createSpy('searchSpy');
|
||||||
|
const passedElement = this.choices.passedElement;
|
||||||
|
|
||||||
|
passedElement.addEventListener('search', searchSpy);
|
||||||
|
|
||||||
|
this.choices.input.focus();
|
||||||
|
this.choices.input.value = 'Javascript';
|
||||||
|
|
||||||
|
// Key down to search
|
||||||
|
this.choices._onKeyUp({
|
||||||
|
target: this.choices.input,
|
||||||
|
keyCode: 13,
|
||||||
|
ctrlKey: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeOptions = this.choices.currentState.choices.filter(function (choice) {
|
||||||
|
return choice.active;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(activeOptions.length).toEqual(this.choices.currentState.choices.length);
|
||||||
expect(searchSpy).toHaveBeenCalled();
|
expect(searchSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue