mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-08 00:42:15 +02:00
ESLint entire project
This commit is contained in:
parent
330eb73594
commit
9f0dc2c8dc
10
.eslintrc
10
.eslintrc
|
@ -10,5 +10,15 @@
|
||||||
"rules": {
|
"rules": {
|
||||||
"quotes": [2, "single"],
|
"quotes": [2, "single"],
|
||||||
"strict": [2, "never"],
|
"strict": [2, "never"],
|
||||||
|
"indent": ["error", 4, {"SwitchCase": 1}],
|
||||||
|
"eol-last": "off",
|
||||||
|
"arrow-body-style": "off",
|
||||||
|
"no-underscore-dangle": "off",
|
||||||
|
"no-new": 0,
|
||||||
|
"max-len": "off",
|
||||||
|
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||||
|
"consistent-return": "off",
|
||||||
|
"no-param-reassign": ["error", { "props": false }],
|
||||||
|
"no-unused-vars": ["error", { "args": "none" }]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
8
.eslintrc.js
Normal file
8
.eslintrc.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = {
|
||||||
|
"extends": "airbnb",
|
||||||
|
"plugins": [
|
||||||
|
"react",
|
||||||
|
"jsx-a11y",
|
||||||
|
"import"
|
||||||
|
]
|
||||||
|
};
|
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
|
@ -6,7 +6,7 @@ export const addItem = (value, label, id, choiceId, activateOptions) => {
|
||||||
id,
|
id,
|
||||||
choiceId,
|
choiceId,
|
||||||
activateOptions,
|
activateOptions,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeItem = (id, choiceId) => {
|
export const removeItem = (id, choiceId) => {
|
||||||
|
@ -14,7 +14,7 @@ export const removeItem = (id, choiceId) => {
|
||||||
type: 'REMOVE_ITEM',
|
type: 'REMOVE_ITEM',
|
||||||
id,
|
id,
|
||||||
choiceId,
|
choiceId,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const highlightItem = (id, highlighted) => {
|
export const highlightItem = (id, highlighted) => {
|
||||||
|
@ -22,7 +22,7 @@ export const highlightItem = (id, highlighted) => {
|
||||||
type: 'HIGHLIGHT_ITEM',
|
type: 'HIGHLIGHT_ITEM',
|
||||||
id,
|
id,
|
||||||
highlighted,
|
highlighted,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addChoice = (value, label, id, groupId, disabled) => {
|
export const addChoice = (value, label, id, groupId, disabled) => {
|
||||||
|
@ -33,21 +33,21 @@ export const addChoice = (value, label, id, groupId, disabled) => {
|
||||||
id,
|
id,
|
||||||
groupId,
|
groupId,
|
||||||
disabled,
|
disabled,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterChoices = (results) => {
|
export const filterChoices = (results) => {
|
||||||
return {
|
return {
|
||||||
type: 'FILTER_CHOICES',
|
type: 'FILTER_CHOICES',
|
||||||
results,
|
results,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const activateChoices = (active = true) => {
|
export const activateChoices = (active = true) => {
|
||||||
return {
|
return {
|
||||||
type: 'ACTIVATE_CHOICES',
|
type: 'ACTIVATE_CHOICES',
|
||||||
active,
|
active,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addGroup = (value, id, active, disabled) => {
|
export const addGroup = (value, id, active, disabled) => {
|
||||||
|
@ -57,11 +57,11 @@ export const addGroup = (value, id, active, disabled) => {
|
||||||
id,
|
id,
|
||||||
active,
|
active,
|
||||||
disabled,
|
disabled,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clearAll = () => {
|
export const clearAll = () => {
|
||||||
return {
|
return {
|
||||||
type: 'CLEAR_ALL',
|
type: 'CLEAR_ALL',
|
||||||
}
|
};
|
||||||
};
|
};
|
|
@ -1,17 +1,36 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import './lib/polyfills.js';
|
|
||||||
import { addItem, removeItem, highlightItem, addChoice, filterChoices, activateChoices, addGroup, clearAll } from './actions/index';
|
|
||||||
import { isScrolledIntoView, getAdjacentEl, findAncestor, wrap, isType, isElement, strToEl, extend, getWidthOfInput, debounce, sortByAlpha, sortByScore } from './lib/utils.js';
|
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import Store from './store/index.js';
|
import Store from './store/index.js';
|
||||||
|
import {
|
||||||
|
addItem,
|
||||||
|
removeItem,
|
||||||
|
highlightItem,
|
||||||
|
addChoice,
|
||||||
|
filterChoices,
|
||||||
|
activateChoices,
|
||||||
|
addGroup,
|
||||||
|
clearAll,
|
||||||
|
} from './actions/index';
|
||||||
|
|
||||||
|
import {
|
||||||
|
isScrolledIntoView,
|
||||||
|
getAdjacentEl,
|
||||||
|
wrap,
|
||||||
|
isType,
|
||||||
|
isElement,
|
||||||
|
strToEl,
|
||||||
|
extend,
|
||||||
|
getWidthOfInput,
|
||||||
|
sortByAlpha,
|
||||||
|
sortByScore,
|
||||||
|
} from './lib/utils.js';
|
||||||
|
import './lib/polyfills.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choices
|
* Choices
|
||||||
*/
|
*/
|
||||||
export class Choices {
|
export default class Choices {
|
||||||
constructor(element = '[data-choice]', userConfig = {}) {
|
constructor(element = '[data-choice]', userConfig = {}) {
|
||||||
|
|
||||||
// If there are multiple elements, create a new instance
|
// If there are multiple elements, create a new instance
|
||||||
// for each element besides the first one (as that already has an instance)
|
// for each element besides the first one (as that already has an instance)
|
||||||
if (isType('String', element)) {
|
if (isType('String', element)) {
|
||||||
|
@ -135,7 +154,7 @@ export class Choices {
|
||||||
this.wasTap = true;
|
this.wasTap = true;
|
||||||
|
|
||||||
// Cutting the mustard
|
// Cutting the mustard
|
||||||
const cuttingTheMustard = 'querySelector' in document && 'addEventListener' in document && 'classList' in document.createElement("div");
|
const cuttingTheMustard = 'querySelector' in document && 'addEventListener' in document && 'classList' in document.createElement('div');
|
||||||
if (!cuttingTheMustard) console.error('Choices: Your browser doesn\'t support Choices');
|
if (!cuttingTheMustard) console.error('Choices: Your browser doesn\'t support Choices');
|
||||||
|
|
||||||
// Input type check
|
// Input type check
|
||||||
|
@ -157,9 +176,9 @@ export class Choices {
|
||||||
* @return
|
* @return
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
init(callback) {
|
init(callback = this.config.callbackOnInit) {
|
||||||
if (this.initialised !== true) {
|
if (this.initialised !== true) {
|
||||||
|
// Set initialise flag
|
||||||
this.initialised = true;
|
this.initialised = true;
|
||||||
|
|
||||||
// Create required elements
|
// Create required elements
|
||||||
|
@ -177,7 +196,7 @@ export class Choices {
|
||||||
this._addEventListeners();
|
this._addEventListeners();
|
||||||
|
|
||||||
// Run callback if it is a function
|
// Run callback if it is a function
|
||||||
if(callback = this.config.callbackOnInit){
|
if (callback) {
|
||||||
if (isType('Function', callback)) {
|
if (isType('Function', callback)) {
|
||||||
callback();
|
callback();
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,7 +420,7 @@ export class Choices {
|
||||||
toggleDropdown() {
|
toggleDropdown() {
|
||||||
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
||||||
if (hasActiveDropdown) {
|
if (hasActiveDropdown) {
|
||||||
this.hideDropdown()
|
this.hideDropdown();
|
||||||
} else {
|
} else {
|
||||||
this.showDropdown();
|
this.showDropdown();
|
||||||
}
|
}
|
||||||
|
@ -417,7 +436,7 @@ export class Choices {
|
||||||
*/
|
*/
|
||||||
getValue(valueOnly = false) {
|
getValue(valueOnly = false) {
|
||||||
const items = this.store.getItemsFilteredByActive();
|
const items = this.store.getItemsFilteredByActive();
|
||||||
let selectedItems = [];
|
const selectedItems = [];
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
if (this.passedElement.type === 'text') {
|
if (this.passedElement.type === 'text') {
|
||||||
|
@ -427,11 +446,11 @@ export class Choices {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.passedElement.type == 'select-one') {
|
if (this.passedElement.type === 'select-one') {
|
||||||
return selectedItems[0];
|
return selectedItems[0];
|
||||||
} else {
|
|
||||||
return selectedItems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return selectedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -446,7 +465,7 @@ export class Choices {
|
||||||
// Convert args to an itterable array
|
// Convert args to an itterable array
|
||||||
const values = [...args];
|
const values = [...args];
|
||||||
|
|
||||||
values.forEach((item, index) => {
|
values.forEach((item) => {
|
||||||
if (isType('Object', item)) {
|
if (isType('Object', item)) {
|
||||||
if (!item.value) return;
|
if (!item.value) return;
|
||||||
// If we are dealing with a select input, we need to create an option first
|
// If we are dealing with a select input, we need to create an option first
|
||||||
|
@ -478,15 +497,11 @@ export class Choices {
|
||||||
setValueByChoice(value) {
|
setValueByChoice(value) {
|
||||||
if (this.passedElement.type !== 'text') {
|
if (this.passedElement.type !== 'text') {
|
||||||
const choices = this.store.getChoices();
|
const choices = this.store.getChoices();
|
||||||
|
|
||||||
// If only one value has been passed, convert to array
|
// If only one value has been passed, convert to array
|
||||||
if (!isType('Array', value)) {
|
const choiceValue = isType('Array', value) ? value : [value];
|
||||||
value = [value];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through each value and
|
// Loop through each value and
|
||||||
value.forEach((val, index) => {
|
choiceValue.forEach((val) => {
|
||||||
|
|
||||||
const foundChoice = choices.find((choice) => {
|
const foundChoice = choices.find((choice) => {
|
||||||
// Check 'value' property exists and the choice isn't already selected
|
// Check 'value' property exists and the choice isn't already selected
|
||||||
return choice.value === val;
|
return choice.value === val;
|
||||||
|
@ -501,7 +516,7 @@ export class Choices {
|
||||||
} else {
|
} else {
|
||||||
console.warn('Attempting to select choice that does not exist');
|
console.warn('Attempting to select choice that does not exist');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -523,8 +538,7 @@ export class Choices {
|
||||||
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
this.containerOuter.classList.remove(this.config.classNames.loadingState);
|
||||||
choices.forEach((result, index) => {
|
choices.forEach((result, index) => {
|
||||||
if (result.choices) {
|
if (result.choices) {
|
||||||
const isFirst = index === 0 ? true : false;
|
this._addGroup(result, index);
|
||||||
this._addGroup(result, index, isFirst);
|
|
||||||
} else {
|
} else {
|
||||||
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
this._addChoice(result.selected ? result.selected : false, result.disabled ? result.disabled : false, result[value], result[label]);
|
||||||
}
|
}
|
||||||
|
@ -608,7 +622,13 @@ export class Choices {
|
||||||
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
this.containerOuter.classList.add(this.config.classNames.loadingState);
|
||||||
this.containerOuter.setAttribute('aria-busy', 'true');
|
this.containerOuter.setAttribute('aria-busy', 'true');
|
||||||
if (this.passedElement.type === 'select-one') {
|
if (this.passedElement.type === 'select-one') {
|
||||||
const placeholderItem = this._getTemplate('item', { id: -1, value: 'Loading', label: this.config.loadingText, active: true});
|
const placeholderItem = this._getTemplate('item', {
|
||||||
|
id: -1,
|
||||||
|
value: 'Loading',
|
||||||
|
label: this.config.loadingText,
|
||||||
|
active: true,
|
||||||
|
});
|
||||||
|
|
||||||
this.itemList.appendChild(placeholderItem);
|
this.itemList.appendChild(placeholderItem);
|
||||||
} else {
|
} else {
|
||||||
this.input.placeholder = this.config.loadingText;
|
this.input.placeholder = this.config.loadingText;
|
||||||
|
@ -680,7 +700,7 @@ export class Choices {
|
||||||
// If we are clicking on a button
|
// If we are clicking on a button
|
||||||
if (this.config.removeItems && this.config.removeItemButton) {
|
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));
|
const itemToRemove = activeItems.find((item) => item.id === parseInt(itemId, 10));
|
||||||
|
|
||||||
// Remove item associated with button
|
// Remove item associated with button
|
||||||
this._removeItem(itemToRemove);
|
this._removeItem(itemToRemove);
|
||||||
|
@ -707,7 +727,7 @@ export class Choices {
|
||||||
// so we deselect any items that aren't the target
|
// so we deselect any items that aren't the target
|
||||||
// unless shift is being pressed
|
// unless shift is being pressed
|
||||||
activeItems.forEach((item) => {
|
activeItems.forEach((item) => {
|
||||||
if(item.id === parseInt(passedId) && !item.highlighted) {
|
if (item.id === parseInt(passedId, 10) && !item.highlighted) {
|
||||||
this.highlightItem(item);
|
this.highlightItem(item);
|
||||||
} else if (!hasShiftKey) {
|
} else if (!hasShiftKey) {
|
||||||
if (item.highlighted) {
|
if (item.highlighted) {
|
||||||
|
@ -736,8 +756,6 @@ export class Choices {
|
||||||
const choice = this.store.getChoiceById(id);
|
const choice = this.store.getChoiceById(id);
|
||||||
|
|
||||||
if (choice && !choice.selected && !choice.disabled) {
|
if (choice && !choice.selected && !choice.disabled) {
|
||||||
|
|
||||||
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
|
||||||
let canAddItem = true;
|
let canAddItem = true;
|
||||||
|
|
||||||
if (this.config.maxItemCount > 0 && this.config.maxItemCount <= activeItems.length && this.passedElement.type === 'select-multiple') {
|
if (this.config.maxItemCount > 0 && this.config.maxItemCount <= activeItems.length && this.passedElement.type === 'select-multiple') {
|
||||||
|
@ -751,14 +769,13 @@ export class Choices {
|
||||||
|
|
||||||
if (this.passedElement.type === 'select-one') {
|
if (this.passedElement.type === 'select-one') {
|
||||||
if (this.canSearch) {
|
if (this.canSearch) {
|
||||||
this.input.value = "";
|
this.input.value = '';
|
||||||
}
|
}
|
||||||
this.isSearching = false;
|
this.isSearching = false;
|
||||||
this.store.dispatch(activateChoices(true));
|
this.store.dispatch(activateChoices(true));
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -783,7 +800,7 @@ export class Choices {
|
||||||
this.removeHighlightedItems();
|
this.removeHighlightedItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates whether an item can be added by a user
|
* Validates whether an item can be added by a user
|
||||||
|
@ -819,13 +836,13 @@ export class Choices {
|
||||||
// in the array
|
// in the array
|
||||||
if (this.config.duplicateItems === false && !isUnique) {
|
if (this.config.duplicateItems === false && !isUnique) {
|
||||||
canAddItem = false;
|
canAddItem = false;
|
||||||
notice = `Only unique values can be added.`;
|
notice = 'Only unique values can be added.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: canAddItem,
|
response: canAddItem,
|
||||||
notice: notice,
|
notice,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,12 +864,12 @@ export class Choices {
|
||||||
const newValue = isType('String', value) ? value.trim() : value;
|
const newValue = isType('String', value) ? value.trim() : value;
|
||||||
const currentValue = isType('String', this.currentValue) ? this.currentValue.trim() : this.currentValue;
|
const currentValue = isType('String', this.currentValue) ? this.currentValue.trim() : this.currentValue;
|
||||||
|
|
||||||
if(newValue.length >= 1 && newValue !== currentValue + ' ') {
|
if (newValue.length >= 1 && newValue !== `${currentValue} `) {
|
||||||
const haystack = this.store.getChoicesFilteredBySelectable();
|
const haystack = this.store.getChoicesFilteredBySelectable();
|
||||||
const needle = newValue;
|
const needle = newValue;
|
||||||
const keys = isType('Array', this.config.sortFields) ? this.config.sortFields : [this.config.sortFields];
|
const keys = isType('Array', this.config.sortFields) ? this.config.sortFields : [this.config.sortFields];
|
||||||
const fuse = new Fuse(haystack, {
|
const fuse = new Fuse(haystack, {
|
||||||
keys: keys,
|
keys,
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
include: 'score',
|
include: 'score',
|
||||||
});
|
});
|
||||||
|
@ -944,8 +961,6 @@ export class Choices {
|
||||||
const downKey = 40;
|
const downKey = 40;
|
||||||
|
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
const activeChoices = this.store.getChoicesFilteredByActive();
|
|
||||||
|
|
||||||
const hasFocusedInput = this.input === document.activeElement;
|
const hasFocusedInput = this.input === document.activeElement;
|
||||||
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
||||||
const hasItems = this.itemList && this.itemList.children;
|
const hasItems = this.itemList && this.itemList.children;
|
||||||
|
@ -1029,7 +1044,6 @@ export class Choices {
|
||||||
case upKey:
|
case upKey:
|
||||||
// If up or down key is pressed, traverse through options
|
// If up or down key is pressed, traverse through options
|
||||||
if (hasActiveDropdown || this.passedElement.type === 'select-one') {
|
if (hasActiveDropdown || this.passedElement.type === 'select-one') {
|
||||||
|
|
||||||
// Show dropdown if focus
|
// Show dropdown if focus
|
||||||
if (!hasActiveDropdown) {
|
if (!hasActiveDropdown) {
|
||||||
this.showDropdown();
|
this.showDropdown();
|
||||||
|
@ -1063,7 +1077,7 @@ export class Choices {
|
||||||
// traversing dropdown options
|
// traversing dropdown options
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
case backKey:
|
case backKey:
|
||||||
case deleteKey:
|
case deleteKey:
|
||||||
|
@ -1071,7 +1085,7 @@ export class Choices {
|
||||||
if (hasFocusedInput && !e.target.value && this.passedElement.type !== 'select-one') {
|
if (hasFocusedInput && !e.target.value && this.passedElement.type !== 'select-one') {
|
||||||
this._handleBackspace(activeItems);
|
this._handleBackspace(activeItems);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1095,8 +1109,6 @@ export class Choices {
|
||||||
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
||||||
const value = this.input.value;
|
const value = this.input.value;
|
||||||
|
|
||||||
let dropdownItem;
|
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
const canAddItem = this._canAddItem(activeItems, value);
|
const canAddItem = this._canAddItem(activeItems, value);
|
||||||
|
@ -1110,17 +1122,12 @@ export class Choices {
|
||||||
if (!hasActiveDropdown) {
|
if (!hasActiveDropdown) {
|
||||||
this.showDropdown();
|
this.showDropdown();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!canAddItem.notice && hasActiveDropdown) {
|
||||||
if(!canAddItem.notice && hasActiveDropdown) {
|
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
}
|
} else if (hasActiveDropdown) {
|
||||||
} else {
|
|
||||||
if(hasActiveDropdown) {
|
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const backKey = 46;
|
const backKey = 46;
|
||||||
const deleteKey = 8;
|
const deleteKey = 8;
|
||||||
|
@ -1132,14 +1139,10 @@ export class Choices {
|
||||||
this.isSearching = false;
|
this.isSearching = false;
|
||||||
this.store.dispatch(activateChoices(true));
|
this.store.dispatch(activateChoices(true));
|
||||||
}
|
}
|
||||||
} else {
|
} else if (this.canSearch) {
|
||||||
// If we have enabled text search
|
|
||||||
if(this.canSearch) {
|
|
||||||
this._searchChoices(this.input.value);
|
this._searchChoices(this.input.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1148,7 +1151,7 @@ export class Choices {
|
||||||
* @return
|
* @return
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onInput(e) {
|
_onInput() {
|
||||||
if (this.passedElement.type !== 'select-one') {
|
if (this.passedElement.type !== 'select-one') {
|
||||||
if (this.config.placeholder && (this.config.placeholderValue || this.passedElement.getAttribute('placeholder'))) {
|
if (this.config.placeholder && (this.config.placeholderValue || this.passedElement.getAttribute('placeholder'))) {
|
||||||
// If there is a placeholder, we only want to set the width of the input when it is a greater
|
// If there is a placeholder, we only want to set the width of the input when it is a greater
|
||||||
|
@ -1170,7 +1173,7 @@ export class Choices {
|
||||||
* @return
|
* @return
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onTouchMove(e) {
|
_onTouchMove() {
|
||||||
if (this.wasTap === true) {
|
if (this.wasTap === true) {
|
||||||
this.wasTap = false;
|
this.wasTap = false;
|
||||||
}
|
}
|
||||||
|
@ -1187,7 +1190,6 @@ export class Choices {
|
||||||
|
|
||||||
// If a user tapped within our container...
|
// If a user tapped within our container...
|
||||||
if (this.wasTap === true && this.containerOuter.contains(target)) {
|
if (this.wasTap === true && this.containerOuter.contains(target)) {
|
||||||
|
|
||||||
// ...and we aren't dealing with a single select box, show dropdown/focus input
|
// ...and we aren't dealing with a single select box, show dropdown/focus input
|
||||||
if ((target === this.containerOuter || target === this.containerInner) && this.passedElement.type !== 'select-one') {
|
if ((target === this.containerOuter || target === this.containerInner) && this.passedElement.type !== 'select-one') {
|
||||||
if (this.passedElement.type === 'text') {
|
if (this.passedElement.type === 'text') {
|
||||||
|
@ -1203,7 +1205,6 @@ export class Choices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevents focus event firing
|
// Prevents focus event firing
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
@ -1221,9 +1222,8 @@ export class Choices {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
|
|
||||||
if (this.containerOuter.contains(target) && target !== this.input) {
|
if (this.containerOuter.contains(target) && target !== this.input) {
|
||||||
|
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
const hasShiftKey = e.shiftKey ? true : false;
|
const hasShiftKey = e.shiftKey;
|
||||||
|
|
||||||
// Prevent input mouse down triggering focus event
|
// Prevent input mouse down triggering focus event
|
||||||
if (target !== this.input) e.preventDefault();
|
if (target !== this.input) e.preventDefault();
|
||||||
|
@ -1249,11 +1249,6 @@ export class Choices {
|
||||||
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
const hasActiveDropdown = this.dropdown.classList.contains(this.config.classNames.activeState);
|
||||||
|
|
||||||
if (this.containerOuter.contains(target)) {
|
if (this.containerOuter.contains(target)) {
|
||||||
// If click is affecting a child node of our element
|
|
||||||
|
|
||||||
const hasShiftKey = e.shiftKey ? true : false;
|
|
||||||
|
|
||||||
// If dropdown is not active...
|
|
||||||
if (!hasActiveDropdown) {
|
if (!hasActiveDropdown) {
|
||||||
if (this.passedElement.type === 'text') {
|
if (this.passedElement.type === 'text') {
|
||||||
if (document.activeElement !== this.input) {
|
if (document.activeElement !== this.input) {
|
||||||
|
@ -1265,17 +1260,10 @@ export class Choices {
|
||||||
this.input.focus();
|
this.input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (this.passedElement.type === 'select-one' && target !== this.input) {
|
||||||
if(this.passedElement.type === 'select-one') {
|
|
||||||
if(target !== this.input) {
|
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Click is outside of our element so close dropdown and de-select items
|
|
||||||
|
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
const hasHighlightedItems = activeItems.some((item) => item.highlighted === true);
|
const hasHighlightedItems = activeItems.some((item) => item.highlighted === true);
|
||||||
|
|
||||||
|
@ -1302,7 +1290,7 @@ export class Choices {
|
||||||
*/
|
*/
|
||||||
_onMouseOver(e) {
|
_onMouseOver(e) {
|
||||||
// If the dropdown is either the target or one of its children is the target
|
// If the dropdown is either the target or one of its children is the target
|
||||||
if((e.target === this.dropdown || findAncestor(e.target, this.config.classNames.listDropdown))) {
|
if (e.target === this.dropdown || this.dropdown.contains(e.target)) {
|
||||||
if (e.target.hasAttribute('data-choice')) this._highlightChoice(e.target);
|
if (e.target.hasAttribute('data-choice')) this._highlightChoice(e.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1347,13 +1335,11 @@ export class Choices {
|
||||||
this.input.focus();
|
this.input.focus();
|
||||||
}
|
}
|
||||||
this.focusAndHideDropdown = false;
|
this.focusAndHideDropdown = false;
|
||||||
} else {
|
} else if (this.canSearch) {
|
||||||
if(this.canSearch) {
|
|
||||||
this.input.focus();
|
this.input.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blur event
|
* Blur event
|
||||||
|
@ -1373,7 +1359,7 @@ export class Choices {
|
||||||
|
|
||||||
// Close the dropdown if it is active, the input is the target (select-multiple, text, select-one (with search))
|
// Close the dropdown if it is active, the input is the target (select-multiple, text, select-one (with search))
|
||||||
// or the outer container is the target with no search (select-one)
|
// or the outer container is the target with no search (select-one)
|
||||||
if(hasActiveDropdown && (e.target === this.input || e.target === this.containerOuter && !this.canSearch)) {
|
if (hasActiveDropdown && (e.target === this.input || (e.target === this.containerOuter && !this.canSearch))) {
|
||||||
this.hideDropdown();
|
this.hideDropdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,12 +1403,13 @@ export class Choices {
|
||||||
const containerScrollPos = this.choiceList.scrollTop + dropdownHeight;
|
const containerScrollPos = this.choiceList.scrollTop + dropdownHeight;
|
||||||
|
|
||||||
// Difference between the choice and scroll position
|
// Difference between the choice and scroll position
|
||||||
let endPoint = direction > 0 ? ((this.choiceList.scrollTop + choicePos) - containerScrollPos) : choice.offsetTop;
|
const endPoint = direction > 0 ? ((this.choiceList.scrollTop + choicePos) - containerScrollPos) : choice.offsetTop;
|
||||||
|
|
||||||
const animateScroll = (time, endPoint, direction) => {
|
const animateScroll = () => {
|
||||||
let continueAnimation = false;
|
|
||||||
let easing, distance;
|
|
||||||
const strength = 4;
|
const strength = 4;
|
||||||
|
let continueAnimation = false;
|
||||||
|
let easing;
|
||||||
|
let distance;
|
||||||
|
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
easing = (endPoint - this.choiceList.scrollTop) / strength;
|
easing = (endPoint - this.choiceList.scrollTop) / strength;
|
||||||
|
@ -1468,9 +1455,9 @@ export class Choices {
|
||||||
const highlightedChoices = Array.from(this.dropdown.querySelectorAll(`.${this.config.classNames.highlightedState}`));
|
const highlightedChoices = Array.from(this.dropdown.querySelectorAll(`.${this.config.classNames.highlightedState}`));
|
||||||
|
|
||||||
// Remove any highlighted choices
|
// Remove any highlighted choices
|
||||||
highlightedChoices.forEach((el) => {
|
highlightedChoices.forEach((choice) => {
|
||||||
el.classList.remove(this.config.classNames.highlightedState);
|
choice.classList.remove(this.config.classNames.highlightedState);
|
||||||
el.setAttribute('aria-selected', 'false');
|
choice.setAttribute('aria-selected', 'false');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
|
@ -1478,20 +1465,20 @@ export class Choices {
|
||||||
el.classList.add(this.config.classNames.highlightedState);
|
el.classList.add(this.config.classNames.highlightedState);
|
||||||
this.highlightPosition = choices.indexOf(el);
|
this.highlightPosition = choices.indexOf(el);
|
||||||
} else {
|
} else {
|
||||||
// Highlight option based on last known highlight location
|
// Highlight choice based on last known highlight location
|
||||||
let el;
|
let choice;
|
||||||
|
|
||||||
if (choices.length > this.highlightPosition) {
|
if (choices.length > this.highlightPosition) {
|
||||||
// If we have an option to highlight
|
// If we have an option to highlight
|
||||||
el = choices[this.highlightPosition];
|
choice = choices[this.highlightPosition];
|
||||||
} else {
|
} else {
|
||||||
// Otherwise highlight the option before
|
// Otherwise highlight the option before
|
||||||
el = choices[choices.length - 1];
|
choice = choices[choices.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!el) el = choices[0];
|
if (!choice) choice = choices[0];
|
||||||
el.classList.add(this.config.classNames.highlightedState);
|
choice.classList.add(this.config.classNames.highlightedState);
|
||||||
el.setAttribute('aria-selected', 'true');
|
choice.setAttribute('aria-selected', 'true');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1504,10 +1491,10 @@ export class Choices {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
_addItem(value, label, choiceId = -1) {
|
_addItem(value, label, choiceId = -1) {
|
||||||
const items = this.store.getItems();
|
|
||||||
let passedValue = isType('String', value) ? value.trim() : value;
|
let passedValue = isType('String', value) ? value.trim() : value;
|
||||||
let passedLabel = label || passedValue;
|
const items = this.store.getItems();
|
||||||
let passedOptionId = parseInt(choiceId) || -1;
|
const passedLabel = label || passedValue;
|
||||||
|
const passedOptionId = parseInt(choiceId, 10) || -1;
|
||||||
|
|
||||||
// If a prepended value has been passed, prepend it
|
// If a prepended value has been passed, prepend it
|
||||||
if (this.config.prependValue) {
|
if (this.config.prependValue) {
|
||||||
|
@ -1516,7 +1503,7 @@ export class Choices {
|
||||||
|
|
||||||
// If an appended value has been passed, append it
|
// If an appended value has been passed, append it
|
||||||
if (this.config.appendValue) {
|
if (this.config.appendValue) {
|
||||||
passedValue = passedValue + this.config.appendValue.toString();
|
passedValue += this.config.appendValue.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate unique id
|
// Generate unique id
|
||||||
|
@ -1583,18 +1570,17 @@ export class Choices {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_addChoice(isSelected, isDisabled, value, label, groupId = -1) {
|
_addChoice(isSelected, isDisabled, value, label, groupId = -1) {
|
||||||
if(!value) return
|
if (!value) return;
|
||||||
|
|
||||||
if(!label) { label = value; }
|
|
||||||
|
|
||||||
// Generate unique id
|
// Generate unique id
|
||||||
const choices = this.store.getChoices();
|
const choices = this.store.getChoices();
|
||||||
const id = choices ? choices.length + 1 : 1;
|
const choiceLabel = label || value;
|
||||||
|
const choiceId = choices ? choices.length + 1 : 1;
|
||||||
|
|
||||||
this.store.dispatch(addChoice(value, label, id, groupId, isDisabled));
|
this.store.dispatch(addChoice(value, choiceLabel, choiceId, groupId, isDisabled));
|
||||||
|
|
||||||
if (isSelected && !isDisabled) {
|
if (isSelected && !isDisabled) {
|
||||||
this._addItem(value, label, id);
|
this._addItem(value, choiceLabel, choiceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1602,11 +1588,10 @@ export class Choices {
|
||||||
* Add group to dropdown
|
* Add group to dropdown
|
||||||
* @param {Object} group Group to add
|
* @param {Object} group Group to add
|
||||||
* @param {Number} id Group ID
|
* @param {Number} id Group ID
|
||||||
* @param {Boolean} isFirst Whether this is the first group to add
|
|
||||||
* @return
|
* @return
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_addGroup(group, id, isFirst) {
|
_addGroup(group, id) {
|
||||||
const groupChoices = isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION'));
|
const groupChoices = isType('Object', group) ? group.choices : Array.from(group.getElementsByTagName('OPTION'));
|
||||||
const groupId = id;
|
const groupId = id;
|
||||||
const isDisabled = group.disabled ? group.disabled : false;
|
const isDisabled = group.disabled ? group.disabled : false;
|
||||||
|
@ -1614,10 +1599,9 @@ export class Choices {
|
||||||
if (groupChoices) {
|
if (groupChoices) {
|
||||||
this.store.dispatch(addGroup(group.label, groupId, true, isDisabled));
|
this.store.dispatch(addGroup(group.label, groupId, true, isDisabled));
|
||||||
|
|
||||||
|
groupChoices.forEach((option) => {
|
||||||
groupChoices.forEach((option, index) => {
|
const isOptDisabled = (option.disabled || (option.parentNode && option.parentNode.disabled)) || false;
|
||||||
const isDisabled = (option.disabled || option.parentNode && option.parentNode.disabled) || false;
|
const isOptSelected = option.selected ? option.selected : false;
|
||||||
const isSelected = option.selected ? option.selected : false;
|
|
||||||
let label;
|
let label;
|
||||||
|
|
||||||
if (isType('Object', option)) {
|
if (isType('Object', option)) {
|
||||||
|
@ -1626,8 +1610,7 @@ export class Choices {
|
||||||
label = option.innerHTML;
|
label = option.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addChoice(isSelected, isDisabled, option.value, label, groupId);
|
this._addChoice(isOptSelected, isOptDisabled, option.value, label, groupId);
|
||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.store.dispatch(addGroup(group.label, group.id, false, group.disabled));
|
this.store.dispatch(addGroup(group.label, group.id, false, group.disabled));
|
||||||
|
@ -1678,13 +1661,13 @@ export class Choices {
|
||||||
<button class="${classNames.button}" data-button>Remove item</button>
|
<button class="${classNames.button}" data-button>Remove item</button>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
<div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''}>
|
<div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}" ${data.active ? 'aria-selected="true"' : ''} ${data.disabled ? 'aria-disabled="true"' : ''}>
|
||||||
${data.label}
|
${data.label}
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
choiceList: () => {
|
choiceList: () => {
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
|
@ -1715,7 +1698,7 @@ export class Choices {
|
||||||
<div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false"></div>
|
<div class="${classNames.list} ${classNames.listDropdown}" aria-expanded="false"></div>
|
||||||
`);
|
`);
|
||||||
},
|
},
|
||||||
notice: (label, clickable) => {
|
notice: (label) => {
|
||||||
return strToEl(`
|
return strToEl(`
|
||||||
<div class="${classNames.item} ${classNames.itemChoice}">${label}</div>
|
<div class="${classNames.item} ${classNames.itemChoice}">${label}</div>
|
||||||
`);
|
`);
|
||||||
|
@ -1796,12 +1779,11 @@ export class Choices {
|
||||||
|
|
||||||
if (passedGroups && passedGroups.length) {
|
if (passedGroups && passedGroups.length) {
|
||||||
passedGroups.forEach((group, index) => {
|
passedGroups.forEach((group, index) => {
|
||||||
const isFirst = index === 0 ? true : false;
|
this._addGroup(group, index);
|
||||||
this._addGroup(group, index, isFirst);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const passedOptions = Array.from(this.passedElement.options);
|
const passedOptions = Array.from(this.passedElement.options);
|
||||||
let allChoices = [];
|
const allChoices = [];
|
||||||
|
|
||||||
// Create array of options from option elements
|
// Create array of options from option elements
|
||||||
passedOptions.forEach((o) => {
|
passedOptions.forEach((o) => {
|
||||||
|
@ -1809,7 +1791,7 @@ export class Choices {
|
||||||
value: o.value,
|
value: o.value,
|
||||||
label: o.innerHTML,
|
label: o.innerHTML,
|
||||||
selected: o.selected,
|
selected: o.selected,
|
||||||
disabled: o.disabled || o.parentNode.disabled
|
disabled: o.disabled || o.parentNode.disabled,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1851,19 +1833,18 @@ export class Choices {
|
||||||
|
|
||||||
groups
|
groups
|
||||||
.sort(filter)
|
.sort(filter)
|
||||||
.forEach((group, i) => {
|
.forEach((group) => {
|
||||||
// Grab options that are children of this group
|
// Grab options that are children of this group
|
||||||
const groupChoices = choices.filter((choice) => {
|
const groupChoices = choices.filter((choice) => {
|
||||||
if (this.passedElement.type === 'select-one') {
|
if (this.passedElement.type === 'select-one') {
|
||||||
return choice.groupId === group.id
|
return choice.groupId === group.id;
|
||||||
} else {
|
|
||||||
return choice.groupId === group.id && !choice.selected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return choice.groupId === group.id && !choice.selected;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (groupChoices.length >= 1) {
|
if (groupChoices.length >= 1) {
|
||||||
const dropdownGroup = this._getTemplate('choiceGroup', group);
|
const dropdownGroup = this._getTemplate('choiceGroup', group);
|
||||||
|
|
||||||
groupFragment.appendChild(dropdownGroup);
|
groupFragment.appendChild(dropdownGroup);
|
||||||
|
|
||||||
this.renderChoices(groupChoices, groupFragment);
|
this.renderChoices(groupChoices, groupFragment);
|
||||||
|
@ -1887,9 +1868,8 @@ export class Choices {
|
||||||
|
|
||||||
choices
|
choices
|
||||||
.sort(filter)
|
.sort(filter)
|
||||||
.forEach((choice, i) => {
|
.forEach((choice) => {
|
||||||
const dropdownItem = this._getTemplate('choice', choice);
|
const dropdownItem = this._getTemplate('choice', choice);
|
||||||
|
|
||||||
if (this.passedElement.type === 'select-one') {
|
if (this.passedElement.type === 'select-one') {
|
||||||
choicesFragment.appendChild(dropdownItem);
|
choicesFragment.appendChild(dropdownItem);
|
||||||
} else if (!choice.selected) {
|
} else if (!choice.selected) {
|
||||||
|
@ -1929,7 +1909,7 @@ export class Choices {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update selected choices
|
// Update selected choices
|
||||||
this.passedElement.innerHTML = "";
|
this.passedElement.innerHTML = '';
|
||||||
this.passedElement.appendChild(selectedOptionsFragment);
|
this.passedElement.appendChild(selectedOptionsFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1955,7 +1935,6 @@ export class Choices {
|
||||||
|
|
||||||
// Only render if our state has actually changed
|
// Only render if our state has actually changed
|
||||||
if (this.currentState !== this.prevState) {
|
if (this.currentState !== this.prevState) {
|
||||||
|
|
||||||
// Choices
|
// Choices
|
||||||
if ((this.currentState.choices !== this.prevState.choices || this.currentState.groups !== this.prevState.groups)) {
|
if ((this.currentState.choices !== this.prevState.choices || this.currentState.groups !== this.prevState.groups)) {
|
||||||
if (this.passedElement.type === 'select-multiple' || this.passedElement.type === 'select-one') {
|
if (this.passedElement.type === 'select-multiple' || this.passedElement.type === 'select-one') {
|
||||||
|
@ -1994,7 +1973,8 @@ export class Choices {
|
||||||
if (this.currentState.items !== this.prevState.items) {
|
if (this.currentState.items !== this.prevState.items) {
|
||||||
const activeItems = this.store.getItemsFilteredByActive();
|
const activeItems = this.store.getItemsFilteredByActive();
|
||||||
if (activeItems) {
|
if (activeItems) {
|
||||||
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
|
// Create a fragment to store our list items
|
||||||
|
// (so we don't have to update the DOM for each item)
|
||||||
const itemListFragment = this.renderItems(activeItems);
|
const itemListFragment = this.renderItems(activeItems);
|
||||||
|
|
||||||
// Clear list
|
// Clear list
|
||||||
|
@ -2011,6 +1991,6 @@ export class Choices {
|
||||||
this.prevState = this.currentState;
|
this.prevState = this.currentState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
window.Choices = module.exports = Choices;
|
window.Choices = module.exports = Choices;
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
// Production steps of ECMA-262, Edition 6, 22.1.2.1
|
// Production steps of ECMA-262, Edition 6, 22.1.2.1
|
||||||
// Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
|
// Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
|
||||||
if (!Array.from) {
|
if (!Array.from) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
export const hasClass = (elem, className) => {
|
/* eslint-disable */
|
||||||
return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capitalises the first letter of each word in a string
|
* Capitalises the first letter of each word in a string
|
||||||
|
@ -46,7 +44,7 @@ export const isElement = (o) => {
|
||||||
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
|
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
|
||||||
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
|
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges unspecified amount of objects into new object
|
* Merges unspecified amount of objects into new object
|
||||||
|
@ -111,7 +109,7 @@ export const whichTransitionEvent = function(){
|
||||||
return transitions[t];
|
return transitions[t];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSS animation end event listener
|
* CSS animation end event listener
|
||||||
|
@ -374,7 +372,7 @@ export const isScrolledIntoView = (el, parent, direction = 1) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return isVisible;
|
return isVisible;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove html tags from a string
|
* Remove html tags from a string
|
||||||
|
@ -414,7 +412,7 @@ export const addAnimation = (el, animation) => {
|
||||||
*/
|
*/
|
||||||
export const getRandomNumber = function(min, max) {
|
export const getRandomNumber = function(min, max) {
|
||||||
return Math.floor(Math.random() * (max - min) + min);
|
return Math.floor(Math.random() * (max - min) + min);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn a string into a node
|
* Turn a string into a node
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
const choices = (state = [], action) => {
|
const choices = (state = [], action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'ADD_CHOICE':
|
case 'ADD_CHOICE': {
|
||||||
|
/*
|
||||||
|
A disabled choice appears in the choice dropdown but cannot be selected
|
||||||
|
A selected choice has been added to the passed input's value (added as an item)
|
||||||
|
An active choice appears within the choice dropdown
|
||||||
|
*/
|
||||||
return [...state, {
|
return [...state, {
|
||||||
id: action.id,
|
id: action.id,
|
||||||
groupId: action.groupId,
|
groupId: action.groupId,
|
||||||
value: action.value,
|
value: action.value,
|
||||||
label: action.label,
|
label: action.label,
|
||||||
disabled: action.disabled, // A disabled choice appears in the choice dropdown but cannot be selected
|
disabled: action.disabled,
|
||||||
selected: false, // A selected choice has been added to the passed input's value (added as an item)
|
selected: false,
|
||||||
active: true, // An active choice appears within the choice dropdown
|
active: true,
|
||||||
score: 9999,
|
score: 9999,
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
case 'ADD_ITEM':
|
case 'ADD_ITEM': {
|
||||||
let newState = state;
|
let newState = state;
|
||||||
|
|
||||||
// If all choices need to be activated
|
// If all choices need to be activated
|
||||||
|
@ -26,7 +32,7 @@ const choices = (state = [], action) => {
|
||||||
// we want to disable it so it can't be chosen again
|
// we want to disable it so it can't be chosen again
|
||||||
if (action.choiceId > -1) {
|
if (action.choiceId > -1) {
|
||||||
newState = state.map((choice) => {
|
newState = state.map((choice) => {
|
||||||
if(choice.id === parseInt(action.choiceId)) {
|
if (choice.id === parseInt(action.choiceId, 10)) {
|
||||||
choice.selected = true;
|
choice.selected = true;
|
||||||
}
|
}
|
||||||
return choice;
|
return choice;
|
||||||
|
@ -34,24 +40,26 @@ const choices = (state = [], action) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
case 'REMOVE_ITEM':
|
case 'REMOVE_ITEM': {
|
||||||
// When an item is removed and it has an associated choice,
|
// When an item is removed and it has an associated choice,
|
||||||
// we want to re-enable it so it can be chosen again
|
// we want to re-enable it so it can be chosen again
|
||||||
if (action.choiceId > -1) {
|
if (action.choiceId > -1) {
|
||||||
return state.map((choice) => {
|
return state.map((choice) => {
|
||||||
if(choice.id === parseInt(action.choiceId)) {
|
if (choice.id === parseInt(action.choiceId, 10)) {
|
||||||
choice.selected = false;
|
choice.selected = false;
|
||||||
}
|
}
|
||||||
return choice;
|
return choice;
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'FILTER_CHOICES':
|
case 'FILTER_CHOICES': {
|
||||||
const filteredResults = action.results;
|
const filteredResults = action.results;
|
||||||
const filteredState = state.map((choice, index) => {
|
const filteredState = state.map((choice) => {
|
||||||
// Set active state based on whether choice is
|
// Set active state based on whether choice is
|
||||||
// within filtered results
|
// within filtered results
|
||||||
|
|
||||||
|
@ -60,22 +68,26 @@ const choices = (state = [], action) => {
|
||||||
choice.score = result.score;
|
choice.score = result.score;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return choice;
|
return choice;
|
||||||
});
|
});
|
||||||
|
|
||||||
return filteredState;
|
return filteredState;
|
||||||
|
}
|
||||||
|
|
||||||
case 'ACTIVATE_CHOICES':
|
case 'ACTIVATE_CHOICES': {
|
||||||
return state.map((choice) => {
|
return state.map((choice) => {
|
||||||
choice.active = action.active;
|
choice.active = action.active;
|
||||||
return choice;
|
return choice;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default choices;
|
export default choices;
|
|
@ -1,16 +1,18 @@
|
||||||
const groups = (state = [], action) => {
|
const groups = (state = [], action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'ADD_GROUP':
|
case 'ADD_GROUP': {
|
||||||
return [...state, {
|
return [...state, {
|
||||||
id: action.id,
|
id: action.id,
|
||||||
value: action.value,
|
value: action.value,
|
||||||
active: action.active,
|
active: action.active,
|
||||||
disabled: action.disabled,
|
disabled: action.disabled,
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default groups;
|
export default groups;
|
|
@ -6,14 +6,14 @@ import choices from './choices';
|
||||||
const appReducer = combineReducers({
|
const appReducer = combineReducers({
|
||||||
items,
|
items,
|
||||||
groups,
|
groups,
|
||||||
choices
|
choices,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootReducer = (state, action) => {
|
const rootReducer = (passedState, action) => {
|
||||||
|
let state = passedState;
|
||||||
// If we are clearing all items, groups and options we reassign
|
// If we are clearing all items, groups and options we reassign
|
||||||
// state and then pass that state to our proper reducer. This isn't
|
// state and then pass that state to our proper reducer. This isn't
|
||||||
// mutating our actual state.
|
// mutating our actual state
|
||||||
//
|
|
||||||
// See: http://stackoverflow.com/a/35641992
|
// See: http://stackoverflow.com/a/35641992
|
||||||
if (action.type === 'CLEAR_ALL') {
|
if (action.type === 'CLEAR_ALL') {
|
||||||
state = undefined;
|
state = undefined;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
const items = (state = [], action) => {
|
const items = (state = [], action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'ADD_ITEM':
|
case 'ADD_ITEM': {
|
||||||
// Add object to items array
|
// Add object to items array
|
||||||
let newState = [...state, {
|
const newState = [...state, {
|
||||||
id: action.id,
|
id: action.id,
|
||||||
choiceId: action.choiceId,
|
choiceId: action.choiceId,
|
||||||
value: action.value,
|
value: action.value,
|
||||||
label: action.label,
|
label: action.label,
|
||||||
active: true,
|
active: true,
|
||||||
highlighted: false
|
highlighted: false,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return newState.map((item) => {
|
return newState.map((item) => {
|
||||||
|
@ -17,8 +17,9 @@ const items = (state = [], action) => {
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case 'REMOVE_ITEM':
|
case 'REMOVE_ITEM': {
|
||||||
// Set item to inactive
|
// Set item to inactive
|
||||||
return state.map((item) => {
|
return state.map((item) => {
|
||||||
if (item.id === action.id) {
|
if (item.id === action.id) {
|
||||||
|
@ -26,18 +27,21 @@ const items = (state = [], action) => {
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case 'HIGHLIGHT_ITEM':
|
case 'HIGHLIGHT_ITEM': {
|
||||||
return state.map((item) => {
|
return state.map((item) => {
|
||||||
if (item.id === action.id) {
|
if (item.id === action.id) {
|
||||||
item.highlighted = action.highlighted;
|
item.highlighted = action.highlighted;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default items;
|
export default items;
|
|
@ -1,10 +1,7 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
import rootReducer from './../reducers/index.js';
|
import rootReducer from './../reducers/index.js';
|
||||||
|
|
||||||
|
export default class Store {
|
||||||
export class Store {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.store = createStore(
|
this.store = createStore(
|
||||||
rootReducer,
|
rootReducer,
|
||||||
|
@ -53,7 +50,6 @@ export class Store {
|
||||||
*/
|
*/
|
||||||
getItemsFilteredByActive() {
|
getItemsFilteredByActive() {
|
||||||
const items = this.getItems();
|
const items = this.getItems();
|
||||||
|
|
||||||
const values = items.filter((item) => {
|
const values = items.filter((item) => {
|
||||||
return item.active === true;
|
return item.active === true;
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -80,7 +76,6 @@ export class Store {
|
||||||
*/
|
*/
|
||||||
getChoices() {
|
getChoices() {
|
||||||
const state = this.store.getState();
|
const state = this.store.getState();
|
||||||
|
|
||||||
return state.choices;
|
return state.choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +85,6 @@ export class Store {
|
||||||
*/
|
*/
|
||||||
getChoicesFilteredByActive() {
|
getChoicesFilteredByActive() {
|
||||||
const choices = this.getChoices();
|
const choices = this.getChoices();
|
||||||
|
|
||||||
const values = choices.filter((choice) => {
|
const values = choices.filter((choice) => {
|
||||||
return choice.active === true;
|
return choice.active === true;
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -116,12 +110,13 @@ export class Store {
|
||||||
* @return {Object} Found choice
|
* @return {Object} Found choice
|
||||||
*/
|
*/
|
||||||
getChoiceById(id) {
|
getChoiceById(id) {
|
||||||
if(!id) return;
|
if (id) {
|
||||||
const choices = this.getChoicesFilteredByActive();
|
const choices = this.getChoicesFilteredByActive();
|
||||||
const foundChoice = choices.find((choice) => choice.id === parseInt(id));
|
const foundChoice = choices.find((choice) => choice.id === parseInt(id, 10));
|
||||||
|
|
||||||
return foundChoice;
|
return foundChoice;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get groups from store
|
* Get groups from store
|
||||||
|
@ -145,11 +140,11 @@ export class Store {
|
||||||
const hasActiveOptions = choices.some((choice) => {
|
const hasActiveOptions = choices.some((choice) => {
|
||||||
return choice.active === true && choice.disabled === false;
|
return choice.active === true && choice.disabled === false;
|
||||||
});
|
});
|
||||||
return isActive && hasActiveOptions ? true : false;
|
return isActive && hasActiveOptions;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = Store;
|
module.exports = Store;
|
13
package.json
13
package.json
|
@ -27,12 +27,18 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^6.3.3",
|
"autoprefixer": "^6.3.3",
|
||||||
"babel-core": "^6.7.2",
|
"babel-core": "^6.7.2",
|
||||||
|
"babel-eslint": "^6.1.2",
|
||||||
"babel-loader": "^6.2.4",
|
"babel-loader": "^6.2.4",
|
||||||
"babel-preset-es2015": "^6.6.0",
|
"babel-preset-es2015": "^6.6.0",
|
||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
"csso": "^1.7.0",
|
"csso": "^1.8.2",
|
||||||
"es6-promise": "^3.2.1",
|
"es6-promise": "^3.2.1",
|
||||||
"fuse.js": "^2.2.0",
|
"eslint": "^3.3.0",
|
||||||
|
"eslint-config-airbnb": "^10.0.1",
|
||||||
|
"eslint-loader": "^1.5.0",
|
||||||
|
"eslint-plugin-import": "^1.13.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^2.1.0",
|
||||||
|
"eslint-plugin-react": "^6.1.0",
|
||||||
"jasmine-core": "^2.4.1",
|
"jasmine-core": "^2.4.1",
|
||||||
"karma": "^1.1.0",
|
"karma": "^1.1.0",
|
||||||
"karma-coverage": "^1.0.0",
|
"karma-coverage": "^1.0.0",
|
||||||
|
@ -52,6 +58,7 @@
|
||||||
"wrapper-webpack-plugin": "^0.1.7"
|
"wrapper-webpack-plugin": "^0.1.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"redux": "^3.3.1"
|
"redux": "^3.3.1",
|
||||||
|
"fuse.js": "^2.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ module.exports = {
|
||||||
filename: 'choices.min.js',
|
filename: 'choices.min.js',
|
||||||
publicPath: '/assets/scripts/dist/'
|
publicPath: '/assets/scripts/dist/'
|
||||||
},
|
},
|
||||||
|
eslint: {
|
||||||
|
configFile: '.eslintrc'
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
|
@ -24,7 +27,7 @@ module.exports = {
|
||||||
loaders: [{
|
loaders: [{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /(node_modules|bower_components)/,
|
exclude: /(node_modules|bower_components)/,
|
||||||
loaders: ['babel'],
|
loaders: ['babel', 'eslint-loader'],
|
||||||
include: path.join(__dirname, 'assets/scripts/src')
|
include: path.join(__dirname, 'assets/scripts/src')
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue