diff --git a/assets/scripts/dist/bundle.js b/assets/scripts/dist/bundle.js index ecca338..c534ec8 100644 --- a/assets/scripts/dist/bundle.js +++ b/assets/scripts/dist/bundle.js @@ -1 +1 @@ -!function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="/assets/scripts/dist/",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0}),t.Choices=void 0;var o=function(){function e(e,t){for(var n=0;ni;i++){var r=arguments[i];(0,l.isType)("Object",r)?n(r):console.error("Custom options must be an object")}return e}},{key:"isOpen",value:function(){}},{key:"isDisabled",value:function(){}},{key:"isEmpty",value:function(){return 0===this.valueCount.length}},{key:"clearInput",value:function(){this.input.value&&(this.input.value="")}},{key:"onKeyUp",value:function(e){}},{key:"onKeyDown",value:function(e){var t=this,n=e.ctrlKey||e.metaKey,i=8,r=13,o=65;if(e.target===this.input){if(n&&e.keyCode===o&&this.list&&this.list.children){var a=function(){t.options.removeItems&&!t.input.value&&t.options.selectAll&&t.selectAll(t.list.children)};a()}e.keyCode===r&&e.target.value&&!function(){var e=t.input.value,n=function(){var n=!0;if(t.options.maxItems&&t.options.maxItems<=t.list.children.length&&(n=!1),t.options.allowDuplicates===!1&&t.element.value&&t.valueArray.indexOf(e)>-1&&(n=!1),n&&"text"===t.element.type){var i=!0;t.options.regexFilter&&(i=t.regexFilter(e)),i&&(t.addItem(e),t.updateInputValue(e),t.clearInput(t.element))}};n()}()}if(e.keyCode===i&&!e.target.value){var s=function(){if(t.options.removeItems){var e=t.list.querySelectorAll(".choices__item"),n=t.list.querySelectorAll(".is-selected"),i=e[e.length-1];i&&!t.options.editItems&&t.selectItem(i),t.options.editItems&&i&&0===n.length?(t.input.value=i.innerHTML,t.removeItem(i)):t.removeAll(e)}};s(),e.preventDefault()}}},{key:"onClick",value:function(e){var t=this;if("LI"===e.target.tagName){var n=e.target,i=function(e){for(var n=e.getAttribute("data-choice-id"),i=t.list.children,r=0;r'),n=(0,l.strToEl)('
');this.element.classList.add("choices__input","choices__input--hidden"),this.element.tabIndex="-1",this.element.setAttribute("style","display:none;"),this.element.setAttribute("aria-hidden","true"),(0,l.wrap)(this.element,n),(0,l.wrap)(n,t);var i=(0,l.strToEl)(''),r=(0,l.strToEl)('');r.placeholder&&(r.placeholder=this.element.placeholder),this.options.addItems||(r.disabled=!0),n.appendChild(i),n.appendChild(r),t.appendChild(n),this.containerOuter=t,this.containerInner=n,this.input=r,this.list=i,""!==this.element.value&&this.valueArray.forEach(function(t){e.addItem(t)}),document.addEventListener("keydown",this.onKeyDown),this.list.addEventListener("click",this.onClick)}},{key:"renderItems",value:function(){var e=this,t=this.store.getState();this.list.innerHTML="",t.forEach(function(t){if(t.active){var n=(0,l.strToEl)('
  • '+t.value+"
  • ");e.list.appendChild(n)}}),console.log(t)}},{key:"renderInput",value:function(){switch(this.options.debug&&console.debug("Render"),this.element.type){case"text":this.renderTextInput(),this.store.subscribe(this.renderItems),this.renderItems();break;case"select-one":break;case"select-multiple":break;default:this.renderTextInput()}}},{key:"destroy",value:function(){this.options=null,this.element=null,this.initialised=null,this.removeEventListeners(this.input)}}]),e}();!function(){var e=document.getElementById(1),t=document.getElementById(2),n=document.getElementById(3),i=document.getElementById(4),r=document.getElementById(5);new d({element:e,editItems:!0,maxItems:5,callbackOnRemoveItem:function(e){console.log(e)},callbackOnAddItem:function(e,t){console.log(e,t)}}),new d({element:t,allowDuplicates:!1,editItems:!0}),new d({element:n,allowDuplicates:!1,editItems:!0,regexFilter:/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/}),new d({element:i,addItems:!1}),new d({element:r,prependValue:"item-",appendValue:"-"+Date.now()})}()},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0,t.compose=t.applyMiddleware=t.bindActionCreators=t.combineReducers=t.createStore=void 0;var r=n(3),o=i(r),a=n(7),s=i(a),u=n(9),c=i(u),l=n(10),d=i(l),f=n(11),p=i(f),h=n(8);i(h);t.createStore=o.default,t.combineReducers=s.default,t.bindActionCreators=c.default,t.applyMiddleware=d.default,t.compose=p.default},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t,n){function i(){h===p&&(h=p.slice())}function o(){return f}function u(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return i(),h.push(e),function(){if(t){t=!1,i();var n=h.indexOf(e);h.splice(n,1)}}}function c(e){if(!(0,a.default)(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if("undefined"==typeof e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(m)throw new Error("Reducers may not dispatch actions.");try{m=!0,f=d(f,e)}finally{m=!1}for(var t=p=h,n=0;nn;n++)t[n]=arguments[n];return function(e){return function(n,i,r){var a=e(n,i,r),u=a.dispatch,c=[],l={getState:a.getState,dispatch:function(e){return u(e)}};return c=t.map(function(e){return e(l)}),u=s.default.apply(void 0,c)(a.dispatch),o({},a,{dispatch:u})}}}var o=Object.assign||function(e){for(var t=1;tn;n++)t[n]=arguments[n];return function(){if(0===t.length)return arguments.length<=0?void 0:arguments[0];var e=t[t.length-1],n=t.slice(0,-1);return n.reduceRight(function(e,t){return t(e)},e.apply(void 0,arguments))}}t.__esModule=!0,t.default=n},function(e,t){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t=0?t:0},t.getElementOffset=function(e,t){var n=t;return n>1&&(n=1),n>0&&(n=0),Math.max(e.offsetHeight*n)},t.getScrollPosition=function(e){return"bottom"===e?Math.max((window.scrollY||window.pageYOffset)+(window.innerHeight||document.documentElement.clientHeight)):window.scrollY||window.pageYOffset},t.isInView=function(e,t,n){return this.getScrollPosition(t)>this.getElemDistance(e)+this.getElementOffset(e,n)},t.stripHTML=function(e){var t=document.createElement("DIV");return t.innerHTML=e,t.textContent||t.innerText||""},t.addAnimation=function(e,t){var i=n(),r=function o(){e.classList.remove(t),e.removeEventListener(i,o,!1)};e.classList.add(t),e.addEventListener(i,r,!1)},t.getRandomNumber=function(e,t){return Math.floor(Math.random()*(t-e)+e)},t.strToEl=function(){var e=document.createElement("div");return function(t){var n;for(e.innerHTML=t,n=e.children[0];e.firstChild;)e.removeChild(e.firstChild);return n}}()}]); \ No newline at end of file +!function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="/assets/scripts/dist/",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0}),t.Choices=void 0;var o=function(){function e(e,t){for(var n=0;n'),n=(0,l.strToEl)('
    ');this.element.classList.add("choices__input","choices__input--hidden"),this.element.tabIndex="-1",this.element.setAttribute("style","display:none;"),this.element.setAttribute("aria-hidden","true"),(0,l.wrap)(this.element,n),(0,l.wrap)(n,t);var i=(0,l.strToEl)('
      '),r=(0,l.strToEl)('');r.placeholder&&(r.placeholder=this.element.placeholder),this.options.addItems||(r.disabled=!0),n.appendChild(i),n.appendChild(r),t.appendChild(n),this.containerOuter=t,this.containerInner=n,this.input=r,this.list=i;var o=""!==this.element.value?this.element.value.split(this.options.delimiter):[];o.forEach(function(t){e.addItem(t)}),document.addEventListener("keydown",this.onKeyDown),this.list.addEventListener("click",this.onClick),this.store.subscribe(this.render),this.render()}},{key:"render",value:function(){var e=this,t=this.store.getState(),n=t.reduce(function(e,t){return e.push(t.value),e},[]);this.element.value=n.join(this.options.delimiter),this.list.innerHTML="",t.forEach(function(t){if(t.active){var n=(0,l.strToEl)('
    • '+t.value+"
    • ");e.list.appendChild(n)}}),console.log(t)}},{key:"renderInput",value:function(e){switch(this.options.debug&&console.debug("Render"),e.type){case"text":this.renderTextInput();break;case"select-one":break;case"select-multiple":break;default:this.renderTextInput()}}},{key:"init",value:function(){this.supports||console.error("init: Your browser doesn'nt support shit"),this.initialised=!0,this.renderInput(this.element)}},{key:"destroy",value:function(){this.options=null,this.element=null,this.initialised=null}}]),e}();!function(){var e=document.getElementById(1),t=document.getElementById(2),n=document.getElementById(3),i=document.getElementById(4),r=document.getElementById(5);new d({element:e,delimiter:" ",editItems:!0,maxItems:5}),new d({element:t,allowDuplicates:!1,editItems:!0}),new d({element:n,allowDuplicates:!1,editItems:!0,regexFilter:/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/}),new d({element:i,addItems:!1}),new d({element:r,prependValue:"item-",appendValue:"-"+Date.now()})}()},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0,t.compose=t.applyMiddleware=t.bindActionCreators=t.combineReducers=t.createStore=void 0;var r=n(3),o=i(r),s=n(8),a=i(s),c=n(10),u=i(c),l=n(11),d=i(l),f=n(12),p=i(f),h=n(9);i(h);t.createStore=o.default,t.combineReducers=a.default,t.bindActionCreators=u.default,t.applyMiddleware=d.default,t.compose=p.default},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}function r(e,t,n){function i(){h===p&&(h=p.slice())}function o(){return f}function c(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return i(),h.push(e),function(){if(t){t=!1,i();var n=h.indexOf(e);h.splice(n,1)}}}function u(e){if(!(0,s.default)(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if("undefined"==typeof e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(m)throw new Error("Reducers may not dispatch actions.");try{m=!0,f=d(f,e)}finally{m=!1}for(var t=p=h,n=0;nn;n++)t[n]=arguments[n];return function(e){return function(n,i,r){var s=e(n,i,r),c=s.dispatch,u=[],l={getState:s.getState,dispatch:function(e){return c(e)}};return u=t.map(function(e){return e(l)}),c=a.default.apply(void 0,u)(s.dispatch),o({},s,{dispatch:c})}}}var o=Object.assign||function(e){for(var t=1;tn;n++)t[n]=arguments[n];return function(){if(0===t.length)return arguments.length<=0?void 0:arguments[0];var e=t[t.length-1],n=t.slice(0,-1);return n.reduceRight(function(e,t){return t(e)},e.apply(void 0,arguments))}}t.__esModule=!0,t.default=n},function(e,t){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);tr;r++){var o=arguments[r];n("Object",o)?i(o):console.error("Custom options must be an object")}return e},t.whichTransitionEvent=function(){var e,t=document.createElement("fakeelement"),n={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(e in n)if(void 0!==t.style[e])return n[e]},t.whichAnimationEvent=function(){var e,t=document.createElement("fakeelement"),n={animation:"animationend",OAnimation:"oAnimationEnd",MozAnimation:"animationend",WebkitAnimation:"webkitAnimationEnd"};for(e in n)if(void 0!==t.style[e])return n[e]});t.getParentsUntil=function(e,t,n){for(var i=[];e&&e!==document;e=e.parentNode){if(t){var r=t.charAt(0);if("."===r&&e.classList.contains(t.substr(1)))break;if("#"===r&&e.id===t.substr(1))break;if("["===r&&e.hasAttribute(t.substr(1,t.length-1)))break;if(e.tagName.toLowerCase()===t)break}if(n){var o=n.charAt(0);"."===o&&e.classList.contains(n.substr(1))&&i.push(e),"#"===o&&e.id===n.substr(1)&&i.push(e),"["===o&&e.hasAttribute(n.substr(1,n.length-1))&&i.push(e),e.tagName.toLowerCase()===n&&i.push(e)}else i.push(e)}return 0===i.length?null:i},t.wrap=function(e,t){return t=t||document.createElement("div"),e.nextSibling?e.parentNode.insertBefore(t,e.nextSibling):e.parentNode.appendChild(t),t.appendChild(e)},t.getSiblings=function(e){for(var t=[],n=e.parentNode.firstChild;n;n=n.nextSibling)1===n.nodeType&&n!==e&&t.push(n);return t},t.findAncestor=function(e,t){for(;(e=e.parentElement)&&!e.classList.contains(t););return e},t.debounce=function(e,t,n){var i;return function(){var r=this,o=arguments,s=function(){i=null,n||e.apply(r,o)},a=n&&!i;clearTimeout(i),i=setTimeout(s,t),a&&e.apply(r,o)}},t.getElemDistance=function(e){var t=0;if(e.offsetParent)do t+=e.offsetTop,e=e.offsetParent;while(e);return t>=0?t:0},t.getElementOffset=function(e,t){var n=t;return n>1&&(n=1),n>0&&(n=0),Math.max(e.offsetHeight*n)},t.getScrollPosition=function(e){return"bottom"===e?Math.max((window.scrollY||window.pageYOffset)+(window.innerHeight||document.documentElement.clientHeight)):window.scrollY||window.pageYOffset},t.isInView=function(e,t,n){return this.getScrollPosition(t)>this.getElemDistance(e)+this.getElementOffset(e,n)},t.stripHTML=function(e){var t=document.createElement("DIV");return t.innerHTML=e,t.textContent||t.innerText||""},t.addAnimation=function(e,t){var n=i(),r=function o(){e.classList.remove(t),e.removeEventListener(n,o,!1)};e.classList.add(t),e.addEventListener(n,r,!1)},t.getRandomNumber=function(e,t){return Math.floor(Math.random()*(t-e)+e)},t.strToEl=function(){var e=document.createElement("div");return function(t){var n;for(e.innerHTML=t,n=e.children[0];e.firstChild;)e.removeChild(e.firstChild);return n}}()}]); \ No newline at end of file diff --git a/assets/scripts/src/actions/index.js b/assets/scripts/src/actions/index.js index f0b31d3..54b1dc5 100644 --- a/assets/scripts/src/actions/index.js +++ b/assets/scripts/src/actions/index.js @@ -6,12 +6,6 @@ export const addItemToStore = (value, id) => { } }; -export const unselectAllFromStore = () => { - return { - type: 'UNSELECT_ALL' - } -} - export const removeItemFromStore = (id) => { return { type: 'REMOVE_ITEM', diff --git a/assets/scripts/src/choices.js b/assets/scripts/src/choices.js index b98d805..8c152ba 100644 --- a/assets/scripts/src/choices.js +++ b/assets/scripts/src/choices.js @@ -2,19 +2,8 @@ import { createStore } from 'redux'; import choices from './reducers/index.js'; -import { addItemToStore, removeItemFromStore, selectItemFromStore, unselectAllFromStore } from './actions/index'; -import { hasClass, wrap, getSiblings, isType, strToEl } from './lib/utils.js'; - - -/** - - TODO: - - State handling - - Dynamically set input width to contents - - Handle select input - - Handle multiple select input ? - - */ +import { addItemToStore, removeItemFromStore, selectItemFromStore } from './actions/index'; +import { hasClass, wrap, getSiblings, isType, strToEl, extend } from './lib/utils.js'; export class Choices { constructor(options) { @@ -41,95 +30,57 @@ export class Choices { callbackOnAddItem: function() {} }; + // Initial instance state + this.initialised = false; + // Merge options with user options - this.options = this.extend(defaultOptions, userOptions || {}); + this.options = extend(defaultOptions, userOptions || {}); + + // Create data store this.store = createStore(choices); - this.initialised = false; + // Cutting the mustard this.supports = 'querySelector' in document && 'addEventListener' in document && 'classList' in fakeEl; // Retrieve triggering element (i.e. element with 'data-choice' trigger) this.element = this.options.element; - // If input already has values, parse the array, otherwise create a blank array - // Hmm, this should really map this.store - this.valueArray = this.element.value !== '' ? this.cleanInputValue(this.element.value) : []; - - // How many values in array - this.valueCount = this.valueArray.length; - // Bind methods this.onKeyDown = this.onKeyDown.bind(this); this.onClick = this.onClick.bind(this); - this.renderItems = this.renderItems.bind(this); + this.render = this.render.bind(this); + // Let's have it large this.init(); } - cleanInputValue(value) { - // Remove spaces and split with delimiter - return value.replace(/\s/g, '').split(this.options.delimiter); - } + /* State tests */ - /** - * Merges unspecified amount of objects into new object - * @private - * @return {Object} Merged object of arguments + /** + * Whether input is disabled + * @return {Boolean} */ - extend() { - let extended = {}; - let length = arguments.length; - - /** - * Merge one object into another - * @param {Object} obj Object to merge into extended object - */ - let merge = function(obj) { - for (let prop in obj) { - extended[prop] = obj[prop]; - } - }; - - // Loop through each passed argument - for (let i = 0; i < length; i++) { - // store argument at position i - let obj = arguments[i]; - - // If we are in fact dealing with an object, merge it. Otherwise throw error - if (isType('Object', obj)) { - merge(obj); - } else { - console.error('Custom options must be an object'); - } - } - - return extended; - }; - - /* State */ - - isOpen() { - - } - isDisabled() { - + return (this.input.disabled) ? true : false; } + /** + * Whether there are no values + * @return {Boolean} + */ isEmpty() { - return (this.valueCount.length === 0) ? true : false; - } - - clearInput() { - if (this.input.value) this.input.value = ''; + return (this.store.getState().length === 0) ? true : false; } /* Event handling */ - onKeyUp(e) { - } - + /** + * Handle keydown event + * @param {Object} e Event + * @return + */ onKeyDown(e) { + const storeValues = this.store.getState(); const ctrlDownKey = e.ctrlKey || e.metaKey; const deleteKey = 8 || 46; const enterKey = 13; @@ -137,6 +88,7 @@ export class Choices { // If we are typing in the input if(e.target === this.input) { + // If CTRL + A or CMD + A have been pressed and there are items to select if (ctrlDownKey && e.keyCode === aKey && this.list && this.list.children) { let handleSelectAll = () => { @@ -164,9 +116,9 @@ export class Choices { // If no duplicates are allowed, and the value already exists // in the array, don't update if (this.options.allowDuplicates === false && this.element.value) { - if (this.valueArray.indexOf(value) > -1) { - canUpdate = false; - } + canUpdate = !storeValues.some((item) => { + return item.value === value; + }); } // All is good, update @@ -184,7 +136,6 @@ export class Choices { // All is good, add if(canAddItem) { this.addItem(value); - this.updateInputValue(value); this.clearInput(this.element); } } @@ -226,6 +177,12 @@ export class Choices { } } + + /** + * Handle click event + * @param {Object} e Event + * @return + */ onClick(e) { if(e.target.tagName === 'LI') { let item = e.target; @@ -235,7 +192,7 @@ export class Choices { let items = this.list.children; // We only want to select one item with a click - // so we unselect 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++) { let singleItem = items[i]; let id = singleItem.getAttribute('data-choice-id');; @@ -243,7 +200,7 @@ export class Choices { if(id === passedId && !singleItem.classList.contains('is-selected')) { this.selectItem(singleItem); } else { - this.unselectItem(singleItem); + this.deselectItem(singleItem); } } } @@ -253,12 +210,20 @@ export class Choices { } /* Methods */ - setValue() {} - getValue() {} - - getValues() {} + /** + * Set value of input to blank + * @return + */ + clearInput() { + if (this.input.value) this.input.value = ''; + } + /** + * Tests value against a regular expression + * @param {string} value Value to test + * @return {Boolean} Whether test passed/failed + */ regexFilter(value) { let expression = new RegExp(this.options.regexFilter, 'i'); let passesTest = expression.test(value); @@ -266,16 +231,32 @@ export class Choices { return passesTest; } + /** + * Select item (a selected item can be deleted) + * @param {Element} item Element to select + * @return + */ selectItem(item) { let id = item.getAttribute('data-choice-id'); this.store.dispatch(selectItemFromStore(id, true)); } - unselectItem(item) { + /** + * Deselect item + * @param {Element} item Element to de-select + * @return + */ + deselectItem(item) { let id = item.getAttribute('data-choice-id'); this.store.dispatch(selectItemFromStore(id, false)); } + + /** + * Select items within array + * @param {Array} items Array of items to select + * @return + */ selectAll(items) { for (let i = 0; i < items.length; i++) { let item = items[i]; @@ -283,25 +264,10 @@ export class Choices { }; } - updateInputValue(value) { - if (this.options.debug) console.debug('Update input value'); - - // Push new value to array - this.valueArray.push(value); - - // Caste array to string and set it as the hidden inputs value - this.element.value = this.valueArray.join(this.options.delimiter); - } - - removeInputValue(value) { - if (this.options.debug) console.debug('Remove input value'); - - let index = this.valueArray.indexOf(value); - this.valueArray.splice(index, 1); - - this.element.value = this.valueArray.join(this.options.delimiter); - } - + /** + * Add item to store with correct value + * @param {String} value Value to add to store + */ addItem(value) { if (this.options.debug) console.debug('Add item'); @@ -330,9 +296,12 @@ export class Choices { } this.store.dispatch(addItemToStore(passedValue, id)); - this.store.dispatch(unselectAllFromStore(passedValue, id)); } + /** + * Remove item from store + * @param + */ removeItem(item) { if(!item) { console.error('removeItem: No item was passed to be removed'); @@ -354,23 +323,27 @@ export class Choices { this.store.dispatch(removeItemFromStore(id)); } + /** + * Remove all items from array + * @param {Array} items Items to remove from store + * @return + */ removeAll(items) { for (let i = 0; i < items.length; i++) { let item = items[i]; if (item.classList.contains('is-selected')) { this.removeItem(item); - this.removeInputValue(item.textContent); } }; } + + /* Rendering */ - init() { - if (!this.supports) console.error('init: Your browser doesn\'nt support shit'); - this.initialised = true; - this.renderInput(this.element); - } - + /** + * Create DOM structure around passed text element + * @return + */ renderTextInput() { /* Template: @@ -419,44 +392,66 @@ export class Choices { this.input = input; this.list = list; - if (this.element.value !== '') { - // Add any preset values - this.valueArray.forEach((value) => { - this.addItem(value); - }); - } + // Add any preset values seperated by delimiter + let valueArray = this.element.value !== '' ? this.element.value.split(this.options.delimiter) : []; + valueArray.forEach((value) => { + this.addItem(value); + }); // Trigger event listeners document.addEventListener('keydown', this.onKeyDown); this.list.addEventListener('click', this.onClick); + + // Subscribe to store + this.store.subscribe(this.render); + + // Render any items + this.render(); } - renderItems(){ - let items = this.store.getState(); + /** + * Render DOM with values + * @return + */ + render() { + let state = this.store.getState(); + // Simplify store data to just values + let valueArray = state.reduce((prev, current) => { + prev.push(current.value); + return prev; + }, []); + + // Assign hidden input array of values + this.element.value = valueArray.join(this.options.delimiter); + + // Clear list this.list.innerHTML = ''; - - items.forEach((item) => { + + // Add each list item to list + state.forEach((item) => { if(item.active) { // Create new list element - let listItem = strToEl(`
    • ${item.value}
    • `); + let listItem = strToEl(`
    • ${ item.value }
    • `); // Append it to list this.list.appendChild(listItem); } }); - console.log(items); + console.log(state); } - renderInput() { + /** + * Determine how an input should be rendered + * @return {Element} Input to test + */ + renderInput(input) { if (this.options.debug) console.debug('Render'); - switch (this.element.type) { + switch (input.type) { case "text": this.renderTextInput(); - this.store.subscribe(this.renderItems); - this.renderItems(); break; case "select-one": // this.renderSelectInput(); @@ -470,11 +465,24 @@ export class Choices { } } + /** + * Initialise Choices + * @return + */ + init() { + if (!this.supports) console.error('init: Your browser doesn\'nt support shit'); + this.initialised = true; + this.renderInput(this.element); + } + + /** + * Destroy Choices and nullify values + * @return + */ destroy() { this.options = null; this.element = null; this.initialised = null; - this.removeEventListeners(this.input); } }; @@ -487,15 +495,15 @@ export class Choices { let choices1 = new Choices({ element : input1, - // delimiter: ' ', + delimiter: ' ', editItems: true, maxItems: 5, - callbackOnRemoveItem: function(value) { - console.log(value); - }, - callbackOnAddItem: function(item, value) { - console.log(item, value); - } + // callbackOnRemoveItem: function(value) { + // console.log(value); + // }, + // callbackOnAddItem: function(item, value) { + // console.log(item, value); + // } }); let choices2 = new Choices({ diff --git a/assets/scripts/src/lib/utils.js b/assets/scripts/src/lib/utils.js index 9b372b7..cacf373 100644 --- a/assets/scripts/src/lib/utils.js +++ b/assets/scripts/src/lib/utils.js @@ -24,6 +24,40 @@ export const isType = function(type, obj) { return obj !== undefined && obj !== null && clas === type; }; +/** + * Merges unspecified amount of objects into new object + * @private + * @return {Object} Merged object of arguments + */ +export const extend = function() { + let extended = {}; + let length = arguments.length; + + /** + * Merge one object into another + * @param {Object} obj Object to merge into extended object + */ + let merge = function(obj) { + for (let prop in obj) { + extended[prop] = obj[prop]; + } + }; + + // Loop through each passed argument + for (let i = 0; i < length; i++) { + // store argument at position i + let obj = arguments[i]; + + // If we are in fact dealing with an object, merge it. Otherwise throw error + if (isType('Object', obj)) { + merge(obj); + } else { + console.error('Custom options must be an object'); + } + } + + return extended; +}; /** * CSS transition end event listener diff --git a/assets/scripts/src/reducers/index.js b/assets/scripts/src/reducers/index.js index ad38128..db4b7a0 100644 --- a/assets/scripts/src/reducers/index.js +++ b/assets/scripts/src/reducers/index.js @@ -1,21 +1,22 @@ -const choices = (state = [], action) => { +const initialState = []; + +const choices = (state = initialState, action) => { switch (action.type) { case 'ADD_ITEM': // Add object to items array - return [...state, { + let newState = [...state, { id: parseInt(action.id), value: action.value, active: true, selected: false }]; - case 'UNSELECT_ALL': - return state.map((item) => { + return newState.map((item) => { if(item.selected) { item.selected = false; } return item; - }); + });; case 'REMOVE_ITEM': // Set item to inactive @@ -35,7 +36,6 @@ const choices = (state = [], action) => { return item; }); - default: return state; } diff --git a/index.html b/index.html index 4f6077e..5d259e9 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@
      - +