Merge branch 'maximmig-master'

This commit is contained in:
Josh Johnson 2017-07-13 09:01:44 +01:00
commit 49c76da629
7 changed files with 339 additions and 267 deletions

View file

@ -76,11 +76,13 @@ Or include Choices directly:
resetScrollPosition: true,
regexFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFilter: () => {...},
placeholder: true,
placeholderValue: null,
prependValue: null,
appendValue: null,
renderSelectedChoices: 'auto',
loadingText: 'Loading...',
noResultsText: 'No results found',
noChoicesText: 'No choices to choose from',
@ -318,14 +320,21 @@ Pass an array of objects:
**Input types affected:** `select-one`, `select-multiple`
**Usage:** Whether choices should be sorted. If false, choices will appear in the order they were given.
**Usage:** Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.
### shouldSortItems
**Type:** `Boolean` **Default:** `false`
**Input types affected:** `text`, `select-multiple`
**Usage:** Whether items should be sorted. If false, items will appear in the order they were selected.
### sortFilter
**Type:** `Function` **Default:** sortByAlpha
**Input types affected:** `select-one`, `select-multiple`
**Usage:** The function that will sort choices before they are displayed (unless a user is searching). By default choices are sorted by alphabetical order.
**Usage:** The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order.
**Example:**
@ -366,6 +375,13 @@ const example = new Choices(element, {
**Usage:** Append a value to each item added/selected.
### renderSelectedChoices
**Type:** `String` **Default:** `auto`
**Input types affected:** `select-one`, `select-multiple`
**Usage:** Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`.
### loadingText
**Type:** `String` **Default:** `Loading...`

View file

@ -137,11 +137,13 @@ return /******/ (function(modules) { // webpackBootstrap
resetScrollPosition: true,
regexFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFilter: _utils.sortByAlpha,
placeholder: true,
placeholderValue: null,
prependValue: null,
appendValue: null,
renderSelectedChoices: 'auto',
loadingText: 'Loading...',
noResultsText: 'No results found',
noChoicesText: 'No choices to choose from',
@ -193,6 +195,13 @@ return /******/ (function(modules) { // webpackBootstrap
// Merge options with user options
this.config = (0, _utils.extend)(defaultConfig, userConfig);
if (this.config.renderSelectedChoices !== 'auto' && this.config.renderSelectedChoices !== 'always') {
if (!this.config.silent) {
console.warn('renderSelectedChoices: Possible values are \'auto\' and \'always\'. Falling back to \'auto\'.');
}
this.config.renderSelectedChoices = 'auto';
}
// Create data store
this.store = new _index2.default(this.render);
@ -215,10 +224,16 @@ return /******/ (function(modules) { // webpackBootstrap
return;
}
if (this.config.shouldSortItems === true && this.passedElement.type === 'select-one') {
if (!this.config.silent) {
console.warn('shouldSortElements: Type of passed element is \'select-one\', falling back to false.');
}
}
this.highlightPosition = 0;
this.canSearch = this.config.searchEnabled;
// Assing preset choices from passed object
// Assign preset choices from passed object
this.presetChoices = this.config.choices;
// Assign preset items from passed object first
@ -418,10 +433,12 @@ return /******/ (function(modules) { // webpackBootstrap
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
var choicesFragment = fragment || document.createDocumentFragment();
var filter = this.isSearching ? _utils.sortByScore : this.config.sortFilter;
var renderSelectedChoices = this.config.renderSelectedChoices;
var appendChoice = function appendChoice(choice) {
var dropdownItem = _this3._getTemplate('choice', choice);
var shouldRender = _this3.passedElement.type === 'select-one' || !choice.selected;
var shouldRender = renderSelectedChoices === 'auto' ? _this3.passedElement.type === 'select-one' || !choice.selected : true;
if (shouldRender) {
var dropdownItem = _this3._getTemplate('choice', choice);
choicesFragment.appendChild(dropdownItem);
}
};
@ -463,6 +480,11 @@ return /******/ (function(modules) { // webpackBootstrap
// Create fragment to add elements to
var itemListFragment = fragment || document.createDocumentFragment();
// If sorting is enabled, filter items
if (this.config.shouldSortItems && this.passedElement.type !== 'select-one') {
items.sort(this.config.sortFilter);
}
if (this.isTextElement) {
// Simplify store data to just values
var itemsFiltered = this.store.getItemsReducedToValues(items);
@ -3624,9 +3646,9 @@ return /******/ (function(modules) { // webpackBootstrap
this.store = (0, _redux.createStore)(_index2.default, window.devToolsExtension ? window.devToolsExtension() : undefined);
}
/**
* Get store object (wrapping Redux method)
* @return {Object} State
/**
* Get store object (wrapping Redux method)
* @return {Object} State
*/
@ -3636,10 +3658,10 @@ return /******/ (function(modules) { // webpackBootstrap
return this.store.getState();
}
/**
* Dispatch event to store (wrapped Redux method)
* @param {Function} action Action function to trigger
* @return
/**
* Dispatch event to store (wrapped Redux method)
* @param {Function} action Action function to trigger
* @return
*/
}, {
@ -3648,10 +3670,10 @@ return /******/ (function(modules) { // webpackBootstrap
this.store.dispatch(action);
}
/**
* Subscribe store to function call (wrapped Redux method)
* @param {Function} onChange Function to trigger when state changes
* @return
/**
* Subscribe store to function call (wrapped Redux method)
* @param {Function} onChange Function to trigger when state changes
* @return
*/
}, {
@ -3660,9 +3682,9 @@ return /******/ (function(modules) { // webpackBootstrap
this.store.subscribe(onChange);
}
/**
* Get items from store
* @return {Array} Item objects
/**
* Get items from store
* @return {Array} Item objects
*/
}, {
@ -3672,9 +3694,9 @@ return /******/ (function(modules) { // webpackBootstrap
return state.items;
}
/**
* Get active items from store
* @return {Array} Item objects
/**
* Get active items from store
* @return {Array} Item objects
*/
}, {
@ -3688,9 +3710,9 @@ return /******/ (function(modules) { // webpackBootstrap
return values;
}
/**
* Get items from store reduced to just their values
* @return {Array} Item objects
/**
* Get items from store reduced to just their values
* @return {Array} Item objects
*/
}, {
@ -3706,9 +3728,9 @@ return /******/ (function(modules) { // webpackBootstrap
return values;
}
/**
* Get choices from store
* @return {Array} Option objects
/**
* Get choices from store
* @return {Array} Option objects
*/
}, {
@ -3718,9 +3740,9 @@ return /******/ (function(modules) { // webpackBootstrap
return state.choices;
}
/**
* Get active choices from store
* @return {Array} Option objects
/**
* Get active choices from store
* @return {Array} Option objects
*/
}, {
@ -3734,9 +3756,9 @@ return /******/ (function(modules) { // webpackBootstrap
return values;
}
/**
* Get selectable choices from store
* @return {Array} Option objects
/**
* Get selectable choices from store
* @return {Array} Option objects
*/
}, {
@ -3750,9 +3772,9 @@ return /******/ (function(modules) { // webpackBootstrap
return values;
}
/**
* Get single choice by it's ID
* @return {Object} Found choice
/**
* Get single choice by it's ID
* @return {Object} Found choice
*/
}, {
@ -3768,9 +3790,9 @@ return /******/ (function(modules) { // webpackBootstrap
return false;
}
/**
* Get groups from store
* @return {Array} Group objects
/**
* Get groups from store
* @return {Array} Group objects
*/
}, {
@ -3780,9 +3802,9 @@ return /******/ (function(modules) { // webpackBootstrap
return state.groups;
}
/**
* Get active groups from store
* @return {Array} Group objects
/**
* Get active groups from store
* @return {Array} Group objects
*/
}, {
@ -3802,10 +3824,10 @@ return /******/ (function(modules) { // webpackBootstrap
return values;
}
/**
* Get group by group id
* @param {Number} id Group ID
* @return {Object} Group data
/**
* Get group by group id
* @param {Number} id Group ID
* @return {Object} Group data
*/
}, {
@ -3907,34 +3929,33 @@ return /******/ (function(modules) { // webpackBootstrap
*/
var ActionTypes = exports.ActionTypes = {
INIT: '@@redux/INIT'
};
/**
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
*
* There should only be a single store in your app. To specify how different
* parts of the state tree respond to actions, you may combine several reducers
* into a single reducer function by using `combineReducers`.
*
* @param {Function} reducer A function that returns the next state tree, given
* the current state tree and the action to handle.
*
* @param {any} [preloadedState] The initial state. You may optionally specify it
* to hydrate the state from the server in universal apps, or to restore a
* previously serialized user session.
* If you use `combineReducers` to produce the root reducer function, this must be
* an object with the same shape as `combineReducers` keys.
*
* @param {Function} enhancer The store enhancer. You may optionally specify it
* to enhance the store with third-party capabilities such as middleware,
* time travel, persistence, etc. The only store enhancer that ships with Redux
* is `applyMiddleware()`.
*
* @returns {Store} A Redux store that lets you read the state, dispatch actions
* and subscribe to changes.
*/
function createStore(reducer, preloadedState, enhancer) {
/**
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
*
* There should only be a single store in your app. To specify how different
* parts of the state tree respond to actions, you may combine several reducers
* into a single reducer function by using `combineReducers`.
*
* @param {Function} reducer A function that returns the next state tree, given
* the current state tree and the action to handle.
*
* @param {any} [preloadedState] The initial state. You may optionally specify it
* to hydrate the state from the server in universal apps, or to restore a
* previously serialized user session.
* If you use `combineReducers` to produce the root reducer function, this must be
* an object with the same shape as `combineReducers` keys.
*
* @param {Function} [enhancer] The store enhancer. You may optionally specify it
* to enhance the store with third-party capabilities such as middleware,
* time travel, persistence, etc. The only store enhancer that ships with Redux
* is `applyMiddleware()`.
*
* @returns {Store} A Redux store that lets you read the state, dispatch actions
* and subscribe to changes.
*/
};function createStore(reducer, preloadedState, enhancer) {
var _ref2;
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
@ -4068,7 +4089,8 @@ return /******/ (function(modules) { // webpackBootstrap
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
listeners[i]();
var listener = listeners[i];
listener();
}
return action;
@ -4097,7 +4119,7 @@ return /******/ (function(modules) { // webpackBootstrap
* Interoperability point for observable/reactive libraries.
* @returns {observable} A minimal observable of state changes.
* For more information, see the observable proposal:
* https://github.com/zenparsing/es-observable
* https://github.com/tc39/proposal-observable
*/
function observable() {
var _ref;
@ -4544,7 +4566,7 @@ return /******/ (function(modules) { // webpackBootstrap
var actionType = action && action.type;
var actionName = actionType && '"' + actionType.toString() + '"' || 'an action';
return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state.';
return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state. ' + 'If you want this reducer to hold no value, you can return null instead of undefined.';
}
function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
@ -4572,18 +4594,18 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
function assertReducerSanity(reducers) {
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT });
if (typeof initialState === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.');
throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined. If you don\'t want to set a value for this reducer, ' + 'you can use null instead of undefined.');
}
var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');
if (typeof reducer(undefined, { type: type }) === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.');
throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined, but can be null.');
}
});
}
@ -4622,23 +4644,24 @@ return /******/ (function(modules) { // webpackBootstrap
}
var finalReducerKeys = Object.keys(finalReducers);
var unexpectedKeyCache = void 0;
if (false) {
var unexpectedKeyCache = {};
unexpectedKeyCache = {};
}
var sanityError;
var shapeAssertionError = void 0;
try {
assertReducerSanity(finalReducers);
assertReducerShape(finalReducers);
} catch (e) {
sanityError = e;
shapeAssertionError = e;
}
return function combination() {
var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var action = arguments[1];
if (sanityError) {
throw sanityError;
if (shapeAssertionError) {
throw shapeAssertionError;
}
if (false) {
@ -4650,16 +4673,16 @@ return /******/ (function(modules) { // webpackBootstrap
var hasChanged = false;
var nextState = {};
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i];
var reducer = finalReducers[key];
var previousStateForKey = state[key];
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action);
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[key] = nextStateForKey;
nextState[_key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
return hasChanged ? nextState : state;
@ -4849,13 +4872,11 @@ return /******/ (function(modules) { // webpackBootstrap
return funcs[0];
}
var last = funcs[funcs.length - 1];
var rest = funcs.slice(0, -1);
return function () {
return rest.reduceRight(function (composed, f) {
return f(composed);
}, last.apply(undefined, arguments));
};
return funcs.reduce(function (a, b) {
return function () {
return a(b.apply(undefined, arguments));
};
});
}
/***/ }),
@ -5034,10 +5055,10 @@ return /******/ (function(modules) { // webpackBootstrap
switch (action.type) {
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
/*
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 [].concat(_toConsumableArray(state), [{
id: action.id,
@ -5238,10 +5259,10 @@ return /******/ (function(modules) { // webpackBootstrap
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/* eslint-disable */
/**
* Capitalises the first letter of each word in a string
* @param {String} str String to capitalise
* @return {String} Capitalised string
/**
* Capitalises the first letter of each word in a string
* @param {String} str String to capitalise
* @return {String} Capitalised string
*/
var capitalise = exports.capitalise = function capitalise(str) {
return str.replace(/\w\S*/g, function (txt) {
@ -5249,10 +5270,10 @@ return /******/ (function(modules) { // webpackBootstrap
});
};
/**
* Generates a string of random chars
* @param {Number} length Length of the string to generate
* @return {String} String of random chars
/**
* Generates a string of random chars
* @param {Number} length Length of the string to generate
* @return {String} String of random chars
*/
var generateChars = exports.generateChars = function generateChars(length) {
var chars = '';
@ -5265,11 +5286,11 @@ return /******/ (function(modules) { // webpackBootstrap
return chars;
};
/**
* Generates a unique id based on an element
* @param {HTMLElement} element Element to generate the id from
* @param {String} Prefix for the Id
* @return {String} Unique Id
/**
* Generates a unique id based on an element
* @param {HTMLElement} element Element to generate the id from
* @param {String} Prefix for the Id
* @return {String} Unique Id
*/
var generateId = exports.generateId = function generateId(element, prefix) {
var id = element.id || element.name && element.name + '-' + generateChars(2) || generateChars(4);
@ -5279,58 +5300,58 @@ return /******/ (function(modules) { // webpackBootstrap
return id;
};
/**
* Tests the type of an object
* @param {String} type Type to test object against
* @param {Object} obj Object to be tested
* @return {Boolean}
/**
* Tests the type of an object
* @param {String} type Type to test object against
* @param {Object} obj Object to be tested
* @return {Boolean}
*/
var getType = exports.getType = function getType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
};
/**
* Tests the type of an object
* @param {String} type Type to test object against
* @param {Object} obj Object to be tested
* @return {Boolean}
/**
* Tests the type of an object
* @param {String} type Type to test object against
* @param {Object} obj Object to be tested
* @return {Boolean}
*/
var isType = exports.isType = function isType(type, obj) {
var clas = getType(obj);
return obj !== undefined && obj !== null && clas === type;
};
/**
* Tests to see if a passed object is a node
* @param {Object} obj Object to be tested
* @return {Boolean}
/**
* Tests to see if a passed object is a node
* @param {Object} obj Object to be tested
* @return {Boolean}
*/
var isNode = exports.isNode = function isNode(o) {
return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === "object" ? o instanceof Node : o && (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string";
};
/**
* Tests to see if a passed object is an element
* @param {Object} obj Object to be tested
* @return {Boolean}
/**
* Tests to see if a passed object is an element
* @param {Object} obj Object to be tested
* @return {Boolean}
*/
var isElement = exports.isElement = function isElement(o) {
return (typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === "object" ? o instanceof HTMLElement : //DOM2
o && (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string";
};
/**
* Merges unspecified amount of objects into new object
* @private
* @return {Object} Merged object of arguments
/**
* Merges unspecified amount of objects into new object
* @private
* @return {Object} Merged object of arguments
*/
var extend = exports.extend = function extend() {
var extended = {};
var length = arguments.length;
/**
* Merge one object into another
* @param {Object} obj Object to merge into extended object
/**
* Merge one object into another
* @param {Object} obj Object to merge into extended object
*/
var merge = function merge(obj) {
for (var prop in obj) {
@ -5359,9 +5380,9 @@ return /******/ (function(modules) { // webpackBootstrap
return extended;
};
/**
* CSS transition end event listener
* @return
/**
* CSS transition end event listener
* @return
*/
var whichTransitionEvent = exports.whichTransitionEvent = function whichTransitionEvent() {
var t,
@ -5381,9 +5402,9 @@ return /******/ (function(modules) { // webpackBootstrap
}
};
/**
* CSS animation end event listener
* @return
/**
* CSS animation end event listener
* @return
*/
var whichAnimationEvent = exports.whichAnimationEvent = function whichAnimationEvent() {
var t,
@ -5403,13 +5424,13 @@ return /******/ (function(modules) { // webpackBootstrap
}
};
/**
* Get the ancestors of each element in the current set of matched elements,
* up to but not including the element matched by the selector
* @param {NodeElement} elem Element to begin search from
* @param {NodeElement} parent Parent to find
* @param {String} selector Class to find
* @return {Array} Array of parent elements
/**
* Get the ancestors of each element in the current set of matched elements,
* up to but not including the element matched by the selector
* @param {NodeElement} elem Element to begin search from
* @param {NodeElement} parent Parent to find
* @param {String} selector Class to find
* @return {Array} Array of parent elements
*/
var getParentsUntil = exports.getParentsUntil = function getParentsUntil(elem, parent, selector) {
var parents = [];
@ -5509,22 +5530,22 @@ return /******/ (function(modules) { // webpackBootstrap
return siblings;
};
/**
* Find ancestor in DOM tree
* @param {NodeElement} el Element to start search from
* @param {[type]} cls Class of parent
* @return {NodeElement} Found parent element
/**
* Find ancestor in DOM tree
* @param {NodeElement} el Element to start search from
* @param {[type]} cls Class of parent
* @return {NodeElement} Found parent element
*/
var findAncestor = exports.findAncestor = function findAncestor(el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls)) {}
return el;
};
/**
* Find ancestor in DOM tree by attribute name
* @param {NodeElement} el Element to start search from
* @param {string} attr Attribute name of parent
* @return {?NodeElement} Found parent element or null
/**
* Find ancestor in DOM tree by attribute name
* @param {NodeElement} el Element to start search from
* @param {string} attr Attribute name of parent
* @return {?NodeElement} Found parent element or null
*/
var findAncestorByAttrName = exports.findAncestorByAttrName = function findAncestorByAttrName(el, attr) {
var target = el;
@ -5540,12 +5561,12 @@ return /******/ (function(modules) { // webpackBootstrap
return null;
};
/**
* Debounce an event handler.
* @param {Function} func Function to run after wait
* @param {Number} wait The delay before the function is executed
* @param {Boolean} immediate If passed, trigger the function on the leading edge, instead of the trailing.
* @return {Function} A function will be called after it stops being called for a given delay
/**
* Debounce an event handler.
* @param {Function} func Function to run after wait
* @param {Number} wait The delay before the function is executed
* @param {Boolean} immediate If passed, trigger the function on the leading edge, instead of the trailing.
* @return {Function} A function will be called after it stops being called for a given delay
*/
var debounce = exports.debounce = function debounce(func, wait, immediate) {
var timeout;
@ -5563,11 +5584,11 @@ return /******/ (function(modules) { // webpackBootstrap
};
};
/**
* Get an element's distance from the top of the page
* @private
* @param {NodeElement} el Element to test for
* @return {Number} Elements Distance from top of page
/**
* Get an element's distance from the top of the page
* @private
* @param {NodeElement} el Element to test for
* @return {Number} Elements Distance from top of page
*/
var getElemDistance = exports.getElemDistance = function getElemDistance(el) {
var location = 0;
@ -5580,11 +5601,11 @@ return /******/ (function(modules) { // webpackBootstrap
return location >= 0 ? location : 0;
};
/**
* Determine element height multiplied by any offsets
* @private
* @param {HTMLElement} el Element to test for
* @return {Number} Height of element
/**
* Determine element height multiplied by any offsets
* @private
* @param {HTMLElement} el Element to test for
* @return {Number} Height of element
*/
var getElementOffset = exports.getElementOffset = function getElementOffset(el, offset) {
var elOffset = offset;
@ -5594,12 +5615,12 @@ return /******/ (function(modules) { // webpackBootstrap
return Math.max(el.offsetHeight * elOffset);
};
/**
* Get the next or previous element from a given start point
* @param {HTMLElement} startEl Element to start position from
* @param {String} className The class we will look through
* @param {Number} direction Positive next element, negative previous element
* @return {[HTMLElement} Found element
/**
* Get the next or previous element from a given start point
* @param {HTMLElement} startEl Element to start position from
* @param {String} className The class we will look through
* @param {Number} direction Positive next element, negative previous element
* @return {[HTMLElement} Found element
*/
var getAdjacentEl = exports.getAdjacentEl = function getAdjacentEl(startEl, className) {
var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
@ -5615,10 +5636,10 @@ return /******/ (function(modules) { // webpackBootstrap
return children[startPos + operatorDirection];
};
/**
* Get scroll position based on top/bottom position
* @private
* @return {String} Position of scroll
/**
* Get scroll position based on top/bottom position
* @private
* @return {String} Position of scroll
*/
var getScrollPosition = exports.getScrollPosition = function getScrollPosition(position) {
if (position === 'bottom') {
@ -5630,23 +5651,23 @@ return /******/ (function(modules) { // webpackBootstrap
}
};
/**
* Determine whether an element is within the viewport
* @param {HTMLElement} el Element to test
* @return {String} Position of scroll
* @return {Boolean}
/**
* Determine whether an element is within the viewport
* @param {HTMLElement} el Element to test
* @return {String} Position of scroll
* @return {Boolean}
*/
var isInView = exports.isInView = function isInView(el, position, offset) {
// If the user has scrolled further than the distance from the element to the top of its parent
return this.getScrollPosition(position) > this.getElemDistance(el) + this.getElementOffset(el, offset) ? true : false;
};
/**
* Determine whether an element is within
* @param {HTMLElement} el Element to test
* @param {HTMLElement} parent Scrolling parent
* @param {Number} direction Whether element is visible from above or below
* @return {Boolean}
/**
* Determine whether an element is within
* @param {HTMLElement} el Element to test
* @param {HTMLElement} parent Scrolling parent
* @param {Number} direction Whether element is visible from above or below
* @return {Boolean}
*/
var isScrolledIntoView = exports.isScrolledIntoView = function isScrolledIntoView(el, parent) {
var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
@ -5666,10 +5687,10 @@ return /******/ (function(modules) { // webpackBootstrap
return isVisible;
};
/**
* Remove html tags from a string
* @param {String} Initial string/html
* @return {String} Sanitised string
/**
* Remove html tags from a string
* @param {String} Initial string/html
* @return {String} Sanitised string
*/
var stripHTML = exports.stripHTML = function stripHTML(html) {
var el = document.createElement("DIV");
@ -5677,11 +5698,11 @@ return /******/ (function(modules) { // webpackBootstrap
return el.textContent || el.innerText || "";
};
/**
* Adds animation to an element and removes it upon animation completion
* @param {Element} el Element to add animation to
* @param {String} animation Animation class to add to element
* @return
/**
* Adds animation to an element and removes it upon animation completion
* @param {Element} el Element to add animation to
* @param {String} animation Animation class to add to element
* @return
*/
var addAnimation = exports.addAnimation = function addAnimation(el, animation) {
var animationEvent = whichAnimationEvent();
@ -5695,20 +5716,20 @@ return /******/ (function(modules) { // webpackBootstrap
el.addEventListener(animationEvent, removeAnimation, false);
};
/**
* Get a random number between a range
* @param {Number} min Minimum range
* @param {Number} max Maximum range
* @return {Number} Random number
/**
* Get a random number between a range
* @param {Number} min Minimum range
* @param {Number} max Maximum range
* @return {Number} Random number
*/
var getRandomNumber = exports.getRandomNumber = function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
};
/**
* Turn a string into a node
* @param {String} String to convert
* @return {HTMLElement} Converted node element
/**
* Turn a string into a node
* @param {String} String to convert
* @return {HTMLElement} Converted node element
*/
var strToEl = exports.strToEl = function () {
var tmpEl = document.createElement('div');
@ -5726,9 +5747,9 @@ return /******/ (function(modules) { // webpackBootstrap
};
}();
/**
* Sets the width of a passed input based on its value
* @return {Number} Width of input
/**
* Sets the width of a passed input based on its value
* @return {Number} Width of input
*/
var getWidthOfInput = exports.getWidthOfInput = function getWidthOfInput(input) {
var value = input.value || input.placeholder;
@ -5755,13 +5776,13 @@ return /******/ (function(modules) { // webpackBootstrap
return width + 'px';
};
/**
* Sorting function for current and previous string
* @param {String} a Current value
* @param {String} b Next value
* @return {Number} -1 for after previous,
* 1 for before,
* 0 for same location
/**
* Sorting function for current and previous string
* @param {String} a Current value
* @param {String} b Next value
* @return {Number} -1 for after previous,
* 1 for before,
* 0 for same location
*/
var sortByAlpha = exports.sortByAlpha = function sortByAlpha(a, b) {
var labelA = (a.label || a.value).toLowerCase();
@ -5772,24 +5793,24 @@ return /******/ (function(modules) { // webpackBootstrap
return 0;
};
/**
* Sort by numeric score
* @param {Object} a Current value
* @param {Object} b Next value
* @return {Number} -1 for after previous,
* 1 for before,
* 0 for same location
/**
* Sort by numeric score
* @param {Object} a Current value
* @param {Object} b Next value
* @return {Number} -1 for after previous,
* 1 for before,
* 0 for same location
*/
var sortByScore = exports.sortByScore = function sortByScore(a, b) {
return a.score - b.score;
};
/**
* Trigger native event
* @param {NodeElement} element Element to trigger event on
* @param {String} type Type of event to trigger
* @param {Object} customArgs Data to pass with event
* @return {Object} Triggered event
/**
* Trigger native event
* @param {NodeElement} element Element to trigger event on
* @param {String} type Type of event to trigger
* @param {Object} customArgs Data to pass with event
* @return {Object} Triggered event
*/
var triggerEvent = exports.triggerEvent = function triggerEvent(element, type) {
var customArgs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -71,11 +71,13 @@ class Choices {
resetScrollPosition: true,
regexFilter: null,
shouldSort: true,
shouldSortItems: false,
sortFilter: sortByAlpha,
placeholder: true,
placeholderValue: null,
prependValue: null,
appendValue: null,
renderSelectedChoices: 'auto',
loadingText: 'Loading...',
noResultsText: 'No results found',
noChoicesText: 'No choices to choose from',
@ -127,6 +129,13 @@ class Choices {
// Merge options with user options
this.config = extend(defaultConfig, userConfig);
if (this.config.renderSelectedChoices !== 'auto' && this.config.renderSelectedChoices !== 'always') {
if (!this.config.silent) {
console.warn('renderSelectedChoices: Possible values are \'auto\' and \'always\'. Falling back to \'auto\'.');
}
this.config.renderSelectedChoices = 'auto';
}
// Create data store
this.store = new Store(this.render);
@ -150,10 +159,16 @@ class Choices {
return;
}
if (this.config.shouldSortItems === true && this.passedElement.type === 'select-one') {
if (!this.config.silent) {
console.warn('shouldSortElements: Type of passed element is \'select-one\', falling back to false.');
}
}
this.highlightPosition = 0;
this.canSearch = this.config.searchEnabled;
// Assing preset choices from passed object
// Assign preset choices from passed object
this.presetChoices = this.config.choices;
// Assign preset items from passed object first
@ -336,10 +351,13 @@ class Choices {
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
const choicesFragment = fragment || document.createDocumentFragment();
const filter = this.isSearching ? sortByScore : this.config.sortFilter;
const { renderSelectedChoices } = this.config;
const appendChoice = (choice) => {
const dropdownItem = this._getTemplate('choice', choice);
const shouldRender = this.passedElement.type === 'select-one' || !choice.selected;
const shouldRender = renderSelectedChoices === 'auto'
? this.passedElement.type === 'select-one' || !choice.selected
: true;
if (shouldRender) {
const dropdownItem = this._getTemplate('choice', choice);
choicesFragment.appendChild(dropdownItem);
}
};
@ -374,6 +392,11 @@ class Choices {
// Create fragment to add elements to
const itemListFragment = fragment || document.createDocumentFragment();
// If sorting is enabled, filter items
if (this.config.shouldSortItems && this.passedElement.type !== 'select-one') {
items.sort(this.config.sortFilter);
}
if (this.isTextElement) {
// Simplify store data to just values
const itemsFiltered = this.store.getItemsReducedToValues(items);
@ -611,9 +634,6 @@ class Choices {
*/
removeItemsByValue(value) {
if (!value || !isType('String', value)) {
if (!this.config.silent) {
console.error('removeItemsByValue: No value was passed to be removed');
}
return;
}
@ -2134,9 +2154,6 @@ class Choices {
*/
_removeItem(item) {
if (!item || !isType('Object', item)) {
if (!this.config.silent) {
console.error('removeItem: No item object was passed to be removed');
}
return;
}

View file

@ -5,8 +5,8 @@
"main": "./assets/scripts/dist/choices.min.js",
"scripts": {
"start": "node server.js",
"test": "./node_modules/karma/bin/karma start --single-run --no-auto-watch tests/karma.config.js",
"test:watch": "./node_modules/karma/bin/karma start --auto-watch --no-single-run tests/karma.config.js",
"test": "karma start --single-run --no-auto-watch tests/karma.config.js",
"test:watch": "karma start --auto-watch --no-single-run tests/karma.config.js",
"css:watch": "nodemon -e scss -x \"npm run css:build\"",
"css:build": "npm run css:sass -s && npm run css:prefix -s && npm run css:min -s",
"css:sass": "node-sass --output-style expanded --include-path scss assets/styles/scss/base.scss assets/styles/css/base.css && node-sass --output-style expanded --include-path scss assets/styles/scss/choices.scss assets/styles/css/choices.css",

View file

@ -36,7 +36,7 @@ describe('Choices', () => {
const reinitialise = new Choices(this.choices.passedElement);
spyOn(reinitialise, '_createTemplates');
expect(reinitialise._createTemplates).not.toHaveBeenCalled();
})
});
it('should have a blank state', function() {
expect(this.choices.currentState.items.length).toEqual(0);
@ -65,10 +65,12 @@ describe('Choices', () => {
expect(this.choices.config.regexFilter).toEqual(null);
expect(this.choices.config.sortFilter).toEqual(jasmine.any(Function));
expect(this.choices.config.shouldSort).toEqual(jasmine.any(Boolean));
expect(this.choices.config.shouldSortItems).toEqual(jasmine.any(Boolean));
expect(this.choices.config.placeholder).toEqual(jasmine.any(Boolean));
expect(this.choices.config.placeholderValue).toEqual(null);
expect(this.choices.config.prependValue).toEqual(null);
expect(this.choices.config.appendValue).toEqual(null);
expect(this.choices.config.renderSelectedChoices).toEqual(jasmine.any(String));
expect(this.choices.config.loadingText).toEqual(jasmine.any(String));
expect(this.choices.config.noResultsText).toEqual(jasmine.any(String));
expect(this.choices.config.noChoicesText).toEqual(jasmine.any(String));
@ -261,7 +263,7 @@ describe('Choices', () => {
this.choices.destroy();
});
it('should open the choice list on focussing', function() {
it('should open the choice list on focusing', function() {
this.choices = new Choices(this.input);
this.choices.input.focus();
expect(this.choices.dropdown.classList).toContain(this.choices.config.classNames.activeState);
@ -276,7 +278,7 @@ describe('Choices', () => {
this.choices = new Choices(this.input);
this.choices.input.focus();
for (var i = 0; i < 2; i++) {
for (let i = 0; i < 2; i++) {
// Key down to third choice
this.choices._onKeyDown({
target: this.choices.input,
@ -498,7 +500,7 @@ describe('Choices', () => {
expect(this.choices.currentState.choices[0].value).toEqual('Value 5');
});
it('should sort choices if shouldSort is false', function() {
it('should sort choices if shouldSort is true', function() {
this.choices = new Choices(this.input, {
shouldSort: true,
choices: [{
@ -927,6 +929,22 @@ describe('Choices', () => {
this.choices.input.focus();
expect(container.classList.contains(this.choices.config.classNames.flippedState)).toBe(false);
});
it('should render selected choices', function() {
this.choices = new Choices(this.input, {
renderSelectedChoices: 'always'
});
const renderedChoices = this.choices.choiceList.querySelectorAll('.choices__item');
expect(renderedChoices.length).toEqual(3);
});
it('shouldn\'t render selected choices', function() {
this.choices = new Choices(this.input, {
renderSelectedChoices: 'auto'
});
const renderedChoices = this.choices.choiceList.querySelectorAll('.choices__item');
expect(renderedChoices.length).toEqual(1);
});
});
describe('should allow custom properties provided by the user on items or choices', function() {
@ -940,7 +958,7 @@ describe('Choices', () => {
customProperties: {
foo: 'bar'
}
}
};
const expectedState = [{
id: randomItem.id,
@ -976,7 +994,7 @@ describe('Choices', () => {
customProperties: {
foo: 'bar'
}
}
};
const expectedState = [{
id: randomChoice.id,
@ -1047,9 +1065,9 @@ describe('Choices', () => {
this.choices = new Choices(this.input);
this.choices.setValue([{
value: 'bar',
label: 'foo',
customProperties: expectedCustomProperties
value: 'bar',
label: 'foo',
customProperties: expectedCustomProperties
}]);
const selectedItems = this.choices.getValue();