- commit
- 44219e6162dbed1af2234f1e2b32cfd5f5e9f661
- parent
- 06ea884731603764305af8bcb73ba32bf057bfc2
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2022-06-17 11:47
add tags.js
Diffstat
| M | demo/index.html | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tags.js | 116 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 184 insertions, 0 deletions
diff --git a/demo/index.html b/demo/index.html
@@ -271,6 +271,74 @@ 271 271 </optgroup> 272 272 </datalist> 273 273 -1 274 <h2>Tags</h2> -1 275 -1 276 <p>The separate file <code>tags.js</code> provides a matching component that allows to enter arbitrary text instead of only the provided options. It combines multi-select with native auto-complete.</p> -1 277 -1 278 <select multiple data-tags> -1 279 <optgroup label="Alaskan/Hawaiian Time Zone"> -1 280 <option value="AK">Alaska</option> -1 281 <option value="HI">Hawaii</option> -1 282 </optgroup> -1 283 <optgroup label="Pacific Time Zone"> -1 284 <option value="CA">California</option> -1 285 <option value="NV">Nevada</option> -1 286 <option value="OR">Oregon</option> -1 287 <option value="WA">Washington</option> -1 288 </optgroup> -1 289 <optgroup label="Mountain Time Zone"> -1 290 <option value="AZ">Arizona</option> -1 291 <option value="CO">Colorado</option> -1 292 <option value="ID">Idaho</option> -1 293 <option value="MT">Montana</option> -1 294 <option value="NE">Nebraska</option> -1 295 <option value="NM">New Mexico</option> -1 296 <option value="ND">North Dakota</option> -1 297 <option value="UT">Utah</option> -1 298 <option value="WY">Wyoming</option> -1 299 </optgroup> -1 300 <optgroup label="Central Time Zone"> -1 301 <option value="AL">Alabama</option> -1 302 <option value="AR">Arkansas</option> -1 303 <option value="IL">Illinois</option> -1 304 <option value="IA">Iowa</option> -1 305 <option value="KS">Kansas</option> -1 306 <option value="KY">Kentucky</option> -1 307 <option value="LA">Louisiana</option> -1 308 <option value="MN">Minnesota</option> -1 309 <option value="MS">Mississippi</option> -1 310 <option value="MO">Missouri</option> -1 311 <option value="OK">Oklahoma</option> -1 312 <option value="SD">South Dakota</option> -1 313 <option value="TX">Texas</option> -1 314 <option value="TN">Tennessee</option> -1 315 <option value="WI">Wisconsin</option> -1 316 </optgroup> -1 317 <optgroup label="Eastern Time Zone"> -1 318 <option value="CT">Connecticut</option> -1 319 <option value="DE">Delaware</option> -1 320 <option value="FL">Florida</option> -1 321 <option value="GA">Georgia</option> -1 322 <option value="IN">Indiana</option> -1 323 <option value="ME">Maine</option> -1 324 <option value="MD">Maryland</option> -1 325 <option value="MA">Massachusetts</option> -1 326 <option value="MI">Michigan</option> -1 327 <option value="NH">New Hampshire</option> -1 328 <option value="NJ">New Jersey</option> -1 329 <option value="NY">New York</option> -1 330 <option value="NC">North Carolina</option> -1 331 <option value="OH">Ohio</option> -1 332 <option value="PA">Pennsylvania</option> -1 333 <option value="RI">Rhode Island</option> -1 334 <option value="SC">South Carolina</option> -1 335 <option value="VT">Vermont</option> -1 336 <option value="VA">Virginia</option> -1 337 <option value="WV">West Virginia</option> -1 338 </optgroup> -1 339 </select> -1 340 274 341 <script src="../select.js" type="module"></script> -1 342 <script src="../tags.js" type="module"></script> 275 343 </body> 276 344 </html>
diff --git a/tags.js b/tags.js
@@ -0,0 +1,116 @@
-1 1 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-1 2
-1 3 var KEYS = {
-1 4 BACKSPACE: 8,
-1 5 ENTER: 13,
-1 6 };
-1 7
-1 8 var randomString = function(length) {
-1 9 var result = [];
-1 10 for (var i = 0; i < length; i++) {
-1 11 var k = Math.floor(Math.random() * chars.length);
-1 12 result.push(chars[k]);
-1 13 }
-1 14 return result.join('');
-1 15 };
-1 16
-1 17 export class TagInput {
-1 18 constructor(id, original) {
-1 19 this.id = id;
-1 20 this.original = original;
-1 21
-1 22 this.createElements();
-1 23 original.hidden = true;
-1 24 original.before(this.wrapper);
-1 25 }
-1 26
-1 27 createElements() {
-1 28 this.wrapper = document.createElement('div');
-1 29
-1 30 this.values = document.createElement('ul');
-1 31 this.values.className = 'select__values';
-1 32 this.values.setAttribute('aria-live', 'polite');
-1 33 this.wrapper.append(this.values);
-1 34
-1 35 this.input = document.createElement('input');
-1 36 this.input.className = 'form-control';
-1 37 this.wrapper.append(this.input);
-1 38
-1 39 this.datalist = document.createElement('datalist');
-1 40 this.datalist.innerHTML = this.original.innerHTML;
-1 41 this.datalist.id = this.id + '-list';
-1 42 this.input.setAttribute('list', this.datalist.id);
-1 43 this.wrapper.append(this.datalist);
-1 44
-1 45 this.input.disabled = this.original.disabled;
-1 46
-1 47 this.input.onkeydown = this.onkeydown.bind(this);
-1 48 this.input.onchange = this.onchange.bind(this);
-1 49
-1 50 this.updateValue();
-1 51 }
-1 52
-1 53 setValue(value) {
-1 54 var option = Array.from(this.original.options).find(op => op.value === value);
-1 55 if (!option) {
-1 56 option = document.createElement('option');
-1 57 option.setAttribute('data-tag-custom', '');
-1 58 option.value = value;
-1 59 option.label = value;
-1 60 this.original.append(option);
-1 61 }
-1 62 option.selected = true;
-1 63 this.original.dispatchEvent(new Event('change'));
-1 64 this.updateValue();
-1 65 }
-1 66
-1 67 onkeydown(event) {
-1 68 if (event.keyCode === KEYS.BACKSPACE) {
-1 69 if (!this.input.value) {
-1 70 event.preventDefault();
-1 71 var n = this.original.selectedOptions.length;
-1 72 if (n) {
-1 73 var op = this.original.selectedOptions[n - 1];
-1 74 op.selected = false;
-1 75 this.updateValue();
-1 76 this.input.value = op.value;
-1 77 }
-1 78 }
-1 79 } else if (event.keyCode === KEYS.ENTER) {
-1 80 if (this.input.value) {
-1 81 this.onchange(event);
-1 82 }
-1 83 }
-1 84 }
-1 85
-1 86 onchange(event) {
-1 87 if (this.input.value) {
-1 88 event.preventDefault();
-1 89 this.setValue(this.input.value);
-1 90 }
-1 91 }
-1 92
-1 93 updateValue() {
-1 94 this.input.value = '';
-1 95 this.values.innerHTML = '';
-1 96 Array.from(this.original.options).forEach((op, i) => {
-1 97 if (op.selected) {
-1 98 var li = document.createElement('li');
-1 99 li.textContent = op.label;
-1 100 li.className = 'badge bg-secondary me-1';
-1 101 li.onclick = () => {
-1 102 op.selected = false;
-1 103 li.remove();
-1 104 this.input.focus();
-1 105 };
-1 106 this.values.append(li);
-1 107 } else if (op.hasAttribute('data-tag-custom')) {
-1 108 op.remove();
-1 109 }
-1 110 });
-1 111 }
-1 112 }
-1 113
-1 114 Array.from(document.querySelectorAll('[data-tags]')).forEach(el => {
-1 115 new TagInput(randomString(), el);
-1 116 });