Merge branch 'develop' of https://github.com/jshjohnson/Choices into develop

This commit is contained in:
Egon Richárd Tőrös 2018-05-10 14:42:53 +02:00
commit ec061adc7c
34 changed files with 1052 additions and 1783 deletions

View file

@ -1,3 +1,3 @@
{
"presets": ["es2015", "stage-2"]
"presets": ["env", "stage-2"]
}

View file

@ -18,6 +18,7 @@
"js:build": "concurrently --prefix-colors yellow,green \"webpack --env.minimize --config webpack.config.prod.js\" \"webpack --config webpack.config.prod.js\"",
"version": "node version.js --current $npm_package_version --new $npm_config_newVersion",
"postversion": "npm run js:build",
"prepush": "npm run lint && npm run test",
"dev": "dev"
},
"repository": {
@ -35,7 +36,7 @@
"babel-core": "^6.26.0",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.6.0",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-2": "^6.24.1",
"chai": "^4.1.0",
"concurrently": "^3.1.0",
@ -49,6 +50,7 @@
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.2.1",
"husky": "^0.14.3",
"jasmine-core": "2.4.1",
"jsdom": "^11.5.1",
"mocha": "^3.4.2",

View file

@ -518,14 +518,12 @@ var isScrolledIntoView = exports.isScrolledIntoView = function isScrolledIntoVie
};
/**
* Remove html tags from a string
* @param {String} Initial string/html
* Escape html in the string
* @param {String} html Initial string/html
* @return {String} Sanitised string
*/
var stripHTML = exports.stripHTML = function stripHTML(html) {
var el = document.createElement('DIV');
el.innerHTML = html;
return el.textContent || el.innerText || '';
return html.replace(/&/g, '&amp;').replace(/>/g, '&rt;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
};
/**
@ -581,12 +579,12 @@ var strToEl = exports.strToEl = function () {
* Sets the width of a passed input based on its value
* @return {Number} Width of input
*/
var getWidthOfInput = exports.getWidthOfInput = function getWidthOfInput(input) {
var calcWidthOfInput = exports.calcWidthOfInput = function calcWidthOfInput(input) {
var value = input.value || input.placeholder;
var width = input.offsetWidth;
if (value) {
var testEl = strToEl('<span>' + value + '</span>');
var testEl = strToEl('<span>' + stripHTML(value) + '</span>');
testEl.style.position = 'absolute';
testEl.style.padding = '0';
testEl.style.top = '-9999px';
@ -725,6 +723,10 @@ var fetchFromObject = exports.fetchFromObject = function fetchFromObject(object,
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SCROLLING_SPEED = exports.KEY_CODES = exports.ACTION_TYPES = exports.EVENTS = exports.DEFAULT_CONFIG = exports.DEFAULT_CLASSNAMES = undefined;
var _utils = __webpack_require__(0);
var DEFAULT_CLASSNAMES = exports.DEFAULT_CLASSNAMES = {
containerOuter: 'choices',
containerInner: 'choices__inner',
@ -789,7 +791,7 @@ var DEFAULT_CONFIG = exports.DEFAULT_CONFIG = {
itemSelectText: 'Press to select',
uniqueItemText: 'Only unique values can be added.',
addItemText: function addItemText(value) {
return 'Press Enter to add <b>"' + value + '"</b>';
return 'Press Enter to add <b>"' + (0, _utils.stripHTML)(value) + '"</b>';
},
maxItemText: function maxItemText(maxItemCount) {
return 'Only ' + maxItemCount + ' values can be added.';
@ -1707,16 +1709,6 @@ var WrappedElement = function () {
}
_createClass(WrappedElement, [{
key: 'getElement',
value: function getElement() {
return this.element;
}
}, {
key: 'getValue',
value: function getValue() {
return this.element.value;
}
}, {
key: 'conceal',
value: function conceal() {
// Hide passed input
@ -1732,7 +1724,6 @@ var WrappedElement = function () {
this.element.setAttribute('data-choice-orig-style', origStyle);
}
this.element.setAttribute('style', 'display:none;');
this.element.setAttribute('aria-hidden', 'true');
this.element.setAttribute('data-choice', 'active');
}
@ -1777,6 +1768,11 @@ var WrappedElement = function () {
value: function triggerEvent(eventType, data) {
(0, _utils.dispatchEvent)(this.element, eventType, data);
}
}, {
key: 'value',
get: function get() {
return this.element.value;
}
}]);
return WrappedElement;
@ -2060,8 +2056,8 @@ var Choices = function () {
this.presetItems = this.config.items;
// Then add any values passed from attribute
if (this.passedElement.getValue()) {
this.presetItems = this.presetItems.concat(this.passedElement.getValue().split(this.config.delimiter));
if (this.passedElement.value) {
this.presetItems = this.presetItems.concat(this.passedElement.value.split(this.config.delimiter));
}
// Set unique base Id
@ -2129,8 +2125,10 @@ var Choices = function () {
// Set initialise flag
this.initialised = true;
// Create required elements
// Create required templates
this._createTemplates();
// Create required elements
this._createElements();
// Generate input markup
this._createStructure();
// Subscribe store to render method
@ -2166,7 +2164,7 @@ var Choices = function () {
this.containerOuter.unwrap(this.passedElement.element);
if (this.isSelectElement) {
this.passedElement.setOptions(this.presetChoices);
this.passedElement.options = this.presetChoices;
}
// Clear data store
@ -2372,10 +2370,10 @@ var Choices = function () {
if (this.isTextElement) {
// Update the value of the hidden input
this.passedElement.setValue(items);
this.passedElement.value = items;
} else {
// Update the options of the hidden input
this.passedElement.setOptions(items);
this.passedElement.options = items;
}
var addItemToFragment = function addItemToFragment(item) {
@ -2402,7 +2400,7 @@ var Choices = function () {
}, {
key: 'render',
value: function render() {
this.currentState = this.store.getState();
this.currentState = this.store.state;
var stateChanged = this.currentState.choices !== this.prevState.choices || this.currentState.groups !== this.prevState.groups || this.currentState.items !== this.prevState.items;
if (!stateChanged) {
@ -2413,8 +2411,8 @@ var Choices = function () {
if (this.isSelectElement) {
// Get active groups/choices
var activeGroups = this.store.getGroupsFilteredByActive();
var activeChoices = this.store.getChoicesFilteredByActive();
var activeGroups = this.store.activeGroups;
var activeChoices = this.store.activeChoices;
var choiceListFragment = document.createDocumentFragment();
@ -2442,8 +2440,8 @@ var Choices = function () {
// If we have choices to show
if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) {
var activeItems = this.store.getItemsFilteredByActive();
var canAddItem = this._canAddItem(activeItems, this.input.getValue());
var activeItems = this.store.activeItems;
var canAddItem = this._canAddItem(activeItems, this.input.value);
// ...and we can select them
if (canAddItem.response) {
@ -2476,7 +2474,7 @@ var Choices = function () {
/* Items */
if (this.currentState.items !== this.prevState.items) {
// Get active items (items that can be selected)
var _activeItems = this.store.getItemsFilteredByActive() || [];
var _activeItems = this.store.activeItems || [];
// Clear list
this.itemList.clear();
@ -2582,7 +2580,7 @@ var Choices = function () {
value: function highlightAll() {
var _this4 = this;
var items = this.store.getItems();
var items = this.store.items;
items.forEach(function (item) {
return _this4.highlightItem(item);
});
@ -2600,7 +2598,7 @@ var Choices = function () {
value: function unhighlightAll() {
var _this5 = this;
var items = this.store.getItems();
var items = this.store.items;
items.forEach(function (item) {
return _this5.unhighlightItem(item);
});
@ -2623,7 +2621,7 @@ var Choices = function () {
return this;
}
var items = this.store.getItemsFilteredByActive();
var items = this.store.activeItems;
items.forEach(function (item) {
if (item.value === value) {
@ -2647,7 +2645,7 @@ var Choices = function () {
value: function removeActiveItems(excludedId) {
var _this7 = this;
var items = this.store.getItemsFilteredByActive();
var items = this.store.activeItems;
items.forEach(function (item) {
if (excludedId !== item.id) {
@ -2672,7 +2670,7 @@ var Choices = function () {
var runEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var items = this.store.getItemsFilteredByHighlighted();
var items = this.store.highlightedActiveItems;
items.forEach(function (item) {
_this8._removeItem(item);
@ -2700,7 +2698,7 @@ var Choices = function () {
}
this.dropdown.show();
this.containerOuter.open(this.dropdown.getVerticalPos());
this.containerOuter.open(this.dropdown.distanceFromTopWindow());
if (focusInput && this.canSearch) {
this.input.focus();
@ -2768,7 +2766,7 @@ var Choices = function () {
value: function getValue() {
var valueOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var items = this.store.getItemsFilteredByActive();
var items = this.store.activeItems;
var values = items.reduce(function (selectedItems, item) {
var itemValue = valueOnly ? item.value : item;
@ -2966,7 +2964,7 @@ var Choices = function () {
}, {
key: '_selectPlaceholderChoice',
value: function _selectPlaceholderChoice() {
var placeholderChoice = this.store.getPlaceholderChoice();
var placeholderChoice = this.store.placeholderChoice;
if (placeholderChoice) {
this._addItem(placeholderChoice.value, placeholderChoice.label, placeholderChoice.id, placeholderChoice.groupId, null, placeholderChoice.placeholder);
@ -3108,7 +3106,7 @@ var Choices = function () {
// If editing the last item is allowed and there are not other selected items,
// we can edit the item value. Otherwise if we can remove items, remove all selected items
if (this.config.editItems && !hasHighlightedItems && lastItem) {
this.input.setValue(lastItem.value);
this.input.value = lastItem.value;
this.input.setWidth();
this._removeItem(lastItem);
this._triggerChange(lastItem.value);
@ -3144,7 +3142,7 @@ var Choices = function () {
placeholderItem.innerHTML = this.config.loadingText;
}
} else {
this.input.setPlaceholder(this.config.loadingText);
this.input.placeholder = this.config.loadingText;
}
} else {
this.containerOuter.removeLoadingState();
@ -3152,7 +3150,7 @@ var Choices = function () {
if (this.isSelectOneElement) {
placeholderItem.innerHTML = this.placeholder || '';
} else {
this.input.setPlaceholder(this.placeholder || '');
this.input.placeholder = this.placeholder || '';
}
}
}
@ -3267,7 +3265,7 @@ var Choices = function () {
}
// If new value matches the desired length and is not the same as the current value with a space
var haystack = this.store.getSearchableChoices();
var haystack = this.store.searchableChoices;
var needle = newValue;
var keys = (0, _utils.isType)('Array', this.config.searchFields) ? this.config.searchFields : [this.config.searchFields];
var options = Object.assign(this.config.fuseOptions, { keys: keys });
@ -3296,7 +3294,7 @@ var Choices = function () {
return;
}
var choices = this.store.getChoices();
var choices = this.store.choices;
var hasUnactiveChoices = choices.some(function (option) {
return !option.active;
});
@ -3389,7 +3387,7 @@ var Choices = function () {
}
var target = e.target;
var activeItems = this.store.getItemsFilteredByActive();
var activeItems = this.store.activeItems;
var hasFocusedInput = this.input.isFocussed;
var hasActiveDropdown = this.dropdown.isActive;
var hasItems = this.itemList.hasChildren;
@ -3416,7 +3414,7 @@ var Choices = function () {
// If CTRL + A or CMD + A have been pressed and there are items to select
if (ctrlDownKey && hasItems) {
_this15.canSearch = false;
if (_this15.config.removeItems && !_this15.input.getValue() && _this15.input.element === document.activeElement) {
if (_this15.config.removeItems && !_this15.input.value && _this15.input.element === document.activeElement) {
// Highlight items
_this15.highlightAll();
}
@ -3426,7 +3424,7 @@ var Choices = function () {
var onEnterKey = function onEnterKey() {
// If enter key is pressed and the input has a value
if (_this15.isTextElement && target.value) {
var value = _this15.input.getValue();
var value = _this15.input.value;
var canAddItem = _this15._canAddItem(activeItems, value);
// All is good, add
@ -3542,8 +3540,8 @@ var Choices = function () {
return;
}
var value = this.input.getValue();
var activeItems = this.store.getItemsFilteredByActive();
var value = this.input.value;
var activeItems = this.store.activeItems;
var canAddItem = this._canAddItem(activeItems, value);
// We are typing into a text input and have a value, we want to show a dropdown
@ -3575,7 +3573,7 @@ var Choices = function () {
this.store.dispatch((0, _choices.activateChoices)(true));
}
} else if (this.canSearch && canAddItem.response) {
this._handleSearch(this.input.getValue());
this._handleSearch(this.input.value);
}
}
// Re-establish canSearch value from changes in _onKeyDown
@ -3645,7 +3643,7 @@ var Choices = function () {
}
if (this.containerOuter.element.contains(target) && target !== this.input.element) {
var activeItems = this.store.getItemsFilteredByActive();
var activeItems = this.store.activeItems;
var hasShiftKey = e.shiftKey;
var buttonTarget = (0, _utils.findAncestorByAttrName)(target, 'data-button');
@ -3695,7 +3693,7 @@ var Choices = function () {
value: function _onClick(e) {
var target = e.target;
var hasActiveDropdown = this.dropdown.isActive;
var activeItems = this.store.getItemsFilteredByActive();
var activeItems = this.store.activeItems;
// If target is something that concerns us
if (this.containerOuter.element.contains(target)) {
@ -3790,7 +3788,7 @@ var Choices = function () {
var target = e.target;
// If target is something that concerns us
if (this.containerOuter.element.contains(target) && !this.isScrollingOnIe) {
var activeItems = this.store.getItemsFilteredByActive();
var activeItems = this.store.activeItems;
var hasHighlightedItems = activeItems.some(function (item) {
return item.highlighted;
});
@ -3982,7 +3980,7 @@ var Choices = function () {
var passedValue = (0, _utils.isType)('String', value) ? value.trim() : value;
var passedKeyCode = keyCode;
var passedCustomProperties = customProperties;
var items = this.store.getItems();
var items = this.store.items;
var passedLabel = label || passedValue;
var passedOptionId = parseInt(choiceId, 10) || -1;
@ -4101,7 +4099,7 @@ var Choices = function () {
}
// Generate unique id
var choices = this.store.getChoices();
var choices = this.store.choices;
var choiceLabel = label || value;
var choiceId = choices ? choices.length + 1 : 1;
var choiceElementId = this.baseId + '-' + this.idNames.itemChoice + '-' + choiceId;
@ -4207,14 +4205,12 @@ var Choices = function () {
}
/**
* Create DOM structure around passed select element
* @return
* @private
* Create DOM elements using templates
*/
}, {
key: '_createStructure',
value: function _createStructure() {
key: '_createElements',
value: function _createElements() {
var direction = this.passedElement.element.getAttribute('dir') || 'ltr';
var containerOuter = this._getTemplate('containerOuter', direction, this.isSelectElement, this.isSelectOneElement, this.config.searchEnabled, this.passedElement.element.type);
var containerInner = this._getTemplate('containerInner');
@ -4229,18 +4225,28 @@ var Choices = function () {
this.choiceList = new _list2.default(this, choiceList, this.config.classNames);
this.itemList = new _list2.default(this, itemList, this.config.classNames);
this.dropdown = new _dropdown2.default(this, dropdown, this.config.classNames);
}
/**
* Create DOM structure around passed select element
* @return
* @private
*/
}, {
key: '_createStructure',
value: function _createStructure() {
// Hide original element
this.passedElement.conceal();
// Wrap input in container preserving DOM ordering
this.containerInner.wrap(this.passedElement.element);
// Wrapper inner container with outer container
this.containerOuter.wrap(this.containerInner.element);
if (this.isSelectOneElement) {
this.input.setPlaceholder(this.config.searchPlaceholderValue || '');
this.input.placeholder = this.config.searchPlaceholderValue || '';
} else if (this.placeholder) {
this.input.setPlaceholder(this.placeholder);
this.input.placeholder = this.placeholder;
this.input.setWidth(true);
}
@ -4250,16 +4256,16 @@ var Choices = function () {
this.containerOuter.element.appendChild(this.containerInner.element);
this.containerOuter.element.appendChild(this.dropdown.element);
this.containerInner.element.appendChild(itemList);
this.containerInner.element.appendChild(this.itemList.element);
if (!this.isTextElement) {
dropdown.appendChild(choiceList);
this.dropdown.element.appendChild(this.choiceList.element);
}
if (!this.isSelectOneElement) {
this.containerInner.element.appendChild(this.input.element);
} else if (this.canSearch) {
dropdown.insertBefore(input, dropdown.firstChild);
this.dropdown.element.insertBefore(this.input.element, this.dropdown.element.firstChild);
}
if (this.isSelectElement) {
@ -4273,14 +4279,14 @@ var Choices = function () {
value: function _addPredefinedChoices() {
var _this21 = this;
var passedGroups = this.passedElement.getOptionGroups();
var passedGroups = this.passedElement.optionGroups;
this.highlightPosition = 0;
this.isSearching = false;
if (passedGroups && passedGroups.length) {
// If we have a placeholder option
var placeholderChoice = this.passedElement.getPlaceholderOption();
var placeholderChoice = this.passedElement.placeholderOption;
if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') {
this._addChoice(placeholderChoice.value, placeholderChoice.innerHTML, placeholderChoice.selected, placeholderChoice.disabled, undefined, undefined,
/* placeholder */true);
@ -4290,7 +4296,7 @@ var Choices = function () {
_this21._addGroup(group, group.id || null);
});
} else {
var passedOptions = this.passedElement.getOptions();
var passedOptions = this.passedElement.options;
var filter = this.config.sortFn;
var allChoices = this.presetChoices;
@ -4397,7 +4403,7 @@ var Choices = function () {
value: function _findAndSelectChoiceByValue(val) {
var _this24 = this;
var choices = this.store.getChoices();
var choices = this.store.choices;
// Check 'value' property exists and the choice isn't already selected
var foundChoice = choices.find(function (choice) {
return _this24.config.itemComparer(choice.value, val);
@ -5484,8 +5490,40 @@ var Store = function () {
*/
}, {
key: 'getState',
value: function getState() {
key: 'getChoiceById',
/**
* Get single choice by it's ID
* @return {Object} Found choice
*/
value: function getChoiceById(id) {
if (id) {
var choices = this.activeChoices;
var foundChoice = choices.find(function (choice) {
return choice.id === parseInt(id, 10);
});
return foundChoice;
}
return false;
}
/**
* Get group by group id
* @param {Number} id Group ID
* @return {Object} Group data
*/
}, {
key: 'getGroupById',
value: function getGroupById(id) {
return this.groups.find(function (group) {
return group.id === parseInt(id, 10);
});
}
}, {
key: 'state',
get: function get() {
return this.store.getState();
}
@ -5495,10 +5533,9 @@ var Store = function () {
*/
}, {
key: 'getItems',
value: function getItems() {
var state = this.store.getState();
return state.items;
key: 'items',
get: function get() {
return this.state.items;
}
/**
@ -5507,14 +5544,11 @@ var Store = function () {
*/
}, {
key: 'getItemsFilteredByActive',
value: function getItemsFilteredByActive() {
var items = this.getItems();
var values = items.filter(function (item) {
key: 'activeItems',
get: function get() {
return this.items.filter(function (item) {
return item.active === true;
});
return values;
}
/**
@ -5523,14 +5557,11 @@ var Store = function () {
*/
}, {
key: 'getItemsFilteredByHighlighted',
value: function getItemsFilteredByHighlighted() {
var items = this.getItems();
var values = items.filter(function (item) {
key: 'highlightedActiveItems',
get: function get() {
return this.items.filter(function (item) {
return item.active && item.highlighted;
});
return values;
}
/**
@ -5539,10 +5570,9 @@ var Store = function () {
*/
}, {
key: 'getChoices',
value: function getChoices() {
var state = this.store.getState();
return state.choices;
key: 'choices',
get: function get() {
return this.state.choices;
}
/**
@ -5551,9 +5581,9 @@ var Store = function () {
*/
}, {
key: 'getChoicesFilteredByActive',
value: function getChoicesFilteredByActive() {
var choices = this.getChoices();
key: 'activeChoices',
get: function get() {
var choices = this.choices;
var values = choices.filter(function (choice) {
return choice.active === true;
});
@ -5567,14 +5597,11 @@ var Store = function () {
*/
}, {
key: 'getChoicesFilteredBySelectable',
value: function getChoicesFilteredBySelectable() {
var choices = this.getChoices();
var values = choices.filter(function (choice) {
key: 'selectableChoices',
get: function get() {
return this.choices.filter(function (choice) {
return choice.disabled !== true;
});
return values;
}
/**
@ -5583,46 +5610,24 @@ var Store = function () {
*/
}, {
key: 'getSearchableChoices',
value: function getSearchableChoices() {
var filtered = this.getChoicesFilteredBySelectable();
return filtered.filter(function (choice) {
key: 'searchableChoices',
get: function get() {
return this.selectableChoices.filter(function (choice) {
return choice.placeholder !== true;
});
}
/**
* Get single choice by it's ID
* @return {Object} Found choice
*/
}, {
key: 'getChoiceById',
value: function getChoiceById(id) {
if (id) {
var choices = this.getChoicesFilteredByActive();
var foundChoice = choices.find(function (choice) {
return choice.id === parseInt(id, 10);
});
return foundChoice;
}
return false;
}
/**
* Get placeholder choice from store
* @return {Object} Found placeholder
*/
}, {
key: 'getPlaceholderChoice',
value: function getPlaceholderChoice() {
var choices = this.getChoices();
var placeholderChoice = [].concat(_toConsumableArray(choices)).reverse().find(function (choice) {
key: 'placeholderChoice',
get: function get() {
return [].concat(_toConsumableArray(this.choices)).reverse().find(function (choice) {
return choice.placeholder === true;
});
return placeholderChoice;
}
/**
@ -5631,10 +5636,9 @@ var Store = function () {
*/
}, {
key: 'getGroups',
value: function getGroups() {
var state = this.store.getState();
return state.groups;
key: 'groups',
get: function get() {
return this.state.groups;
}
/**
@ -5643,37 +5647,18 @@ var Store = function () {
*/
}, {
key: 'getGroupsFilteredByActive',
value: function getGroupsFilteredByActive() {
var groups = this.getGroups();
var choices = this.getChoices();
key: 'activeGroups',
get: function get() {
var groups = this.groups;
var choices = this.choices;
var values = groups.filter(function (group) {
return groups.filter(function (group) {
var isActive = group.active === true && group.disabled === false;
var hasActiveOptions = choices.some(function (choice) {
return choice.active === true && choice.disabled === false;
});
return isActive && hasActiveOptions;
}, []);
return values;
}
/**
* Get group by group id
* @param {Number} id Group ID
* @return {Object} Group data
*/
}, {
key: 'getGroupById',
value: function getGroupById(id) {
var groups = this.getGroups();
var foundGroup = groups.find(function (group) {
return group.id === parseInt(id, 10);
});
return foundGroup;
}
}]);
@ -6098,21 +6083,16 @@ var Dropdown = function () {
this.isActive = false;
}
/**
* Determine how far the top of our element is from
* the top of the window
* @return {Number} Vertical position
*/
_createClass(Dropdown, [{
key: 'getElement',
value: function getElement() {
return this.element;
}
/**
* Determine how far the top of our element is from
* the top of the window
* @return {Number} Vertical position
*/
}, {
key: 'getVerticalPos',
value: function getVerticalPos() {
key: 'distanceFromTopWindow',
value: function distanceFromTopWindow() {
this.dimensions = this.element.getBoundingClientRect();
this.position = Math.ceil(this.dimensions.top + window.pageYOffset + this.element.offsetHeight);
return this.position;
@ -6199,17 +6179,12 @@ var Container = function () {
this.onBlur = this.onBlur.bind(this);
}
/**
* Add event listeners
*/
_createClass(Container, [{
key: 'getElement',
value: function getElement() {
return this.element;
}
/**
* Add event listeners
*/
}, {
key: 'addEventListeners',
value: function addEventListeners() {
this.element.addEventListener('focus', this.onFocus);
@ -6448,11 +6423,6 @@ var Input = function () {
}
_createClass(Input, [{
key: 'getElement',
value: function getElement() {
return this.element;
}
}, {
key: 'addEventListeners',
value: function addEventListeners() {
this.element.addEventListener('input', this.onInput);
@ -6580,32 +6550,17 @@ var Input = function () {
// If there is a placeholder, we only want to set the width of the input when it is a greater
// length than 75% of the placeholder. This stops the input jumping around.
if (this.element.value && this.element.value.length >= this.parentInstance.placeholder.length / 1.25 || enforceWidth) {
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
} else {
// If there is no placeholder, resize input to contents
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
}
}, {
key: 'getWidth',
value: function getWidth() {
return (0, _utils.getWidthOfInput)(this.element);
}
}, {
key: 'setPlaceholder',
value: function setPlaceholder(placeholder) {
this.element.placeholder = placeholder;
}
}, {
key: 'setValue',
value: function setValue(value) {
this.element.value = value;
}
}, {
key: 'getValue',
value: function getValue() {
return this.element.value;
key: 'calcWidth',
value: function calcWidth() {
return (0, _utils.calcWidthOfInput)(this.element);
}
}, {
key: 'setActiveDescendant',
@ -6617,6 +6572,19 @@ var Input = function () {
value: function removeActiveDescendant() {
this.element.removeAttribute('aria-activedescendant');
}
}, {
key: 'placeholder',
set: function set(placeholder) {
this.element.placeholder = placeholder;
}
}, {
key: 'value',
set: function set(value) {
this.element.value = value;
},
get: function get() {
return this.element.value;
}
}]);
return Input;
@ -6651,17 +6619,12 @@ var List = function () {
this.hasChildren = !!this.element.children;
}
/**
* Clear List contents
*/
_createClass(List, [{
key: 'getElement',
value: function getElement() {
return this.element;
}
/**
* Clear List contents
*/
}, {
key: 'clear',
value: function clear() {
this.element.innerHTML = '';
@ -6749,39 +6712,20 @@ var WrappedInput = function (_WrappedElement) {
}
_createClass(WrappedInput, [{
key: 'getElement',
value: function getElement() {
_get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'getElement', this).call(this);
}
}, {
key: 'conceal',
value: function conceal() {
_get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'conceal', this).call(this);
}
}, {
key: 'reveal',
value: function reveal() {
_get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'reveal', this).call(this);
}
}, {
key: 'enable',
value: function enable() {
_get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'enable', this).call(this);
}
}, {
key: 'disable',
value: function disable() {
_get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'disable', this).call(this);
}
}, {
key: 'setValue',
value: function setValue(items) {
key: 'value',
set: function set(items) {
var itemsFiltered = (0, _utils.reduceToValues)(items);
var itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
this.element.setAttribute('value', itemsFilteredString);
this.element.value = itemsFilteredString;
}
// @todo figure out why we need this? Perhaps a babel issue
,
get: function get() {
return _get(WrappedInput.prototype.__proto__ || Object.getPrototypeOf(WrappedInput.prototype), 'value', this);
}
}]);
return WrappedInput;
@ -6802,8 +6746,6 @@ Object.defineProperty(exports, "__esModule", {
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _wrappedElement = __webpack_require__(4);
var _wrappedElement2 = _interopRequireDefault(_wrappedElement);
@ -6835,48 +6777,27 @@ var WrappedSelect = function (_WrappedElement) {
}
_createClass(WrappedSelect, [{
key: 'getElement',
value: function getElement() {
_get(WrappedSelect.prototype.__proto__ || Object.getPrototypeOf(WrappedSelect.prototype), 'getElement', this).call(this);
key: 'appendDocFragment',
value: function appendDocFragment(fragment) {
this.element.innerHTML = '';
this.element.appendChild(fragment);
}
}, {
key: 'conceal',
value: function conceal() {
_get(WrappedSelect.prototype.__proto__ || Object.getPrototypeOf(WrappedSelect.prototype), 'conceal', this).call(this);
}
}, {
key: 'reveal',
value: function reveal() {
_get(WrappedSelect.prototype.__proto__ || Object.getPrototypeOf(WrappedSelect.prototype), 'reveal', this).call(this);
}
}, {
key: 'enable',
value: function enable() {
_get(WrappedSelect.prototype.__proto__ || Object.getPrototypeOf(WrappedSelect.prototype), 'enable', this).call(this);
}
}, {
key: 'disable',
value: function disable() {
_get(WrappedSelect.prototype.__proto__ || Object.getPrototypeOf(WrappedSelect.prototype), 'disable', this).call(this);
}
}, {
key: 'getPlaceholderOption',
value: function getPlaceholderOption() {
key: 'placeholderOption',
get: function get() {
return this.element.querySelector('option[placeholder]');
}
}, {
key: 'getOptions',
value: function getOptions() {
return Array.from(this.element.options);
}
}, {
key: 'getOptionGroups',
value: function getOptionGroups() {
key: 'optionGroups',
get: function get() {
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
}
}, {
key: 'setOptions',
value: function setOptions(options) {
key: 'options',
get: function get() {
return Array.from(this.element.options);
},
set: function set(options) {
var fragment = document.createDocumentFragment();
var addOptionToFragment = function addOptionToFragment(data) {
// Create a standard select option
@ -6892,12 +6813,6 @@ var WrappedSelect = function (_WrappedElement) {
this.appendDocFragment(fragment);
}
}, {
key: 'appendDocFragment',
value: function appendDocFragment(fragment) {
this.element.innerHTML = '';
this.element.appendChild(fragment);
}
}]);
return WrappedSelect;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -120,9 +120,9 @@ class Choices {
this.presetItems = this.config.items;
// Then add any values passed from attribute
if (this.passedElement.getValue()) {
if (this.passedElement.value) {
this.presetItems = this.presetItems.concat(
this.passedElement.getValue().split(this.config.delimiter),
this.passedElement.value.split(this.config.delimiter),
);
}
@ -187,8 +187,10 @@ class Choices {
// Set initialise flag
this.initialised = true;
// Create required elements
// Create required templates
this._createTemplates();
// Create required elements
this._createElements();
// Generate input markup
this._createStructure();
// Subscribe store to render method
@ -221,7 +223,7 @@ class Choices {
this.containerOuter.unwrap(this.passedElement.element);
if (this.isSelectElement) {
this.passedElement.setOptions(this.presetChoices);
this.passedElement.options = this.presetChoices;
}
// Clear data store
@ -392,10 +394,10 @@ class Choices {
if (this.isTextElement) {
// Update the value of the hidden input
this.passedElement.setValue(items);
this.passedElement.value = items;
} else {
// Update the options of the hidden input
this.passedElement.setOptions(items);
this.passedElement.options = items;
}
const addItemToFragment = (item) => {
@ -417,7 +419,7 @@ class Choices {
* @private
*/
render() {
this.currentState = this.store.getState();
this.currentState = this.store.state;
const stateChanged = (
this.currentState.choices !== this.prevState.choices ||
this.currentState.groups !== this.prevState.groups ||
@ -432,8 +434,8 @@ class Choices {
if (this.isSelectElement) {
// Get active groups/choices
const activeGroups = this.store.getGroupsFilteredByActive();
const activeChoices = this.store.getChoicesFilteredByActive();
const activeGroups = this.store.activeGroups;
const activeChoices = this.store.activeChoices;
let choiceListFragment = document.createDocumentFragment();
@ -465,8 +467,8 @@ class Choices {
// If we have choices to show
if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) {
const activeItems = this.store.getItemsFilteredByActive();
const canAddItem = this._canAddItem(activeItems, this.input.getValue());
const activeItems = this.store.activeItems;
const canAddItem = this._canAddItem(activeItems, this.input.value);
// ...and we can select them
if (canAddItem.response) {
@ -503,7 +505,7 @@ class Choices {
/* Items */
if (this.currentState.items !== this.prevState.items) {
// Get active items (items that can be selected)
const activeItems = this.store.getItemsFilteredByActive() || [];
const activeItems = this.store.activeItems || [];
// Clear list
this.itemList.clear();
@ -582,7 +584,7 @@ class Choices {
* @public
*/
highlightAll() {
const items = this.store.getItems();
const items = this.store.items;
items.forEach(item => this.highlightItem(item));
return this;
}
@ -593,7 +595,7 @@ class Choices {
* @public
*/
unhighlightAll() {
const items = this.store.getItems();
const items = this.store.items;
items.forEach(item => this.unhighlightItem(item));
return this;
}
@ -609,7 +611,7 @@ class Choices {
return this;
}
const items = this.store.getItemsFilteredByActive();
const items = this.store.activeItems;
items.forEach((item) => {
if (item.value === value) {
@ -628,7 +630,7 @@ class Choices {
* @public
*/
removeActiveItems(excludedId) {
const items = this.store.getItemsFilteredByActive();
const items = this.store.activeItems;
items.forEach((item) => {
if (excludedId !== item.id) {
@ -646,7 +648,7 @@ class Choices {
* @public
*/
removeHighlightedItems(runEvent = false) {
const items = this.store.getItemsFilteredByHighlighted();
const items = this.store.highlightedActiveItems;
items.forEach((item) => {
this._removeItem(item);
@ -671,7 +673,7 @@ class Choices {
}
this.dropdown.show();
this.containerOuter.open(this.dropdown.getVerticalPos());
this.containerOuter.open(this.dropdown.distanceFromTopWindow());
if (focusInput && this.canSearch) {
this.input.focus();
@ -728,7 +730,7 @@ class Choices {
* @public
*/
getValue(valueOnly = false) {
const items = this.store.getItemsFilteredByActive();
const items = this.store.activeItems;
const values = items.reduce((selectedItems, item) => {
const itemValue = valueOnly ? item.value : item;
@ -899,7 +901,7 @@ class Choices {
* Select placeholder choice
*/
_selectPlaceholderChoice() {
const placeholderChoice = this.store.getPlaceholderChoice();
const placeholderChoice = this.store.placeholderChoice;
if (placeholderChoice) {
this._addItem(
@ -1047,7 +1049,7 @@ class Choices {
// If editing the last item is allowed and there are not other selected items,
// we can edit the item value. Otherwise if we can remove items, remove all selected items
if (this.config.editItems && !hasHighlightedItems && lastItem) {
this.input.setValue(lastItem.value);
this.input.value = lastItem.value;
this.input.setWidth();
this._removeItem(lastItem);
this._triggerChange(lastItem.value);
@ -1078,7 +1080,7 @@ class Choices {
placeholderItem.innerHTML = this.config.loadingText;
}
} else {
this.input.setPlaceholder(this.config.loadingText);
this.input.placeholder = this.config.loadingText;
}
} else {
this.containerOuter.removeLoadingState();
@ -1086,7 +1088,7 @@ class Choices {
if (this.isSelectOneElement) {
placeholderItem.innerHTML = (this.placeholder || '');
} else {
this.input.setPlaceholder(this.placeholder || '');
this.input.placeholder = (this.placeholder || '');
}
}
}
@ -1216,7 +1218,7 @@ class Choices {
}
// If new value matches the desired length and is not the same as the current value with a space
const haystack = this.store.getSearchableChoices();
const haystack = this.store.searchableChoices;
const needle = newValue;
const keys = isType('Array', this.config.searchFields) ?
this.config.searchFields :
@ -1244,7 +1246,7 @@ class Choices {
return;
}
const choices = this.store.getChoices();
const choices = this.store.choices;
const hasUnactiveChoices = choices.some(option => !option.active);
// Check that we have a value to search and the input was an alphanumeric character
@ -1323,7 +1325,7 @@ class Choices {
}
const target = e.target;
const activeItems = this.store.getItemsFilteredByActive();
const activeItems = this.store.activeItems;
const hasFocusedInput = this.input.isFocussed;
const hasActiveDropdown = this.dropdown.isActive;
const hasItems = this.itemList.hasChildren;
@ -1352,7 +1354,7 @@ class Choices {
this.canSearch = false;
if (
this.config.removeItems &&
!this.input.getValue() &&
!this.input.value &&
this.input.element === document.activeElement
) {
// Highlight items
@ -1364,7 +1366,7 @@ class Choices {
const onEnterKey = () => {
// If enter key is pressed and the input has a value
if (this.isTextElement && target.value) {
const value = this.input.getValue();
const value = this.input.value;
const canAddItem = this._canAddItem(activeItems, value);
// All is good, add
@ -1491,8 +1493,8 @@ class Choices {
return;
}
const value = this.input.getValue();
const activeItems = this.store.getItemsFilteredByActive();
const value = this.input.value;
const activeItems = this.store.activeItems;
const canAddItem = this._canAddItem(activeItems, value);
// We are typing into a text input and have a value, we want to show a dropdown
@ -1524,7 +1526,7 @@ class Choices {
this.store.dispatch(activateChoices(true));
}
} else if (this.canSearch && canAddItem.response) {
this._handleSearch(this.input.getValue());
this._handleSearch(this.input.value);
}
}
// Re-establish canSearch value from changes in _onKeyDown
@ -1588,7 +1590,7 @@ class Choices {
}
if (this.containerOuter.element.contains(target) && target !== this.input.element) {
const activeItems = this.store.getItemsFilteredByActive();
const activeItems = this.store.activeItems;
const hasShiftKey = e.shiftKey;
const buttonTarget = findAncestorByAttrName(target, 'data-button');
@ -1634,7 +1636,7 @@ class Choices {
_onClick(e) {
const target = e.target;
const hasActiveDropdown = this.dropdown.isActive;
const activeItems = this.store.getItemsFilteredByActive();
const activeItems = this.store.activeItems;
// If target is something that concerns us
if (this.containerOuter.element.contains(target)) {
@ -1721,7 +1723,7 @@ class Choices {
const target = e.target;
// If target is something that concerns us
if (this.containerOuter.element.contains(target) && !this.isScrollingOnIe) {
const activeItems = this.store.getItemsFilteredByActive();
const activeItems = this.store.activeItems;
const hasHighlightedItems = activeItems.some(item => item.highlighted);
const blurActions = {
text: () => {
@ -1902,7 +1904,7 @@ class Choices {
let passedValue = isType('String', value) ? value.trim() : value;
const passedKeyCode = keyCode;
const passedCustomProperties = customProperties;
const items = this.store.getItems();
const items = this.store.items;
const passedLabel = label || passedValue;
const passedOptionId = parseInt(choiceId, 10) || -1;
@ -2022,7 +2024,7 @@ class Choices {
}
// Generate unique id
const choices = this.store.getChoices();
const choices = this.store.choices;
const choiceLabel = label || value;
const choiceId = choices ? choices.length + 1 : 1;
const choiceElementId = `${this.baseId}-${this.idNames.itemChoice}-${choiceId}`;
@ -2060,9 +2062,7 @@ class Choices {
* @private
*/
_clearChoices() {
this.store.dispatch(
clearChoices(),
);
this.store.dispatch(clearChoices());
}
/**
@ -2150,11 +2150,9 @@ class Choices {
}
/**
* Create DOM structure around passed select element
* @return
* @private
* Create DOM elements using templates
*/
_createStructure() {
_createElements() {
const direction = this.passedElement.element.getAttribute('dir') || 'ltr';
const containerOuter = this._getTemplate('containerOuter',
direction,
@ -2175,18 +2173,25 @@ class Choices {
this.choiceList = new List(this, choiceList, this.config.classNames);
this.itemList = new List(this, itemList, this.config.classNames);
this.dropdown = new Dropdown(this, dropdown, this.config.classNames);
}
/**
* Create DOM structure around passed select element
* @return
* @private
*/
_createStructure() {
// Hide original element
this.passedElement.conceal();
// Wrap input in container preserving DOM ordering
this.containerInner.wrap(this.passedElement.element);
// Wrapper inner container with outer container
this.containerOuter.wrap(this.containerInner.element);
if (this.isSelectOneElement) {
this.input.setPlaceholder(this.config.searchPlaceholderValue || '');
this.input.placeholder = (this.config.searchPlaceholderValue || '');
} else if (this.placeholder) {
this.input.setPlaceholder(this.placeholder);
this.input.placeholder = this.placeholder;
this.input.setWidth(true);
}
@ -2196,16 +2201,16 @@ class Choices {
this.containerOuter.element.appendChild(this.containerInner.element);
this.containerOuter.element.appendChild(this.dropdown.element);
this.containerInner.element.appendChild(itemList);
this.containerInner.element.appendChild(this.itemList.element);
if (!this.isTextElement) {
dropdown.appendChild(choiceList);
this.dropdown.element.appendChild(this.choiceList.element);
}
if (!this.isSelectOneElement) {
this.containerInner.element.appendChild(this.input.element);
} else if (this.canSearch) {
dropdown.insertBefore(input, dropdown.firstChild);
this.dropdown.element.insertBefore(this.input.element, this.dropdown.element.firstChild);
}
if (this.isSelectElement) {
@ -2216,14 +2221,14 @@ class Choices {
}
_addPredefinedChoices() {
const passedGroups = this.passedElement.getOptionGroups();
const passedGroups = this.passedElement.optionGroups;
this.highlightPosition = 0;
this.isSearching = false;
if (passedGroups && passedGroups.length) {
// If we have a placeholder option
const placeholderChoice = this.passedElement.getPlaceholderOption();
const placeholderChoice = this.passedElement.placeholderOption;
if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') {
this._addChoice(
placeholderChoice.value,
@ -2240,7 +2245,7 @@ class Choices {
this._addGroup(group, (group.id || null));
});
} else {
const passedOptions = this.passedElement.getOptions();
const passedOptions = this.passedElement.options;
const filter = this.config.sortFn;
const allChoices = this.presetChoices;
@ -2375,7 +2380,7 @@ class Choices {
}
_findAndSelectChoiceByValue(val) {
const choices = this.store.getChoices();
const choices = this.store.choices;
// Check 'value' property exists and the choice isn't already selected
const foundChoice = choices.find(choice => this.config.itemComparer(choice.value, val));

File diff suppressed because it is too large Load diff

View file

@ -767,18 +767,17 @@ describe('choices', () => {
];
beforeEach(() => {
storeGetItemsStub = stub().returns(items);
storeGetItemsStub = stub(instance.store, 'items').get(() => items);
highlightItemStub = stub();
instance.highlightItem = highlightItemStub;
instance.store.getItems = storeGetItemsStub;
output = instance.highlightAll();
});
afterEach(() => {
highlightItemStub.reset();
instance.store.getItems.reset();
storeGetItemsStub.reset();
});
returnsInstance(output);
@ -806,18 +805,17 @@ describe('choices', () => {
];
beforeEach(() => {
storeGetItemsStub = stub().returns(items);
storeGetItemsStub = stub(instance.store, 'items').get(() => items);
unhighlightItemStub = stub();
instance.unhighlightItem = unhighlightItemStub;
instance.store.getItems = storeGetItemsStub;
output = instance.unhighlightAll();
});
afterEach(() => {
instance.unhighlightItem.reset();
instance.store.getItems.reset();
storeGetItemsStub.reset();
});
returnsInstance(output);
@ -1109,7 +1107,7 @@ describe('choices', () => {
});
describe('getValue', () => {
let getItemsFilteredByActiveStub;
let activeItemsStub;
const items = [
{
id: '1',
@ -1122,12 +1120,11 @@ describe('choices', () => {
];
beforeEach(() => {
getItemsFilteredByActiveStub = stub().returns(items);
instance.store.getItemsFilteredByActive = getItemsFilteredByActiveStub;
activeItemsStub = stub(instance.store, 'activeItems').get(() => items);
});
afterEach(() => {
instance.store.getItemsFilteredByActive.reset();
activeItemsStub.reset();
});
describe('passing true valueOnly flag', () => {
@ -1189,7 +1186,7 @@ describe('choices', () => {
});
describe('passing valid value', () => {
let getItemsFilteredByActiveStub;
let activeItemsStub;
let removeItemStub;
const value = 'Removed';
const items = [
@ -1209,15 +1206,14 @@ describe('choices', () => {
beforeEach(() => {
removeItemStub = stub();
getItemsFilteredByActiveStub = stub().returns(items);
instance.store.getItemsFilteredByActive = getItemsFilteredByActiveStub;
activeItemsStub = stub(instance.store, 'activeItems').get(() => items);
instance._removeItem = removeItemStub;
output = instance.removeActiveItemsByValue(value);
});
afterEach(() => {
instance.store.getItemsFilteredByActive.reset();
activeItemsStub.reset();
instance._removeItem.reset();
});
@ -1230,7 +1226,7 @@ describe('choices', () => {
});
describe('removeActiveItems', () => {
let getItemsFilteredByActiveStub;
let activeItemsStub;
let removeItemStub;
const items = [
{
@ -1249,13 +1245,12 @@ describe('choices', () => {
beforeEach(() => {
removeItemStub = stub();
getItemsFilteredByActiveStub = stub().returns(items);
instance.store.getItemsFilteredByActive = getItemsFilteredByActiveStub;
activeItemsStub = stub(instance.store, 'activeItems').get(() => items);
instance._removeItem = removeItemStub;
});
afterEach(() => {
instance.store.getItemsFilteredByActive.reset();
activeItemsStub.reset();
instance._removeItem.reset();
});
@ -1288,7 +1283,7 @@ describe('choices', () => {
});
describe('removeHighlightedItems', () => {
let getItemsFilteredByHighlightedStub;
let highlightedActiveItemsStub;
let removeItemStub;
let triggerChangeStub;
@ -1305,17 +1300,16 @@ describe('choices', () => {
beforeEach(() => {
getItemsFilteredByHighlightedStub = stub().returns(items);
highlightedActiveItemsStub = stub(instance.store, 'highlightedActiveItems').get(() => items);
removeItemStub = stub();
triggerChangeStub = stub();
instance.store.getItemsFilteredByHighlighted = getItemsFilteredByHighlightedStub;
instance._removeItem = removeItemStub;
instance._triggerChange = triggerChangeStub;
});
afterEach(() => {
instance.store.getItemsFilteredByHighlighted.reset();
highlightedActiveItemsStub.reset();
instance._removeItem.reset();
instance._triggerChange.reset();
});
@ -1747,38 +1741,4 @@ describe('choices', () => {
});
});
});
describe.skip('private methods', () => {
describe('_triggerChange', () => {});
describe('_selectPlaceholderChoice', () => {});
describe('_handleButtonAction', () => {});
describe('_handleItemAction', () => {});
describe('_handleChoiceAction', () => {});
describe('_handleBackspace', () => {});
describe('_handleLoadingState', () => {});
describe('_canAddItem', () => {});
describe('_ajaxCallback', () => {});
describe('_searchChoices', () => {});
describe('_handleSearch', () => {});
describe('_addEventListeners', () => {});
describe('_removeEventListeners', () => {});
describe('_onKeyDown', () => {});
describe('_onTouchMove', () => {});
describe('_onTouchEnd', () => {});
describe('_onMouseDown', () => {});
describe('_onMouseOver', () => {});
describe('_onClick', () => {});
describe('_onFocus', () => {});
describe('_onBlur', () => {});
describe('_scrollToChoice', () => {});
describe('_highlightChoice', () => {});
describe('_addItem', () => {});
describe('_removeItem', () => {});
describe('_addChoice', () => {});
describe('_clearChoices', () => {});
describe('_addGroup', () => {});
describe('_getTemplate', () => {});
describe('_createTemplates', () => {});
describe('_createStructure', () => {});
});
});

View file

@ -15,10 +15,6 @@ export default class Container {
this.onBlur = this.onBlur.bind(this);
}
getElement() {
return this.element;
}
/**
* Add event listeners
*/

View file

@ -40,12 +40,6 @@ describe('components/container', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(element);
});
});
describe('addEventListeners', () => {
let addEventListenerStub;

View file

@ -8,16 +8,12 @@ export default class Dropdown {
this.isActive = false;
}
getElement() {
return this.element;
}
/**
* Determine how far the top of our element is from
* the top of the window
* @return {Number} Vertical position
*/
getVerticalPos() {
distanceFromTopWindow() {
this.dimensions = this.element.getBoundingClientRect();
this.position = Math.ceil(this.dimensions.top + window.pageYOffset + this.element.offsetHeight);
return this.position;

View file

@ -39,13 +39,7 @@ describe('components/dropdown', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('getVerticalPos', () => {
describe('distanceFromTopWindow', () => {
let top;
let offset;
let dimensions;
@ -74,18 +68,18 @@ describe('components/dropdown', () => {
it('determines how far the top of our element is from the top of the window', () => {
const expectedResponse = top + offset;
const actualResponse = instance.getVerticalPos();
const actualResponse = instance.distanceFromTopWindow();
expect(actualResponse).to.equal(expectedResponse);
});
it('assigns dimensions to instance', () => {
instance.getVerticalPos();
instance.distanceFromTopWindow();
const expectedResponse = dimensions;
expect(instance.dimensions).to.equal(expectedResponse);
});
it('assigns posisiton to instance', () => {
instance.getVerticalPos();
instance.distanceFromTopWindow();
const expectedResponse = top + offset;
expect(instance.position).to.equal(expectedResponse);
});

View file

@ -1,4 +1,4 @@
import { getWidthOfInput } from '../lib/utils';
import { calcWidthOfInput } from '../lib/utils';
export default class Input {
constructor(instance, element, classNames) {
@ -15,8 +15,16 @@ export default class Input {
this.onBlur = this.onBlur.bind(this);
}
getElement() {
return this.element;
set placeholder(placeholder) {
this.element.placeholder = placeholder;
}
set value(value) {
this.element.value = value;
}
get value() {
return this.element.value;
}
addEventListeners() {
@ -124,28 +132,16 @@ export default class Input {
this.element.value.length >= (this.parentInstance.placeholder.length / 1.25)) ||
enforceWidth
) {
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
} else {
// If there is no placeholder, resize input to contents
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
}
getWidth() {
return getWidthOfInput(this.element);
}
setPlaceholder(placeholder) {
this.element.placeholder = placeholder;
}
setValue(value) {
this.element.value = value;
}
getValue() {
return this.element.value;
calcWidth() {
return calcWidthOfInput(this.element);
}
setActiveDescendant(activeDescendantID) {

View file

@ -37,12 +37,6 @@ describe('components/input', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('addEventListeners', () => {
let addEventListenerStub;
@ -278,15 +272,15 @@ describe('components/input', () => {
});
describe('setWidth', () => {
let getWidthStub;
let calcWidthStub;
const inputWidth = '200px';
beforeEach(() => {
getWidthStub = stub(instance, 'getWidth').returns(inputWidth);
calcWidthStub = stub(instance, 'calcWidth').returns(inputWidth);
});
afterEach(() => {
getWidthStub.restore();
calcWidthStub.restore();
});
describe('with a placeholder', () => {
@ -296,7 +290,7 @@ describe('components/input', () => {
instance.element.value = 'This is a test';
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth();
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
@ -307,7 +301,7 @@ describe('components/input', () => {
instance.element.value = '';
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth(true);
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
@ -317,7 +311,7 @@ describe('components/input', () => {
instance.parentInstance.placeholder = 'This is a test';
instance.element.value = 'Test';
instance.setWidth();
expect(getWidthStub.callCount).to.equal(0);
expect(calcWidthStub.callCount).to.equal(0);
});
});
});
@ -327,35 +321,35 @@ describe('components/input', () => {
instance.placeholder = null;
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth();
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
});
describe('setPlaceholder', () => {
describe('placeholder setter', () => {
it('sets value of element to passed placeholder', () => {
const placeholder = 'test';
expect(instance.element.placeholder).to.equal('');
instance.setPlaceholder(placeholder);
instance.placeholder = placeholder;
expect(instance.element.placeholder).to.equal(placeholder);
});
});
describe('setValue', () => {
describe('value setter', () => {
it('sets value of element to passed value', () => {
const value = 'test';
expect(instance.element.value).to.equal('');
instance.setValue(value);
instance.value = value;
expect(instance.element.value).to.equal(value);
});
});
describe('getValue', () => {
describe('value getter', () => {
it('sets value of element to passed value', () => {
const value = 'test';
instance.element.value = value;
const actualResponse = instance.getValue();
const actualResponse = instance.value;
expect(actualResponse).to.equal(value);
});
});

View file

@ -8,10 +8,6 @@ export default class List {
this.hasChildren = !!this.element.children;
}
getElement() {
return this.element;
}
/**
* Clear List contents
*/

View file

@ -36,12 +36,6 @@ describe('components/list', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('clear', () => {
it('clears element\'s inner HTML', () => {
const innerHTML = 'test';

View file

@ -8,11 +8,7 @@ export default class WrappedElement {
this.isDisabled = false;
}
getElement() {
return this.element;
}
getValue() {
get value() {
return this.element.value;
}
@ -33,7 +29,6 @@ export default class WrappedElement {
this.element.setAttribute('data-choice-orig-style', origStyle);
}
this.element.setAttribute('style', 'display:none;');
this.element.setAttribute('aria-hidden', 'true');
this.element.setAttribute('data-choice', 'active');
}

View file

@ -41,9 +41,9 @@ describe('components/wrappedElement', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(element);
describe('value getter', () => {
it('returns element value', () => {
expect(instance.value).to.eql(element.value);
});
});
@ -60,7 +60,6 @@ describe('components/wrappedElement', () => {
expect(instance.element.tabIndex).to.equal(-1);
expect(instance.element.classList.contains(instance.classNames.input)).to.equal(true);
expect(instance.element.classList.contains(instance.classNames.hiddenState)).to.equal(true);
expect(instance.element.getAttribute('style')).to.equal('display:none;');
expect(instance.element.getAttribute('aria-hidden')).to.equal('true');
expect(instance.element.getAttribute('data-choice')).to.equal('active');
expect(instance.element.getAttribute('data-choice-orig-style')).to.equal(originalStyling);

View file

@ -9,31 +9,16 @@ export default class WrappedInput extends WrappedElement {
this.classNames = classNames;
}
getElement() {
super.getElement();
}
conceal() {
super.conceal();
}
reveal() {
super.reveal();
}
enable() {
super.enable();
}
disable() {
super.disable();
}
setValue(items) {
set value(items) {
const itemsFiltered = reduceToValues(items);
const itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
this.element.setAttribute('value', itemsFilteredString);
this.element.value = itemsFilteredString;
}
// @todo figure out why we need this? Perhaps a babel issue
get value() {
return super.value;
}
}

View file

@ -39,7 +39,7 @@ describe('components/wrappedInput', () => {
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
['conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
describe(method, () => {
beforeEach(() => {
stub(WrappedElement.prototype, method);
@ -58,7 +58,7 @@ describe('components/wrappedInput', () => {
});
});
describe('setValue', () => {
describe('value setter', () => {
const data = [
{
id: 'ID 1',
@ -76,8 +76,8 @@ describe('components/wrappedInput', () => {
it('sets delimited value of element based on passed data', () => {
expect(instance.element.value).to.equal('');
instance.setValue(data);
expect(instance.element.value).to.equal('Value 1,Value 2,Value 3');
instance.value = data;
expect(instance.value).to.equal('Value 1,Value 2,Value 3');
});
});
});

View file

@ -9,39 +9,19 @@ export default class WrappedSelect extends WrappedElement {
this.classNames = classNames;
}
getElement() {
super.getElement();
}
conceal() {
super.conceal();
}
reveal() {
super.reveal();
}
enable() {
super.enable();
}
disable() {
super.disable();
}
getPlaceholderOption() {
get placeholderOption() {
return this.element.querySelector('option[placeholder]');
}
getOptions() {
return Array.from(this.element.options);
}
getOptionGroups() {
get optionGroups() {
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
}
setOptions(options) {
get options() {
return Array.from(this.element.options);
}
set options(options) {
const fragment = document.createDocumentFragment();
const addOptionToFragment = (data) => {
// Create a standard select option

View file

@ -55,7 +55,7 @@ describe('components/wrappedSelect', () => {
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
['conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
beforeEach(() => {
stub(WrappedElement.prototype, method);
});
@ -74,39 +74,38 @@ describe('components/wrappedSelect', () => {
});
});
describe('getPlaceholderOption', () => {
describe('placeholderOption getter', () => {
it('returns option element with placeholder attribute', () => {
const output = instance.getPlaceholderOption();
expect(output).to.be.instanceOf(HTMLOptionElement);
expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);
});
});
describe('getOptions', () => {
describe('options getter', () => {
it('returns all option elements', () => {
const output = instance.getOptions();
expect(output).to.be.an('array');
output.forEach((option) => {
const { options } = instance;
expect(options).to.be.an('array');
options.forEach((option) => {
expect(option).to.be.instanceOf(HTMLOptionElement);
});
});
});
describe('getOptionGroups', () => {
describe('optionGroups getter', () => {
it('returns an array of all option groups', () => {
for (let i = 1; i <= 3; i++) {
const group = document.createElement('optgroup');
instance.element.appendChild(group);
}
const output = instance.getOptionGroups();
expect(output.length).to.equal(3);
output.forEach((option) => {
const { optionGroups } = instance;
expect(optionGroups.length).to.equal(3);
optionGroups.forEach((option) => {
expect(option).to.be.instanceOf(HTMLOptGroupElement);
});
});
});
describe('setOptions', () => {
describe('options setter', () => {
let appendDocFragmentStub;
const options = [
{
@ -134,7 +133,7 @@ describe('components/wrappedSelect', () => {
it('creates an option element for each passed object, adds it to a fragment and calls appendDocFragment with created fragment', () => {
expect(appendDocFragmentStub.called).to.equal(false);
instance.setOptions(options);
instance.options = options;
expect(appendDocFragmentStub.called).to.equal(true);
const fragment = appendDocFragmentStub.firstCall.args[0];

View file

@ -1,3 +1,4 @@
import { stripHTML } from './lib/utils';
export const DEFAULT_CLASSNAMES = {
containerOuter: 'choices',
@ -62,7 +63,7 @@ export const DEFAULT_CONFIG = {
noChoicesText: 'No choices to choose from',
itemSelectText: 'Press to select',
uniqueItemText: 'Only unique values can be added.',
addItemText: value => `Press Enter to add <b>"${value}"</b>`,
addItemText: value => `Press Enter to add <b>"${stripHTML(value)}"</b>`,
maxItemText: maxItemCount => `Only ${maxItemCount} values can be added.`,
itemComparer: (choice, item) => (choice === item),
fuseOptions: {

View file

@ -421,15 +421,15 @@ export const isScrolledIntoView = (el, parent, direction = 1) => {
};
/**
* Remove html tags from a string
* @param {String} Initial string/html
* Escape html in the string
* @param {String} html Initial string/html
* @return {String} Sanitised string
*/
export const stripHTML = function(html) {
const el = document.createElement('DIV');
el.innerHTML = html;
return el.textContent || el.innerText || '';
};
export const stripHTML = html =>
html.replace(/&/g, '&amp;')
.replace(/>/g, '&rt;')
.replace(/</g, '&lt;')
.replace(/"/g, '&quot;');
/**
* Adds animation to an element and removes it upon animation completion
@ -485,12 +485,12 @@ export const strToEl = (function() {
* Sets the width of a passed input based on its value
* @return {Number} Width of input
*/
export const getWidthOfInput = (input) => {
export const calcWidthOfInput = (input) => {
const value = input.value || input.placeholder;
let width = input.offsetWidth;
if (value) {
const testEl = strToEl(`<span>${value}</span>`);
const testEl = strToEl(`<span>${stripHTML(value)}</span>`);
testEl.style.position = 'absolute';
testEl.style.padding = '0';
testEl.style.top = '-9999px';

View file

@ -33,7 +33,7 @@ export default class Store {
* Get store object (wrapping Redux method)
* @return {Object} State
*/
getState() {
get state() {
return this.store.getState();
}
@ -41,48 +41,40 @@ export default class Store {
* Get items from store
* @return {Array} Item objects
*/
getItems() {
const state = this.store.getState();
return state.items;
get items() {
return this.state.items;
}
/**
* Get active items from store
* @return {Array} Item objects
*/
getItemsFilteredByActive() {
const items = this.getItems();
const values = items.filter(item => item.active === true);
return values;
get activeItems() {
return this.items.filter(item => item.active === true);
}
/**
* Get highlighted items from store
* @return {Array} Item objects
*/
getItemsFilteredByHighlighted() {
const items = this.getItems();
const values = items.filter(item => item.active && item.highlighted);
return values;
get highlightedActiveItems() {
return this.items.filter(item => item.active && item.highlighted);
}
/**
* Get choices from store
* @return {Array} Option objects
*/
getChoices() {
const state = this.store.getState();
return state.choices;
get choices() {
return this.state.choices;
}
/**
* Get active choices from store
* @return {Array} Option objects
*/
getChoicesFilteredByActive() {
const choices = this.getChoices();
get activeChoices() {
const choices = this.choices;
const values = choices.filter(choice => choice.active === true);
return values;
@ -92,20 +84,51 @@ export default class Store {
* Get selectable choices from store
* @return {Array} Option objects
*/
getChoicesFilteredBySelectable() {
const choices = this.getChoices();
const values = choices.filter(choice => choice.disabled !== true);
return values;
get selectableChoices() {
return this.choices.filter(choice => choice.disabled !== true);
}
/**
* Get choices that can be searched (excluding placeholders)
* @return {Array} Option objects
*/
getSearchableChoices() {
const filtered = this.getChoicesFilteredBySelectable();
return filtered.filter(choice => choice.placeholder !== true);
get searchableChoices() {
return this.selectableChoices.filter(choice => choice.placeholder !== true);
}
/**
* Get placeholder choice from store
* @return {Object} Found placeholder
*/
get placeholderChoice() {
return [...this.choices]
.reverse()
.find(choice => choice.placeholder === true);
}
/**
* Get groups from store
* @return {Array} Group objects
*/
get groups() {
return this.state.groups;
}
/**
* Get active groups from store
* @return {Array} Group objects
*/
get activeGroups() {
const groups = this.groups;
const choices = this.choices;
return groups.filter((group) => {
const isActive = group.active === true && group.disabled === false;
const hasActiveOptions = choices.some(choice =>
choice.active === true && choice.disabled === false,
);
return isActive && hasActiveOptions;
}, []);
}
/**
@ -114,63 +137,19 @@ export default class Store {
*/
getChoiceById(id) {
if (id) {
const choices = this.getChoicesFilteredByActive();
const choices = this.activeChoices;
const foundChoice = choices.find(choice => choice.id === parseInt(id, 10));
return foundChoice;
}
return false;
}
/**
* Get placeholder choice from store
* @return {Object} Found placeholder
*/
getPlaceholderChoice() {
const choices = this.getChoices();
const placeholderChoice = [...choices]
.reverse()
.find(choice => choice.placeholder === true);
return placeholderChoice;
}
/**
* Get groups from store
* @return {Array} Group objects
*/
getGroups() {
const state = this.store.getState();
return state.groups;
}
/**
* Get active groups from store
* @return {Array} Group objects
*/
getGroupsFilteredByActive() {
const groups = this.getGroups();
const choices = this.getChoices();
const values = groups.filter((group) => {
const isActive = group.active === true && group.disabled === false;
const hasActiveOptions = choices.some(choice =>
choice.active === true && choice.disabled === false,
);
return isActive && hasActiveOptions;
}, []);
return values;
}
/**
* Get group by group id
* @param {Number} id Group ID
* @return {Object} Group data
*/
getGroupById(id) {
const groups = this.getGroups();
const foundGroup = groups.find(group => group.id === parseInt(id, 10));
return foundGroup;
return this.groups.find(group => group.id === parseInt(id, 10));
}
}

View file

@ -53,11 +53,12 @@ describe('reducers/store', () => {
});
});
describe('getState', () => {
it('wraps redux getState method', () => {
expect(getStateStub.callCount).to.equal(0);
instance.getState();
expect(getStateStub.callCount).to.equal(1);
describe('state getter', () => {
it('returns state', () => {
const state = { items: [] };
getStateStub.returns(state);
expect(instance.state).to.equal(state);
});
});
@ -153,59 +154,52 @@ describe('reducers/store', () => {
getStateStub.returns(state);
});
describe('getItems', () => {
describe('items getter', () => {
it('returns items', () => {
const expectedResponse = state.items;
const actualResponse = instance.getItems();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.items).to.eql(expectedResponse);
});
});
describe('getItemsFilteredByActive', () => {
describe('activeItems getter', () => {
it('returns items that are active', () => {
const expectedResponse = state.items.filter((item => item.active));
const actualResponse = instance.getItemsFilteredByActive();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.activeItems).to.eql(expectedResponse);
});
});
describe('getItemsFilteredByHighlighted', () => {
describe('highlightedActiveItems getter', () => {
it('returns items that are active and highlighted', () => {
const expectedResponse = state.items.filter((item => item.highlighted && item.active));
const actualResponse = instance.getItemsFilteredByHighlighted();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.highlightedActiveItems).to.eql(expectedResponse);
});
});
describe('getChoices', () => {
describe('choices getter', () => {
it('returns choices', () => {
const expectedResponse = state.choices;
const actualResponse = instance.getChoices();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.choices).to.eql(expectedResponse);
});
});
describe('getChoicesFilteredByActive', () => {
describe('activeChoices getter', () => {
it('returns choices that are active', () => {
const expectedResponse = state.choices.filter((choice => choice.active));
const actualResponse = instance.getChoicesFilteredByActive();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.activeChoices).to.eql(expectedResponse);
});
});
describe('getChoicesFilteredBySelectable', () => {
describe('selectableChoices getter', () => {
it('returns choices that are not disabled', () => {
const expectedResponse = state.choices.filter((choice => !choice.disabled));
const actualResponse = instance.getChoicesFilteredBySelectable();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.selectableChoices).to.eql(expectedResponse);
});
});
describe('getSearchableChoices', () => {
describe('searchableChoices getter', () => {
it('returns choices that are not placeholders and are selectable', () => {
const expectedResponse = state.choices.filter((choice => !choice.disabled && !choice.placeholder));
const actualResponse = instance.getSearchableChoices();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.searchableChoices).to.eql(expectedResponse);
});
});
@ -227,27 +221,24 @@ describe('reducers/store', () => {
});
});
describe('getPlaceholderChoice', () => {
describe('placeholderChoice getter', () => {
it('returns placeholder choice', () => {
const expectedResponse = state.choices.reverse().find(choice => choice.placeholder);
const actualResponse = instance.getPlaceholderChoice();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.getPlaceholderChoice).to.eql(expectedResponse);
});
});
describe('getGroups', () => {
describe('groups getter', () => {
it('returns groups', () => {
const expectedResponse = state.groups;
const actualResponse = instance.getGroups();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.groups).to.eql(expectedResponse);
});
});
describe('getGroupsFilteredByActive', () => {
describe('activeGroups getter', () => {
it('returns active groups', () => {
const expectedResponse = state.groups.filter(group => group.active);
const actualResponse = instance.getGroupsFilteredByActive();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.activeGroups).to.eql(expectedResponse);
});
});

View file

@ -40,7 +40,8 @@ export const TEMPLATES = {
},
itemList(globalClasses, isSelectOneElement) {
const localClasses = classNames(
globalClasses.list, {
globalClasses.list,
{
[globalClasses.listSingle]: (isSelectOneElement),
[globalClasses.listItems]: (!isSelectOneElement),
},
@ -214,7 +215,8 @@ export const TEMPLATES = {
notice(globalClasses, label, type = '') {
const localClasses = classNames(
globalClasses.item,
globalClasses.itemChoice, {
globalClasses.itemChoice,
{
[globalClasses.noResults]: (type === 'no-results'),
[globalClasses.noChoices]: (type === 'no-choices'),
},

View file

@ -0,0 +1,593 @@
import { expect } from 'chai';
import templates from './templates';
import { getType, strToEl } from './lib/utils';
const stripElement = element => element.outerHTML.replace(/(^|>)\s+|\s+(?=<|$)/g, '$1');
describe('templates', () => {
describe('containerOuter', () => {
const classes = {
containerOuter: 'test',
};
const direction = 'rtl';
describe('select element', () => {
describe('search enabled', () => {
it('returns expected html', () => {
const isSelectElement = true;
const isSelectOneElement = false;
const searchEnabled = true;
const passedElementType = 'select-multiple';
const expectedOutput = strToEl(`
<div
class="${classes.containerOuter}"
data-type="${passedElementType}"
role="combobox"
aria-autocomplete="list"
aria-haspopup="true"
aria-expanded="false"
dir="${direction}"
>
</div>
`);
const actualOutput = templates.containerOuter(
classes,
direction,
isSelectElement,
isSelectOneElement,
searchEnabled,
passedElementType,
);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('search disabled', () => {
it('returns expected html', () => {
const isSelectElement = true;
const isSelectOneElement = false;
const searchEnabled = false;
const passedElementType = 'select-multiple';
const expectedOutput = strToEl(`
<div
class="${classes.containerOuter}"
data-type="${passedElementType}"
role="listbox"
aria-haspopup="true"
aria-expanded="false"
dir="${direction}"
>
</div>
`);
const actualOutput = templates.containerOuter(
classes,
direction,
isSelectElement,
isSelectOneElement,
searchEnabled,
passedElementType,
);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('select one element', () => {
it('returns expected html', () => {
const isSelectElement = true;
const isSelectOneElement = true;
const searchEnabled = false;
const passedElementType = 'select-one';
const expectedOutput = strToEl(`
<div
class="${classes.containerOuter}"
data-type="${passedElementType}"
role="listbox"
tabindex="0"
aria-haspopup="true"
aria-expanded="false"
dir="${direction}"
>
</div>
`);
const actualOutput = templates.containerOuter(
classes,
direction,
isSelectElement,
isSelectOneElement,
searchEnabled,
passedElementType,
);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('non select element', () => {
it('returns expected html', () => {
const isSelectElement = false;
const isSelectOneElement = false;
const searchEnabled = false;
const passedElementType = 'text';
const expectedOutput = strToEl(`
<div
class="${classes.containerOuter}"
data-type="${passedElementType}"
aria-haspopup="true"
aria-expanded="false"
dir="${direction}"
>
</div>
`);
const actualOutput = templates.containerOuter(
classes,
direction,
isSelectElement,
isSelectOneElement,
searchEnabled,
passedElementType,
);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('containerInner', () => {
it('returns expected html', () => {
const classes = {
containerInner: 'test',
};
const expectedOutput = strToEl(`<div class="${classes.containerInner}"></div>`);
const actualOutput = templates.containerInner(classes);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('itemList', () => {
const classes = {
list: 'test 1',
listSingle: 'test 2',
listItems: 'test 3',
};
describe('select one element', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`<div class="${classes.list} ${classes.listSingle}"></div>`);
const actualOutput = templates.itemList(classes, true);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('non select one element', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`<div class="${classes.list} ${classes.listItems}"></div>`);
const actualOutput = templates.itemList(classes, false);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('placeholder', () => {
it('returns expected html', () => {
const classes = {
placeholder: 'test',
};
const value = 'test';
const expectedOutput = strToEl(`
<div class="${classes.placeholder}">${value}</div>`,
);
const actualOutput = templates.placeholder(classes, value);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
// describe('item', () => {
// });
describe('choiceList', () => {
const classes = {
list: 'test',
};
describe('select one element', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.list}"
dir="ltr"
role="listbox"
>
</div>
`);
const actualOutput = templates.choiceList(classes, true);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('non select one element', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.list}"
dir="ltr"
role="listbox"
aria-multiselectable="true"
>
</div>
`);
const actualOutput = templates.choiceList(classes, false);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('choiceGroup', () => {
const classes = {
group: 'test 1',
groupHeading: 'test 2',
itemDisabled: 'test 3',
};
let data;
beforeEach(() => {
data = {
id: 1,
value: 'test',
disabled: false,
};
});
describe('enabled state', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.group}"
data-group
data-id="${data.id}"
data-value="${data.value}"
role="group"
>
<div class="${classes.groupHeading}">${data.value}</div>
</div>
`);
const actualOutput = templates.choiceGroup(classes, data);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('disabled state', () => {
beforeEach(() => {
data = {
...data,
disabled: true,
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.group} ${classes.itemDisabled}"
data-group
data-id="${data.id}"
data-value="${data.value}"
role="group"
aria-disabled="true"
>
<div class="${classes.groupHeading}">${data.value}</div>
</div>
`);
const actualOutput = templates.choiceGroup(classes, data);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('choice', () => {
const classes = {
item: 'test 1',
itemChoice: 'test 2',
itemDisabled: 'test 3',
itemSelectable: 'test 4',
placeholder: 'test 5',
};
const itemSelectText = 'test 6';
let data;
beforeEach(() => {
data = {
id: 1,
groupId: -1,
disabled: false,
elementId: 'test',
label: 'test',
value: 'test',
};
});
describe('enabled state', () => {
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable}"
data-select-text="${itemSelectText}"
data-choice
data-id="${data.id}"
data-value="${data.value}"
data-choice-selectable
id="${data.elementId}"
role="option"
>
${data.label}
</div>
`);
const actualOutput = templates.choice(classes, data, itemSelectText);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('disabled state', () => {
beforeEach(() => {
data = {
...data,
disabled: true,
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.item} ${classes.itemChoice} ${classes.itemDisabled}"
data-select-text="${itemSelectText}"
data-choice
data-id="${data.id}"
data-value="${data.value}"
data-choice-disabled
aria-disabled="true"
id="${data.elementId}"
role="option"
>
${data.label}
</div>
`);
const actualOutput = templates.choice(classes, data, itemSelectText);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('placeholder', () => {
beforeEach(() => {
data = {
...data,
placeholder: true,
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable} ${classes.placeholder}"
data-select-text="${itemSelectText}"
data-choice
data-id="${data.id}"
data-value="${data.value}"
data-choice-selectable
id="${data.elementId}"
role="option"
>
${data.label}
</div>
`);
const actualOutput = templates.choice(classes, data, itemSelectText);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('child of group', () => {
beforeEach(() => {
data = {
...data,
groupId: 1
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable}"
data-select-text="${itemSelectText}"
data-choice
data-id="${data.id}"
data-value="${data.value}"
data-choice-selectable
id="${data.elementId}"
role="treeitem"
>
${data.label}
</div>
`);
const actualOutput = templates.choice(classes, data, itemSelectText);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
describe('input', () => {
const classes = {
input: 'test 1',
inputCloned: 'test 2',
};
it('returns expected html', () => {
const expectedOutput = strToEl(`
<input
type="text"
class="${classes.input} ${classes.inputCloned}"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
role="textbox"
aria-autocomplete="list"
>
`);
const actualOutput = templates.input(classes);
expect(getType(actualOutput)).to.equal('HTMLInputElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('dropdown', () => {
const classes = {
list: 'test 1',
listDropdown: 'test 2',
}
;
it('returns expected html', () => {
const value = 'test';
const expectedOutput = strToEl(`<div class="${classes.list} ${classes.listDropdown}" aria-expanded="false"></div>`);
const actualOutput = templates.dropdown(classes, value);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('notice', () => {
const classes = {
item: 'test 1',
itemChoice: 'test 2',
noResults: 'test 3',
noChoices: 'test 4',
};
const label = 'test';
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div class="${classes.item} ${classes.itemChoice}">
${label}
</div>
`);
const actualOutput = templates.notice(classes, label);
expect(getType(actualOutput)).to.equal('HTMLDivElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
describe('passing a notice type', () => {
describe('no results', () => {
it('adds no results classname', () => {
const expectedOutput = strToEl(`
<div class="${classes.item} ${classes.itemChoice} ${classes.noResults}">
${label}
</div>
`);
const actualOutput = templates.notice(classes, label, 'no-results');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
describe('no choices', () => {
it('adds no choices classname', () => {
const expectedOutput = strToEl(`
<div class="${classes.item} ${classes.itemChoice} ${classes.noChoices}">
${label}
</div>
`);
const actualOutput = templates.notice(classes, label, 'no-choices');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
});
});
});
describe('option', () => {
let data;
beforeEach(() => {
data = {
disabled: false,
selected: false,
value: 'test value',
label: 'test label',
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`<option value="${data.value}" ${data.selected ? 'selected' : ''} ${data.disabled ? 'disabled' : ''}>${data.label}</option>`);
const actualOutput = templates.option(data);
expect(getType(actualOutput)).to.equal('HTMLOptionElement');
expect(stripElement(actualOutput)).to.equal(stripElement(expectedOutput));
});
describe('when selected', () => {
beforeEach(() => {
data = {
...data,
selected: true,
};
});
it('sets selected attr to true', () => {
const output = templates.option(data);
expect(output.selected).to.equal(true);
});
});
describe('when disabled', () => {
beforeEach(() => {
data = {
...data,
disabled: true,
};
});
it('sets disabled attr to true', () => {
const output = templates.option(data);
expect(output.disabled).to.equal(true);
});
});
});
});

View file

@ -150,4 +150,8 @@ h6, .h6 {
text-align: center;
}
.is-hidden {
display: none;
}
/*===== End of Section comment block ======*/

View file

@ -1 +1 @@
*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{position:relative;margin:0;width:100%;height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:16px;line-height:1.4;color:#fff;background-color:#333;overflow-x:hidden}hr,label{display:block}label{margin-bottom:8px;font-size:14px;font-weight:500;cursor:pointer}p{margin-top:0}hr{margin:30px 0;border:0;border-bottom:1px solid #eaeaea;height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:12px;font-weight:400;line-height:1.2}a,a:focus,a:visited{color:#fff;text-decoration:none;font-weight:600}.form-control{display:block;width:100%;background-color:#f9f9f9;padding:12px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;margin-bottom:24px}.h1,h1{font-size:32px}.h2,h2{font-size:24px}.h3,h3{font-size:20px}.h4,h4{font-size:18px}.h5,h5{font-size:16px}.h6,h6{font-size:14px}.container{display:block;margin:auto;max-width:40em;padding:48px}@media (max-width:620px){.container{padding:0}}.section{background-color:#fff;padding:24px;color:#333}.section a,.section a:focus,.section a:visited{color:#00bcd4}.logo{display:block;margin-bottom:12px}.logo__img{width:100%;height:auto;display:inline-block;max-width:100%;vertical-align:top;padding:6px 0}.visible-ie{display:none}.zero-bottom{margin-bottom:0}.zero-top{margin-top:0}.text-center{text-align:center}
*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{position:relative;margin:0;width:100%;height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:16px;line-height:1.4;color:#fff;background-color:#333;overflow-x:hidden}hr,label{display:block}label{margin-bottom:8px;font-size:14px;font-weight:500;cursor:pointer}p{margin-top:0}hr{margin:30px 0;border:0;border-bottom:1px solid #eaeaea;height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:12px;font-weight:400;line-height:1.2}a,a:focus,a:visited{color:#fff;text-decoration:none;font-weight:600}.form-control{display:block;width:100%;background-color:#f9f9f9;padding:12px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;margin-bottom:24px}.h1,h1{font-size:32px}.h2,h2{font-size:24px}.h3,h3{font-size:20px}.h4,h4{font-size:18px}.h5,h5{font-size:16px}.h6,h6{font-size:14px}.container{display:block;margin:auto;max-width:40em;padding:48px}@media (max-width:620px){.container{padding:0}}.section{background-color:#fff;padding:24px;color:#333}.section a,.section a:focus,.section a:visited{color:#00bcd4}.logo{display:block;margin-bottom:12px}.logo__img{width:100%;height:auto;display:inline-block;max-width:100%;vertical-align:top;padding:6px 0}.visible-ie{display:none}.zero-bottom{margin-bottom:0}.zero-top{margin-top:0}.text-center{text-align:center}.is-hidden{display:none}

View file

@ -356,4 +356,10 @@
opacity: .5;
}
.choices__input.is-hidden,
.choices[data-type*="select-one"] .choices__input.is-hidden,
.choices[data-type*="select-multiple"] .choices__input.is-hidden {
display: none;
}
/*===== End of Choices ======*/

File diff suppressed because one or more lines are too long

View file

@ -121,5 +121,6 @@ h6, .h6 { font-size: $global-font-size-h6; }
.zero-bottom { margin-bottom: 0; }
.zero-top { margin-top: 0; }
.text-center { text-align: center; }
.is-hidden { display: none; }
/*===== End of Section comment block ======*/

View file

@ -292,4 +292,10 @@ $choices-icon-cross-inverse: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiI
.#{$choices-selector}__placeholder { opacity: .5; }
.#{$choices-selector}__input.is-hidden,
.#{$choices-selector}[data-type*="select-one"] .#{$choices-selector}__input.is-hidden,
.#{$choices-selector}[data-type*="select-multiple"] .#{$choices-selector}__input.is-hidden {
display: none;
}
/*===== End of Choices ======*/