This commit is contained in:
Josh Johnson 2016-03-18 12:26:38 +00:00
parent a247c0c031
commit 6228463c71
5 changed files with 62 additions and 59 deletions

File diff suppressed because one or more lines are too long

View file

@ -10,9 +10,9 @@ import { hasClass, wrap, getSiblings, isType } from './lib/utils.js';
*/ */
class Choices { export class Choices {
constructor(options) { constructor(options) {
const fakeEl = document.createElement("fakeelement"); const FAKE_EL = document.createElement("FAKE_ELement");
const USER_OPTIONS = options || {}; const USER_OPTIONS = options || {};
const DEFAULT_OPTIONS = { const DEFAULT_OPTIONS = {
element: document.querySelector('[data-choice]'), element: document.querySelector('[data-choice]'),
@ -23,23 +23,25 @@ class Choices {
allowDuplicates: true, allowDuplicates: true,
debug: false, debug: false,
placeholder: false, placeholder: false,
callbackOnInit: function(){}, callbackOnInit: function() {},
callbackOnRender: function(){}, callbackOnRender: function() {},
callbackOnKeyUp: function(){}, callbackOnKeyUp: function() {},
callbackOnKeyDown: function(){}, callbackOnKeyDown: function() {},
callbackOnEntry: function(){}, callbackOnEntry: function() {},
callbackOnRemove: function(){} callbackOnRemove: function() {}
}; };
// Merge options with user options // Merge options with user options
this.options = this.extend(DEFAULT_OPTIONS, USER_OPTIONS || {}); this.options = this.extend(DEFAULT_OPTIONS, USER_OPTIONS || {});
this.initialised = false; this.initialised = false;
this.supports = 'querySelector' in document && 'addEventListener' in document && 'classList' in fakeEl; this.supports = 'querySelector' in document && 'addEventListener' in document && 'classList' in FAKE_EL;
// Retrieve elements // Retrieve elements
this.element = this.options.element; this.element = this.options.element;
// If input already has values, parse the array, otherwise create a blank array // If input already has values, parse the array, otherwise create a blank array
this.valueArray = this.element.value !== '' ? this.cleanInputValue(this.element.value) : []; this.valueArray = this.element.value !== '' ? this.cleanInputValue(this.element.value) : [];
// How many values in array
this.valueCount = this.valueArray.length;
// Bind methods // Bind methods
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
@ -47,9 +49,12 @@ class Choices {
this.onChange = this.onChange.bind(this); this.onChange = this.onChange.bind(this);
this.onFocus = this.onFocus.bind(this); this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onChange.bind(this); this.onBlur = this.onChange.bind(this);
this.init();
} }
cleanInputValue(value) { cleanInputValue(value) {
// Remove spaces and split with delimiter
return value.replace(/\s/g, '').split(this.options.delimiter); return value.replace(/\s/g, '').split(this.options.delimiter);
} }
@ -67,18 +72,18 @@ class Choices {
* @param {Object} obj Object to merge into extended object * @param {Object} obj Object to merge into extended object
*/ */
let merge = function(obj) { let merge = function(obj) {
for(let prop in obj) { for (let prop in obj) {
extended[prop] = obj[prop]; extended[prop] = obj[prop];
} }
}; };
// Loop through each passed argument // Loop through each passed argument
for(let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
// Store argument at position i // Store argument at position i
let obj = arguments[i]; let obj = arguments[i];
// If we are in fact dealing with an object, merge it. Otherwise throw error // If we are in fact dealing with an object, merge it. Otherwise throw error
if(isType('Object', obj)) { if (isType('Object', obj)) {
merge(obj); merge(obj);
} else { } else {
console.error('Custom options must be an object'); console.error('Custom options must be an object');
@ -91,19 +96,19 @@ class Choices {
/* State */ /* State */
isOpen() { isOpen() {
} }
isDisabled() { isDisabled() {
} }
isEmpty() { isEmpty() {
return (this.valueCount.length === 0) ? true : false;
} }
clearInput() { clearInput() {
if(this.input.value) this.input.value = ''; if (this.input.value) this.input.value = '';
} }
/* Event handling */ /* Event handling */
@ -116,7 +121,7 @@ class Choices {
let ctrlDown = e.ctrlKey || e.metaKey; let ctrlDown = e.ctrlKey || e.metaKey;
// Handle select all // Handle select all
if(ctrlDown && e.keyCode === 65) { if (ctrlDown && e.keyCode === 65) {
for (let i = 0; i < this.list.children.length; i++) { for (let i = 0; i < this.list.children.length; i++) {
let listItem = this.list.children[i]; let listItem = this.list.children[i];
@ -125,7 +130,7 @@ class Choices {
} }
// Handle enter key // Handle enter key
if(e.keyCode === 13 && e.target.value) { if (e.keyCode === 13 && e.target.value) {
let value = this.input.value; let value = this.input.value;
let handleEnterKey = () => { let handleEnterKey = () => {
@ -133,41 +138,41 @@ class Choices {
// If there is a max entry limit and we have reached that limit // If there is a max entry limit and we have reached that limit
// don't update // don't update
if(this.options.maxItems && this.options.maxItems <= this.list.children.length) { if (this.options.maxItems && this.options.maxItems <= this.list.children.length) {
canUpdate = false; canUpdate = false;
} }
// If no duplicates are allowed, and the value already exists // If no duplicates are allowed, and the value already exists
// in the array, don't update // in the array, don't update
if(this.options.allowDuplicates === false && this.element.value) { if (this.options.allowDuplicates === false && this.element.value) {
if(this.valueArray.indexOf(value) > -1) { if (this.valueArray.indexOf(value) > -1) {
canUpdate = false; canUpdate = false;
} }
} }
// All is good, update // All is good, update
if(canUpdate) { if (canUpdate) {
this.addItem(value); this.addItem(value);
this.updateInputValue(value); this.updateInputValue(value);
this.clearInput(this.element); this.clearInput(this.element);
} }
}; };
handleEnterKey(); handleEnterKey();
} }
if((e.keyCode === 8 || e.keyCode === 46) && !e.target.value) { if ((e.keyCode === 8 || e.keyCode === 46) && !e.target.value) {
let handleBackspaceKey = () => { let handleBackspaceKey = () => {
let currentListItems = this.list.querySelectorAll('.choices__item'); let currentListItems = this.list.querySelectorAll('.choices__item');
let lastItem = currentListItems[currentListItems.length - 1]; let lastItem = currentListItems[currentListItems.length - 1];
lastItem.classList.add('is-selected'); lastItem.classList.add('is-selected');
for (let i = 0; i < currentListItems.length; i++) { for (let i = 0; i < currentListItems.length; i++) {
let listItem = currentListItems[i]; let listItem = currentListItems[i];
if(listItem.classList.contains('is-selected')) { if (listItem.classList.contains('is-selected')) {
this.removeItem(listItem); this.removeItem(listItem);
this.removeInputValue(listItem.textContent); this.removeInputValue(listItem.textContent);
} }
@ -235,10 +240,10 @@ class Choices {
} }
updateInputValue(value) { updateInputValue(value) {
if(this.options.debug) console.debug('Update input value'); if (this.options.debug) console.debug('Update input value');
// Push new value to array // Push new value to array
this.valueArray.push(value); this.valueArray.push(value);
// Caste array to string and set it as the hidden inputs value // Caste array to string and set it as the hidden inputs value
this.element.value = this.valueArray.join(this.options.delimiter); this.element.value = this.valueArray.join(this.options.delimiter);
@ -247,8 +252,8 @@ class Choices {
} }
removeInputValue(value) { removeInputValue(value) {
if(this.options.debug) console.debug('Remove input value'); if (this.options.debug) console.debug('Remove input value');
let index = this.valueArray.indexOf(value); let index = this.valueArray.indexOf(value);
this.valueArray.splice(index, 1); this.valueArray.splice(index, 1);
@ -256,8 +261,8 @@ class Choices {
} }
addItem(value) { addItem(value) {
if(this.options.debug) console.debug('Add item'); if (this.options.debug) console.debug('Add item');
// // Create new list element // // Create new list element
let item = document.createElement('li'); let item = document.createElement('li');
item.classList.add('choices__item'); item.classList.add('choices__item');
@ -268,21 +273,21 @@ class Choices {
} }
removeItem(item) { removeItem(item) {
if(item) item.parentNode.removeChild(item); if (item) item.parentNode.removeChild(item);
} }
init() { init() {
if(!this.supports) console.error('Your browser doesn\'nt support shit'); if (!this.supports) console.error('Your browser doesn\'nt support shit');
this.initialised = true; this.initialised = true;
this.render(this.element); this.render(this.element);
} }
renderTextInput() { renderTextInput() {
let containerOuter = document.createElement('div'); let containerOuter = document.createElement('div');
containerOuter.className = 'choices choices--active'; containerOuter.className = 'choices choices--active';
let containerInner = document.createElement('div'); let containerInner = document.createElement('div');
containerInner.className = 'choices__inner'; containerInner.className = 'choices__inner';
// Hide passed input // Hide passed input
this.element.classList.add('choices__input', 'choices__input--hidden'); this.element.classList.add('choices__input', 'choices__input--hidden');
@ -292,21 +297,21 @@ class Choices {
// Wrap input in container preserving DOM ordering // Wrap input in container preserving DOM ordering
wrap(this.element, containerInner); wrap(this.element, containerInner);
// Wrapper inner container with outer container // Wrapper inner container with outer container
wrap(containerInner, containerOuter); wrap(containerInner, containerOuter);
let list = document.createElement('ul'); let list = document.createElement('ul');
list.className = 'choices__list'; list.className = 'choices__list';
let input = document.createElement('input'); let input = document.createElement('input');
input.type = 'text'; input.type = 'text';
input.className = 'choices__input choices__input--cloned'; input.className = 'choices__input choices__input--cloned';
if(input.placeholder) { if (input.placeholder) {
input.placeholder = this.element.placeholder; input.placeholder = this.element.placeholder;
} }
containerInner.appendChild(list); containerInner.appendChild(list);
containerInner.appendChild(input); containerInner.appendChild(input);
containerOuter.appendChild(containerInner); containerOuter.appendChild(containerInner);
@ -316,7 +321,7 @@ class Choices {
this.input = input; this.input = input;
this.list = list; this.list = list;
if(this.element.value !== '') { if (this.element.value !== '') {
// Add any preset values // Add any preset values
this.valueArray.forEach((value) => { this.valueArray.forEach((value) => {
this.addItem(value); this.addItem(value);
@ -332,9 +337,9 @@ class Choices {
} }
render() { render() {
if(this.options.debug) console.debug('Render'); if (this.options.debug) console.debug('Render');
switch(this.element.type) { switch (this.element.type) {
case "text": case "text":
this.renderTextInput(); this.renderTextInput();
break; break;
@ -359,8 +364,7 @@ class Choices {
} }
}; };
window.addEventListener('load', function() { (function(){
let input1 = document.getElementById(1); let input1 = document.getElementById(1);
let input2 = document.getElementById(2); let input2 = document.getElementById(2);
let input3 = document.getElementById(3); let input3 = document.getElementById(3);
@ -379,9 +383,4 @@ window.addEventListener('load', function() {
let choices3 = new Choices({ let choices3 = new Choices({
element : input3 element : input3
}); });
})();
choices1.init();
choices2.init();
choices3.init();
});

View file

@ -62,6 +62,8 @@ label {
background-color: #00BCD4; background-color: #00BCD4;
text-shadow: 0px 1px 0px #008fa1; text-shadow: 0px 1px 0px #008fa1;
border: 1px solid #00a5bb; border: 1px solid #00a5bb;
color: #FFFFFF; } box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
color: #FFFFFF;
cursor: pointer; }
.choices__item.is-selected { .choices__item.is-selected {
background-color: #00a5bb; } background-color: #00a5bb; }

View file

@ -1 +1 @@
*,:after,:before{box-sizing:border-box}body,html{margin:0;height:100%;widows:100%}html{font-size:62.5%}body{background-color:#fafafa;font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;font-size:1.6rem;color:#222;padding:2.4rem}label{display:block;margin-bottom:.8rem}.choices{margin-bottom:2.4rem;position:relative}.choices__inner{background-color:#fff;padding:.75rem .75rem .375rem;border:1px solid #ddd;border-radius:.25rem;font-size:1.4rem}.choices__inner:focus{outline:1px solid #00bcd4;outline-offset:-1px}.choices__list{margin:0;padding-left:0;list-style-type:none;display:inline}.choices__input{font-size:1.4rem;padding:0;margin-bottom:.5rem;display:inline-block;vertical-align:baseline;border:0;border-radius:0;max-width:100%}.choices__input:focus{outline:0}.choices__item{display:inline-block;border-radius:.4rem;padding:.4rem .8rem;font-size:1.4rem;margin-right:.375rem;margin-bottom:.375rem;background-color:#00bcd4;text-shadow:0 1px 0 #008fa1;border:1px solid #00a5bb;color:#fff}.choices__item.is-selected{background-color:#00a5bb} *,:after,:before{box-sizing:border-box}body,html{margin:0;height:100%;widows:100%}html{font-size:62.5%}body{background-color:#fafafa;font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;font-size:1.6rem;color:#222;padding:2.4rem}label{display:block;margin-bottom:.8rem}.choices{margin-bottom:2.4rem;position:relative}.choices__inner{background-color:#fff;padding:.75rem .75rem .375rem;border:1px solid #ddd;border-radius:.25rem;font-size:1.4rem}.choices__inner:focus{outline:1px solid #00bcd4;outline-offset:-1px}.choices__list{margin:0;padding-left:0;list-style-type:none;display:inline}.choices__input{font-size:1.4rem;padding:0;margin-bottom:.5rem;display:inline-block;vertical-align:baseline;border:0;border-radius:0;max-width:100%}.choices__input:focus{outline:0}.choices__item{display:inline-block;border-radius:.4rem;padding:.4rem .8rem;font-size:1.4rem;margin-right:.375rem;margin-bottom:.375rem;background-color:#00bcd4;text-shadow:0 1px 0 #008fa1;border:1px solid #00a5bb;box-shadow:0 1px 1px rgba(0,0,0,.2);color:#fff;cursor:pointer}.choices__item.is-selected{background-color:#00a5bb}

View file

@ -71,6 +71,8 @@ label {
background-color: #00BCD4; background-color: #00BCD4;
text-shadow: 0px 1px 0px darken(#00BCD4, 10%); text-shadow: 0px 1px 0px darken(#00BCD4, 10%);
border: 1px solid darken(#00BCD4, 5%); border: 1px solid darken(#00BCD4, 5%);
box-shadow: 0px 1px 1px rgba(#000000, 0.2);
color: #FFFFFF; color: #FFFFFF;
cursor: pointer;
&.is-selected { background-color: darken(#00BCD4, 5%); } &.is-selected { background-color: darken(#00BCD4, 5%); }
} }