mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-02 14:02:17 +02:00
Less querying of the DOM - use state instead + deselect all items if click outside
This commit is contained in:
parent
4947da2b43
commit
cd43799258
2
assets/scripts/dist/bundle.js
vendored
2
assets/scripts/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
|
@ -2,22 +2,22 @@ export const addItem = (value, id) => {
|
||||||
return {
|
return {
|
||||||
type: 'ADD_ITEM',
|
type: 'ADD_ITEM',
|
||||||
value: value,
|
value: value,
|
||||||
id: id
|
id: id,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeItem = (id) => {
|
export const removeItem = (id) => {
|
||||||
return {
|
return {
|
||||||
type: 'REMOVE_ITEM',
|
type: 'REMOVE_ITEM',
|
||||||
id: id
|
id: id,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectItem = (id, value) => {
|
export const selectItem = (id, selected) => {
|
||||||
return {
|
return {
|
||||||
type: 'SELECT_ITEM',
|
type: 'SELECT_ITEM',
|
||||||
id: id,
|
id: id,
|
||||||
value: value
|
selected: selected,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +25,14 @@ export const addOption = (value, id) => {
|
||||||
return {
|
return {
|
||||||
type: 'ADD_OPTION',
|
type: 'ADD_OPTION',
|
||||||
value: value,
|
value: value,
|
||||||
id: id
|
id: id,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const selectOption = (id, selected) => {
|
||||||
|
return {
|
||||||
|
type: 'SELECT_OPTION',
|
||||||
|
id: id,
|
||||||
|
selected: selected,
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
import rootReducer from './reducers/index.js';
|
import rootReducer from './reducers/index.js';
|
||||||
import { addItem, removeItem, selectItem, addOption } from './actions/index';
|
import { addItem, removeItem, selectItem, addOption, selectOption } from './actions/index';
|
||||||
import { hasClass, wrap, getSiblings, isType, strToEl, extend } from './lib/utils.js';
|
import { hasClass, wrap, getSiblings, isType, strToEl, extend } from './lib/utils.js';
|
||||||
|
|
||||||
export class Choices {
|
export class Choices {
|
||||||
|
@ -191,13 +191,12 @@ export class Choices {
|
||||||
let handleBackspaceKey = () => {
|
let handleBackspaceKey = () => {
|
||||||
if(this.options.removeItems) {
|
if(this.options.removeItems) {
|
||||||
|
|
||||||
|
let inputIsFocussed = this.input === document.activeElement;
|
||||||
let lastItem = items[items.length - 1];
|
let lastItem = items[items.length - 1];
|
||||||
let selectedItems = items.filter((item) => {
|
let selectedItems = items.filter((item) => {
|
||||||
return item.selected === true;
|
return item.selected === true;
|
||||||
});
|
});
|
||||||
|
|
||||||
let inputIsFocussed = this.input === document.activeElement;
|
|
||||||
|
|
||||||
if(items && lastItem && !this.options.editItems && inputIsFocussed && this.options.removeItems) {
|
if(items && lastItem && !this.options.editItems && inputIsFocussed && this.options.removeItems) {
|
||||||
this.selectItem(lastItem);
|
this.selectItem(lastItem);
|
||||||
}
|
}
|
||||||
|
@ -229,6 +228,10 @@ export class Choices {
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
// If click is affecting a child node of our element
|
// If click is affecting a child node of our element
|
||||||
if(this.containerOuter.contains(e.target)) {
|
if(this.containerOuter.contains(e.target)) {
|
||||||
|
const state = this.store.getState();
|
||||||
|
const items = state.items;
|
||||||
|
const options = state.options;
|
||||||
|
|
||||||
if(this.input !== document.activeElement) {
|
if(this.input !== document.activeElement) {
|
||||||
this.input.focus();
|
this.input.focus();
|
||||||
}
|
}
|
||||||
|
@ -239,20 +242,16 @@ export class Choices {
|
||||||
let handleClick = (item) => {
|
let handleClick = (item) => {
|
||||||
if(this.options.removeItems) {
|
if(this.options.removeItems) {
|
||||||
let passedId = item.getAttribute('data-choice-id');
|
let passedId = item.getAttribute('data-choice-id');
|
||||||
let items = this.list.children;
|
|
||||||
|
|
||||||
// We only want to select one item with a click
|
// We only want to select one item with a click
|
||||||
// so we deselect any items that aren't the target
|
// so we deselect any items that aren't the target
|
||||||
for (var i = 0; i < items.length; i++) {
|
items.forEach((item) => {
|
||||||
let singleItem = items[i];
|
if(item.id === parseInt(passedId) && !item.selected) {
|
||||||
let id = singleItem.getAttribute('data-choice-id');;
|
this.selectItem(item);
|
||||||
|
|
||||||
if(id === passedId && !singleItem.classList.contains(this.options.classNames.selectedState)) {
|
|
||||||
this.selectItem(singleItem);
|
|
||||||
} else {
|
} else {
|
||||||
this.deselectItem(singleItem);
|
this.deselectItem(item);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,13 +259,24 @@ export class Choices {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(e.target.hasAttribute('data-choice-selectable')) {
|
if(e.target.hasAttribute('data-choice-selectable')) {
|
||||||
let item = e.target;
|
let id = e.target.getAttribute('data-choice-id');
|
||||||
let value = e.target.getAttribute('data-choice-value');
|
|
||||||
this.addItem(value);
|
let option = options.find((option) => {
|
||||||
|
return option.id === parseInt(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(option) {
|
||||||
|
this.selectOption(id);
|
||||||
|
this.addItem(option.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(this.dropdown && this.dropdown.classList.contains(this.options.classNames.activeState)) {
|
} else {
|
||||||
this.toggleDropdown();
|
// Click is outside of our element so close dropdown and de-select items
|
||||||
|
this.deselectAll();
|
||||||
|
if(this.dropdown && this.dropdown.classList.contains(this.options.classNames.activeState)) {
|
||||||
|
this.toggleDropdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -328,7 +338,8 @@ export class Choices {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
selectItem(item) {
|
selectItem(item) {
|
||||||
let id = item.getAttribute('data-choice-id');
|
if(!item) return;
|
||||||
|
let id = item.id;
|
||||||
this.store.dispatch(selectItem(id, true));
|
this.store.dispatch(selectItem(id, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +349,8 @@ export class Choices {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
deselectItem(item) {
|
deselectItem(item) {
|
||||||
let id = item.getAttribute('data-choice-id');
|
if(!item) return;
|
||||||
|
let id = item.id;
|
||||||
this.store.dispatch(selectItem(id, false));
|
this.store.dispatch(selectItem(id, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,11 +359,25 @@ export class Choices {
|
||||||
* @param {Array} items Array of items to select
|
* @param {Array} items Array of items to select
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
selectAll(items) {
|
selectAll() {
|
||||||
for (let i = 0; i < items.length; i++) {
|
const state = this.store.getState();
|
||||||
let item = items[i];
|
const items = state.items;
|
||||||
|
items.forEach((item) => {
|
||||||
this.selectItem(item);
|
this.selectItem(item);
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deselectAll() {
|
||||||
|
const state = this.store.getState();
|
||||||
|
const items = state.items;
|
||||||
|
items.forEach((item) => {
|
||||||
|
this.deselectItem(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
selectOption(id) {
|
||||||
|
if(!id) return;
|
||||||
|
this.store.dispatch(selectOption(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -632,7 +658,7 @@ export class Choices {
|
||||||
|
|
||||||
// Add each option to dropdown
|
// Add each option to dropdown
|
||||||
options.forEach((option) => {
|
options.forEach((option) => {
|
||||||
const dropdownItem = strToEl(`<li class="${ this.options.classNames.item } ${ this.options.classNames.itemSelectable }" data-choice-selectable data-choice-value="${ option.value }">${ option.value }</li>`);
|
const dropdownItem = strToEl(`<li class="${ this.options.classNames.item } ${ this.options.classNames.itemSelectable }" data-choice-selectable data-choice-id="${ option.id }" data-choice-value="${ option.value }">${ option.value }</li>`);
|
||||||
this.dropdown.appendChild(dropdownItem);
|
this.dropdown.appendChild(dropdownItem);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const items = (state = [], action) => {
|
||||||
case 'SELECT_ITEM':
|
case 'SELECT_ITEM':
|
||||||
return state.map((item) => {
|
return state.map((item) => {
|
||||||
if(item.id === parseInt(action.id)) {
|
if(item.id === parseInt(action.id)) {
|
||||||
item.selected = action.value;
|
item.selected = action.selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|
|
@ -10,6 +10,16 @@ const options = (state = [], action) => {
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
|
|
||||||
|
case 'SELECT_OPTION':
|
||||||
|
return state.map((option) => {
|
||||||
|
if(option.id === parseInt(action.id)) {
|
||||||
|
option.selected = action.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue