Early returns + reduce repitition

This commit is contained in:
Josh Johnson 2017-08-30 13:04:19 +01:00
parent c1df7461c0
commit 31396569b7
4 changed files with 272 additions and 315 deletions

View file

@ -6,17 +6,17 @@
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>Choices</title> <title>Choices</title>
<meta name=description itemprop=description content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency."> <meta name=description itemprop=description content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.">
<link rel="apple-touch-icon" sizes="180x180" href="assets/images/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="src/images/apple-touch-icon.png">
<link rel="icon" type="image/png" href="assets/images/favicon-32x32.png" sizes="32x32"> <link rel="icon" type="image/png" href="src/images/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="assets/images/favicon-16x16.png" sizes="16x16"> <link rel="icon" type="image/png" href="src/images/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="assets/images/manifest.json"> <link rel="manifest" href="src/images/manifest.json">
<link rel="mask-icon" href="assets/images/safari-pinned-tab.svg" color="#00bcd4"> <link rel="mask-icon" href="src/images/safari-pinned-tab.svg" color="#00bcd4">
<link rel="shortcut icon" href="assets/images/favicon.ico"> <link rel="shortcut icon" href="src/images/favicon.ico">
<meta name="msapplication-config" content="/assets/images/browserconfig.xml"> <meta name="msapplication-config" content="/src/images/browserconfig.xml">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<!-- Ignore these --> <!-- Ignore these -->
<link rel="stylesheet" href="assets/styles/css/base.min.css?version=3.0.2"> <link rel="stylesheet" href="src/styles/css/base.min.css?version=3.0.2">
<!-- End ignore these --> <!-- End ignore these -->
<!-- Optional includes --> <!-- Optional includes -->
@ -24,8 +24,8 @@
<!-- End optional includes --> <!-- End optional includes -->
<!-- Choices includes --> <!-- Choices includes -->
<link rel="stylesheet" href="assets/styles/css/choices.min.css?version=3.0.2"> <link rel="stylesheet" href="src/styles/css/choices.min.css?version=3.0.2">
<script src="assets/scripts/dist/choices.min.js?version=2.8.8"></script> <script src="src/scripts/dist/choices.min.js?version=2.8.8"></script>
<!-- End Choices includes --> <!-- End Choices includes -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
@ -40,7 +40,7 @@
<div class="container"> <div class="container">
<div class="section"> <div class="section">
<a href="https://github.com/jshjohnson/Choices" class="logo"> <a href="https://github.com/jshjohnson/Choices" class="logo">
<img src="assets/images/logo.svg" alt="Choices.js logo" class="logo__img hidden-ie"> <img src="src/images/logo.svg" alt="Choices.js logo" class="logo__img hidden-ie">
<h1 class="visible-ie">Choices.js</h1> <h1 class="visible-ie">Choices.js</h1>
</a> </a>
<p>Choices.js is a lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without <p>Choices.js is a lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without

View file

@ -245,12 +245,10 @@ class Choices {
* @public * @public
*/ */
init() { init() {
if (this.initialised === true) { if (this.initialised) {
return; return;
} }
const callback = this.config.callbackOnInit;
// Set initialise flag // Set initialise flag
this.initialised = true; this.initialised = true;
// Create required elements // Create required elements
@ -264,6 +262,7 @@ class Choices {
// Trigger event listeners // Trigger event listeners
this._addEventListeners(); this._addEventListeners();
const callback = this.config.callbackOnInit;
// Run callback if it is a function // Run callback if it is a function
if (callback && isType('Function', callback)) { if (callback && isType('Function', callback)) {
callback.call(this); callback.call(this);
@ -276,7 +275,7 @@ class Choices {
* @public * @public
*/ */
destroy() { destroy() {
if (this.initialised === false) { if (!this.initialised) {
return; return;
} }
@ -485,11 +484,11 @@ class Choices {
if (this.currentState !== this.prevState) { if (this.currentState !== this.prevState) {
// Choices // Choices
if ( if (
this.currentState.choices !== this.prevState.choices || (this.currentState.choices !== this.prevState.choices ||
this.currentState.groups !== this.prevState.groups || this.currentState.groups !== this.prevState.groups ||
this.currentState.items !== this.prevState.items this.currentState.items !== this.prevState.items) &&
this.isSelectElement
) { ) {
if (this.isSelectElement) {
// Get active groups/choices // Get active groups/choices
const activeGroups = this.store.getGroupsFilteredByActive(); const activeGroups = this.store.getGroupsFilteredByActive();
const activeChoices = this.store.getChoicesFilteredByActive(); const activeChoices = this.store.getChoicesFilteredByActive();
@ -547,7 +546,6 @@ class Choices {
this.choiceList.append(dropdownItem); this.choiceList.append(dropdownItem);
} }
} }
}
// Items // Items
if (this.currentState.items !== this.prevState.items) { if (this.currentState.items !== this.prevState.items) {
@ -557,7 +555,7 @@ class Choices {
// Clear list // Clear list
this.itemList.clear(); this.itemList.clear();
if (activeItems && activeItems) { if (activeItems && activeItems.length) {
// Create a fragment to store our list items // Create a fragment to store our list items
// (so we don't have to update the DOM for each item) // (so we don't have to update the DOM for each item)
const itemListFragment = this.renderItems(activeItems); const itemListFragment = this.renderItems(activeItems);
@ -595,20 +593,17 @@ class Choices {
); );
if (runEvent) { if (runEvent) {
const eventResponse = {
id,
value: item.value,
label: item.label,
};
if (group && group.value) { if (group && group.value) {
triggerEvent(this.passedElement, 'highlightItem', { eventResponse.groupValue = group.value;
id,
value: item.value,
label: item.label,
groupValue: group.value,
});
} else {
triggerEvent(this.passedElement, 'highlightItem', {
id,
value: item.value,
label: item.label,
});
} }
triggerEvent(this.passedElement, 'highlightItem', eventResponse);
} }
return this; return this;
@ -628,25 +623,21 @@ class Choices {
const id = item.id; const id = item.id;
const groupId = item.groupId; const groupId = item.groupId;
const group = groupId >= 0 ? this.store.getGroupById(groupId) : null; const group = groupId >= 0 ? this.store.getGroupById(groupId) : null;
const eventResponse = {
id,
value: item.value,
label: item.label,
};
if (group && group.value) {
eventResponse.groupValue = group.value;
}
this.store.dispatch( this.store.dispatch(
highlightItem(id, false), highlightItem(id, false),
); );
if (group && group.value) { triggerEvent(this.passedElement, 'highlightItem', eventResponse);
triggerEvent(this.passedElement, 'unhighlightItem', {
id,
value: item.value,
label: item.label,
groupValue: group.value,
});
} else {
triggerEvent(this.passedElement, 'unhighlightItem', {
id,
value: item.value,
label: item.label,
});
}
return this; return this;
} }
@ -743,6 +734,10 @@ class Choices {
* @public * @public
*/ */
showDropdown(focusInput = false) { showDropdown(focusInput = false) {
if (this.dropdown.isActive) {
return this;
}
this.containerOuter.open(this.dropdown.getVerticalPos()); this.containerOuter.open(this.dropdown.getVerticalPos());
this.dropdown.show(); this.dropdown.show();
this.input.activate(focusInput); this.input.activate(focusInput);
@ -757,6 +752,10 @@ class Choices {
* @public * @public
*/ */
hideDropdown(blurInput = false) { hideDropdown(blurInput = false) {
if (!this.dropdown.isActive) {
return this;
}
this.containerOuter.close(); this.containerOuter.close();
this.dropdown.hide(); this.dropdown.hide();
this.input.deactivate(blurInput); this.input.deactivate(blurInput);
@ -793,18 +792,12 @@ class Choices {
items.forEach((item) => { items.forEach((item) => {
const itemValue = valueOnly ? item.value : item; const itemValue = valueOnly ? item.value : item;
if (this.isTextElement) { if (this.isTextElement || item.active) {
selectedItems.push(itemValue);
} else if (item.active) {
selectedItems.push(itemValue); selectedItems.push(itemValue);
} }
}); });
if (this.isSelectOneElement) { return this.isSelectOneElement ? selectedItems[0] : selectedItems;
return selectedItems[0];
}
return selectedItems;
} }
/** /**
@ -822,8 +815,9 @@ class Choices {
// Convert args to an iterable array // Convert args to an iterable array
const values = [...args]; const values = [...args];
const handleValue = (item) => { const handleValue = (item) => {
const itemType = getType(item); const itemType = getType(item).toLowerCase();
if (itemType === 'Object') { const handleType = {
object: () => {
if (!item.value) { if (!item.value) {
return; return;
} }
@ -849,7 +843,8 @@ class Choices {
item.placeholder, item.placeholder,
); );
} }
} else if (itemType === 'String') { },
string: () => {
if (!this.isTextElement) { if (!this.isTextElement) {
this._addChoice( this._addChoice(
item, item,
@ -861,14 +856,13 @@ class Choices {
} else { } else {
this._addItem(item); this._addItem(item);
} }
} },
};
handleType[itemType]();
}; };
if (values.length > 1) {
values.forEach(value => handleValue(value)); values.forEach(value => handleValue(value));
} else {
handleValue(values[0]);
}
return this; return this;
} }
@ -911,6 +905,7 @@ class Choices {
console.warn('Attempting to select choice that does not exist'); console.warn('Attempting to select choice that does not exist');
} }
}); });
return this; return this;
} }
@ -974,9 +969,7 @@ class Choices {
* @public * @public
*/ */
clearStore() { clearStore() {
this.store.dispatch( this.store.dispatch(clearAll());
clearAll(),
);
return this; return this;
} }
@ -991,9 +984,7 @@ class Choices {
if (!this.isTextElement && this.config.searchEnabled) { if (!this.isTextElement && this.config.searchEnabled) {
this.isSearching = false; this.isSearching = false;
this.store.dispatch( this.store.dispatch(activateChoices(true));
activateChoices(true),
);
} }
return this; return this;
@ -1009,9 +1000,8 @@ class Choices {
} }
this.passedElement.disabled = false; this.passedElement.disabled = false;
const isDisabled = this.containerOuter.isDisabled;
if (isDisabled) { if (this.containerOuter.isDisabled) {
this._addEventListeners(); this._addEventListeners();
this.passedElement.removeAttribute('disabled'); this.passedElement.removeAttribute('disabled');
this.input.enable(); this.input.enable();
@ -1032,9 +1022,8 @@ class Choices {
} }
this.passedElement.disabled = true; this.passedElement.disabled = true;
const isEnabled = !this.containerOuter.isDisabled;
if (isEnabled) { if (!this.containerOuter.isDisabled) {
this._removeEventListeners(); this._removeEventListeners();
this.passedElement.setAttribute('disabled', ''); this.passedElement.setAttribute('disabled', '');
this.input.disable(); this.input.disable();
@ -1093,12 +1082,15 @@ class Choices {
* @private * @private
*/ */
_handleButtonAction(activeItems, element) { _handleButtonAction(activeItems, element) {
if (!activeItems || !element) { if (
!activeItems ||
!element ||
!this.config.removeItems ||
!this.config.removeItemButton
) {
return; return;
} }
// If we are clicking on a button
if (this.config.removeItems && this.config.removeItemButton) {
const itemId = element.parentNode.getAttribute('data-id'); const itemId = element.parentNode.getAttribute('data-id');
const itemToRemove = activeItems.find(item => item.id === parseInt(itemId, 10)); const itemToRemove = activeItems.find(item => item.id === parseInt(itemId, 10));
@ -1110,7 +1102,6 @@ class Choices {
this._selectPlaceholderChoice(); this._selectPlaceholderChoice();
} }
} }
}
/** /**
* Select placeholder choice * Select placeholder choice
@ -1140,12 +1131,15 @@ class Choices {
* @private * @private
*/ */
_handleItemAction(activeItems, element, hasShiftKey = false) { _handleItemAction(activeItems, element, hasShiftKey = false) {
if (!activeItems || !element) { if (
!activeItems ||
!element ||
!this.config.removeItems ||
this.isSelectOneElement
) {
return; return;
} }
// If we are clicking on an item
if (this.config.removeItems && !this.isSelectOneElement) {
const passedId = element.getAttribute('data-id'); const passedId = element.getAttribute('data-id');
// We only want to select one item with a click // We only want to select one item with a click
@ -1154,18 +1148,15 @@ class Choices {
activeItems.forEach((item) => { activeItems.forEach((item) => {
if (item.id === parseInt(passedId, 10) && !item.highlighted) { if (item.id === parseInt(passedId, 10) && !item.highlighted) {
this.highlightItem(item); this.highlightItem(item);
} else if (!hasShiftKey) { } else if (!hasShiftKey && item.highlighted) {
if (item.highlighted) {
this.unhighlightItem(item); this.unhighlightItem(item);
} }
}
}); });
// Focus input as without focus, a user cannot do anything with a // Focus input as without focus, a user cannot do anything with a
// highlighted item // highlighted item
this.input.focus(); this.input.focus();
} }
}
/** /**
* Process click of a choice * Process click of a choice
@ -1224,7 +1215,10 @@ class Choices {
* @private * @private
*/ */
_handleBackspace(activeItems) { _handleBackspace(activeItems) {
if (this.config.removeItems && activeItems) { if (!this.config.removeItems || !activeItems) {
return;
}
const lastItem = activeItems[activeItems.length - 1]; const lastItem = activeItems[activeItems.length - 1];
const hasHighlightedItems = activeItems.some(item => item.highlighted); const hasHighlightedItems = activeItems.some(item => item.highlighted);
@ -1242,7 +1236,6 @@ class Choices {
this.removeHighlightedItems(true); this.removeHighlightedItems(true);
} }
} }
}
/** /**
* Validates whether an item can be added by a user * Validates whether an item can be added by a user
@ -1408,9 +1401,7 @@ class Choices {
this.currentValue = newValue; this.currentValue = newValue;
this.highlightPosition = 0; this.highlightPosition = 0;
this.isSearching = true; this.isSearching = true;
this.store.dispatch( this.store.dispatch(filterChoices(results));
filterChoices(results),
);
return results.length; return results.length;
} }
@ -1425,23 +1416,16 @@ class Choices {
* @private * @private
*/ */
_handleSearch(value) { _handleSearch(value) {
if (!value) { if (!value || !this.input.isFocussed) {
return; return;
} }
const choices = this.store.getChoices(); const choices = this.store.getChoices();
const hasUnactiveChoices = choices.some(option => !option.active); const hasUnactiveChoices = choices.some(option => !option.active);
// Run callback if it is a function
if (this.input.isFocussed) {
// 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) {
let resultCount = 0; const resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;
// Check flag to filter search input
if (this.config.searchChoices) {
// Filter available choices
resultCount = this._searchChoices(value);
}
// Trigger search event // Trigger search event
triggerEvent(this.passedElement, 'search', { triggerEvent(this.passedElement, 'search', {
value, value,
@ -1450,10 +1434,7 @@ class Choices {
} else if (hasUnactiveChoices) { } else if (hasUnactiveChoices) {
// Otherwise reset choices to active // Otherwise reset choices to active
this.isSearching = false; this.isSearching = false;
this.store.dispatch( this.store.dispatch(activateChoices(true));
activateChoices(true),
);
}
} }
} }
@ -1524,6 +1505,7 @@ class Choices {
const hasItems = this.itemList.hasChildren; const hasItems = this.itemList.hasChildren;
const keyString = String.fromCharCode(e.keyCode); const keyString = String.fromCharCode(e.keyCode);
// TO DO: Move into constants file
const backKey = 46; const backKey = 46;
const deleteKey = 8; const deleteKey = 8;
const enterKey = 13; const enterKey = 13;
@ -1536,7 +1518,7 @@ class Choices {
const ctrlDownKey = (e.ctrlKey || e.metaKey); const ctrlDownKey = (e.ctrlKey || e.metaKey);
// If a user is typing and the dropdown is not active // If a user is typing and the dropdown is not active
if (!this.isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString) && !hasActiveDropdown) { if (!this.isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString)) {
this.showDropdown(true); this.showDropdown(true);
} }
@ -1565,9 +1547,7 @@ class Choices {
// All is good, add // All is good, add
if (canAddItem.response) { if (canAddItem.response) {
if (hasActiveDropdown) {
this.hideDropdown(); this.hideDropdown();
}
this._addItem(value); this._addItem(value);
this._triggerChange(value); this._triggerChange(value);
this.clearInput(); this.clearInput();
@ -1591,7 +1571,7 @@ class Choices {
} }
this._handleChoiceAction(activeItems, highlighted); this._handleChoiceAction(activeItems, highlighted);
} }
} else if (this.isSelectOneElement && !hasActiveDropdown) { } else if (this.isSelectOneElement) {
// Open single select dropdown if it's not active // Open single select dropdown if it's not active
this.showDropdown(true); this.showDropdown(true);
e.preventDefault(); e.preventDefault();
@ -1609,9 +1589,7 @@ class Choices {
// If up or down key is pressed, traverse through options // If up or down key is pressed, traverse through options
if (hasActiveDropdown || this.isSelectOneElement) { if (hasActiveDropdown || this.isSelectOneElement) {
// Show dropdown if focus // Show dropdown if focus
if (!hasActiveDropdown) {
this.showDropdown(true); this.showDropdown(true);
}
this.canSearch = false; this.canSearch = false;
@ -1698,8 +1676,6 @@ class Choices {
// 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) {
const hasActiveDropdown = this.dropdown.isActive;
if (value) { if (value) {
if (canAddItem.notice) { if (canAddItem.notice) {
const dropdownItem = this._getTemplate('notice', canAddItem.notice); const dropdownItem = this._getTemplate('notice', canAddItem.notice);
@ -1707,13 +1683,11 @@ class Choices {
} }
if (canAddItem.response === true) { if (canAddItem.response === true) {
if (!hasActiveDropdown) {
this.showDropdown(); this.showDropdown();
} } else if (!canAddItem.notice) {
} else if (!canAddItem.notice && hasActiveDropdown) {
this.hideDropdown(); this.hideDropdown();
} }
} else if (hasActiveDropdown) { } else {
this.hideDropdown(); this.hideDropdown();
} }
} else { } else {
@ -1756,7 +1730,6 @@ class Choices {
*/ */
_onTouchEnd(e) { _onTouchEnd(e) {
const target = (e.target || e.touches[0].target); const target = (e.target || e.touches[0].target);
const hasActiveDropdown = this.dropdown.isActive;
// If a user tapped within our container... // If a user tapped within our container...
if (this.wasTap === true && this.containerOuter.element.contains(target)) { if (this.wasTap === true && this.containerOuter.element.contains(target)) {
@ -1768,7 +1741,7 @@ class Choices {
if (this.isTextElement) { if (this.isTextElement) {
// If text element, we only want to focus the input // If text element, we only want to focus the input
this.input.focus(); this.input.focus();
} else if (!hasActiveDropdown) { } else {
// If a select box, we want to show the dropdown // If a select box, we want to show the dropdown
this.showDropdown(true); this.showDropdown(true);
} }
@ -1857,11 +1830,9 @@ class Choices {
this.containerOuter.removeFocusState(); this.containerOuter.removeFocusState();
// Close all other dropdowns // Close all other dropdowns
if (hasActiveDropdown) {
this.hideDropdown(); this.hideDropdown();
} }
} }
}
/** /**
* Mouse over (hover) event * Mouse over (hover) event
@ -1889,7 +1860,6 @@ class Choices {
const target = e.target; const target = e.target;
// If target is something that concerns us // If target is something that concerns us
if (this.containerOuter.element.contains(target)) { if (this.containerOuter.element.contains(target)) {
const hasActiveDropdown = this.dropdown.isActive;
const focusActions = { const focusActions = {
text: () => { text: () => {
if (target === this.input.element) { if (target === this.input.element) {
@ -1898,7 +1868,7 @@ class Choices {
}, },
'select-one': () => { 'select-one': () => {
this.containerOuter.addFocusState(); this.containerOuter.addFocusState();
if ((target === this.input.element) && !hasActiveDropdown) { if (target === this.input.element) {
// Show dropdown if it isn't already showing // Show dropdown if it isn't already showing
this.showDropdown(); this.showDropdown();
} }
@ -1908,10 +1878,8 @@ class Choices {
// If element is a select box, the focused element is the container and the dropdown // If element is a select box, the focused element is the container and the dropdown
// isn't already open, focus and show dropdown // isn't already open, focus and show dropdown
this.containerOuter.addFocusState(); this.containerOuter.addFocusState();
if (!hasActiveDropdown) {
this.showDropdown(true); this.showDropdown(true);
} }
}
}, },
}; };
@ -1930,7 +1898,6 @@ class Choices {
// If target is something that concerns us // If target is something that concerns us
if (this.containerOuter.element.contains(target) && !this.isScrollingOnIe) { if (this.containerOuter.element.contains(target) && !this.isScrollingOnIe) {
const activeItems = this.store.getItemsFilteredByActive(); const activeItems = this.store.getItemsFilteredByActive();
const hasActiveDropdown = this.dropdown.isActive;
const hasHighlightedItems = activeItems.some(item => item.highlighted); const hasHighlightedItems = activeItems.some(item => item.highlighted);
const blurActions = { const blurActions = {
text: () => { text: () => {
@ -1941,21 +1908,18 @@ class Choices {
if (hasHighlightedItems) { if (hasHighlightedItems) {
this.unhighlightAll(); this.unhighlightAll();
} }
// Hide dropdown if it is showing
if (hasActiveDropdown) {
this.hideDropdown(); this.hideDropdown();
} }
}
}, },
'select-one': () => { 'select-one': () => {
this.containerOuter.removeFocusState(); this.containerOuter.removeFocusState();
if (target === this.containerOuter.element) { if (target === this.containerOuter.element) {
// Hide dropdown if it is showing // Hide dropdown if it is showing
if (hasActiveDropdown && !this.canSearch) { if (!this.canSearch) {
this.hideDropdown(); this.hideDropdown();
} }
} }
if (target === this.input.element && hasActiveDropdown) { if (target === this.input.element) {
// Hide dropdown if it is showing // Hide dropdown if it is showing
this.hideDropdown(); this.hideDropdown();
} }
@ -1964,10 +1928,7 @@ class Choices {
if (target === this.input.element) { if (target === this.input.element) {
// Remove the focus state // Remove the focus state
this.containerOuter.removeFocusState(); this.containerOuter.removeFocusState();
// Hide dropdown if it is showing
if (hasActiveDropdown) {
this.hideDropdown(); this.hideDropdown();
}
// De-select any highlighted items // De-select any highlighted items
if (hasHighlightedItems) { if (hasHighlightedItems) {
this.unhighlightAll(); this.unhighlightAll();

View file

@ -10,7 +10,7 @@ import itemReducer from './reducers/items.js';
import choiceReducer from './reducers/choices.js'; import choiceReducer from './reducers/choices.js';
import { import {
addItem as addItemAction, addItem as addItemAction,
addChoice as addChoiceAction addChoice as addChoiceAction,
} from './actions/actions.js'; } from './actions/actions.js';
describe('Choices', () => { describe('Choices', () => {
@ -189,7 +189,7 @@ describe('Choices', () => {
instance._onKeyDown({ instance._onKeyDown({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
expect(instance.currentState.items[0].value).to.include(instance.input.value); expect(instance.currentState.items[0].value).to.include(instance.input.value);
@ -213,7 +213,7 @@ describe('Choices', () => {
instance._onKeyDown({ instance._onKeyDown({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
expect(instance.currentState.items[instance.currentState.items.length - 1]).not.to.include(instance.input.value); expect(instance.currentState.items[instance.currentState.items.length - 1]).not.to.include(instance.input.value);
@ -230,7 +230,7 @@ describe('Choices', () => {
instance._onKeyDown({ instance._onKeyDown({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
instance.input.focus(); instance.input.focus();
@ -239,7 +239,7 @@ describe('Choices', () => {
instance._onKeyDown({ instance._onKeyDown({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
const lastItem = instance.currentState.items[instance.currentState.items.length - 1]; const lastItem = instance.currentState.items[instance.currentState.items.length - 1];
@ -260,7 +260,7 @@ describe('Choices', () => {
instance._onKeyDown({ instance._onKeyDown({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
const lastItem = instance.currentState.items[instance.currentState.items.length - 1]; const lastItem = instance.currentState.items[instance.currentState.items.length - 1];
@ -308,7 +308,7 @@ describe('Choices', () => {
it('should highlight the choices on keydown', () => { it('should highlight the choices on keydown', () => {
instance = new Choices(input, { instance = new Choices(input, {
renderChoiceLimit: -1 renderChoiceLimit: -1,
}); });
instance.input.focus(); instance.input.focus();
@ -318,7 +318,7 @@ describe('Choices', () => {
target: instance.input, target: instance.input,
keyCode: 40, keyCode: 40,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
} }
@ -334,7 +334,7 @@ describe('Choices', () => {
target: instance.input, target: instance.input,
keyCode: 40, keyCode: 40,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
// Key down to select choice // Key down to select choice
@ -342,7 +342,7 @@ describe('Choices', () => {
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
expect(instance.currentState.items.length).to.equal(2); expect(instance.currentState.items.length).to.equal(2);
@ -365,7 +365,7 @@ describe('Choices', () => {
target: instance.input, target: instance.input,
keyCode: 40, keyCode: 40,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
// Key down to select choice // Key down to select choice
@ -373,7 +373,7 @@ describe('Choices', () => {
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
const returnValue = onChangeStub.calls.mostRecent().args[0].detail.value; const returnValue = onChangeStub.calls.mostRecent().args[0].detail.value;
@ -388,7 +388,7 @@ describe('Choices', () => {
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
expect(document.activeElement === instance.input && container.classList.contains('is-open')).to.be.true; expect(document.activeElement === instance.input && container.classList.contains('is-open')).to.be.true;
@ -402,13 +402,13 @@ describe('Choices', () => {
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
expect(document.activeElement === instance.input && container.classList.contains(openState)).to.be.false; expect(document.activeElement === instance.input && container.classList.contains(openState)).to.be.false;
@ -428,7 +428,7 @@ describe('Choices', () => {
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
expect(showDropdownStub.callCount).to.equal(1); expect(showDropdownStub.callCount).to.equal(1);
@ -448,13 +448,13 @@ describe('Choices', () => {
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
instance._onClick({ instance._onClick({
target: container, target: container,
ctrlKey: false, ctrlKey: false,
preventDefault: () => {} preventDefault: () => {},
}); });
expect(hideDropdownStub.callCount).to.equal(1); expect(hideDropdownStub.callCount).to.equal(1);
@ -475,12 +475,10 @@ describe('Choices', () => {
instance._onKeyUp({ instance._onKeyUp({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
const mostAccurateResult = instance.currentState.choices.filter((choice) => { const mostAccurateResult = instance.currentState.choices.filter(choice => choice.active);
return choice.active;
});
expect(instance.isSearching && mostAccurateResult[0].value === 'Value 3').to.be.true; expect(instance.isSearching && mostAccurateResult[0].value === 'Value 3').to.be.true;
expect(onSearchStub.callCount).to.equal(1); expect(onSearchStub.callCount).to.equal(1);
@ -488,7 +486,7 @@ describe('Choices', () => {
it('shouldn\'t filter choices when searching', () => { it('shouldn\'t filter choices when searching', () => {
instance = new Choices(input, { instance = new Choices(input, {
searchChoices: false searchChoices: false,
}); });
instance.setValue(['Javascript', 'HTML', 'Jasmine']); instance.setValue(['Javascript', 'HTML', 'Jasmine']);
@ -505,12 +503,10 @@ describe('Choices', () => {
instance._onKeyUp({ instance._onKeyUp({
target: instance.input, target: instance.input,
keyCode: 13, keyCode: 13,
ctrlKey: false ctrlKey: false,
}); });
const activeOptions = instance.currentState.choices.filter(function (choice) { const activeOptions = instance.currentState.choices.filter((choice) => choice.active);
return choice.active;
});
expect(activeOptions.length).to.equal(instance.currentState.choices.length); expect(activeOptions.length).to.equal(instance.currentState.choices.length);
expect(onSearchStub.callCount).to.equal(1); expect(onSearchStub.callCount).to.equal(1);
@ -522,13 +518,13 @@ describe('Choices', () => {
choices: [ choices: [
{ {
value: 'Value 5', value: 'Value 5',
label: 'Label Five' label: 'Label Five',
}, { }, {
value: 'Value 6', value: 'Value 6',
label: 'Label Six' label: 'Label Six',
}, { }, {
value: 'Value 7', value: 'Value 7',
label: 'Label Seven' label: 'Label Seven',
}, },
], ],
}); });
@ -542,13 +538,13 @@ describe('Choices', () => {
choices: [ choices: [
{ {
value: 'Value 5', value: 'Value 5',
label: 'Label Five' label: 'Label Five',
}, { }, {
value: 'Value 6', value: 'Value 6',
label: 'Label Six' label: 'Label Six',
}, { }, {
value: 'Value 7', value: 'Value 7',
label: 'Label Seven' label: 'Label Seven',
}, },
], ],
}); });
@ -588,14 +584,14 @@ describe('Choices', () => {
value: 'One', value: 'One',
label: 'Label One', label: 'Label One',
selected: true, selected: true,
disabled: false disabled: false,
}, { }, {
value: 'Two', value: 'Two',
label: 'Label Two', label: 'Label Two',
disabled: true disabled: true,
}, { }, {
value: 'Three', value: 'Three',
label: 'Label Three' label: 'Label Three',
}, },
], ],
}); });
@ -672,7 +668,7 @@ describe('Choices', () => {
instance.highlightAll(); instance.highlightAll();
const unhighlightedItems = items.some((item) => item.highlighted === false); const unhighlightedItems = items.some(item => item.highlighted === false);
expect(unhighlightedItems).to.be.false; expect(unhighlightedItems).to.be.false;
}); });
@ -682,7 +678,7 @@ describe('Choices', () => {
instance.unhighlightAll(); instance.unhighlightAll();
const highlightedItems = items.some((item) => item.highlighted === true); const highlightedItems = items.some(item => item.highlighted === true);
expect(highlightedItems).to.be.false; expect(highlightedItems).to.be.false;
}); });
@ -692,7 +688,7 @@ describe('Choices', () => {
instance.highlightAll(); instance.highlightAll();
instance.removeHighlightedItems(); instance.removeHighlightedItems();
const activeItems = items.some((item) => item.active === true); const activeItems = items.some(item => item.active === true);
expect(activeItems).to.be.false; expect(activeItems).to.be.false;
}); });
@ -771,14 +767,14 @@ describe('Choices', () => {
{ {
value: 'Child One', value: 'Child One',
label: 'Child One', label: 'Child One',
selected: true selected: true,
}, { }, {
value: 'Child Two', value: 'Child Two',
label: 'Child Two', label: 'Child Two',
disabled: true disabled: true,
}, { }, {
value: 'Child Three', value: 'Child Three',
label: 'Child Three' label: 'Child Three',
}, },
], ],
}, { }, {
@ -789,13 +785,13 @@ describe('Choices', () => {
{ {
value: 'Child Four', value: 'Child Four',
label: 'Child Four', label: 'Child Four',
disabled: true disabled: true,
}, { }, {
value: 'Child Five', value: 'Child Five',
label: 'Child Five' label: 'Child Five',
}, { }, {
value: 'Child Six', value: 'Child Six',
label: 'Child Six' label: 'Child Six',
}, },
], ],
}], 'value', 'label'); }], 'value', 'label');
@ -813,10 +809,10 @@ describe('Choices', () => {
it('should handle setChoices() with blank values', () => { it('should handle setChoices() with blank values', () => {
instance.setChoices([{ instance.setChoices([{
label: 'Choice one', label: 'Choice one',
value: 'one' value: 'one',
}, { }, {
label: 'Choice two', label: 'Choice two',
value: '' value: '',
}], 'value', 'label', true); }], 'value', 'label', true);
@ -984,7 +980,7 @@ describe('Choices', () => {
it('shouldn\'t flip the dropdown', () => { it('shouldn\'t flip the dropdown', () => {
instance = new Choices(input, { instance = new Choices(input, {
position: 'bottom' position: 'bottom',
}); });
const container = instance.containerOuter; const container = instance.containerOuter;
@ -995,7 +991,7 @@ describe('Choices', () => {
it('should render selected choices', () => { it('should render selected choices', () => {
instance = new Choices(input, { instance = new Choices(input, {
renderSelectedChoices: 'always', renderSelectedChoices: 'always',
renderChoiceLimit: -1 renderChoiceLimit: -1,
}); });
const renderedChoices = instance.choiceList.querySelectorAll('.choices__item'); const renderedChoices = instance.choiceList.querySelectorAll('.choices__item');
@ -1005,7 +1001,7 @@ describe('Choices', () => {
it('shouldn\'t render selected choices', () => { it('shouldn\'t render selected choices', () => {
instance = new Choices(input, { instance = new Choices(input, {
renderSelectedChoices: 'auto', renderSelectedChoices: 'auto',
renderChoiceLimit: -1 renderChoiceLimit: -1,
}); });
const renderedChoices = instance.choiceList.querySelectorAll('.choices__item'); const renderedChoices = instance.choiceList.querySelectorAll('.choices__item');
@ -1042,7 +1038,7 @@ describe('Choices', () => {
}, },
], ],
renderSelectedChoices: 'auto', renderSelectedChoices: 'auto',
renderChoiceLimit: 4 renderChoiceLimit: 4,
}); });
const renderedChoices = instance.choiceList.querySelectorAll('.choices__item'); const renderedChoices = instance.choiceList.querySelectorAll('.choices__item');
@ -1059,9 +1055,9 @@ describe('Choices', () => {
value: 'value', value: 'value',
label: 'label', label: 'label',
customProperties: { customProperties: {
foo: 'bar' foo: 'bar',
}, },
keyCode: null keyCode: null,
}; };
const expectedState = [{ const expectedState = [{
@ -1073,7 +1069,7 @@ describe('Choices', () => {
active: true, active: true,
highlighted: false, highlighted: false,
customProperties: randomItem.customProperties, customProperties: randomItem.customProperties,
keyCode: randomItem.keyCode keyCode: randomItem.keyCode,
}]; }];
const action = addItemAction( const action = addItemAction(
@ -1083,7 +1079,7 @@ describe('Choices', () => {
randomItem.choiceId, randomItem.choiceId,
randomItem.groupId, randomItem.groupId,
randomItem.customProperties, randomItem.customProperties,
randomItem.keyCode randomItem.keyCode,
); );
expect(itemReducer([], action)).to.deep.equal(expectedState); expect(itemReducer([], action)).to.deep.equal(expectedState);
@ -1098,9 +1094,9 @@ describe('Choices', () => {
label: 'label', label: 'label',
disabled: false, disabled: false,
customProperties: { customProperties: {
foo: 'bar' foo: 'bar',
}, },
keyCode: null keyCode: null,
}; };
const expectedState = [{ const expectedState = [{
@ -1114,7 +1110,7 @@ describe('Choices', () => {
active: true, active: true,
score: 9999, score: 9999,
customProperties: randomChoice.customProperties, customProperties: randomChoice.customProperties,
keyCode: randomChoice.keyCode keyCode: randomChoice.keyCode,
}]; }];
const action = addChoiceAction( const action = addChoiceAction(
@ -1125,7 +1121,7 @@ describe('Choices', () => {
randomChoice.disabled, randomChoice.disabled,
randomChoice.elementId, randomChoice.elementId,
randomChoice.customProperties, randomChoice.customProperties,
randomChoice.keyCode randomChoice.keyCode,
); );
expect(choiceReducer([], action)).to.deep.equal(expectedState); expect(choiceReducer([], action)).to.deep.equal(expectedState);
@ -1150,7 +1146,7 @@ describe('Choices', () => {
it('should allow the user to supply custom properties for a choice that will be inherited by the item when the user selects the choice', () => { it('should allow the user to supply custom properties for a choice that will be inherited by the item when the user selects the choice', () => {
const expectedCustomProperties = { const expectedCustomProperties = {
isBestOptionEver: true isBestOptionEver: true,
}; };
instance = new Choices(input); instance = new Choices(input);
@ -1159,7 +1155,7 @@ describe('Choices', () => {
label: 'My awesome choice', label: 'My awesome choice',
selected: false, selected: false,
disabled: false, disabled: false,
customProperties: expectedCustomProperties customProperties: expectedCustomProperties,
}], 'value', 'label', true); }], 'value', 'label', true);
instance.setValueByChoice('42'); instance.setValueByChoice('42');
@ -1171,7 +1167,7 @@ describe('Choices', () => {
it('should allow the user to supply custom properties when directly creating a selected item', () => { it('should allow the user to supply custom properties when directly creating a selected item', () => {
const expectedCustomProperties = { const expectedCustomProperties = {
isBestOptionEver: true isBestOptionEver: true,
}; };
instance = new Choices(input); instance = new Choices(input);
@ -1179,7 +1175,7 @@ describe('Choices', () => {
instance.setValue([{ instance.setValue([{
value: 'bar', value: 'bar',
label: 'foo', label: 'foo',
customProperties: expectedCustomProperties customProperties: expectedCustomProperties,
}]); }]);
const selectedItems = instance.getValue(); const selectedItems = instance.getValue();

View file

@ -2,13 +2,13 @@ import 'whatwg-fetch';
import 'es6-promise'; import 'es6-promise';
import 'core-js/fn/object/assign'; import 'core-js/fn/object/assign';
import 'core-js/fn/array/includes'; import 'core-js/fn/array/includes';
import Choices from '../../src/scripts/src/choices.js'; import Choices from '../../src/scripts/src/choices';
import itemReducer from '../../src/scripts/src/reducers/items.js'; import itemReducer from '../../src/scripts/src/reducers/items';
import choiceReducer from '../../src/scripts/src/reducers/choices.js'; import choiceReducer from '../../src/scripts/src/reducers/choices';
import { import {
addItem as addItemAction, addItem as addItemAction,
addChoice as addChoiceAction, addChoice as addChoiceAction,
} from '../../assets/scripts/src/actions/actions'; } from '../../src/scripts/src/actions/actions';
describe('Choices', () => { describe('Choices', () => {
describe('should initialize Choices', () => { describe('should initialize Choices', () => {