Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Introduce allowHTML option to allow people to disable injecting HTML into choices. #984

Merged
merged 9 commits into from
Dec 26, 2021
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Or include Choices directly:
removeItems: true,
removeItemButton: false,
editItems: false,
allowHTML: true
duplicateItemsAllowed: true,
delimiter: ',',
paste: true,
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
79 changes: 78 additions & 1 deletion cypress/integration/select-multiple.spec.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand Down Expand Up @@ -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>');
});
});
});
});
});
});
Loading