Add support for standard-compliant placeholder option (#617)

* Add support for standard-compliant placeholder option

* Bump version and rebuild files
This commit is contained in:
Christophe Coevoet 2019-10-22 12:25:36 +02:00 committed by Josh Johnson
parent 4de6e677d1
commit 8782564ddf
11 changed files with 323 additions and 291 deletions

View file

@ -400,13 +400,15 @@ const example = new Choices(element, {
```html
<select>
<option placeholder>This is a placeholder</option>
<option value="">This is a placeholder</option>
<option>...</option>
<option>...</option>
<option>...</option>
</select>
```
For backward compatibility, `<option placeholder>This is a placeholder</option>` is also supported.
### placeholderValue
**Type:** `String` **Default:** `null`

View file

@ -1,6 +1,6 @@
{
"name": "choices.js",
"version": "7.0.6",
"version": "7.1.0",
"description": "A vanilla JS customisable text input/select box plugin",
"main": "./public/assets/scripts/choices.min.js",
"types": "./types/index.d.ts",

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -78,8 +78,7 @@ a:focus {
border-radius: 2.5px;
font-size: 14px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
appearance: none;
margin-bottom: 24px;
}

View file

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

View file

@ -19,7 +19,9 @@
.choices.is-disabled .choices__input {
background-color: #EAEAEA;
cursor: not-allowed;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.choices.is-disabled .choices__item {
@ -302,7 +304,9 @@
.choices__item--disabled {
cursor: not-allowed;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: .5;
}

File diff suppressed because one or more lines are too long

View file

@ -157,7 +157,7 @@
<h2>Single select input</h2>
<label for="choices-single-default">Default</label>
<select class="form-control" data-trigger name="choices-single-default" id="choices-single-default" placeholder="This is a search placeholder">
<option placeholder>This is a placeholder</option>
<option value="">This is a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
@ -167,12 +167,12 @@
<label for="choices-single-remote-fetch">Options from remote source (Fetch API)</label>
<select class="form-control" name="choices-single-remote-fetch" id="choices-single-remote-fetch">
<option placeholder>Pick an Arctic Monkeys' record</option>
<option value="">Pick an Arctic Monkeys' record</option>
</select>
<label for="choices-single-remove-xhr">Options from remote source (XHR) &amp; remove button</label>
<select class="form-control" name="choices-single-remove-xhr" id="choices-single-remove-xhr">
<option placeholder>Pick a Smiths' record</option>
<option value="">Pick a Smiths' record</option>
</select>
<label for="choices-single-groups">Option groups</label>

View file

@ -7,7 +7,11 @@ export default class WrappedSelect extends WrappedElement {
}
get placeholderOption() {
return this.element.querySelector('option[placeholder]');
return (
this.element.querySelector('option[value=""]') ||
// Backward compatibility layer for the non-standard placeholder attribute supported in older versions.
this.element.querySelector('option[placeholder]')
);
}
get optionGroups() {

View file

@ -12,11 +12,16 @@ describe('components/wrappedSelect', () => {
beforeEach(() => {
element = document.createElement('select');
element.id = 'target';
for (let i = 1; i <= 4; i++) {
for (let i = 0; i <= 4; i++) {
const option = document.createElement('option');
option.value = `Value ${i}`;
option.innerHTML = `Label ${i}`;
if (i === 0) {
option.value = '';
option.innerHTML = 'Placeholder label';
} else {
option.value = `Value ${i}`;
option.innerHTML = `Label ${i}`;
}
if (i === 1) {
option.setAttribute('placeholder', '');
@ -69,8 +74,16 @@ describe('components/wrappedSelect', () => {
});
describe('placeholderOption getter', () => {
it('returns option element with placeholder attribute', () => {
it('returns option element with empty value attribute', () => {
expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);
expect(instance.placeholderOption.value).to.equal('');
});
it('returns option element with placeholder attribute as fallback', () => {
instance.element.removeChild(instance.element.firstChild);
expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);
expect(instance.placeholderOption.value).to.equal('Value 1');
});
});
@ -145,7 +158,7 @@ describe('components/wrappedSelect', () => {
describe('appendDocFragment', () => {
it('empties contents of element', () => {
expect(instance.element.getElementsByTagName('option').length).to.equal(
4,
5,
);
instance.appendDocFragment(document.createDocumentFragment());
expect(instance.element.getElementsByTagName('option').length).to.equal(