mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-15 20:25:18 +02:00
Merge pull request #984 from victiondev/feat/allowHTML
feat: Introduce allowHTML option to allow people to disable injecting HTML into choices.
This commit is contained in:
commit
0b6973b322
17
README.md
17
README.md
|
@ -109,6 +109,7 @@ Or include Choices directly:
|
|||
removeItems: true,
|
||||
removeItemButton: false,
|
||||
editItems: false,
|
||||
allowHTML: true
|
||||
duplicateItemsAllowed: true,
|
||||
delimiter: ',',
|
||||
paste: true,
|
||||
|
@ -314,6 +315,16 @@ Pass an array of objects:
|
|||
|
||||
**Usage:** Whether a user can edit items. An item's value can be edited by pressing the backspace.
|
||||
|
||||
### allowHTML
|
||||
|
||||
**Type:** `Boolean` **Default:** `true`
|
||||
|
||||
**Input types affected:** `text`, `select-one`, `select-multiple`
|
||||
|
||||
**Usage:** Whether HTML should be rendered in all Choices elements. If `false`, all elements (placeholder, items, etc.) will be treated as plain text. If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.
|
||||
|
||||
**Deprecation Warning:** This will default to `false` in a future release.
|
||||
|
||||
### duplicateItemsAllowed
|
||||
|
||||
**Type:** `Boolean` **Default:** `true`
|
||||
|
@ -637,6 +648,8 @@ classNames: {
|
|||
If you want just extend a little original template then you may use `Choices.defaults.templates` to get access to
|
||||
original template function.
|
||||
|
||||
Templates receive the full Choices config as the first argument to any template, which allows you to conditionally display things based on the options specified.
|
||||
|
||||
**Example:**
|
||||
|
||||
```js
|
||||
|
@ -656,7 +669,7 @@ or more complex:
|
|||
const example = new Choices(element, {
|
||||
callbackOnCreateTemplates: function(template) {
|
||||
return {
|
||||
item: (classNames, data) => {
|
||||
item: ({ classNames }, data) => {
|
||||
return template(`
|
||||
<div class="${classNames.item} ${
|
||||
data.highlighted
|
||||
|
@ -671,7 +684,7 @@ const example = new Choices(element, {
|
|||
</div>
|
||||
`);
|
||||
},
|
||||
choice: (classNames, data) => {
|
||||
choice: ({ classNames }, data) => {
|
||||
return template(`
|
||||
<div class="${classNames.item} ${classNames.itemChoice} ${
|
||||
data.disabled ? classNames.itemDisabled : classNames.itemSelectable
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
describe('Choices - select multiple', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/select-multiple');
|
||||
cy.visit('/select-multiple', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win.console, 'warn').as('consoleWarn');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('scenarios', () => {
|
||||
|
@ -865,5 +869,78 @@ describe('Choices - select multiple', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('allow html', () => {
|
||||
describe('is undefined', () => {
|
||||
it('logs a deprecation warning', () => {
|
||||
cy.get('@consoleWarn').should(
|
||||
'be.calledOnceWithExactly',
|
||||
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not show as text when selected', () => {
|
||||
cy.get('[data-test-hook=allowhtml-undefined]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 1');
|
||||
});
|
||||
});
|
||||
|
||||
it('does not show html as text in dropdown', () => {
|
||||
cy.get('[data-test-hook=allowhtml-undefined]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to true', () => {
|
||||
it('does not show as text when selected', () => {
|
||||
cy.get('[data-test-hook=allowhtml-true]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 1');
|
||||
});
|
||||
});
|
||||
|
||||
it('does not show html as text in dropdown', () => {
|
||||
cy.get('[data-test-hook=allowhtml-true]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to false', () => {
|
||||
it('shows html as text when selected', () => {
|
||||
cy.get('[data-test-hook=allowhtml-false]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('<b>Choice 1</b>');
|
||||
});
|
||||
});
|
||||
|
||||
it('shows html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-false]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('<b>Choice 2</b>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
describe('Choices - select one', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/select-one');
|
||||
cy.visit('/select-one', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win.console, 'warn').as('consoleWarn');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('scenarios', () => {
|
||||
|
@ -51,9 +55,7 @@ describe('Choices - select one', () => {
|
|||
describe('selecting choices', () => {
|
||||
beforeEach(() => {
|
||||
// open dropdown
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=basic]').find('.choices').click();
|
||||
});
|
||||
|
||||
const selectedChoiceText = 'Choice 1';
|
||||
|
@ -68,7 +70,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($item => {
|
||||
.should(($item) => {
|
||||
expect($item).to.contain(selectedChoiceText);
|
||||
});
|
||||
});
|
||||
|
@ -84,7 +86,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($item => {
|
||||
.should(($item) => {
|
||||
expect($item).to.contain(selectedChoiceText);
|
||||
});
|
||||
});
|
||||
|
@ -93,9 +95,7 @@ describe('Choices - select one', () => {
|
|||
describe('searching choices', () => {
|
||||
beforeEach(() => {
|
||||
// open dropdown
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=basic]').find('.choices').click();
|
||||
});
|
||||
|
||||
describe('on input', () => {
|
||||
|
@ -109,7 +109,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 2');
|
||||
});
|
||||
});
|
||||
|
@ -125,7 +125,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 3');
|
||||
});
|
||||
});
|
||||
|
@ -140,7 +140,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should($dropdown => {
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal('No results found');
|
||||
});
|
||||
|
@ -206,7 +206,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.then($choice => {
|
||||
.then(($choice) => {
|
||||
removedChoiceText = $choice.text().trim();
|
||||
})
|
||||
.click();
|
||||
|
@ -229,7 +229,7 @@ describe('Choices - select one', () => {
|
|||
it('updates the value of the original input', () => {
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__input[hidden]')
|
||||
.should($select => {
|
||||
.should(($select) => {
|
||||
const val = $select.val() || [];
|
||||
|
||||
expect(val).to.not.contain(removedChoiceText);
|
||||
|
@ -248,7 +248,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
cy.get('[data-test-hook=disabled-choice]')
|
||||
.find('.choices__list--dropdown .choices__item--disabled')
|
||||
.then($choice => {
|
||||
.then(($choice) => {
|
||||
selectedChoiceText = $choice.text().trim();
|
||||
})
|
||||
.click();
|
||||
|
@ -258,7 +258,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text()).to.not.contain(selectedChoiceText);
|
||||
});
|
||||
});
|
||||
|
@ -305,9 +305,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
describe('on click', () => {
|
||||
it('does not open choice dropdown', () => {
|
||||
cy.get('[data-test-hook=disabled-via-attr]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=disabled-via-attr]').find('.choices').click();
|
||||
|
||||
cy.get('[data-test-hook=disabled-via-attr]')
|
||||
.find('.choices__list--dropdown')
|
||||
|
@ -335,7 +333,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.last()
|
||||
.then($choice => {
|
||||
.then(($choice) => {
|
||||
selectedChoiceText = $choice.text().trim();
|
||||
})
|
||||
.click();
|
||||
|
@ -345,7 +343,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.data('value')).to.equal(
|
||||
`before-${selectedChoiceText}-after`,
|
||||
);
|
||||
|
@ -356,7 +354,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text()).to.not.contain(
|
||||
`before-${selectedChoiceText}-after`,
|
||||
);
|
||||
|
@ -389,9 +387,7 @@ describe('Choices - select one', () => {
|
|||
const selectedChoiceText = 'Choice 3';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=search-disabled]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=search-disabled]').find('.choices').click();
|
||||
});
|
||||
|
||||
it('does not display a search input', () => {
|
||||
|
@ -410,7 +406,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=search-disabled]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($item => {
|
||||
.should(($item) => {
|
||||
expect($item).to.contain(selectedChoiceText);
|
||||
});
|
||||
});
|
||||
|
@ -442,7 +438,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.not.contain(searchTerm);
|
||||
});
|
||||
});
|
||||
|
@ -460,7 +456,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.contain(searchTerm);
|
||||
});
|
||||
});
|
||||
|
@ -476,7 +472,7 @@ describe('Choices - select one', () => {
|
|||
.children()
|
||||
.first()
|
||||
.should('have.class', 'choices__placeholder')
|
||||
.and($placeholder => {
|
||||
.and(($placeholder) => {
|
||||
expect($placeholder).to.contain('I am a placeholder');
|
||||
});
|
||||
});
|
||||
|
@ -524,7 +520,7 @@ describe('Choices - select one', () => {
|
|||
.children()
|
||||
.first()
|
||||
.should('have.class', 'choices__placeholder')
|
||||
.and($placeholder => {
|
||||
.and(($placeholder) => {
|
||||
expect($placeholder).to.contain('I am a placeholder');
|
||||
});
|
||||
});
|
||||
|
@ -577,7 +573,7 @@ describe('Choices - select one', () => {
|
|||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.class', 'choices__placeholder')
|
||||
.and($placeholder => {
|
||||
.and(($placeholder) => {
|
||||
expect($placeholder).to.contain('Loading...');
|
||||
});
|
||||
});
|
||||
|
@ -620,19 +616,17 @@ describe('Choices - select one', () => {
|
|||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=scrolling-dropdown]')
|
||||
.find('.choices__list--dropdown .choices__list .choices__item')
|
||||
.then($choices => {
|
||||
.then(($choices) => {
|
||||
choicesCount = $choices.length;
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=scrolling-dropdown]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=scrolling-dropdown]').find('.choices').click();
|
||||
});
|
||||
|
||||
it('highlights first choice on dropdown open', () => {
|
||||
cy.get('[data-test-hook=scrolling-dropdown]')
|
||||
.find('.choices__list--dropdown .choices__list .is-highlighted')
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 1');
|
||||
});
|
||||
});
|
||||
|
@ -641,7 +635,7 @@ describe('Choices - select one', () => {
|
|||
for (let index = 0; index < choicesCount; index++) {
|
||||
cy.get('[data-test-hook=scrolling-dropdown]')
|
||||
.find('.choices__list--dropdown .choices__list .is-highlighted')
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
|
||||
});
|
||||
|
||||
|
@ -665,7 +659,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
cy.get('[data-test-hook=scrolling-dropdown]')
|
||||
.find('.choices__list--dropdown .choices__list .is-highlighted')
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(`Choice ${index}`);
|
||||
});
|
||||
|
||||
|
@ -684,7 +678,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=groups]')
|
||||
.find('.choices__list--dropdown .choices__list .choices__group')
|
||||
.first()
|
||||
.then($group => {
|
||||
.then(($group) => {
|
||||
groupValue = $group.text().trim();
|
||||
});
|
||||
});
|
||||
|
@ -705,7 +699,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=groups]')
|
||||
.find('.choices__list--dropdown .choices__list .choices__group')
|
||||
.first()
|
||||
.should($group => {
|
||||
.should(($group) => {
|
||||
expect($group.text().trim()).to.not.equal(groupValue);
|
||||
});
|
||||
});
|
||||
|
@ -736,7 +730,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=groups]')
|
||||
.find('.choices__list--dropdown .choices__list .choices__group')
|
||||
.first()
|
||||
.should($group => {
|
||||
.should(($group) => {
|
||||
expect($group.text().trim()).to.equal(groupValue);
|
||||
});
|
||||
});
|
||||
|
@ -806,9 +800,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
describe('custom properties', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=custom-properties]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=custom-properties]').find('.choices').click();
|
||||
});
|
||||
|
||||
describe('on input', () => {
|
||||
|
@ -837,7 +829,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(city);
|
||||
});
|
||||
|
||||
|
@ -851,9 +843,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
describe('non-string values', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=non-string-values]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=non-string-values]').find('.choices').click();
|
||||
});
|
||||
|
||||
it('displays expected amount of choices in dropdown', () => {
|
||||
|
@ -869,7 +859,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.then($choice => {
|
||||
.then(($choice) => {
|
||||
$selectedChoice = $choice;
|
||||
})
|
||||
.click();
|
||||
|
@ -877,7 +867,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=non-string-values]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($item => {
|
||||
.should(($item) => {
|
||||
expect($item.text().trim()).to.equal($selectedChoice.text().trim());
|
||||
});
|
||||
});
|
||||
|
@ -887,7 +877,7 @@ describe('Choices - select one', () => {
|
|||
describe('selecting choice', () => {
|
||||
describe('on enter key', () => {
|
||||
it('does not submit form', () => {
|
||||
cy.get('[data-test-hook=within-form] form').then($form => {
|
||||
cy.get('[data-test-hook=within-form] form').then(($form) => {
|
||||
$form.submit(() => {
|
||||
// this will fail the test if the form submits
|
||||
throw new Error('Form submitted');
|
||||
|
@ -900,14 +890,12 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__input--cloned')
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=within-form]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=within-form]').find('.choices').click();
|
||||
|
||||
cy.get('[data-test-hook=within-form]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($item => {
|
||||
.should(($item) => {
|
||||
expect($item).to.contain('Choice 1');
|
||||
});
|
||||
});
|
||||
|
@ -922,7 +910,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=set-choice-by-value]')
|
||||
.find('.choices__list--single .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(
|
||||
dynamicallySelectedChoiceValue,
|
||||
);
|
||||
|
@ -932,7 +920,7 @@ describe('Choices - select one', () => {
|
|||
it('does not remove choice from dropdown list', () => {
|
||||
cy.get('[data-test-hook=set-choice-by-value]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.then($choicesList => {
|
||||
.then(($choicesList) => {
|
||||
expect($choicesList).to.contain(dynamicallySelectedChoiceValue);
|
||||
});
|
||||
});
|
||||
|
@ -940,7 +928,7 @@ describe('Choices - select one', () => {
|
|||
it('updates the value of the original input', () => {
|
||||
cy.get('[data-test-hook=set-choice-by-value]')
|
||||
.find('.choices__input[hidden]')
|
||||
.should($select => {
|
||||
.should(($select) => {
|
||||
const val = $select.val() || [];
|
||||
expect(val).to.contain(dynamicallySelectedChoiceValue);
|
||||
});
|
||||
|
@ -949,9 +937,7 @@ describe('Choices - select one', () => {
|
|||
|
||||
describe('searching by label only', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=search-by-label]')
|
||||
.find('.choices')
|
||||
.click();
|
||||
cy.get('[data-test-hook=search-by-label]').find('.choices').click();
|
||||
});
|
||||
|
||||
it('gets zero results when searching by value', () => {
|
||||
|
@ -963,7 +949,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('No results found');
|
||||
});
|
||||
});
|
||||
|
@ -977,7 +963,7 @@ describe('Choices - select one', () => {
|
|||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('label1');
|
||||
});
|
||||
});
|
||||
|
@ -998,7 +984,7 @@ describe('Choices - select one', () => {
|
|||
.children()
|
||||
.first()
|
||||
.should('have.class', 'choices__item--disabled')
|
||||
.then($choice => {
|
||||
.then(($choice) => {
|
||||
disabledValue = $choice.val();
|
||||
});
|
||||
});
|
||||
|
@ -1006,19 +992,64 @@ describe('Choices - select one', () => {
|
|||
it('selects the first enabled choice', () => {
|
||||
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||
.find('.choices__input[hidden]')
|
||||
.then($option => {
|
||||
.then(($option) => {
|
||||
expect($option.text().trim()).to.not.equal(disabledValue);
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=disabled-first-choice-via-options]')
|
||||
.find('.choices__item.choices__item--selectable')
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.not.equal(disabledValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('allow html', () => {
|
||||
describe('is undefined', () => {
|
||||
it('logs a deprecation warning', () => {
|
||||
cy.get('@consoleWarn').should(
|
||||
'be.calledOnceWithExactly',
|
||||
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not show html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-undefined]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to true', () => {
|
||||
it('does not show html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-true]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Choice 1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to false', () => {
|
||||
it('shows html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-false]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
.children()
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('<b>Choice 1</b>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('re-initialising a choices instance', () => {
|
||||
it('preserves the choices list', () => {
|
||||
cy.get('[data-test-hook=new-destroy-init]')
|
||||
|
@ -1029,9 +1060,7 @@ describe('Choices - select one', () => {
|
|||
cy.get('[data-test-hook=new-destroy-init]')
|
||||
.find('button.destroy')
|
||||
.click();
|
||||
cy.get('[data-test-hook=new-destroy-init]')
|
||||
.find('button.init')
|
||||
.click();
|
||||
cy.get('[data-test-hook=new-destroy-init]').find('button.init').click();
|
||||
|
||||
cy.get('[data-test-hook=new-destroy-init]')
|
||||
.find('.choices__list--dropdown .choices__list')
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
describe('Choices - text element', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/text');
|
||||
cy.visit('/text', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win.console, 'warn').as('consoleWarn');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('scenarios', () => {
|
||||
|
@ -17,7 +21,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($el => {
|
||||
.should(($el) => {
|
||||
expect($el).to.contain(textInput);
|
||||
});
|
||||
});
|
||||
|
@ -42,7 +46,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should($dropdown => {
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
`Press Enter to add "${textInput}"`,
|
||||
|
@ -74,7 +78,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.data('value')).to.equal(`${textInput}-edited`);
|
||||
});
|
||||
});
|
||||
|
@ -90,7 +94,7 @@ describe('Choices - text element', () => {
|
|||
it('highlights all items', () => {
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.each($choice => {
|
||||
.each(($choice) => {
|
||||
expect($choice.hasClass('is-highlighted')).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
@ -124,7 +128,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple')
|
||||
.children()
|
||||
.should($items => {
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(1);
|
||||
});
|
||||
|
||||
|
@ -137,7 +141,7 @@ describe('Choices - text element', () => {
|
|||
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.should($items => {
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
@ -152,7 +156,7 @@ describe('Choices - text element', () => {
|
|||
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__input[hidden]')
|
||||
.then($input => {
|
||||
.then(($input) => {
|
||||
expect($input.val()).to.not.contain(textInput);
|
||||
});
|
||||
});
|
||||
|
@ -175,7 +179,7 @@ describe('Choices - text element', () => {
|
|||
.find('.choices__list--multiple')
|
||||
.first()
|
||||
.children()
|
||||
.should($items => {
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
@ -185,7 +189,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=unique-values]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should($dropdown => {
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
'Only unique values can be added',
|
||||
|
@ -212,7 +216,7 @@ describe('Choices - text element', () => {
|
|||
.find('.choices__list--multiple')
|
||||
.first()
|
||||
.children()
|
||||
.should($items => {
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(inputLimit);
|
||||
});
|
||||
});
|
||||
|
@ -222,7 +226,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=input-limit]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should($dropdown => {
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
`Only ${inputLimit} values can be added`,
|
||||
|
@ -245,7 +249,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(input);
|
||||
});
|
||||
});
|
||||
|
@ -261,7 +265,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should($dropdown => {
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
'Only values matching specific conditions can be added',
|
||||
|
@ -283,7 +287,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.data('value')).to.equal(`before-${textInput}-after`);
|
||||
});
|
||||
});
|
||||
|
@ -292,7 +296,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text()).to.not.contain(`before-${textInput}-after`);
|
||||
expect($choice.text()).to.contain(textInput);
|
||||
});
|
||||
|
@ -319,21 +323,21 @@ describe('Choices - text element', () => {
|
|||
it('pre-populates choices', () => {
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.should($choices => {
|
||||
.should(($choices) => {
|
||||
expect($choices.length).to.equal(2);
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Josh Johnson');
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($choice => {
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Joe Bloggs');
|
||||
});
|
||||
});
|
||||
|
@ -355,11 +359,53 @@ describe('Choices - text element', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('allow html', () => {
|
||||
describe('is undefined', () => {
|
||||
it('logs a deprecation warning', () => {
|
||||
cy.get('@consoleWarn').should(
|
||||
'be.calledOnceWithExactly',
|
||||
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not show html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-undefined]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Mason Rogers');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to true', () => {
|
||||
it('does not show html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-true]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Mason Rogers');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to false', () => {
|
||||
it('shows html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-false]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('<b>Mason Rogers</b>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('within form', () => {
|
||||
describe('inputting item', () => {
|
||||
describe('on enter key', () => {
|
||||
it('does not submit form', () => {
|
||||
cy.get('[data-test-hook=within-form] form').then($form => {
|
||||
cy.get('[data-test-hook=within-form] form').then(($form) => {
|
||||
$form.submit(() => {
|
||||
// this will fail the test if the form submits
|
||||
throw new Error('Form submitted');
|
||||
|
@ -374,7 +420,7 @@ describe('Choices - text element', () => {
|
|||
cy.get('[data-test-hook=within-form]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should($el => {
|
||||
.should(($el) => {
|
||||
expect($el).to.contain(textInput);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*! choices.js v9.0.1 | © 2021 Josh Johnson | https://github.com/jshjohnson/Choices#readme */
|
||||
/*! choices.js v9.1.0 | © 2021 Josh Johnson | https://github.com/jshjohnson/Choices#readme */
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory();
|
||||
|
@ -291,6 +291,10 @@ function () {
|
|||
userConfig = {};
|
||||
}
|
||||
|
||||
if (userConfig.allowHTML === undefined) {
|
||||
console.warn('Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.');
|
||||
}
|
||||
|
||||
this.config = deepmerge_1.default.all([defaults_1.DEFAULT_CONFIG, Choices.defaults.options, userConfig], // When merging array configs, replace with a copy of the userConfig array,
|
||||
// instead of concatenating with the default array
|
||||
{
|
||||
|
@ -2209,8 +2213,7 @@ function () {
|
|||
args[_i - 1] = arguments[_i];
|
||||
}
|
||||
|
||||
var classNames = this.config.classNames;
|
||||
return (_a = this._templates[template]).call.apply(_a, __spreadArray([this, classNames], args, false));
|
||||
return (_a = this._templates[template]).call.apply(_a, __spreadArray([this, this.config], args, false));
|
||||
};
|
||||
|
||||
Choices.prototype._createTemplates = function () {
|
||||
|
@ -3483,6 +3486,7 @@ exports.DEFAULT_CONFIG = {
|
|||
removeItems: true,
|
||||
removeItemButton: false,
|
||||
editItems: false,
|
||||
allowHTML: true,
|
||||
duplicateItemsAllowed: true,
|
||||
delimiter: ',',
|
||||
paste: true,
|
||||
|
@ -3644,7 +3648,7 @@ var sanitise = function (value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
return value.replace(/&/g, '&').replace(/>/g, '&rt;').replace(/</g, '<').replace(/"/g, '"');
|
||||
return value.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"');
|
||||
};
|
||||
|
||||
exports.sanitise = sanitise;
|
||||
|
@ -4376,7 +4380,7 @@ Object.defineProperty(exports, "__esModule", ({
|
|||
}));
|
||||
var templates = {
|
||||
containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType) {
|
||||
var containerOuter = _a.containerOuter;
|
||||
var containerOuter = _a.classNames.containerOuter;
|
||||
var div = Object.assign(document.createElement('div'), {
|
||||
className: containerOuter
|
||||
});
|
||||
|
@ -4403,32 +4407,39 @@ var templates = {
|
|||
return div;
|
||||
},
|
||||
containerInner: function (_a) {
|
||||
var containerInner = _a.containerInner;
|
||||
var containerInner = _a.classNames.containerInner;
|
||||
return Object.assign(document.createElement('div'), {
|
||||
className: containerInner
|
||||
});
|
||||
},
|
||||
itemList: function (_a, isSelectOneElement) {
|
||||
var list = _a.list,
|
||||
listSingle = _a.listSingle,
|
||||
listItems = _a.listItems;
|
||||
var _b = _a.classNames,
|
||||
list = _b.list,
|
||||
listSingle = _b.listSingle,
|
||||
listItems = _b.listItems;
|
||||
return Object.assign(document.createElement('div'), {
|
||||
className: "".concat(list, " ").concat(isSelectOneElement ? listSingle : listItems)
|
||||
});
|
||||
},
|
||||
placeholder: function (_a, value) {
|
||||
var placeholder = _a.placeholder;
|
||||
return Object.assign(document.createElement('div'), {
|
||||
className: placeholder,
|
||||
innerHTML: value
|
||||
});
|
||||
var _b;
|
||||
|
||||
var allowHTML = _a.allowHTML,
|
||||
placeholder = _a.classNames.placeholder;
|
||||
return Object.assign(document.createElement('div'), (_b = {
|
||||
className: placeholder
|
||||
}, _b[allowHTML ? 'innerHTML' : 'innerText'] = value, _b));
|
||||
},
|
||||
item: function (_a, _b, removeItemButton) {
|
||||
var item = _a.item,
|
||||
button = _a.button,
|
||||
highlightedState = _a.highlightedState,
|
||||
itemSelectable = _a.itemSelectable,
|
||||
placeholder = _a.placeholder;
|
||||
var _c, _d;
|
||||
|
||||
var allowHTML = _a.allowHTML,
|
||||
_e = _a.classNames,
|
||||
item = _e.item,
|
||||
button = _e.button,
|
||||
highlightedState = _e.highlightedState,
|
||||
itemSelectable = _e.itemSelectable,
|
||||
placeholder = _e.placeholder;
|
||||
var id = _b.id,
|
||||
value = _b.value,
|
||||
label = _b.label,
|
||||
|
@ -4437,10 +4448,9 @@ var templates = {
|
|||
disabled = _b.disabled,
|
||||
highlighted = _b.highlighted,
|
||||
isPlaceholder = _b.placeholder;
|
||||
var div = Object.assign(document.createElement('div'), {
|
||||
className: item,
|
||||
innerHTML: label
|
||||
});
|
||||
var div = Object.assign(document.createElement('div'), (_c = {
|
||||
className: item
|
||||
}, _c[allowHTML ? 'innerHTML' : 'innerText'] = label, _c));
|
||||
Object.assign(div.dataset, {
|
||||
item: '',
|
||||
id: id,
|
||||
|
@ -4471,11 +4481,10 @@ var templates = {
|
|||
/** @todo This MUST be localizable, not hardcoded! */
|
||||
|
||||
var REMOVE_ITEM_TEXT = 'Remove item';
|
||||
var removeButton = Object.assign(document.createElement('button'), {
|
||||
var removeButton = Object.assign(document.createElement('button'), (_d = {
|
||||
type: 'button',
|
||||
className: button,
|
||||
innerHTML: REMOVE_ITEM_TEXT
|
||||
});
|
||||
className: button
|
||||
}, _d[allowHTML ? 'innerHTML' : 'innerText'] = REMOVE_ITEM_TEXT, _d));
|
||||
removeButton.setAttribute('aria-label', "".concat(REMOVE_ITEM_TEXT, ": '").concat(value, "'"));
|
||||
removeButton.dataset.button = '';
|
||||
div.appendChild(removeButton);
|
||||
|
@ -4484,7 +4493,7 @@ var templates = {
|
|||
return div;
|
||||
},
|
||||
choiceList: function (_a, isSelectOneElement) {
|
||||
var list = _a.list;
|
||||
var list = _a.classNames.list;
|
||||
var div = Object.assign(document.createElement('div'), {
|
||||
className: list
|
||||
});
|
||||
|
@ -4497,9 +4506,13 @@ var templates = {
|
|||
return div;
|
||||
},
|
||||
choiceGroup: function (_a, _b) {
|
||||
var group = _a.group,
|
||||
groupHeading = _a.groupHeading,
|
||||
itemDisabled = _a.itemDisabled;
|
||||
var _c;
|
||||
|
||||
var allowHTML = _a.allowHTML,
|
||||
_d = _a.classNames,
|
||||
group = _d.group,
|
||||
groupHeading = _d.groupHeading,
|
||||
itemDisabled = _d.itemDisabled;
|
||||
var id = _b.id,
|
||||
value = _b.value,
|
||||
disabled = _b.disabled;
|
||||
|
@ -4517,19 +4530,22 @@ var templates = {
|
|||
div.setAttribute('aria-disabled', 'true');
|
||||
}
|
||||
|
||||
div.appendChild(Object.assign(document.createElement('div'), {
|
||||
className: groupHeading,
|
||||
innerHTML: value
|
||||
}));
|
||||
div.appendChild(Object.assign(document.createElement('div'), (_c = {
|
||||
className: groupHeading
|
||||
}, _c[allowHTML ? 'innerHTML' : 'innerText'] = value, _c)));
|
||||
return div;
|
||||
},
|
||||
choice: function (_a, _b, selectText) {
|
||||
var item = _a.item,
|
||||
itemChoice = _a.itemChoice,
|
||||
itemSelectable = _a.itemSelectable,
|
||||
selectedState = _a.selectedState,
|
||||
itemDisabled = _a.itemDisabled,
|
||||
placeholder = _a.placeholder;
|
||||
var _c;
|
||||
|
||||
var allowHTML = _a.allowHTML,
|
||||
_d = _a.classNames,
|
||||
item = _d.item,
|
||||
itemChoice = _d.itemChoice,
|
||||
itemSelectable = _d.itemSelectable,
|
||||
selectedState = _d.selectedState,
|
||||
itemDisabled = _d.itemDisabled,
|
||||
placeholder = _d.placeholder;
|
||||
var id = _b.id,
|
||||
value = _b.value,
|
||||
label = _b.label,
|
||||
|
@ -4538,11 +4554,9 @@ var templates = {
|
|||
isDisabled = _b.disabled,
|
||||
isSelected = _b.selected,
|
||||
isPlaceholder = _b.placeholder;
|
||||
var div = Object.assign(document.createElement('div'), {
|
||||
id: elementId,
|
||||
innerHTML: label,
|
||||
className: "".concat(item, " ").concat(itemChoice)
|
||||
});
|
||||
var div = Object.assign(document.createElement('div'), (_c = {
|
||||
id: elementId
|
||||
}, _c[allowHTML ? 'innerHTML' : 'innerText'] = label, _c.className = "".concat(item, " ").concat(itemChoice), _c));
|
||||
|
||||
if (isSelected) {
|
||||
div.classList.add(selectedState);
|
||||
|
@ -4572,10 +4586,12 @@ var templates = {
|
|||
return div;
|
||||
},
|
||||
input: function (_a, placeholderValue) {
|
||||
var input = _a.input,
|
||||
inputCloned = _a.inputCloned;
|
||||
var _b = _a.classNames,
|
||||
input = _b.input,
|
||||
inputCloned = _b.inputCloned;
|
||||
var inp = Object.assign(document.createElement('input'), {
|
||||
type: 'text',
|
||||
type: 'search',
|
||||
name: 'search_terms',
|
||||
className: "".concat(input, " ").concat(inputCloned),
|
||||
autocomplete: 'off',
|
||||
autocapitalize: 'off',
|
||||
|
@ -4587,18 +4603,23 @@ var templates = {
|
|||
return inp;
|
||||
},
|
||||
dropdown: function (_a) {
|
||||
var list = _a.list,
|
||||
listDropdown = _a.listDropdown;
|
||||
var _b = _a.classNames,
|
||||
list = _b.list,
|
||||
listDropdown = _b.listDropdown;
|
||||
var div = document.createElement('div');
|
||||
div.classList.add(list, listDropdown);
|
||||
div.setAttribute('aria-expanded', 'false');
|
||||
return div;
|
||||
},
|
||||
notice: function (_a, innerHTML, type) {
|
||||
var item = _a.item,
|
||||
itemChoice = _a.itemChoice,
|
||||
noResults = _a.noResults,
|
||||
noChoices = _a.noChoices;
|
||||
notice: function (_a, innerText, type) {
|
||||
var _b;
|
||||
|
||||
var allowHTML = _a.allowHTML,
|
||||
_c = _a.classNames,
|
||||
item = _c.item,
|
||||
itemChoice = _c.itemChoice,
|
||||
noResults = _c.noResults,
|
||||
noChoices = _c.noChoices;
|
||||
|
||||
if (type === void 0) {
|
||||
type = '';
|
||||
|
@ -4612,10 +4633,7 @@ var templates = {
|
|||
classes.push(noResults);
|
||||
}
|
||||
|
||||
return Object.assign(document.createElement('div'), {
|
||||
innerHTML: innerHTML,
|
||||
className: classes.join(' ')
|
||||
});
|
||||
return Object.assign(document.createElement('div'), (_b = {}, _b[allowHTML ? 'innerHTML' : 'innerText'] = innerText, _b.className = classes.join(' '), _b));
|
||||
},
|
||||
option: function (_a) {
|
||||
var label = _a.label,
|
||||
|
|
2
public/assets/scripts/choices.min.js
vendored
2
public/assets/scripts/choices.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -534,6 +534,7 @@
|
|||
for (i = 0; i < genericExamples.length; ++i) {
|
||||
var element = genericExamples[i];
|
||||
new Choices(element, {
|
||||
allowHTML: true,
|
||||
placeholderValue: 'This is a placeholder set in the config',
|
||||
searchPlaceholderValue: 'This is a search placeholder',
|
||||
});
|
||||
|
@ -542,6 +543,7 @@
|
|||
var textRemove = new Choices(
|
||||
document.getElementById('choices-text-remove-button'),
|
||||
{
|
||||
allowHTML: true,
|
||||
delimiter: ',',
|
||||
editItems: true,
|
||||
maxItemCount: 5,
|
||||
|
@ -550,12 +552,14 @@
|
|||
);
|
||||
|
||||
var textUniqueVals = new Choices('#choices-text-unique-values', {
|
||||
allowHTML: true,
|
||||
paste: false,
|
||||
duplicateItemsAllowed: false,
|
||||
editItems: true,
|
||||
});
|
||||
|
||||
var texti18n = new Choices('#choices-text-i18n', {
|
||||
allowHTML: true,
|
||||
paste: false,
|
||||
duplicateItemsAllowed: false,
|
||||
editItems: true,
|
||||
|
@ -572,6 +576,7 @@
|
|||
});
|
||||
|
||||
var textEmailFilter = new Choices('#choices-text-email-filter', {
|
||||
allowHTML: true,
|
||||
editItems: true,
|
||||
addItemFilter: function(value) {
|
||||
if (!value) {
|
||||
|
@ -585,6 +590,7 @@
|
|||
}).setValue(['joe@bloggs.com']);
|
||||
|
||||
var textDisabled = new Choices('#choices-text-disabled', {
|
||||
allowHTML: true,
|
||||
addItems: false,
|
||||
removeItems: false,
|
||||
}).disable();
|
||||
|
@ -592,12 +598,14 @@
|
|||
var textPrependAppendVal = new Choices(
|
||||
'#choices-text-prepend-append-value',
|
||||
{
|
||||
allowHTML: true,
|
||||
prependValue: 'item-',
|
||||
appendValue: '-' + Date.now(),
|
||||
}
|
||||
).removeActiveItems();
|
||||
|
||||
var textPresetVal = new Choices('#choices-text-preset-values', {
|
||||
allowHTML: true,
|
||||
items: [
|
||||
'Josh Johnson',
|
||||
{
|
||||
|
@ -611,10 +619,12 @@
|
|||
});
|
||||
|
||||
var multipleDefault = new Choices(
|
||||
document.getElementById('choices-multiple-groups')
|
||||
document.getElementById('choices-multiple-groups'),
|
||||
{ allowHTML: true }
|
||||
);
|
||||
|
||||
var multipleFetch = new Choices('#choices-multiple-remote-fetch', {
|
||||
allowHTML: false,
|
||||
placeholder: true,
|
||||
placeholderValue: 'Pick an Strokes record',
|
||||
maxItemCount: 5,
|
||||
|
@ -635,12 +645,14 @@
|
|||
var multipleCancelButton = new Choices(
|
||||
'#choices-multiple-remove-button',
|
||||
{
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
}
|
||||
);
|
||||
|
||||
/* Use label on event */
|
||||
var choicesSelect = new Choices('#choices-multiple-labels', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
choices: [
|
||||
{ value: 'One', label: 'Label One' },
|
||||
|
@ -675,6 +687,7 @@
|
|||
);
|
||||
|
||||
var singleFetch = new Choices('#choices-single-remote-fetch', {
|
||||
allowHTML: false,
|
||||
searchPlaceholderValue: 'Search for an Arctic Monkeys record',
|
||||
})
|
||||
.setChoices(function() {
|
||||
|
@ -695,6 +708,7 @@
|
|||
});
|
||||
|
||||
var singleXhrRemove = new Choices('#choices-single-remove-xhr', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
searchPlaceholderValue: "Search for a Smiths' record",
|
||||
}).setChoices(function(callback) {
|
||||
|
@ -712,6 +726,7 @@
|
|||
});
|
||||
|
||||
var singleNoSearch = new Choices('#choices-single-no-search', {
|
||||
allowHTML: true,
|
||||
searchEnabled: false,
|
||||
removeItemButton: true,
|
||||
choices: [
|
||||
|
@ -731,6 +746,7 @@
|
|||
);
|
||||
|
||||
var singlePresetOpts = new Choices('#choices-single-preset-options', {
|
||||
allowHTML: true,
|
||||
placeholder: true,
|
||||
}).setChoices(
|
||||
[
|
||||
|
@ -760,6 +776,7 @@
|
|||
);
|
||||
|
||||
var singleSelectedOpt = new Choices('#choices-single-selected-option', {
|
||||
allowHTML: true,
|
||||
searchFields: ['label', 'value', 'customProperties.description'],
|
||||
choices: [
|
||||
{ value: 'One', label: 'Label One', selected: true },
|
||||
|
@ -777,17 +794,20 @@
|
|||
var customChoicesPropertiesViaDataAttributes = new Choices(
|
||||
'#choices-with-custom-props-via-html',
|
||||
{
|
||||
allowHTML: true,
|
||||
searchFields: ['label', 'value', 'customProperties'],
|
||||
}
|
||||
);
|
||||
|
||||
var singleNoSorting = new Choices('#choices-single-no-sorting', {
|
||||
allowHTML: true,
|
||||
shouldSort: false,
|
||||
});
|
||||
|
||||
var cities = new Choices(document.getElementById('cities'));
|
||||
var cities = new Choices(document.getElementById('cities'), { allowHTML: true });
|
||||
var tubeStations = new Choices(
|
||||
document.getElementById('tube-stations')
|
||||
document.getElementById('tube-stations'),
|
||||
{ allowHTML: true }
|
||||
).disable();
|
||||
|
||||
cities.passedElement.element.addEventListener('change', function(e) {
|
||||
|
@ -801,11 +821,12 @@
|
|||
var customTemplates = new Choices(
|
||||
document.getElementById('choices-single-custom-templates'),
|
||||
{
|
||||
allowHTML: true,
|
||||
callbackOnCreateTemplates: function(strToEl) {
|
||||
var classNames = this.config.classNames;
|
||||
var itemSelectText = this.config.itemSelectText;
|
||||
return {
|
||||
item: function(classNames, data) {
|
||||
item: function({ classNames }, data) {
|
||||
return strToEl(
|
||||
'\
|
||||
<div\
|
||||
|
@ -839,7 +860,7 @@
|
|||
'
|
||||
);
|
||||
},
|
||||
choice: function(classNames, data) {
|
||||
choice: function({ classNames }, data) {
|
||||
return strToEl(
|
||||
'\
|
||||
<div\
|
||||
|
@ -889,9 +910,12 @@
|
|||
}
|
||||
);
|
||||
|
||||
var resetSimple = new Choices(document.getElementById('reset-simple'));
|
||||
var resetSimple = new Choices(document.getElementById('reset-simple'), {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
var resetMultiple = new Choices('#reset-multiple', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -345,11 +345,43 @@
|
|||
<option value="value2">label2</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-undefined">
|
||||
<label for="choices-allowhtml-undefined">HTML allowed by default</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-undefined"
|
||||
id="choices-allowhtml-undefined"
|
||||
multiple
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-true">
|
||||
<label for="choices-allowhtml-true">HTML allowed</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-true"
|
||||
id="choices-allowhtml-true"
|
||||
multiple
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-false">
|
||||
<label for="choices-allowhtml-false">HTML disabled</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-false"
|
||||
id="choices-allowhtml-false"
|
||||
multiple
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const choicesBasic = new Choices('#choices-basic');
|
||||
const choicesBasic = new Choices('#choices-basic', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector('button.disable')
|
||||
|
@ -364,39 +396,54 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-remove-button', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-choice');
|
||||
new Choices('#choices-disabled-choice', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-add-items-disabled', {
|
||||
allowHTML: true,
|
||||
addItems: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-via-attr');
|
||||
new Choices('#choices-disabled-via-attr', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-selection-limit', {
|
||||
allowHTML: true,
|
||||
maxItemCount: 5,
|
||||
});
|
||||
|
||||
new Choices('#choices-prepend-append', {
|
||||
allowHTML: true,
|
||||
prependValue: 'before-',
|
||||
appendValue: '-after',
|
||||
});
|
||||
|
||||
new Choices('#choices-render-choice-limit', {
|
||||
allowHTML: true,
|
||||
renderChoiceLimit: 1,
|
||||
});
|
||||
|
||||
new Choices('#choices-search-floor', {
|
||||
allowHTML: true,
|
||||
searchFloor: 5,
|
||||
});
|
||||
|
||||
new Choices('#choices-placeholder-via-option-value');
|
||||
new Choices('#choices-placeholder-via-option-value', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-placeholder-via-option-attr');
|
||||
new Choices('#choices-placeholder-via-option-attr', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-remote-data', {
|
||||
allowHTML: true,
|
||||
shouldSort: false,
|
||||
}).setChoices(async () => {
|
||||
const data = await fetch('/data');
|
||||
|
@ -404,12 +451,16 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-scrolling-dropdown', {
|
||||
allowHTML: true,
|
||||
shouldSort: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-groups');
|
||||
new Choices('#choices-groups', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-custom-properties', {
|
||||
allowHTML: true,
|
||||
searchFields: ['label', 'value', 'customProperties.country'],
|
||||
choices: [
|
||||
{
|
||||
|
@ -440,6 +491,7 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-non-string-values', {
|
||||
allowHTML: true,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
|
@ -466,13 +518,83 @@
|
|||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-within-form');
|
||||
new Choices('#choices-within-form', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-set-choice-by-value').setChoiceByValue(
|
||||
'Choice 2',
|
||||
);
|
||||
new Choices('#choices-set-choice-by-value', {
|
||||
allowHTML: true,
|
||||
}).setChoiceByValue('Choice 2');
|
||||
|
||||
new Choices('#choices-search-by-label', { searchFields: ['label'] });
|
||||
new Choices('#choices-search-by-label', {
|
||||
allowHTML: true,
|
||||
searchFields: ['label']
|
||||
});
|
||||
|
||||
new Choices('#choices-allowhtml-undefined', {
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
selected: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '<b>Choice 2</b>',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Choice 3',
|
||||
value: 'Choice 3',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-allowhtml-true', {
|
||||
allowHTML: true,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
selected: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '<b>Choice 2</b>',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Choice 3',
|
||||
value: 'Choice 3',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-allowhtml-false', {
|
||||
allowHTML: false,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
selected: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '<b>Choice 2</b>',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Choice 3',
|
||||
value: 'Choice 3',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -354,6 +354,33 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-undefined">
|
||||
<label for="choices-allowhtml-undefined">HTML allowed by default</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-undefined"
|
||||
id="choices-allowhtml-undefined"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-true">
|
||||
<label for="choices-allowhtml-true">HTML allowed</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-true"
|
||||
id="choices-allowhtml-true"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-false">
|
||||
<label for="choices-allowhtml-false">HTML disabled</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="choices-allowhtml-false"
|
||||
id="choices-allowhtml-false"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div data-test-hook="new-destroy-init">
|
||||
<label for="choices-new-destroy-init">New, Destroy, Init</label>
|
||||
<select
|
||||
|
@ -372,7 +399,9 @@
|
|||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const choicesBasic = new Choices('#choices-basic');
|
||||
const choicesBasic = new Choices('#choices-basic', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector('button.disable')
|
||||
|
@ -387,14 +416,17 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-remove-button', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-choice', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-choice-via-options', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
choices: [
|
||||
{
|
||||
|
@ -418,33 +450,45 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-add-items-disabled', {
|
||||
allowHTML: true,
|
||||
addItems: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-via-attr');
|
||||
new Choices('#choices-disabled-via-attr', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-prepend-append', {
|
||||
allowHTML: true,
|
||||
prependValue: 'before-',
|
||||
appendValue: '-after',
|
||||
});
|
||||
|
||||
new Choices('#choices-render-choice-limit', {
|
||||
allowHTML: true,
|
||||
renderChoiceLimit: 1,
|
||||
});
|
||||
|
||||
new Choices('#choices-search-disabled', {
|
||||
allowHTML: true,
|
||||
searchEnabled: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-search-floor', {
|
||||
allowHTML: true,
|
||||
searchFloor: 5,
|
||||
});
|
||||
|
||||
new Choices('#choices-placeholder-via-option-value');
|
||||
new Choices('#choices-placeholder-via-option-value', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-placeholder-via-option-attr');
|
||||
new Choices('#choices-placeholder-via-option-attr', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-remote-data', {
|
||||
allowHTML: true,
|
||||
shouldSort: false,
|
||||
}).setChoices(async () => {
|
||||
const res = await fetch('/data');
|
||||
|
@ -452,13 +496,20 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-scrolling-dropdown', {
|
||||
allowHTML: true,
|
||||
shouldSort: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-groups');
|
||||
new Choices('#choices-groups', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
const parent = new Choices('#choices-parent');
|
||||
const child = new Choices('#choices-child').disable();
|
||||
const parent = new Choices('#choices-parent', {
|
||||
allowHTML: true,
|
||||
});
|
||||
const child = new Choices('#choices-child', {
|
||||
allowHTML: true,
|
||||
}).disable();
|
||||
|
||||
parent.passedElement.element.addEventListener('change', event => {
|
||||
if (event.detail.value === 'Parent choice 2') {
|
||||
|
@ -469,6 +520,7 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-custom-properties', {
|
||||
allowHTML: true,
|
||||
searchFields: ['label', 'value', 'customProperties.country'],
|
||||
choices: [
|
||||
{
|
||||
|
@ -499,6 +551,7 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-non-string-values', {
|
||||
allowHTML: true,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
|
@ -525,15 +578,69 @@
|
|||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-within-form');
|
||||
new Choices('#choices-within-form', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-set-choice-by-value').setChoiceByValue(
|
||||
'Choice 2',
|
||||
);
|
||||
new Choices('#choices-set-choice-by-value', {
|
||||
allowHTML: true,
|
||||
}).setChoiceByValue('Choice 2');
|
||||
|
||||
new Choices('#choices-search-by-label', { searchFields: ['label'] });
|
||||
new Choices('#choices-search-by-label', {
|
||||
allowHTML: true,
|
||||
searchFields: ['label']
|
||||
});
|
||||
|
||||
const newDestroyInitChoices = new Choices('#choices-new-destroy-init');
|
||||
new Choices('#choices-allowhtml-undefined', {
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Choice 2',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-allowhtml-true', {
|
||||
allowHTML: true,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Choice 2',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-allowhtml-false', {
|
||||
allowHTML: false,
|
||||
choices: [
|
||||
{
|
||||
id: 1,
|
||||
label: '<b>Choice 1</b>',
|
||||
value: 'Choice 1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Choice 2',
|
||||
value: 'Choice 2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const newDestroyInitChoices = new Choices('#choices-new-destroy-init', {
|
||||
allowHTML: true,
|
||||
});
|
||||
document
|
||||
.querySelector('button.destroy')
|
||||
.addEventListener('click', () => {
|
||||
|
|
|
@ -76,6 +76,21 @@
|
|||
<input class="form-control" id="choices-unique-values" type="text" />
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-undefined">
|
||||
<label for="allowhtml-undefined">HTML allowed by default</label>
|
||||
<input class="form-control" id="allowhtml-undefined" type="text" />
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-true">
|
||||
<label for="allowhtml-true">HTML allowed</label>
|
||||
<input class="form-control" id="allowhtml-true" type="text" />
|
||||
</div>
|
||||
|
||||
<div data-test-hook="allowhtml-false">
|
||||
<label for="allowhtml-false">HTML disabled</label>
|
||||
<input class="form-control" id="allowhtml-false" type="text" />
|
||||
</div>
|
||||
|
||||
<div data-test-hook="input-limit">
|
||||
<label for="choices-input-limit">Input limit</label>
|
||||
<input class="form-control" id="choices-input-limit" type="text" />
|
||||
|
@ -134,25 +149,52 @@
|
|||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
new Choices('#choices-basic');
|
||||
new Choices('#choices-basic', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-edit-items', {
|
||||
allowHTML: true,
|
||||
editItems: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-remove-button', {
|
||||
allowHTML: true,
|
||||
removeItemButton: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-unique-values', {
|
||||
allowHTML: true,
|
||||
duplicateItemsAllowed: false,
|
||||
});
|
||||
|
||||
new Choices('#allowhtml-undefined', {
|
||||
items: [
|
||||
'<b>Mason Rogers</b>'
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#allowhtml-true', {
|
||||
allowHTML: true,
|
||||
items: [
|
||||
'<b>Mason Rogers</b>'
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#allowhtml-false', {
|
||||
allowHTML: false,
|
||||
items: [
|
||||
'<b>Mason Rogers</b>'
|
||||
],
|
||||
});
|
||||
|
||||
new Choices('#choices-input-limit', {
|
||||
allowHTML: true,
|
||||
maxItemCount: 5,
|
||||
});
|
||||
|
||||
new Choices('#choices-add-item-filter', {
|
||||
allowHTML: true,
|
||||
addItems: true,
|
||||
addItemFilter: value => {
|
||||
const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
|
@ -162,17 +204,22 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-adding-items-disabled', {
|
||||
allowHTML: true,
|
||||
addItems: false,
|
||||
});
|
||||
|
||||
new Choices('#choices-disabled-via-attr');
|
||||
new Choices('#choices-disabled-via-attr', {
|
||||
allowHTML: true,
|
||||
});
|
||||
|
||||
new Choices('#choices-prepend-append', {
|
||||
allowHTML: true,
|
||||
prependValue: 'before-',
|
||||
appendValue: '-after',
|
||||
});
|
||||
|
||||
new Choices('#choices-prepopulated', {
|
||||
allowHTML: true,
|
||||
items: [
|
||||
'Josh Johnson',
|
||||
{
|
||||
|
@ -186,11 +233,14 @@
|
|||
});
|
||||
|
||||
new Choices('#choices-placeholder', {
|
||||
allowHTML: true,
|
||||
placeholder: true,
|
||||
placeholderValue: 'I am a placeholder',
|
||||
});
|
||||
|
||||
new Choices('#choices-within-form');
|
||||
new Choices('#choices-within-form', {
|
||||
allowHTML: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -26,7 +26,7 @@ describe('choices', () => {
|
|||
passedElement.className = 'js-choices';
|
||||
document.body.appendChild(passedElement);
|
||||
|
||||
instance = new Choices(passedElement);
|
||||
instance = new Choices(passedElement, { allowHTML: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -55,6 +55,7 @@ describe('choices', () => {
|
|||
`;
|
||||
|
||||
const config = {
|
||||
allowHTML: true,
|
||||
renderChoiceLimit: 5,
|
||||
};
|
||||
instance = new Choices('[data-choice]', config);
|
||||
|
@ -73,6 +74,7 @@ describe('choices', () => {
|
|||
`;
|
||||
|
||||
instance = new Choices('[data-choice]', {
|
||||
allowHTML: true,
|
||||
searchEnabled: false,
|
||||
});
|
||||
|
||||
|
@ -88,6 +90,7 @@ describe('choices', () => {
|
|||
`;
|
||||
|
||||
instance = new Choices('[data-choice]', {
|
||||
allowHTML: true,
|
||||
renderSelectedChoices: 'test' as any,
|
||||
});
|
||||
|
||||
|
@ -108,7 +111,7 @@ describe('choices', () => {
|
|||
const inputs = document.querySelectorAll('[data-choice]');
|
||||
expect(inputs.length).to.equal(3);
|
||||
|
||||
instance = new Choices();
|
||||
instance = new Choices(undefined, { allowHTML: true });
|
||||
|
||||
expect(instance.passedElement.element.id).to.equal(inputs[0].id);
|
||||
});
|
||||
|
@ -116,7 +119,7 @@ describe('choices', () => {
|
|||
describe('when an element cannot be found in the DOM', () => {
|
||||
it('throws an error', () => {
|
||||
document.body.innerHTML = ``;
|
||||
expect(() => new Choices()).to.throw(
|
||||
expect(() => new Choices(undefined, { allowHTML: true })).to.throw(
|
||||
TypeError,
|
||||
'Expected one of the following types text|select-one|select-multiple',
|
||||
);
|
||||
|
@ -133,7 +136,7 @@ describe('choices', () => {
|
|||
});
|
||||
|
||||
it('sets the initialised flag to true', () => {
|
||||
instance = new Choices('#input-1');
|
||||
instance = new Choices('#input-1', { allowHTML: true });
|
||||
expect(instance.initialised).to.equal(true);
|
||||
});
|
||||
|
||||
|
@ -141,6 +144,7 @@ describe('choices', () => {
|
|||
const initSpy = spy();
|
||||
// initialise with the same element
|
||||
instance = new Choices('#input-1', {
|
||||
allowHTML: true,
|
||||
silent: true,
|
||||
callbackOnInit: initSpy,
|
||||
});
|
||||
|
@ -156,12 +160,12 @@ describe('choices', () => {
|
|||
`;
|
||||
|
||||
// initialise once
|
||||
new Choices('#input-1', { silent: true });
|
||||
new Choices('#input-1', { allowHTML: true, silent: true });
|
||||
});
|
||||
|
||||
it('sets the initialised flag to true', () => {
|
||||
// initialise with the same element
|
||||
instance = new Choices('#input-1', { silent: true });
|
||||
instance = new Choices('#input-1', { allowHTML: true, silent: true });
|
||||
|
||||
expect(instance.initialised).to.equal(true);
|
||||
});
|
||||
|
@ -170,6 +174,7 @@ describe('choices', () => {
|
|||
const initSpy = spy();
|
||||
// initialise with the same element
|
||||
instance = new Choices('#input-1', {
|
||||
allowHTML: true,
|
||||
silent: true,
|
||||
callbackOnInit: initSpy,
|
||||
});
|
||||
|
@ -185,7 +190,7 @@ describe('choices', () => {
|
|||
<input data-choice type="text" id="input-1" />
|
||||
`;
|
||||
|
||||
instance = new Choices('[data-choice]');
|
||||
instance = new Choices('[data-choice]', { allowHTML: true });
|
||||
|
||||
expect(instance.passedElement).to.be.an.instanceOf(WrappedInput);
|
||||
});
|
||||
|
@ -197,7 +202,7 @@ describe('choices', () => {
|
|||
<select data-choice id="select-1"></select>
|
||||
`;
|
||||
|
||||
instance = new Choices('[data-choice]');
|
||||
instance = new Choices('[data-choice]', { allowHTML: true });
|
||||
|
||||
expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect);
|
||||
});
|
||||
|
@ -211,7 +216,7 @@ describe('choices', () => {
|
|||
<input data-choice type="text" id="input-1" />
|
||||
`;
|
||||
|
||||
instance = new Choices('[data-choice]');
|
||||
instance = new Choices('[data-choice]', { allowHTML: true });
|
||||
|
||||
expect(instance.passedElement).to.be.an.instanceOf(WrappedInput);
|
||||
});
|
||||
|
@ -223,7 +228,7 @@ describe('choices', () => {
|
|||
<select data-choice id="select-1"></select>
|
||||
`;
|
||||
|
||||
instance = new Choices('[data-choice]');
|
||||
instance = new Choices('[data-choice]', { allowHTML: true });
|
||||
|
||||
expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect);
|
||||
});
|
||||
|
@ -235,7 +240,9 @@ describe('choices', () => {
|
|||
document.body.innerHTML = `
|
||||
<div data-choice id="div-1"></div>
|
||||
`;
|
||||
expect(() => new Choices('[data-choice]')).to.throw(
|
||||
expect(
|
||||
() => new Choices('[data-choice]', { allowHTML: true }),
|
||||
).to.throw(
|
||||
TypeError,
|
||||
'Expected one of the following types text|select-one|select-multiple',
|
||||
);
|
||||
|
@ -250,6 +257,7 @@ describe('choices', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
instance = new Choices(passedElement, {
|
||||
allowHTML: true,
|
||||
callbackOnInit: callbackOnInitSpy,
|
||||
silent: true,
|
||||
});
|
||||
|
@ -330,7 +338,7 @@ describe('choices', () => {
|
|||
passedElement.className = 'js-choices';
|
||||
document.body.appendChild(passedElement);
|
||||
|
||||
instance = new Choices(passedElement);
|
||||
instance = new Choices(passedElement, { allowHTML: true });
|
||||
});
|
||||
|
||||
describe('not already initialised', () => {
|
||||
|
@ -1188,7 +1196,7 @@ describe('choices', () => {
|
|||
describe('select element', () => {
|
||||
it('fetches and sets choices', async () => {
|
||||
document.body.innerHTML = '<select id="test" />';
|
||||
const choice = new Choices('#test');
|
||||
const choice = new Choices('#test', { allowHTML: true });
|
||||
const handleLoadingStateSpy = spy(choice, '_handleLoadingState');
|
||||
|
||||
let fetcherCalled = false;
|
||||
|
@ -2063,7 +2071,7 @@ describe('choices', () => {
|
|||
output = instance._getTemplate(templateKey, customArg);
|
||||
expect(output).to.deep.equal(element);
|
||||
expect(instance._templates[templateKey]).to.have.been.calledOnceWith(
|
||||
instance.config.classNames,
|
||||
instance.config,
|
||||
customArg,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -151,6 +151,12 @@ class Choices implements Choices {
|
|||
| HTMLSelectElement = '[data-choice]',
|
||||
userConfig: Partial<Options> = {},
|
||||
) {
|
||||
if (userConfig.allowHTML === undefined) {
|
||||
console.warn(
|
||||
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
|
||||
);
|
||||
}
|
||||
|
||||
this.config = merge.all<Options>(
|
||||
[DEFAULT_CONFIG, Choices.defaults.options, userConfig],
|
||||
// When merging array configs, replace with a copy of the userConfig array,
|
||||
|
@ -2105,9 +2111,7 @@ class Choices implements Choices {
|
|||
}
|
||||
|
||||
_getTemplate(template: string, ...args: any): any {
|
||||
const { classNames } = this.config;
|
||||
|
||||
return this._templates[template].call(this, classNames, ...args);
|
||||
return this._templates[template].call(this, this.config, ...args);
|
||||
}
|
||||
|
||||
_createTemplates(): void {
|
||||
|
|
|
@ -54,6 +54,7 @@ describe('constants', () => {
|
|||
expect(DEFAULT_CONFIG.removeItems).to.be.a('boolean');
|
||||
expect(DEFAULT_CONFIG.removeItemButton).to.be.a('boolean');
|
||||
expect(DEFAULT_CONFIG.editItems).to.be.a('boolean');
|
||||
expect(DEFAULT_CONFIG.allowHTML).to.be.a('boolean');
|
||||
expect(DEFAULT_CONFIG.duplicateItemsAllowed).to.be.a('boolean');
|
||||
expect(DEFAULT_CONFIG.delimiter).to.be.a('string');
|
||||
expect(DEFAULT_CONFIG.paste).to.be.a('boolean');
|
||||
|
|
|
@ -42,6 +42,7 @@ export const DEFAULT_CONFIG: Options = {
|
|||
removeItems: true,
|
||||
removeItemButton: false,
|
||||
editItems: false,
|
||||
allowHTML: true,
|
||||
duplicateItemsAllowed: true,
|
||||
delimiter: ',',
|
||||
paste: true,
|
||||
|
|
|
@ -159,6 +159,19 @@ export interface Options {
|
|||
*/
|
||||
editItems: boolean;
|
||||
|
||||
/**
|
||||
* Whether HTML should be rendered in all Choices elements.
|
||||
* If `false`, all elements (placeholder, items, etc.) will be treated as plain text.
|
||||
* If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.
|
||||
*
|
||||
* **Deprecation Warning:** This will default to `false` in a future release.
|
||||
*
|
||||
* **Input types affected:** text, select-one, select-multiple
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
allowHTML: boolean;
|
||||
|
||||
/**
|
||||
* Whether each inputted/chosen item should be unique.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { expect } from 'chai';
|
||||
import templates from './templates';
|
||||
import { strToEl } from './lib/utils';
|
||||
import { DEFAULT_CLASSNAMES, DEFAULT_CONFIG } from './defaults';
|
||||
import { Options } from './interfaces/options';
|
||||
import { ClassNames } from './interfaces/class-names';
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element1
|
||||
|
@ -21,11 +24,25 @@ function expectEqualElements(element1, element2): void {
|
|||
}
|
||||
}
|
||||
|
||||
function createOptionsWithPartialClasses(
|
||||
classNames: Partial<ClassNames>,
|
||||
options: Partial<Options> = {},
|
||||
): Options {
|
||||
return {
|
||||
...DEFAULT_CONFIG,
|
||||
...options,
|
||||
classNames: {
|
||||
...DEFAULT_CLASSNAMES,
|
||||
...classNames,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('templates', () => {
|
||||
describe('containerOuter', () => {
|
||||
const classes = {
|
||||
const options = createOptionsWithPartialClasses({
|
||||
containerOuter: 'class-1',
|
||||
};
|
||||
});
|
||||
const direction = 'rtl';
|
||||
|
||||
describe('select element', () => {
|
||||
|
@ -38,7 +55,7 @@ describe('templates', () => {
|
|||
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.containerOuter}"
|
||||
class="${options.classNames.containerOuter}"
|
||||
data-type="${passedElementType}"
|
||||
role="combobox"
|
||||
aria-autocomplete="list"
|
||||
|
@ -49,7 +66,7 @@ describe('templates', () => {
|
|||
</div>
|
||||
`);
|
||||
const actualOutput = templates.containerOuter(
|
||||
classes,
|
||||
options,
|
||||
direction,
|
||||
isSelectElement,
|
||||
isSelectOneElement,
|
||||
|
@ -69,7 +86,7 @@ describe('templates', () => {
|
|||
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.containerOuter}"
|
||||
class="${options.classNames.containerOuter}"
|
||||
data-type="${passedElementType}"
|
||||
role="listbox"
|
||||
aria-haspopup="true"
|
||||
|
@ -79,7 +96,7 @@ describe('templates', () => {
|
|||
</div>
|
||||
`);
|
||||
const actualOutput = templates.containerOuter(
|
||||
classes,
|
||||
options,
|
||||
direction,
|
||||
isSelectElement,
|
||||
isSelectOneElement,
|
||||
|
@ -100,7 +117,7 @@ describe('templates', () => {
|
|||
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.containerOuter}"
|
||||
class="${options.classNames.containerOuter}"
|
||||
data-type="${passedElementType}"
|
||||
role="listbox"
|
||||
tabindex="0"
|
||||
|
@ -111,7 +128,7 @@ describe('templates', () => {
|
|||
</div>
|
||||
`);
|
||||
const actualOutput = templates.containerOuter(
|
||||
classes,
|
||||
options,
|
||||
direction,
|
||||
isSelectElement,
|
||||
isSelectOneElement,
|
||||
|
@ -133,7 +150,7 @@ describe('templates', () => {
|
|||
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.containerOuter}"
|
||||
class="${options.classNames.containerOuter}"
|
||||
data-type="${passedElementType}"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
|
@ -142,7 +159,7 @@ describe('templates', () => {
|
|||
</div>
|
||||
`);
|
||||
const actualOutput = templates.containerOuter(
|
||||
classes,
|
||||
options,
|
||||
direction,
|
||||
isSelectElement,
|
||||
isSelectOneElement,
|
||||
|
@ -157,31 +174,31 @@ describe('templates', () => {
|
|||
|
||||
describe('containerInner', () => {
|
||||
it('returns expected html', () => {
|
||||
const classes = {
|
||||
const innerOptions = createOptionsWithPartialClasses({
|
||||
containerInner: 'class-1',
|
||||
};
|
||||
});
|
||||
const expectedOutput = strToEl(
|
||||
`<div class="${classes.containerInner}"></div>`,
|
||||
`<div class="${innerOptions.classNames.containerInner}"></div>`,
|
||||
);
|
||||
const actualOutput = templates.containerInner(classes);
|
||||
const actualOutput = templates.containerInner(innerOptions);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
describe('itemList', () => {
|
||||
const classes = {
|
||||
const itemOptions = createOptionsWithPartialClasses({
|
||||
list: 'class-1',
|
||||
listSingle: 'class-2',
|
||||
listItems: 'class-3',
|
||||
};
|
||||
});
|
||||
|
||||
describe('select one element', () => {
|
||||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(
|
||||
`<div class="${classes.list} ${classes.listSingle}"></div>`,
|
||||
`<div class="${itemOptions.classNames.list} ${itemOptions.classNames.listSingle}"></div>`,
|
||||
);
|
||||
const actualOutput = templates.itemList(classes, true);
|
||||
const actualOutput = templates.itemList(itemOptions, true);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -190,9 +207,9 @@ describe('templates', () => {
|
|||
describe('non select one element', () => {
|
||||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(
|
||||
`<div class="${classes.list} ${classes.listItems}"></div>`,
|
||||
`<div class="${itemOptions.classNames.list} ${itemOptions.classNames.listItems}"></div>`,
|
||||
);
|
||||
const actualOutput = templates.itemList(classes, false);
|
||||
const actualOutput = templates.itemList(itemOptions, false);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -201,33 +218,33 @@ describe('templates', () => {
|
|||
|
||||
describe('placeholder', () => {
|
||||
it('returns expected html', () => {
|
||||
const classes = {
|
||||
const placeholderOptions = createOptionsWithPartialClasses({
|
||||
placeholder: 'class-1',
|
||||
};
|
||||
});
|
||||
const value = 'test';
|
||||
const expectedOutput = strToEl(`
|
||||
<div class="${classes.placeholder}">${value}</div>`);
|
||||
const actualOutput = templates.placeholder(classes, value);
|
||||
<div class="${placeholderOptions.classNames.placeholder}">${value}</div>`);
|
||||
const actualOutput = templates.placeholder(placeholderOptions, value);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
describe('choiceList', () => {
|
||||
const classes = {
|
||||
const choiceListOptions = createOptionsWithPartialClasses({
|
||||
list: 'class-1',
|
||||
};
|
||||
});
|
||||
|
||||
describe('select one element', () => {
|
||||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.list}"
|
||||
class="${choiceListOptions.classNames.list}"
|
||||
role="listbox"
|
||||
>
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choiceList(classes, true);
|
||||
const actualOutput = templates.choiceList(choiceListOptions, true);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -237,13 +254,13 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.list}"
|
||||
class="${choiceListOptions.classNames.list}"
|
||||
role="listbox"
|
||||
aria-multiselectable="true"
|
||||
>
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choiceList(classes, false);
|
||||
const actualOutput = templates.choiceList(choiceListOptions, false);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -251,11 +268,11 @@ describe('templates', () => {
|
|||
});
|
||||
|
||||
describe('choiceGroup', () => {
|
||||
const classes = {
|
||||
const groupOptions = createOptionsWithPartialClasses({
|
||||
group: 'class-1',
|
||||
groupHeading: 'class-2',
|
||||
itemDisabled: 'class-3',
|
||||
};
|
||||
});
|
||||
|
||||
let data;
|
||||
|
||||
|
@ -271,16 +288,16 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.group}"
|
||||
class="${groupOptions.classNames.group}"
|
||||
data-group
|
||||
data-id="${data.id}"
|
||||
data-value="${data.value}"
|
||||
role="group"
|
||||
>
|
||||
<div class="${classes.groupHeading}">${data.value}</div>
|
||||
<div class="${groupOptions.classNames.groupHeading}">${data.value}</div>
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choiceGroup(classes, data);
|
||||
const actualOutput = templates.choiceGroup(groupOptions, data);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -297,17 +314,17 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.group} ${classes.itemDisabled}"
|
||||
class="${groupOptions.classNames.group} ${groupOptions.classNames.itemDisabled}"
|
||||
data-group
|
||||
data-id="${data.id}"
|
||||
data-value="${data.value}"
|
||||
role="group"
|
||||
aria-disabled="true"
|
||||
>
|
||||
<div class="${classes.groupHeading}">${data.value}</div>
|
||||
<div class="${groupOptions.classNames.groupHeading}">${data.value}</div>
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choiceGroup(classes, data);
|
||||
const actualOutput = templates.choiceGroup(groupOptions, data);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -315,14 +332,14 @@ describe('templates', () => {
|
|||
});
|
||||
|
||||
describe('choice', () => {
|
||||
const classes = {
|
||||
const choiceOptions = createOptionsWithPartialClasses({
|
||||
item: 'class-1',
|
||||
itemChoice: 'class-2',
|
||||
itemDisabled: 'class-3',
|
||||
itemSelectable: 'class-4',
|
||||
placeholder: 'class-5',
|
||||
selectedState: 'class-6',
|
||||
};
|
||||
});
|
||||
|
||||
const itemSelectText = 'test 6';
|
||||
|
||||
|
@ -344,7 +361,7 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable}"
|
||||
class="${choiceOptions.classNames.item} ${choiceOptions.classNames.itemChoice} ${choiceOptions.classNames.itemSelectable}"
|
||||
data-select-text="${itemSelectText}"
|
||||
data-choice
|
||||
data-id="${data.id}"
|
||||
|
@ -356,7 +373,11 @@ describe('templates', () => {
|
|||
${data.label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choice(classes, data, itemSelectText);
|
||||
const actualOutput = templates.choice(
|
||||
choiceOptions,
|
||||
data,
|
||||
itemSelectText,
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -373,7 +394,7 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.item} ${classes.itemChoice} ${classes.itemDisabled}"
|
||||
class="${choiceOptions.classNames.item} ${choiceOptions.classNames.itemChoice} ${choiceOptions.classNames.itemDisabled}"
|
||||
data-select-text="${itemSelectText}"
|
||||
data-choice
|
||||
data-id="${data.id}"
|
||||
|
@ -386,7 +407,11 @@ describe('templates', () => {
|
|||
${data.label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choice(classes, data, itemSelectText);
|
||||
const actualOutput = templates.choice(
|
||||
choiceOptions,
|
||||
data,
|
||||
itemSelectText,
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -403,7 +428,7 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.item} ${classes.itemChoice} ${classes.selectedState} ${classes.itemSelectable}"
|
||||
class="${choiceOptions.classNames.item} ${choiceOptions.classNames.itemChoice} ${choiceOptions.classNames.selectedState} ${choiceOptions.classNames.itemSelectable}"
|
||||
data-select-text="${itemSelectText}"
|
||||
data-choice
|
||||
data-id="${data.id}"
|
||||
|
@ -415,7 +440,11 @@ describe('templates', () => {
|
|||
${data.label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choice(classes, data, itemSelectText);
|
||||
const actualOutput = templates.choice(
|
||||
choiceOptions,
|
||||
data,
|
||||
itemSelectText,
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -432,7 +461,7 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.item} ${classes.itemChoice} ${classes.placeholder} ${classes.itemSelectable}"
|
||||
class="${choiceOptions.classNames.item} ${choiceOptions.classNames.itemChoice} ${choiceOptions.classNames.placeholder} ${choiceOptions.classNames.itemSelectable}"
|
||||
data-select-text="${itemSelectText}"
|
||||
data-choice
|
||||
data-id="${data.id}"
|
||||
|
@ -444,7 +473,11 @@ describe('templates', () => {
|
|||
${data.label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choice(classes, data, itemSelectText);
|
||||
const actualOutput = templates.choice(
|
||||
choiceOptions,
|
||||
data,
|
||||
itemSelectText,
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -461,7 +494,7 @@ describe('templates', () => {
|
|||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div
|
||||
class="${classes.item} ${classes.itemChoice} ${classes.itemSelectable}"
|
||||
class="${choiceOptions.classNames.item} ${choiceOptions.classNames.itemChoice} ${choiceOptions.classNames.itemSelectable}"
|
||||
data-select-text="${itemSelectText}"
|
||||
data-choice
|
||||
data-id="${data.id}"
|
||||
|
@ -473,7 +506,11 @@ describe('templates', () => {
|
|||
${data.label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.choice(classes, data, itemSelectText);
|
||||
const actualOutput = templates.choice(
|
||||
choiceOptions,
|
||||
data,
|
||||
itemSelectText,
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -481,10 +518,10 @@ describe('templates', () => {
|
|||
});
|
||||
|
||||
describe('input', () => {
|
||||
const classes = {
|
||||
const inputOptions = createOptionsWithPartialClasses({
|
||||
input: 'class-1',
|
||||
inputCloned: 'class-2',
|
||||
};
|
||||
});
|
||||
|
||||
it('returns expected html', () => {
|
||||
/*
|
||||
|
@ -496,52 +533,52 @@ describe('templates', () => {
|
|||
<input
|
||||
type="search"
|
||||
name="search_terms"
|
||||
class="${classes.input} ${classes.inputCloned}"
|
||||
class="${inputOptions.classNames.input} ${inputOptions.classNames.inputCloned}"
|
||||
autocomplete="off"
|
||||
role="textbox"
|
||||
aria-autocomplete="list"
|
||||
aria-label="test placeholder"
|
||||
>
|
||||
`);
|
||||
const actualOutput = templates.input(classes, 'test placeholder');
|
||||
const actualOutput = templates.input(inputOptions, 'test placeholder');
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dropdown', () => {
|
||||
const classes = {
|
||||
const dropdownOptions = createOptionsWithPartialClasses({
|
||||
list: 'class-1',
|
||||
listDropdown: 'class-2',
|
||||
};
|
||||
});
|
||||
|
||||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(
|
||||
`<div class="${classes.list} ${classes.listDropdown}" aria-expanded="false"></div>`,
|
||||
`<div class="${dropdownOptions.classNames.list} ${dropdownOptions.classNames.listDropdown}" aria-expanded="false"></div>`,
|
||||
);
|
||||
const actualOutput = templates.dropdown(classes);
|
||||
const actualOutput = templates.dropdown(dropdownOptions);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notice', () => {
|
||||
const classes = {
|
||||
const noticeOptions = createOptionsWithPartialClasses({
|
||||
item: 'class-1',
|
||||
itemChoice: 'class-2',
|
||||
noResults: 'class-3',
|
||||
noChoices: 'class-4',
|
||||
};
|
||||
});
|
||||
|
||||
const label = 'test';
|
||||
|
||||
it('returns expected html', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div class="${classes.item} ${classes.itemChoice}">
|
||||
<div class="${noticeOptions.classNames.item} ${noticeOptions.classNames.itemChoice}">
|
||||
${label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.notice(classes, label);
|
||||
const actualOutput = templates.notice(noticeOptions, label);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -550,11 +587,15 @@ describe('templates', () => {
|
|||
describe('no results', () => {
|
||||
it('adds no results classname', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div class="${classes.item} ${classes.itemChoice} ${classes.noResults}">
|
||||
<div class="${noticeOptions.classNames.item} ${noticeOptions.classNames.itemChoice} ${noticeOptions.classNames.noResults}">
|
||||
${label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.notice(classes, label, 'no-results');
|
||||
const actualOutput = templates.notice(
|
||||
noticeOptions,
|
||||
label,
|
||||
'no-results',
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
@ -563,11 +604,15 @@ describe('templates', () => {
|
|||
describe('no choices', () => {
|
||||
it('adds no choices classname', () => {
|
||||
const expectedOutput = strToEl(`
|
||||
<div class="${classes.item} ${classes.itemChoice} ${classes.noChoices}">
|
||||
<div class="${noticeOptions.classNames.item} ${noticeOptions.classNames.itemChoice} ${noticeOptions.classNames.noChoices}">
|
||||
${label}
|
||||
</div>
|
||||
`);
|
||||
const actualOutput = templates.notice(classes, label, 'no-choices');
|
||||
const actualOutput = templates.notice(
|
||||
noticeOptions,
|
||||
label,
|
||||
'no-choices',
|
||||
);
|
||||
|
||||
expectEqualElements(actualOutput, expectedOutput);
|
||||
});
|
||||
|
|
|
@ -4,14 +4,16 @@
|
|||
*/
|
||||
|
||||
import { Choice } from './interfaces/choice';
|
||||
import { ClassNames } from './interfaces/class-names';
|
||||
import { Group } from './interfaces/group';
|
||||
import { Item } from './interfaces/item';
|
||||
import { PassedElementType } from './interfaces/passed-element-type';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type TemplateOptions = Record<'classNames' | 'allowHTML', any>;
|
||||
|
||||
const templates = {
|
||||
containerOuter(
|
||||
{ containerOuter }: Pick<ClassNames, 'containerOuter'>,
|
||||
{ classNames: { containerOuter } }: TemplateOptions,
|
||||
dir: HTMLElement['dir'],
|
||||
isSelectElement: boolean,
|
||||
isSelectOneElement: boolean,
|
||||
|
@ -46,19 +48,15 @@ const templates = {
|
|||
},
|
||||
|
||||
containerInner({
|
||||
containerInner,
|
||||
}: Pick<ClassNames, 'containerInner'>): HTMLDivElement {
|
||||
classNames: { containerInner },
|
||||
}: TemplateOptions): HTMLDivElement {
|
||||
return Object.assign(document.createElement('div'), {
|
||||
className: containerInner,
|
||||
});
|
||||
},
|
||||
|
||||
itemList(
|
||||
{
|
||||
list,
|
||||
listSingle,
|
||||
listItems,
|
||||
}: Pick<ClassNames, 'list' | 'listSingle' | 'listItems'>,
|
||||
{ classNames: { list, listSingle, listItems } }: TemplateOptions,
|
||||
isSelectOneElement: boolean,
|
||||
): HTMLDivElement {
|
||||
return Object.assign(document.createElement('div'), {
|
||||
|
@ -67,26 +65,26 @@ const templates = {
|
|||
},
|
||||
|
||||
placeholder(
|
||||
{ placeholder }: Pick<ClassNames, 'placeholder'>,
|
||||
{ allowHTML, classNames: { placeholder } }: TemplateOptions,
|
||||
value: string,
|
||||
): HTMLDivElement {
|
||||
return Object.assign(document.createElement('div'), {
|
||||
className: placeholder,
|
||||
innerHTML: value,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: value,
|
||||
});
|
||||
},
|
||||
|
||||
item(
|
||||
{
|
||||
allowHTML,
|
||||
classNames: {
|
||||
item,
|
||||
button,
|
||||
highlightedState,
|
||||
itemSelectable,
|
||||
placeholder,
|
||||
}: Pick<
|
||||
ClassNames,
|
||||
'item' | 'button' | 'highlightedState' | 'itemSelectable' | 'placeholder'
|
||||
>,
|
||||
},
|
||||
}: TemplateOptions,
|
||||
{
|
||||
id,
|
||||
value,
|
||||
|
@ -101,7 +99,7 @@ const templates = {
|
|||
): HTMLDivElement {
|
||||
const div = Object.assign(document.createElement('div'), {
|
||||
className: item,
|
||||
innerHTML: label,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: label,
|
||||
});
|
||||
|
||||
Object.assign(div.dataset, {
|
||||
|
@ -135,7 +133,7 @@ const templates = {
|
|||
const removeButton = Object.assign(document.createElement('button'), {
|
||||
type: 'button',
|
||||
className: button,
|
||||
innerHTML: REMOVE_ITEM_TEXT,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: REMOVE_ITEM_TEXT,
|
||||
});
|
||||
removeButton.setAttribute(
|
||||
'aria-label',
|
||||
|
@ -149,7 +147,7 @@ const templates = {
|
|||
},
|
||||
|
||||
choiceList(
|
||||
{ list }: Pick<ClassNames, 'list'>,
|
||||
{ classNames: { list } }: TemplateOptions,
|
||||
isSelectOneElement: boolean,
|
||||
): HTMLDivElement {
|
||||
const div = Object.assign(document.createElement('div'), {
|
||||
|
@ -166,10 +164,9 @@ const templates = {
|
|||
|
||||
choiceGroup(
|
||||
{
|
||||
group,
|
||||
groupHeading,
|
||||
itemDisabled,
|
||||
}: Pick<ClassNames, 'group' | 'groupHeading' | 'itemDisabled'>,
|
||||
allowHTML,
|
||||
classNames: { group, groupHeading, itemDisabled },
|
||||
}: TemplateOptions,
|
||||
{ id, value, disabled }: Group,
|
||||
): HTMLDivElement {
|
||||
const div = Object.assign(document.createElement('div'), {
|
||||
|
@ -191,7 +188,7 @@ const templates = {
|
|||
div.appendChild(
|
||||
Object.assign(document.createElement('div'), {
|
||||
className: groupHeading,
|
||||
innerHTML: value,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: value,
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -200,21 +197,16 @@ const templates = {
|
|||
|
||||
choice(
|
||||
{
|
||||
allowHTML,
|
||||
classNames: {
|
||||
item,
|
||||
itemChoice,
|
||||
itemSelectable,
|
||||
selectedState,
|
||||
itemDisabled,
|
||||
placeholder,
|
||||
}: Pick<
|
||||
ClassNames,
|
||||
| 'item'
|
||||
| 'itemChoice'
|
||||
| 'itemSelectable'
|
||||
| 'selectedState'
|
||||
| 'itemDisabled'
|
||||
| 'placeholder'
|
||||
>,
|
||||
},
|
||||
}: TemplateOptions,
|
||||
{
|
||||
id,
|
||||
value,
|
||||
|
@ -229,7 +221,7 @@ const templates = {
|
|||
): HTMLDivElement {
|
||||
const div = Object.assign(document.createElement('div'), {
|
||||
id: elementId,
|
||||
innerHTML: label,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: label,
|
||||
className: `${item} ${itemChoice}`,
|
||||
});
|
||||
|
||||
|
@ -263,7 +255,7 @@ const templates = {
|
|||
},
|
||||
|
||||
input(
|
||||
{ input, inputCloned }: Pick<ClassNames, 'input' | 'inputCloned'>,
|
||||
{ classNames: { input, inputCloned } }: TemplateOptions,
|
||||
placeholderValue: string,
|
||||
): HTMLInputElement {
|
||||
const inp = Object.assign(document.createElement('input'), {
|
||||
|
@ -283,9 +275,8 @@ const templates = {
|
|||
},
|
||||
|
||||
dropdown({
|
||||
list,
|
||||
listDropdown,
|
||||
}: Pick<ClassNames, 'list' | 'listDropdown'>): HTMLDivElement {
|
||||
classNames: { list, listDropdown },
|
||||
}: TemplateOptions): HTMLDivElement {
|
||||
const div = document.createElement('div');
|
||||
|
||||
div.classList.add(list, listDropdown);
|
||||
|
@ -296,12 +287,10 @@ const templates = {
|
|||
|
||||
notice(
|
||||
{
|
||||
item,
|
||||
itemChoice,
|
||||
noResults,
|
||||
noChoices,
|
||||
}: Pick<ClassNames, 'item' | 'itemChoice' | 'noResults' | 'noChoices'>,
|
||||
innerHTML: string,
|
||||
allowHTML,
|
||||
classNames: { item, itemChoice, noResults, noChoices },
|
||||
}: TemplateOptions,
|
||||
innerText: string,
|
||||
type: 'no-choices' | 'no-results' | '' = '',
|
||||
): HTMLDivElement {
|
||||
const classes = [item, itemChoice];
|
||||
|
@ -313,7 +302,7 @@ const templates = {
|
|||
}
|
||||
|
||||
return Object.assign(document.createElement('div'), {
|
||||
innerHTML,
|
||||
[allowHTML ? 'innerHTML' : 'innerText']: innerText,
|
||||
className: classes.join(' '),
|
||||
});
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue