Remove redundant check (#755)

* Remove redundant check

* Add integration tests covering fix

* Add missing test
This commit is contained in:
Josh Johnson 2019-11-13 15:40:47 +00:00 committed by GitHub
parent 84b952e115
commit 933ea6093f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 200 additions and 63 deletions

View file

@ -12,6 +12,30 @@ describe('Choices - select one', () => {
.click(); .click();
}); });
describe('focusing on container', () => {
describe('pressing enter key', () => {
it('toggles the dropdown', () => {
cy.get('[data-test-hook=basic]')
.find('.choices')
.focus()
.type('{enter}');
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('not.be.visible');
cy.get('[data-test-hook=basic]')
.find('.choices')
.focus()
.type('{enter}');
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
});
});
});
describe('focusing on text input', () => { describe('focusing on text input', () => {
it('displays a dropdown of choices', () => { it('displays a dropdown of choices', () => {
cy.get('[data-test-hook=basic]') cy.get('[data-test-hook=basic]')

View file

@ -1334,14 +1334,6 @@ var utils_wrap = function wrap(element, wrapper) {
return wrapper.appendChild(element); return wrapper.appendChild(element);
}; };
/**
* @param {HTMLElement} el
* @param {string} attr
*/
var findAncestorByAttrName = function findAncestorByAttrName(el, attr) {
return el.closest("[" + attr + "]");
};
/** /**
* @param {Element} startEl * @param {Element} startEl
* @param {string} selector * @param {string} selector
@ -1474,14 +1466,6 @@ var dispatchEvent = function dispatchEvent(element, type, customArgs) {
}); });
return element.dispatchEvent(event); return element.dispatchEvent(event);
}; };
/**
* @param {string} userAgent
* @returns {boolean}
*/
var isIE11 = function isIE11(userAgent) {
return !!(userAgent.match(/Trident/) && userAgent.match(/rv[ :]11/));
};
/** /**
* @param {array} array * @param {array} array
* @param {any} value * @param {any} value
@ -1875,6 +1859,7 @@ var DEFAULT_CLASSNAMES = {
openState: 'is-open', openState: 'is-open',
disabledState: 'is-disabled', disabledState: 'is-disabled',
highlightedState: 'is-highlighted', highlightedState: 'is-highlighted',
selectedState: 'is-selected',
flippedState: 'is-flipped', flippedState: 'is-flipped',
loadingState: 'is-loading', loadingState: 'is-loading',
noResults: 'has-no-results', noResults: 'has-no-results',
@ -2794,10 +2779,23 @@ function (_WrappedElement) {
* Helpers to create HTML elements used by Choices * Helpers to create HTML elements used by Choices
* Can be overridden by providing `callbackOnCreateTemplates` option * Can be overridden by providing `callbackOnCreateTemplates` option
* @typedef {import('../../types/index').Choices.Templates} Templates * @typedef {import('../../types/index').Choices.Templates} Templates
* @typedef {import('../../types/index').Choices.ClassNames} ClassNames
* @typedef {import('../../types/index').Choices.Options} Options
* @typedef {import('../../types/index').Choices.Item} Item
* @typedef {import('../../types/index').Choices.Choice} Choice
* @typedef {import('../../types/index').Choices.Group} Group
*/ */
var TEMPLATES = var TEMPLATES =
/** @type {Templates} */ /** @type {Templates} */
{ {
/**
* @param {Partial<ClassNames>} classNames
* @param {"ltr" | "rtl" | "auto"} dir
* @param {boolean} isSelectElement
* @param {boolean} isSelectOneElement
* @param {boolean} searchEnabled
* @param {"select-one" | "select-multiple" | "text"} passedElementType
*/
containerOuter: function containerOuter(_ref, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) { containerOuter: function containerOuter(_ref, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) {
var _containerOuter = _ref.containerOuter; var _containerOuter = _ref.containerOuter;
var div = Object.assign(document.createElement('div'), { var div = Object.assign(document.createElement('div'), {
@ -2825,12 +2823,21 @@ var TEMPLATES =
div.setAttribute('aria-expanded', 'false'); div.setAttribute('aria-expanded', 'false');
return div; return div;
}, },
/**
* @param {Partial<ClassNames>} classNames
*/
containerInner: function containerInner(_ref2) { containerInner: function containerInner(_ref2) {
var _containerInner = _ref2.containerInner; var _containerInner = _ref2.containerInner;
return Object.assign(document.createElement('div'), { return Object.assign(document.createElement('div'), {
className: _containerInner className: _containerInner
}); });
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {boolean} isSelectOneElement
*/
itemList: function itemList(_ref3, isSelectOneElement) { itemList: function itemList(_ref3, isSelectOneElement) {
var list = _ref3.list, var list = _ref3.list,
listSingle = _ref3.listSingle, listSingle = _ref3.listSingle,
@ -2839,6 +2846,11 @@ var TEMPLATES =
className: list + " " + (isSelectOneElement ? listSingle : listItems) className: list + " " + (isSelectOneElement ? listSingle : listItems)
}); });
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {string} value
*/
placeholder: function placeholder(_ref4, value) { placeholder: function placeholder(_ref4, value) {
var _placeholder = _ref4.placeholder; var _placeholder = _ref4.placeholder;
return Object.assign(document.createElement('div'), { return Object.assign(document.createElement('div'), {
@ -2846,6 +2858,12 @@ var TEMPLATES =
innerHTML: value innerHTML: value
}); });
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {Item} item
* @param {boolean} removeItemButton
*/
item: function item(_ref5, _ref6, removeItemButton) { item: function item(_ref5, _ref6, removeItemButton) {
var _item = _ref5.item, var _item = _ref5.item,
button = _ref5.button, button = _ref5.button,
@ -2906,6 +2924,11 @@ var TEMPLATES =
return div; return div;
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {boolean} isSelectOneElement
*/
choiceList: function choiceList(_ref7, isSelectOneElement) { choiceList: function choiceList(_ref7, isSelectOneElement) {
var list = _ref7.list; var list = _ref7.list;
var div = Object.assign(document.createElement('div'), { var div = Object.assign(document.createElement('div'), {
@ -2919,6 +2942,11 @@ var TEMPLATES =
div.setAttribute('role', 'listbox'); div.setAttribute('role', 'listbox');
return div; return div;
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {Group} group
*/
choiceGroup: function choiceGroup(_ref8, _ref9) { choiceGroup: function choiceGroup(_ref8, _ref9) {
var group = _ref8.group, var group = _ref8.group,
groupHeading = _ref8.groupHeading, groupHeading = _ref8.groupHeading,
@ -2946,10 +2974,17 @@ var TEMPLATES =
})); }));
return div; return div;
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {Choice} choice
* @param {Options['itemSelectText']} selectText
*/
choice: function choice(_ref10, _ref11, selectText) { choice: function choice(_ref10, _ref11, selectText) {
var item = _ref10.item, var item = _ref10.item,
itemChoice = _ref10.itemChoice, itemChoice = _ref10.itemChoice,
itemSelectable = _ref10.itemSelectable, itemSelectable = _ref10.itemSelectable,
selectedState = _ref10.selectedState,
itemDisabled = _ref10.itemDisabled, itemDisabled = _ref10.itemDisabled,
placeholder = _ref10.placeholder; placeholder = _ref10.placeholder;
var id = _ref11.id, var id = _ref11.id,
@ -2957,13 +2992,23 @@ var TEMPLATES =
label = _ref11.label, label = _ref11.label,
groupId = _ref11.groupId, groupId = _ref11.groupId,
elementId = _ref11.elementId, elementId = _ref11.elementId,
disabled = _ref11.disabled, isDisabled = _ref11.disabled,
isSelected = _ref11.selected,
isPlaceholder = _ref11.placeholder; isPlaceholder = _ref11.placeholder;
var div = Object.assign(document.createElement('div'), { var div = Object.assign(document.createElement('div'), {
id: elementId, id: elementId,
innerHTML: label, innerHTML: label,
className: item + " " + itemChoice + " " + (disabled ? itemDisabled : itemSelectable) + " " + (isPlaceholder ? placeholder : '') className: item + " " + itemChoice
}); });
if (isSelected) {
div.classList.add(selectedState);
}
if (isPlaceholder) {
div.classList.add(placeholder);
}
div.setAttribute('role', groupId > 0 ? 'treeitem' : 'option'); div.setAttribute('role', groupId > 0 ? 'treeitem' : 'option');
Object.assign(div.dataset, { Object.assign(div.dataset, {
choice: '', choice: '',
@ -2972,15 +3017,22 @@ var TEMPLATES =
selectText: selectText selectText: selectText
}); });
if (disabled) { if (isDisabled) {
div.classList.add(itemDisabled);
div.dataset.choiceDisabled = ''; div.dataset.choiceDisabled = '';
div.setAttribute('aria-disabled', 'true'); div.setAttribute('aria-disabled', 'true');
} else { } else {
div.classList.add(itemSelectable);
div.dataset.choiceSelectable = ''; div.dataset.choiceSelectable = '';
} }
return div; return div;
}, },
/**
* @param {Partial<ClassNames>} classNames
* @param {string} placeholderValue
*/
input: function input(_ref12, placeholderValue) { input: function input(_ref12, placeholderValue) {
var _input = _ref12.input, var _input = _ref12.input,
inputCloned = _ref12.inputCloned; inputCloned = _ref12.inputCloned;
@ -2996,6 +3048,10 @@ var TEMPLATES =
inp.setAttribute('aria-label', placeholderValue); inp.setAttribute('aria-label', placeholderValue);
return inp; return inp;
}, },
/**
* @param {Partial<ClassNames>} classNames
*/
dropdown: function dropdown(_ref13) { dropdown: function dropdown(_ref13) {
var list = _ref13.list, var list = _ref13.list,
listDropdown = _ref13.listDropdown; listDropdown = _ref13.listDropdown;
@ -3004,6 +3060,13 @@ var TEMPLATES =
div.setAttribute('aria-expanded', 'false'); div.setAttribute('aria-expanded', 'false');
return div; return div;
}, },
/**
*
* @param {Partial<ClassNames>} classNames
* @param {string} innerHTML
* @param {"no-choices" | "no-results" | ""} type
*/
notice: function notice(_ref14, innerHTML, type) { notice: function notice(_ref14, innerHTML, type) {
var item = _ref14.item, var item = _ref14.item,
itemChoice = _ref14.itemChoice, itemChoice = _ref14.itemChoice,
@ -3027,6 +3090,10 @@ var TEMPLATES =
className: classes.join(' ') className: classes.join(' ')
}); });
}, },
/**
* @param {Item} option
*/
option: function option(_ref15) { option: function option(_ref15) {
var label = _ref15.label, var label = _ref15.label,
value = _ref15.value, value = _ref15.value,
@ -3248,6 +3315,9 @@ function choices_createClass(Constructor, protoProps, staticProps) { if (protoPr
/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */
var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style;
/** /**
* @typedef {import('../../types/index').Choices.Choice} Choice * @typedef {import('../../types/index').Choices.Choice} Choice
* @typedef {import('../../types/index').Choices.Item} Item * @typedef {import('../../types/index').Choices.Item} Item
@ -4469,9 +4539,9 @@ function () {
var _document = document, var _document = document,
documentElement = _document.documentElement; // capture events - can cancel event processing or propagation documentElement = _document.documentElement; // capture events - can cancel event processing or propagation
documentElement.addEventListener('keydown', this._onKeyDown, true);
documentElement.addEventListener('touchend', this._onTouchEnd, true); documentElement.addEventListener('touchend', this._onTouchEnd, true);
documentElement.addEventListener('mousedown', this._onMouseDown, true); // passive events - doesn't call `preventDefault` or `stopPropagation` this.containerOuter.element.addEventListener('keydown', this._onKeyDown, true);
this.containerOuter.element.addEventListener('mousedown', this._onMouseDown, true); // passive events - doesn't call `preventDefault` or `stopPropagation`
documentElement.addEventListener('click', this._onClick, { documentElement.addEventListener('click', this._onClick, {
passive: true passive: true
@ -4479,7 +4549,7 @@ function () {
documentElement.addEventListener('touchmove', this._onTouchMove, { documentElement.addEventListener('touchmove', this._onTouchMove, {
passive: true passive: true
}); });
documentElement.addEventListener('mouseover', this._onMouseOver, { this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {
passive: true passive: true
}); });
@ -4514,19 +4584,19 @@ function () {
_proto._removeEventListeners = function _removeEventListeners() { _proto._removeEventListeners = function _removeEventListeners() {
var _document2 = document, var _document2 = document,
documentElement = _document2.documentElement; documentElement = _document2.documentElement;
documentElement.removeEventListener('keydown', this._onKeyDown, true);
documentElement.removeEventListener('touchend', this._onTouchEnd, true); documentElement.removeEventListener('touchend', this._onTouchEnd, true);
documentElement.removeEventListener('mousedown', this._onMouseDown, true); this.containerOuter.element.removeEventListener('keydown', this._onKeyDown, true);
documentElement.removeEventListener('keyup', this._onKeyUp); this.containerOuter.element.removeEventListener('mousedown', this._onMouseDown, true);
documentElement.removeEventListener('click', this._onClick); documentElement.removeEventListener('click', this._onClick);
documentElement.removeEventListener('touchmove', this._onTouchMove); documentElement.removeEventListener('touchmove', this._onTouchMove);
documentElement.removeEventListener('mouseover', this._onMouseOver); this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);
if (this._isSelectOneElement) { if (this._isSelectOneElement) {
this.containerOuter.element.removeEventListener('focus', this._onFocus); this.containerOuter.element.removeEventListener('focus', this._onFocus);
this.containerOuter.element.removeEventListener('blur', this._onBlur); this.containerOuter.element.removeEventListener('blur', this._onBlur);
} }
this.input.element.removeEventListener('keyup', this._onKeyUp);
this.input.element.removeEventListener('focus', this._onFocus); this.input.element.removeEventListener('focus', this._onFocus);
this.input.element.removeEventListener('blur', this._onBlur); this.input.element.removeEventListener('blur', this._onBlur);
@ -4535,7 +4605,11 @@ function () {
} }
this.input.removeEventListeners(); this.input.removeEventListeners();
}; }
/**
* @param {KeyboardEvent} event
*/
;
_proto._onKeyDown = function _onKeyDown(event) { _proto._onKeyDown = function _onKeyDown(event) {
var _keyDownActions; var _keyDownActions;
@ -4544,11 +4618,6 @@ function () {
keyCode = event.keyCode, keyCode = event.keyCode,
ctrlKey = event.ctrlKey, ctrlKey = event.ctrlKey,
metaKey = event.metaKey; metaKey = event.metaKey;
if (target !== this.input.element && !this.containerOuter.element.contains(target)) {
return;
}
var activeItems = this._store.activeItems; var activeItems = this._store.activeItems;
var hasFocusedInput = this.input.isFocussed; var hasFocusedInput = this.input.isFocussed;
var hasActiveDropdown = this.dropdown.isActive; var hasActiveDropdown = this.dropdown.isActive;
@ -4793,43 +4862,62 @@ function () {
} }
this._wasTap = true; this._wasTap = true;
}; }
/**
* Handles mousedown event in capture mode for containetOuter.element
* @param {MouseEvent} event
*/
;
_proto._onMouseDown = function _onMouseDown(event) { _proto._onMouseDown = function _onMouseDown(event) {
var target = event.target, var target = event.target;
shiftKey = event.shiftKey; // If we have our mouse down on the scrollbar and are on IE11...
if (this.choiceList.element.contains(target) && isIE11(navigator.userAgent)) { if (!(target instanceof HTMLElement)) {
this._isScrollingOnIe = true; return;
} // If we have our mouse down on the scrollbar and are on IE11...
if (IS_IE11 && this.choiceList.element.contains(target)) {
// check if click was on a scrollbar area
var firstChoice =
/** @type {HTMLElement} */
this.choiceList.element.firstElementChild;
var isOnScrollbar = this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;
this._isScrollingOnIe = isOnScrollbar;
} }
if (!this.containerOuter.element.contains(target) || target === this.input.element) { if (target === this.input.element) {
return; return;
} }
var activeItems = this._store.activeItems; var item = target.closest('[data-button],[data-item],[data-choice]');
var hasShiftKey = shiftKey;
var buttonTarget = findAncestorByAttrName(target, 'data-button');
var itemTarget = findAncestorByAttrName(target, 'data-item');
var choiceTarget = findAncestorByAttrName(target, 'data-choice');
if (buttonTarget) { if (item instanceof HTMLElement) {
this._handleButtonAction(activeItems, buttonTarget); var hasShiftKey = event.shiftKey;
} else if (itemTarget) { var activeItems = this._store.activeItems;
this._handleItemAction(activeItems, itemTarget, hasShiftKey); var dataset = item.dataset;
} else if (choiceTarget) {
this._handleChoiceAction(activeItems, choiceTarget); if ('button' in dataset) {
this._handleButtonAction(activeItems, item);
} else if ('item' in dataset) {
this._handleItemAction(activeItems, item, hasShiftKey);
} else if ('choice' in dataset) {
this._handleChoiceAction(activeItems, item);
}
} }
event.preventDefault(); event.preventDefault();
}; }
/**
* Handles mouseover event over this.dropdown
* @param {MouseEvent} event
*/
;
_proto._onMouseOver = function _onMouseOver(_ref9) { _proto._onMouseOver = function _onMouseOver(_ref9) {
var target = _ref9.target; var target = _ref9.target;
var targetWithinDropdown = target === this.dropdown || this.dropdown.element.contains(target);
var shouldHighlightChoice = targetWithinDropdown && target.hasAttribute('data-choice');
if (shouldHighlightChoice) { if (target instanceof HTMLElement && 'choice' in target.dataset) {
this._highlightChoice(target); this._highlightChoice(target);
} }
}; };

File diff suppressed because one or more lines are too long

View file

@ -200,6 +200,7 @@
border: 1px solid #00a5bb; border: 1px solid #00a5bb;
color: #ffffff; color: #ffffff;
word-break: break-all; word-break: break-all;
box-sizing: border-box;
} }
.choices__list--multiple .choices__item[data-deletable] { .choices__list--multiple .choices__item[data-deletable] {

File diff suppressed because one or more lines are too long

View file

@ -1319,11 +1319,6 @@ class Choices {
*/ */
_onKeyDown(event) { _onKeyDown(event) {
const { target, keyCode, ctrlKey, metaKey } = event; const { target, keyCode, ctrlKey, metaKey } = event;
if (target !== this.input.element) {
return;
}
const { activeItems } = this._store; const { activeItems } = this._store;
const hasFocusedInput = this.input.isFocussed; const hasFocusedInput = this.input.isFocussed;
const hasActiveDropdown = this.dropdown.isActive; const hasActiveDropdown = this.dropdown.isActive;

View file

@ -13,6 +13,7 @@ function expectEqualElements(element1, element2) {
expect(Object.keys(element1.dataset)).to.have.members( expect(Object.keys(element1.dataset)).to.have.members(
Object.keys(element2.dataset), Object.keys(element2.dataset),
); );
expect(element1.classList).to.include(element2.classList);
// compare attributes values // compare attributes values
for (const attribute of Object.values(element1.attributes)) { for (const attribute of Object.values(element1.attributes)) {
expect(element1.getAttribute(attribute)).to.equal( expect(element1.getAttribute(attribute)).to.equal(
@ -336,6 +337,7 @@ describe('templates', () => {
elementId: 'test', elementId: 'test',
label: 'test', label: 'test',
value: 'test', value: 'test',
selected: false,
}; };
}); });
@ -357,8 +359,6 @@ describe('templates', () => {
`); `);
const actualOutput = templates.choice(classes, data, itemSelectText); const actualOutput = templates.choice(classes, data, itemSelectText);
console.log(actualOutput);
expectEqualElements(actualOutput, expectedOutput); expectEqualElements(actualOutput, expectedOutput);
}); });
}); });
@ -393,6 +393,35 @@ describe('templates', () => {
}); });
}); });
describe('selected state', () => {
beforeEach(() => {
data = {
...data,
selected: true,
};
});
it('returns expected html', () => {
const expectedOutput = strToEl(`
<div
class="${classes.item} ${classes.itemChoice} ${classes.selectedState} ${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);
expectEqualElements(actualOutput, expectedOutput);
});
});
describe('placeholder', () => { describe('placeholder', () => {
beforeEach(() => { beforeEach(() => {
data = { data = {
@ -404,7 +433,7 @@ describe('templates', () => {
it('returns expected html', () => { it('returns expected html', () => {
const expectedOutput = strToEl(` const expectedOutput = strToEl(`
<div <div
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable} ${classes.placeholder}" class="${classes.item} ${classes.itemChoice} ${classes.placeholder} ${classes.itemSelectable}"
data-select-text="${itemSelectText}" data-select-text="${itemSelectText}"
data-choice data-choice
data-id="${data.id}" data-id="${data.id}"