mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-16 20:46:35 +02:00
Refactoring + tests + documentation
This commit is contained in:
parent
b947ef17a7
commit
2cfb347c9f
|
@ -512,10 +512,10 @@ const example = new Choices(element, {
|
|||
example.setValueByChoice('Two'); // Choice with value of 'Two' has now been selected.
|
||||
```
|
||||
|
||||
### clearValue();
|
||||
<strong>Input types affected:</strong> `text`
|
||||
### clearStore();
|
||||
<strong>Input types affected:</strong> `text`, `select-one`, `select-multiple`
|
||||
|
||||
<strong>Usage:</strong> Clear value of input.
|
||||
<strong>Usage:</strong> Removes all items, choices and groups. Use with caution.
|
||||
|
||||
|
||||
### clearInput();
|
||||
|
|
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
|
@ -261,7 +261,10 @@ export class Choices {
|
|||
* @public
|
||||
*/
|
||||
removeItemsByValue(value) {
|
||||
if(!value || !isType('String', value)) console.error('removeItemsByValue: No value was passed to be removed'); return;
|
||||
if(!value || !isType('String', value)) {
|
||||
console.error('removeItemsByValue: No value was passed to be removed');
|
||||
return;
|
||||
}
|
||||
|
||||
const items = this.store.getItemsFilteredByActive();
|
||||
|
||||
|
@ -276,7 +279,7 @@ export class Choices {
|
|||
|
||||
/**
|
||||
* Remove all items from store array
|
||||
* Note: removed items are soft deleted
|
||||
* @note Removed items are soft deleted
|
||||
* @param {Number} excludedId Optionally exclude item by ID
|
||||
* @return {Object} Class instance
|
||||
* @public
|
||||
|
@ -295,7 +298,7 @@ export class Choices {
|
|||
|
||||
/**
|
||||
* Remove all selected items from store
|
||||
* Note: removed items are soft deleted
|
||||
* @note Removed items are soft deleted
|
||||
* @return {Object} Class instance
|
||||
* @public
|
||||
*/
|
||||
|
@ -322,7 +325,6 @@ export class Choices {
|
|||
|
||||
this.dropdown.classList.add(this.config.classNames.activeState);
|
||||
|
||||
|
||||
const dimensions = this.dropdown.getBoundingClientRect();
|
||||
const shouldFlip = this.config.flip ? dimensions.top + dimensions.height >= document.body.offsetHeight : false;
|
||||
|
||||
|
@ -450,13 +452,10 @@ export class Choices {
|
|||
|
||||
// Loop through each value and
|
||||
value.forEach((val, index) => {
|
||||
|
||||
const foundChoice = choices.find((choice) => {
|
||||
// Check 'value' property exists and the choice isn't already selected
|
||||
if(choice.value === val) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return choice.value === val;
|
||||
});
|
||||
|
||||
if(foundChoice) {
|
||||
|
@ -503,11 +502,12 @@ export class Choices {
|
|||
}
|
||||
|
||||
/**
|
||||
* Clear value of inputs
|
||||
* Clear items,choices and groups
|
||||
* @note Hard delete
|
||||
* @return {Object} Class instance
|
||||
* @public
|
||||
*/
|
||||
clearValue() {
|
||||
clearStore() {
|
||||
this.store.dispatch(clearAll());
|
||||
return this;
|
||||
}
|
||||
|
@ -1218,6 +1218,7 @@ export class Choices {
|
|||
/**
|
||||
* Add item to store with correct value
|
||||
* @param {String} value Value to add to store
|
||||
* @param {String} label Label to add to store
|
||||
* @return {Object} Class instance
|
||||
* @public
|
||||
*/
|
||||
|
@ -1261,7 +1262,8 @@ export class Choices {
|
|||
|
||||
/**
|
||||
* Remove item from store
|
||||
* @param
|
||||
* @param {Object} item Item to remove
|
||||
* @param {Function} callback Callback to trigger
|
||||
* @return {Object} Class instance
|
||||
* @public
|
||||
*/
|
||||
|
@ -1279,7 +1281,10 @@ export class Choices {
|
|||
|
||||
// Run callback
|
||||
if(callback){
|
||||
if(!isType('Function', callback)) console.error('callbackOnRemoveItem: Callback is not a function'); return;
|
||||
if(!isType('Function', callback)) {
|
||||
console.error('callbackOnRemoveItem: Callback is not a function');
|
||||
return;
|
||||
}
|
||||
callback(id, value, this.passedElement);
|
||||
}
|
||||
|
||||
|
@ -1287,7 +1292,12 @@ export class Choices {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add choice to dropdoww
|
||||
* Add choice to dropdown
|
||||
* @param {Boolean} isSelected Whether choice is selected
|
||||
* @param {Boolean} isDisabled Whether choice is disabled
|
||||
* @param {String} value Value of choice
|
||||
* @param {String} Label Label of choice
|
||||
* @param {Number} groupId ID of group choice is within. Negative number indicates no group
|
||||
* @return
|
||||
* @private
|
||||
*/
|
||||
|
@ -1310,7 +1320,8 @@ export class Choices {
|
|||
/**
|
||||
* Add group to dropdown
|
||||
* @param {Object} group Group to add
|
||||
* @param {Number} index Whether this is the first group to add
|
||||
* @param {Number} id Group ID
|
||||
* @param {Boolean} isFirst Whether this is the first group to add
|
||||
* @return
|
||||
* @private
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { sortByAlpha } from './../lib/utils.js';
|
||||
|
||||
const groups = (state = [], action) => {
|
||||
switch (action.type) {
|
||||
case 'ADD_GROUP':
|
||||
|
|
|
@ -87,7 +87,7 @@ describe('Choices', function() {
|
|||
expect(this.choices.setValue).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.setValueByChoice).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.setChoices).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.clearValue).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.clearStore).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.disable).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.enable).toEqual(jasmine.any(Function));
|
||||
expect(this.choices.ajax).toEqual(jasmine.any(Function));
|
||||
|
@ -181,7 +181,7 @@ describe('Choices', function() {
|
|||
|
||||
it('should open the choice list on focussing', function() {
|
||||
this.choices.input.focus();
|
||||
expect(this.choices.dropdown.classList).toContain('is-active');
|
||||
expect(this.choices.dropdown.classList).toContain(this.choices.config.classNames.activeState);
|
||||
});
|
||||
|
||||
it('should select the first choice', function() {
|
||||
|
@ -308,25 +308,197 @@ describe('Choices', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('should handle AJAX-populated choices', function() {
|
||||
describe('should handle public methods on select input types', function() {
|
||||
beforeEach(function() {
|
||||
this.input = document.createElement('select');
|
||||
this.input.className = 'js-choices';
|
||||
this.input.multiple = false;
|
||||
this.input.multiple = true;
|
||||
this.input.placeholder = 'Placeholder text';
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
for (let i = 1; i < 10; i++) {
|
||||
const option = document.createElement('option');
|
||||
|
||||
option.value = `Value ${i}`;
|
||||
option.innerHTML = `Value ${i}`;
|
||||
|
||||
if(i % 2) {
|
||||
option.selected = true;
|
||||
}
|
||||
|
||||
this.input.appendChild(option);
|
||||
}
|
||||
|
||||
document.body.appendChild(this.input);
|
||||
|
||||
this.choices = new Choices(this.input);
|
||||
});
|
||||
|
||||
it('should handle highlightItem()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
const randomItem = items[Math.floor(Math.random()*items.length)];
|
||||
|
||||
this.choices.highlightItem(randomItem);
|
||||
|
||||
expect(randomItem.highlighted).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle unhighlightItem()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
const randomItem = items[Math.floor(Math.random()*items.length)];
|
||||
|
||||
this.choices.unhighlightItem(randomItem);
|
||||
|
||||
expect(randomItem.highlighted).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle highlightAll()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
|
||||
this.choices.highlightAll();
|
||||
|
||||
const unhighlightedItems = items.some((item) => item.highlighted === false);
|
||||
|
||||
expect(unhighlightedItems).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle unhighlightAll()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
|
||||
this.choices.unhighlightAll();
|
||||
|
||||
const highlightedItems = items.some((item) => item.highlighted === true);
|
||||
|
||||
expect(highlightedItems).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle removeHighlightedItems()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
this.choices.highlightAll();
|
||||
this.choices.removeHighlightedItems();
|
||||
|
||||
const activeItems = items.some((item) => item.active === true);
|
||||
|
||||
expect(activeItems).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle showDropdown()', function() {
|
||||
this.choices.showDropdown();
|
||||
const hasOpenState = this.choices.containerOuter.classList.contains(this.choices.config.classNames.openState);
|
||||
const hasAttr = this.choices.containerOuter.getAttribute('aria-expanded') === 'true';
|
||||
const hasActiveState = this.choices.dropdown.classList.contains(this.choices.config.classNames.activeState);
|
||||
expect(hasOpenState && hasAttr && hasActiveState).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle hideDropdown()', function() {
|
||||
this.choices.showDropdown();
|
||||
this.choices.hideDropdown();
|
||||
const hasOpenState = this.choices.containerOuter.classList.contains(this.choices.config.classNames.openState);
|
||||
const hasAttr = this.choices.containerOuter.getAttribute('aria-expanded') === 'true';
|
||||
const hasActiveState = this.choices.dropdown.classList.contains(this.choices.config.classNames.activeState);
|
||||
|
||||
expect(hasOpenState && hasAttr && hasActiveState).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle toggleDropdown()', function() {
|
||||
spyOn(this.choices, 'hideDropdown');
|
||||
this.choices.showDropdown();
|
||||
this.choices.toggleDropdown();
|
||||
expect(this.choices.hideDropdown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle hideDropdown()', function() {
|
||||
this.choices.showDropdown();
|
||||
expect(this.choices.containerOuter.classList).toContain(this.choices.config.classNames.openState);
|
||||
});
|
||||
|
||||
it('should handle getValue()', function() {
|
||||
const valueObjects = this.choices.getValue();
|
||||
const valueStrings = this.choices.getValue(true);
|
||||
|
||||
expect(valueStrings[0]).toEqual(jasmine.any(String));
|
||||
expect(valueObjects[0]).toEqual(jasmine.any(Object));
|
||||
expect(valueObjects).toEqual(jasmine.any(Array));
|
||||
expect(valueObjects.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should handle setValue()', function() {
|
||||
this.choices.setValue(['Set value 1', 'Set value 2', 'Set value 3']);
|
||||
const valueStrings = this.choices.getValue(true);
|
||||
|
||||
expect(valueStrings[valueStrings.length - 1]).toBe('Set value 3');
|
||||
expect(valueStrings[valueStrings.length - 2]).toBe('Set value 2');
|
||||
expect(valueStrings[valueStrings.length - 3]).toBe('Set value 1');
|
||||
});
|
||||
|
||||
it('should handle setValueByChoice()', function() {
|
||||
const choices = this.choices.store.getChoicesFilteredByActive();
|
||||
const randomChoice = choices[Math.floor(Math.random()*choices.length)];
|
||||
|
||||
this.choices.highlightAll();
|
||||
this.choices.removeHighlightedItems();
|
||||
this.choices.setValueByChoice(randomChoice.value);
|
||||
|
||||
const value = this.choices.getValue(true);
|
||||
|
||||
expect(value[0]).toBe(randomChoice.value);
|
||||
});
|
||||
|
||||
it('should handle setChoices()', function() {
|
||||
this.choices.setChoices([{
|
||||
label: 'Group one',
|
||||
id: 1,
|
||||
disabled: false,
|
||||
choices: [
|
||||
{value: 'Child One', label: 'Child One', selected: true},
|
||||
{value: 'Child Two', label: 'Child Two', disabled: true},
|
||||
{value: 'Child Three', label: 'Child Three'},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Group two',
|
||||
id: 2,
|
||||
disabled: false,
|
||||
choices: [
|
||||
{value: 'Child Four', label: 'Child Four', disabled: true},
|
||||
{value: 'Child Five', label: 'Child Five'},
|
||||
{value: 'Child Six', label: 'Child Six'},
|
||||
]
|
||||
}], 'value', 'label');
|
||||
|
||||
|
||||
const groups = this.choices.currentState.groups;
|
||||
const choices = this.choices.currentState.choices;
|
||||
|
||||
expect(groups[groups.length - 1].value).toEqual('Group two');
|
||||
expect(groups[groups.length - 2].value).toEqual('Group one');
|
||||
expect(choices[choices.length - 1].value).toEqual('Child Six');
|
||||
expect(choices[choices.length - 2].value).toEqual('Child Five');
|
||||
});
|
||||
|
||||
it('should handle clearStore()', function() {
|
||||
this.choices.clearStore();
|
||||
|
||||
expect(this.choices.currentState.items).toEqual([]);
|
||||
expect(this.choices.currentState.choices).toEqual([]);
|
||||
expect(this.choices.currentState.groups).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle disable()', function() {
|
||||
this.choices.disable();
|
||||
|
||||
expect(this.choices.input.disabled).toBe(true);
|
||||
expect(this.choices.containerOuter.classList.contains(this.choices.config.classNames.disabledState)).toBe(true);
|
||||
expect(this.choices.containerOuter.getAttribute('aria-disabled')).toBe('true');
|
||||
});
|
||||
|
||||
it('should handle enable()', function() {
|
||||
this.choices.enable();
|
||||
|
||||
expect(this.choices.input.disabled).toBe(false);
|
||||
expect(this.choices.containerOuter.classList.contains(this.choices.config.classNames.disabledState)).toBe(false);
|
||||
expect(this.choices.containerOuter.hasAttribute('aria-disabled')).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle ajax()', function() {
|
||||
spyOn(this.choices, 'ajax');
|
||||
|
||||
this.choices.ajax((callback) => {
|
||||
|
@ -340,10 +512,36 @@ describe('Choices', function() {
|
|||
console.log(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should call ajax()', function() {
|
||||
|
||||
expect(this.choices.ajax).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
describe('should handle public methods on text input types', function() {
|
||||
beforeEach(function() {
|
||||
this.input = document.createElement('input');
|
||||
this.input.type = "text";
|
||||
this.input.className = 'js-choices';
|
||||
this.input.value = "Value 1, Value 2, Value 3, Value 4";
|
||||
|
||||
document.body.appendChild(this.input);
|
||||
this.choices = new Choices(this.input);
|
||||
});
|
||||
|
||||
it('should handle clearInput()', function() {
|
||||
this.choices.clearInput();
|
||||
expect(this.choices.input.value).toBe('');
|
||||
});
|
||||
|
||||
it('should handle removeItemsByValue()', function() {
|
||||
const items = this.choices.currentState.items;
|
||||
const randomItem = items[Math.floor(Math.random()*items.length)];
|
||||
|
||||
this.choices.removeItemsByValue(randomItem.value);
|
||||
|
||||
expect(randomItem.active).toBe(false);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue