Browse code

Add tom select npm package

Benjamin Roth authored on02/02/2023 12:00:30
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,4680 @@
1
+/**
2
+* Tom Select v2.2.2
3
+* Licensed under the Apache License, Version 2.0 (the "License");
4
+*/
5
+
6
+'use strict';
7
+
8
+/**
9
+ * MicroEvent - to make any js object an event emitter
10
+ *
11
+ * - pure javascript - server compatible, browser compatible
12
+ * - dont rely on the browser doms
13
+ * - super simple - you get it immediatly, no mistery, no magic involved
14
+ *
15
+ * @author Jerome Etienne (https://github.com/jeromeetienne)
16
+ */
17
+
18
+/**
19
+ * Execute callback for each event in space separated list of event names
20
+ *
21
+ */
22
+function forEvents(events, callback) {
23
+  events.split(/\s+/).forEach(event => {
24
+    callback(event);
25
+  });
26
+}
27
+
28
+class MicroEvent {
29
+  constructor() {
30
+    this._events = void 0;
31
+    this._events = {};
32
+  }
33
+
34
+  on(events, fct) {
35
+    forEvents(events, event => {
36
+      const event_array = this._events[event] || [];
37
+      event_array.push(fct);
38
+      this._events[event] = event_array;
39
+    });
40
+  }
41
+
42
+  off(events, fct) {
43
+    var n = arguments.length;
44
+
45
+    if (n === 0) {
46
+      this._events = {};
47
+      return;
48
+    }
49
+
50
+    forEvents(events, event => {
51
+      if (n === 1) {
52
+        delete this._events[event];
53
+        return;
54
+      }
55
+
56
+      const event_array = this._events[event];
57
+      if (event_array === undefined) return;
58
+      event_array.splice(event_array.indexOf(fct), 1);
59
+      this._events[event] = event_array;
60
+    });
61
+  }
62
+
63
+  trigger(events, ...args) {
64
+    var self = this;
65
+    forEvents(events, event => {
66
+      const event_array = self._events[event];
67
+      if (event_array === undefined) return;
68
+      event_array.forEach(fct => {
69
+        fct.apply(self, args);
70
+      });
71
+    });
72
+  }
73
+
74
+}
75
+
76
+/**
77
+ * microplugin.js
78
+ * Copyright (c) 2013 Brian Reavis & contributors
79
+ *
80
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
81
+ * file except in compliance with the License. You may obtain a copy of the License at:
82
+ * http://www.apache.org/licenses/LICENSE-2.0
83
+ *
84
+ * Unless required by applicable law or agreed to in writing, software distributed under
85
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
86
+ * ANY KIND, either express or implied. See the License for the specific language
87
+ * governing permissions and limitations under the License.
88
+ *
89
+ * @author Brian Reavis <brian@thirdroute.com>
90
+ */
91
+function MicroPlugin(Interface) {
92
+  Interface.plugins = {};
93
+  return class extends Interface {
94
+    constructor(...args) {
95
+      super(...args);
96
+      this.plugins = {
97
+        names: [],
98
+        settings: {},
99
+        requested: {},
100
+        loaded: {}
101
+      };
102
+    }
103
+
104
+    /**
105
+     * Registers a plugin.
106
+     *
107
+     * @param {function} fn
108
+     */
109
+    static define(name, fn) {
110
+      Interface.plugins[name] = {
111
+        'name': name,
112
+        'fn': fn
113
+      };
114
+    }
115
+    /**
116
+     * Initializes the listed plugins (with options).
117
+     * Acceptable formats:
118
+     *
119
+     * List (without options):
120
+     *   ['a', 'b', 'c']
121
+     *
122
+     * List (with options):
123
+     *   [{'name': 'a', options: {}}, {'name': 'b', options: {}}]
124
+     *
125
+     * Hash (with options):
126
+     *   {'a': { ... }, 'b': { ... }, 'c': { ... }}
127
+     *
128
+     * @param {array|object} plugins
129
+     */
130
+
131
+
132
+    initializePlugins(plugins) {
133
+      var key, name;
134
+      const self = this;
135
+      const queue = [];
136
+
137
+      if (Array.isArray(plugins)) {
138
+        plugins.forEach(plugin => {
139
+          if (typeof plugin === 'string') {
140
+            queue.push(plugin);
141
+          } else {
142
+            self.plugins.settings[plugin.name] = plugin.options;
143
+            queue.push(plugin.name);
144
+          }
145
+        });
146
+      } else if (plugins) {
147
+        for (key in plugins) {
148
+          if (plugins.hasOwnProperty(key)) {
149
+            self.plugins.settings[key] = plugins[key];
150
+            queue.push(key);
151
+          }
152
+        }
153
+      }
154
+
155
+      while (name = queue.shift()) {
156
+        self.require(name);
157
+      }
158
+    }
159
+
160
+    loadPlugin(name) {
161
+      var self = this;
162
+      var plugins = self.plugins;
163
+      var plugin = Interface.plugins[name];
164
+
165
+      if (!Interface.plugins.hasOwnProperty(name)) {
166
+        throw new Error('Unable to find "' + name + '" plugin');
167
+      }
168
+
169
+      plugins.requested[name] = true;
170
+      plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]);
171
+      plugins.names.push(name);
172
+    }
173
+    /**
174
+     * Initializes a plugin.
175
+     *
176
+     */
177
+
178
+
179
+    require(name) {
180
+      var self = this;
181
+      var plugins = self.plugins;
182
+
183
+      if (!self.plugins.loaded.hasOwnProperty(name)) {
184
+        if (plugins.requested[name]) {
185
+          throw new Error('Plugin has circular dependency ("' + name + '")');
186
+        }
187
+
188
+        self.loadPlugin(name);
189
+      }
190
+
191
+      return plugins.loaded[name];
192
+    }
193
+
194
+  };
195
+}
196
+
197
+/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
198
+/**
199
+ * Convert array of strings to a regular expression
200
+ *	ex ['ab','a'] => (?:ab|a)
201
+ * 	ex ['a','b'] => [ab]
202
+ * @param {string[]} chars
203
+ * @return {string}
204
+ */
205
+const arrayToPattern = chars => {
206
+  chars = chars.filter(Boolean);
207
+
208
+  if (chars.length < 2) {
209
+    return chars[0] || '';
210
+  }
211
+
212
+  return maxValueLength(chars) == 1 ? '[' + chars.join('') + ']' : '(?:' + chars.join('|') + ')';
213
+};
214
+/**
215
+ * @param {string[]} array
216
+ * @return {string}
217
+ */
218
+
219
+const sequencePattern = array => {
220
+  if (!hasDuplicates(array)) {
221
+    return array.join('');
222
+  }
223
+
224
+  let pattern = '';
225
+  let prev_char_count = 0;
226
+
227
+  const prev_pattern = () => {
228
+    if (prev_char_count > 1) {
229
+      pattern += '{' + prev_char_count + '}';
230
+    }
231
+  };
232
+
233
+  array.forEach((char, i) => {
234
+    if (char === array[i - 1]) {
235
+      prev_char_count++;
236
+      return;
237
+    }
238
+
239
+    prev_pattern();
240
+    pattern += char;
241
+    prev_char_count = 1;
242
+  });
243
+  prev_pattern();
244
+  return pattern;
245
+};
246
+/**
247
+ * Convert array of strings to a regular expression
248
+ *	ex ['ab','a'] => (?:ab|a)
249
+ * 	ex ['a','b'] => [ab]
250
+ * @param {Set<string>} chars
251
+ * @return {string}
252
+ */
253
+
254
+const setToPattern = chars => {
255
+  let array = toArray(chars);
256
+  return arrayToPattern(array);
257
+};
258
+/**
259
+ *
260
+ * https://stackoverflow.com/questions/7376598/in-javascript-how-do-i-check-if-an-array-has-duplicate-values
261
+ * @param {any[]} array
262
+ */
263
+
264
+const hasDuplicates = array => {
265
+  return new Set(array).size !== array.length;
266
+};
267
+/**
268
+ * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error
269
+ * @param {string} str
270
+ * @return {string}
271
+ */
272
+
273
+const escape_regex = str => {
274
+  return (str + '').replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu, '\\$1');
275
+};
276
+/**
277
+ * Return the max length of array values
278
+ * @param {string[]} array
279
+ *
280
+ */
281
+
282
+const maxValueLength = array => {
283
+  return array.reduce((longest, value) => Math.max(longest, unicodeLength(value)), 0);
284
+};
285
+/**
286
+ * @param {string} str
287
+ */
288
+
289
+const unicodeLength = str => {
290
+  return toArray(str).length;
291
+};
292
+/**
293
+ * @param {any} p
294
+ * @return {any[]}
295
+ */
296
+
297
+const toArray = p => Array.from(p);
298
+
299
+/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
300
+/**
301
+ * Get all possible combinations of substrings that add up to the given string
302
+ * https://stackoverflow.com/questions/30169587/find-all-the-combination-of-substrings-that-add-up-to-the-given-string
303
+ * @param {string} input
304
+ * @return {string[][]}
305
+ */
306
+const allSubstrings = input => {
307
+  if (input.length === 1) return [[input]];
308
+  /** @type {string[][]} */
309
+
310
+  let result = [];
311
+  const start = input.substring(1);
312
+  const suba = allSubstrings(start);
313
+  suba.forEach(function (subresult) {
314
+    let tmp = subresult.slice(0);
315
+    tmp[0] = input.charAt(0) + tmp[0];
316
+    result.push(tmp);
317
+    tmp = subresult.slice(0);
318
+    tmp.unshift(input.charAt(0));
319
+    result.push(tmp);
320
+  });
321
+  return result;
322
+};
323
+
324
+/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
325
+
326
+/**
327
+ * @typedef {{[key:string]:string}} TUnicodeMap
328
+ * @typedef {{[key:string]:Set<string>}} TUnicodeSets
329
+ * @typedef {[[number,number]]} TCodePoints
330
+ * @typedef {{folded:string,composed:string,code_point:number}} TCodePointObj
331
+ * @typedef {{start:number,end:number,length:number,substr:string}} TSequencePart
332
+ */
333
+/** @type {TCodePoints} */
334
+
335
+const code_points = [[0, 65535]];
336
+const accent_pat = '[\u0300-\u036F\u{b7}\u{2be}\u{2bc}]';
337
+/** @type {TUnicodeMap} */
338
+
339
+let unicode_map;
340
+/** @type {RegExp} */
341
+
342
+let multi_char_reg;
343
+const max_char_length = 3;
344
+/** @type {TUnicodeMap} */
345
+
346
+const latin_convert = {};
347
+/** @type {TUnicodeMap} */
348
+
349
+const latin_condensed = {
350
+  '/': '⁄∕',
351
+  '0': '߀',
352
+  "a": "ⱥɐɑ",
353
+  "aa": "ꜳ",
354
+  "ae": "æǽǣ",
355
+  "ao": "ꜵ",
356
+  "au": "ꜷ",
357
+  "av": "ꜹꜻ",
358
+  "ay": "ꜽ",
359
+  "b": "ƀɓƃ",
360
+  "c": "ꜿƈȼↄ",
361
+  "d": "đɗɖᴅƌꮷԁɦ",
362
+  "e": "ɛǝᴇɇ",
363
+  "f": "ꝼƒ",
364
+  "g": "ǥɠꞡᵹꝿɢ",
365
+  "h": "ħⱨⱶɥ",
366
+  "i": "ɨı",
367
+  "j": "ɉȷ",
368
+  "k": "ƙⱪꝁꝃꝅꞣ",
369
+  "l": "łƚɫⱡꝉꝇꞁɭ",
370
+  "m": "ɱɯϻ",
371
+  "n": "ꞥƞɲꞑᴎлԉ",
372
+  "o": "øǿɔɵꝋꝍᴑ",
373
+  "oe": "œ",
374
+  "oi": "ƣ",
375
+  "oo": "ꝏ",
376
+  "ou": "ȣ",
377
+  "p": "ƥᵽꝑꝓꝕρ",
378
+  "q": "ꝗꝙɋ",
379
+  "r": "ɍɽꝛꞧꞃ",
380
+  "s": "ßȿꞩꞅʂ",
381
+  "t": "ŧƭʈⱦꞇ",
382
+  "th": "þ",
383
+  "tz": "ꜩ",
384
+  "u": "ʉ",
385
+  "v": "ʋꝟʌ",
386
+  "vy": "ꝡ",
387
+  "w": "ⱳ",
388
+  "y": "ƴɏỿ",
389
+  "z": "ƶȥɀⱬꝣ",
390
+  "hv": "ƕ"
391
+};
392
+
393
+for (let latin in latin_condensed) {
394
+  let unicode = latin_condensed[latin] || '';
395
+
396
+  for (let i = 0; i < unicode.length; i++) {
397
+    let char = unicode.substring(i, i + 1);
398
+    latin_convert[char] = latin;
399
+  }
400
+}
401
+
402
+const convert_pat = new RegExp(Object.keys(latin_convert).join('|') + '|' + accent_pat, 'gu');
403
+/**
404
+ * Initialize the unicode_map from the give code point ranges
405
+ *
406
+ * @param {TCodePoints=} _code_points
407
+ */
408
+
409
+const initialize = _code_points => {
410
+  if (unicode_map !== undefined) return;
411
+  unicode_map = generateMap(_code_points || code_points);
412
+};
413
+/**
414
+ * Helper method for normalize a string
415
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
416
+ * @param {string} str
417
+ * @param {string} form
418
+ */
419
+
420
+const normalize = (str, form = 'NFKD') => str.normalize(form);
421
+/**
422
+ * Remove accents without reordering string
423
+ * calling str.normalize('NFKD') on \u{594}\u{595}\u{596} becomes \u{596}\u{594}\u{595}
424
+ * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703
425
+ * @param {string} str
426
+ * @return {string}
427
+ */
428
+
429
+const asciifold = str => {
430
+  return toArray(str).reduce(
431
+  /**
432
+   * @param {string} result
433
+   * @param {string} char
434
+   */
435
+  (result, char) => {
436
+    return result + _asciifold(char);
437
+  }, '');
438
+};
439
+/**
440
+ * @param {string} str
441
+ * @return {string}
442
+ */
443
+
444
+const _asciifold = str => {
445
+  str = normalize(str).toLowerCase().replace(convert_pat, (
446
+  /** @type {string} */
447
+  char) => {
448
+    return latin_convert[char] || '';
449
+  }); //return str;
450
+
451
+  return normalize(str, 'NFC');
452
+};
453
+/**
454
+ * Generate a list of unicode variants from the list of code points
455
+ * @param {TCodePoints} code_points
456
+ * @yield {TCodePointObj}
457
+ */
458
+
459
+function* generator(code_points) {
460
+  for (const [code_point_min, code_point_max] of code_points) {
461
+    for (let i = code_point_min; i <= code_point_max; i++) {
462
+      let composed = String.fromCharCode(i);
463
+      let folded = asciifold(composed);
464
+
465
+      if (folded == composed.toLowerCase()) {
466
+        continue;
467
+      } // skip when folded is a string longer than 3 characters long
468
+      // bc the resulting regex patterns will be long
469
+      // eg:
470
+      // folded صلى الله عليه وسلم length 18 code point 65018
471
+      // folded جل جلاله length 8 code point 65019
472
+
473
+
474
+      if (folded.length > max_char_length) {
475
+        continue;
476
+      }
477
+
478
+      if (folded.length == 0) {
479
+        continue;
480
+      }
481
+
482
+      yield {
483
+        folded: folded,
484
+        composed: composed,
485
+        code_point: i
486
+      };
487
+    }
488
+  }
489
+}
490
+/**
491
+ * Generate a unicode map from the list of code points
492
+ * @param {TCodePoints} code_points
493
+ * @return {TUnicodeSets}
494
+ */
495
+
496
+const generateSets = code_points => {
497
+  /** @type {{[key:string]:Set<string>}} */
498
+  const unicode_sets = {};
499
+  /**
500
+   * @param {string} folded
501
+   * @param {string} to_add
502
+   */
503
+
504
+  const addMatching = (folded, to_add) => {
505
+    /** @type {Set<string>} */
506
+    const folded_set = unicode_sets[folded] || new Set();
507
+    const patt = new RegExp('^' + setToPattern(folded_set) + '$', 'iu');
508
+
509
+    if (to_add.match(patt)) {
510
+      return;
511
+    }
512
+
513
+    folded_set.add(escape_regex(to_add));
514
+    unicode_sets[folded] = folded_set;
515
+  };
516
+
517
+  for (let value of generator(code_points)) {
518
+    addMatching(value.folded, value.folded);
519
+    addMatching(value.folded, value.composed);
520
+  }
521
+
522
+  return unicode_sets;
523
+};
524
+/**
525
+ * Generate a unicode map from the list of code points
526
+ * ae => (?:(?:ae|Æ|Ǽ|Ǣ)|(?:A|Ⓐ|A...)(?:E|ɛ|Ⓔ...))
527
+ *
528
+ * @param {TCodePoints} code_points
529
+ * @return {TUnicodeMap}
530
+ */
531
+
532
+const generateMap = code_points => {
533
+  /** @type {TUnicodeSets} */
534
+  const unicode_sets = generateSets(code_points);
535
+  /** @type {TUnicodeMap} */
536
+
537
+  const unicode_map = {};
538
+  /** @type {string[]} */
539
+
540
+  let multi_char = [];
541
+
542
+  for (let folded in unicode_sets) {
543
+    let set = unicode_sets[folded];
544
+
545
+    if (set) {
546
+      unicode_map[folded] = setToPattern(set);
547
+    }
548
+
549
+    if (folded.length > 1) {
550
+      multi_char.push(escape_regex(folded));
551
+    }
552
+  }
553
+
554
+  multi_char.sort((a, b) => b.length - a.length);
555
+  const multi_char_patt = arrayToPattern(multi_char);
556
+  multi_char_reg = new RegExp('^' + multi_char_patt, 'u');
557
+  return unicode_map;
558
+};
559
+/**
560
+ * Map each element of an array from it's folded value to all possible unicode matches
561
+ * @param {string[]} strings
562
+ * @param {number} min_replacement
563
+ * @return {string}
564
+ */
565
+
566
+const mapSequence = (strings, min_replacement = 1) => {
567
+  let chars_replaced = 0;
568
+  strings = strings.map(str => {
569
+    if (unicode_map[str]) {
570
+      chars_replaced += str.length;
571
+    }
572
+
573
+    return unicode_map[str] || str;
574
+  });
575
+
576
+  if (chars_replaced >= min_replacement) {
577
+    return sequencePattern(strings);
578
+  }
579
+
580
+  return '';
581
+};
582
+/**
583
+ * Convert a short string and split it into all possible patterns
584
+ * Keep a pattern only if min_replacement is met
585
+ *
586
+ * 'abc'
587
+ * 		=> [['abc'],['ab','c'],['a','bc'],['a','b','c']]
588
+ *		=> ['abc-pattern','ab-c-pattern'...]
589
+ *
590
+ *
591
+ * @param {string} str
592
+ * @param {number} min_replacement
593
+ * @return {string}
594
+ */
595
+
596
+const substringsToPattern = (str, min_replacement = 1) => {
597
+  min_replacement = Math.max(min_replacement, str.length - 1);
598
+  return arrayToPattern(allSubstrings(str).map(sub_pat => {
599
+    return mapSequence(sub_pat, min_replacement);
600
+  }));
601
+};
602
+/**
603
+ * Convert an array of sequences into a pattern
604
+ * [{start:0,end:3,length:3,substr:'iii'}...] => (?:iii...)
605
+ *
606
+ * @param {Sequence[]} sequences
607
+ * @param {boolean} all
608
+ */
609
+
610
+const sequencesToPattern = (sequences, all = true) => {
611
+  let min_replacement = sequences.length > 1 ? 1 : 0;
612
+  return arrayToPattern(sequences.map(sequence => {
613
+    let seq = [];
614
+    const len = all ? sequence.length() : sequence.length() - 1;
615
+
616
+    for (let j = 0; j < len; j++) {
617
+      seq.push(substringsToPattern(sequence.substrs[j] || '', min_replacement));
618
+    }
619
+
620
+    return sequencePattern(seq);
621
+  }));
622
+};
623
+/**
624
+ * Return true if the sequence is already in the sequences
625
+ * @param {Sequence} needle_seq
626
+ * @param {Sequence[]} sequences
627
+ */
628
+
629
+
630
+const inSequences = (needle_seq, sequences) => {
631
+  for (const seq of sequences) {
632
+    if (seq.start != needle_seq.start || seq.end != needle_seq.end) {
633
+      continue;
634
+    }
635
+
636
+    if (seq.substrs.join('') !== needle_seq.substrs.join('')) {
637
+      continue;
638
+    }
639
+
640
+    let needle_parts = needle_seq.parts;
641
+    /**
642
+     * @param {TSequencePart} part
643
+     */
644
+
645
+    const filter = part => {
646
+      for (const needle_part of needle_parts) {
647
+        if (needle_part.start === part.start && needle_part.substr === part.substr) {
648
+          return false;
649
+        }
650
+
651
+        if (part.length == 1 || needle_part.length == 1) {
652
+          continue;
653
+        } // check for overlapping parts
654
+        // a = ['::=','==']
655
+        // b = ['::','===']
656
+        // a = ['r','sm']
657
+        // b = ['rs','m']
658
+
659
+
660
+        if (part.start < needle_part.start && part.end > needle_part.start) {
661
+          return true;
662
+        }
663
+
664
+        if (needle_part.start < part.start && needle_part.end > part.start) {
665
+          return true;
666
+        }
667
+      }
668
+
669
+      return false;
670
+    };
671
+
672
+    let filtered = seq.parts.filter(filter);
673
+
674
+    if (filtered.length > 0) {
675
+      continue;
676
+    }
677
+
678
+    return true;
679
+  }
680
+
681
+  return false;
682
+};
683
+
684
+class Sequence {
685
+  constructor() {
686
+    /** @type {TSequencePart[]} */
687
+    this.parts = [];
688
+    /** @type {string[]} */
689
+
690
+    this.substrs = [];
691
+    this.start = 0;
692
+    this.end = 0;
693
+  }
694
+  /**
695
+   * @param {TSequencePart|undefined} part
696
+   */
697
+
698
+
699
+  add(part) {
700
+    if (part) {
701
+      this.parts.push(part);
702
+      this.substrs.push(part.substr);
703
+      this.start = Math.min(part.start, this.start);
704
+      this.end = Math.max(part.end, this.end);
705
+    }
706
+  }
707
+
708
+  last() {
709
+    return this.parts[this.parts.length - 1];
710
+  }
711
+
712
+  length() {
713
+    return this.parts.length;
714
+  }
715
+  /**
716
+   * @param {number} position
717
+   * @param {TSequencePart} last_piece
718
+   */
719
+
720
+
721
+  clone(position, last_piece) {
722
+    let clone = new Sequence();
723
+    let parts = JSON.parse(JSON.stringify(this.parts));
724
+    let last_part = parts.pop();
725
+
726
+    for (const part of parts) {
727
+      clone.add(part);
728
+    }
729
+
730
+    let last_substr = last_piece.substr.substring(0, position - last_part.start);
731
+    let clone_last_len = last_substr.length;
732
+    clone.add({
733
+      start: last_part.start,
734
+      end: last_part.start + clone_last_len,
735
+      length: clone_last_len,
736
+      substr: last_substr
737
+    });
738
+    return clone;
739
+  }
740
+
741
+}
742
+/**
743
+ * Expand a regular expression pattern to include unicode variants
744
+ * 	eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/
745
+ *
746
+ * Issue:
747
+ *  ﺊﺋ [ 'ﺊ = \\u{fe8a}', 'ﺋ = \\u{fe8b}' ]
748
+ *	becomes:	ئئ [ 'ي = \\u{64a}', 'ٔ = \\u{654}', 'ي = \\u{64a}', 'ٔ = \\u{654}' ]
749
+ *
750
+ *	İIJ = IIJ = ⅡJ
751
+ *
752
+ * 	1/2/4
753
+ *
754
+ * @param {string} str
755
+ * @return {string|undefined}
756
+ */
757
+
758
+
759
+const getPattern = str => {
760
+  initialize();
761
+  str = asciifold(str);
762
+  let pattern = '';
763
+  let sequences = [new Sequence()];
764
+
765
+  for (let i = 0; i < str.length; i++) {
766
+    let substr = str.substring(i);
767
+    let match = substr.match(multi_char_reg);
768
+    const char = str.substring(i, i + 1);
769
+    const match_str = match ? match[0] : null; // loop through sequences
770
+    // add either the char or multi_match
771
+
772
+    let overlapping = [];
773
+    let added_types = new Set();
774
+
775
+    for (const sequence of sequences) {
776
+      const last_piece = sequence.last();
777
+
778
+      if (!last_piece || last_piece.length == 1 || last_piece.end <= i) {
779
+        // if we have a multi match
780
+        if (match_str) {
781
+          const len = match_str.length;
782
+          sequence.add({
783
+            start: i,
784
+            end: i + len,
785
+            length: len,
786
+            substr: match_str
787
+          });
788
+          added_types.add('1');
789
+        } else {
790
+          sequence.add({
791
+            start: i,
792
+            end: i + 1,
793
+            length: 1,
794
+            substr: char
795
+          });
796
+          added_types.add('2');
797
+        }
798
+      } else if (match_str) {
799
+        let clone = sequence.clone(i, last_piece);
800
+        const len = match_str.length;
801
+        clone.add({
802
+          start: i,
803
+          end: i + len,
804
+          length: len,
805
+          substr: match_str
806
+        });
807
+        overlapping.push(clone);
808
+      } else {
809
+        // don't add char
810
+        // adding would create invalid patterns: 234 => [2,34,4]
811
+        added_types.add('3');
812
+      }
813
+    } // if we have overlapping
814
+
815
+
816
+    if (overlapping.length > 0) {
817
+      // ['ii','iii'] before ['i','i','iii']
818
+      overlapping = overlapping.sort((a, b) => {
819
+        return a.length() - b.length();
820
+      });
821
+
822
+      for (let clone of overlapping) {
823
+        // don't add if we already have an equivalent sequence
824
+        if (inSequences(clone, sequences)) {
825
+          continue;
826
+        }
827
+
828
+        sequences.push(clone);
829
+      }
830
+
831
+      continue;
832
+    } // if we haven't done anything unique
833
+    // clean up the patterns
834
+    // helps keep patterns smaller
835
+    // if str = 'r₨㎧aarss', pattern will be 446 instead of 655
836
+
837
+
838
+    if (i > 0 && added_types.size == 1 && !added_types.has('3')) {
839
+      pattern += sequencesToPattern(sequences, false);
840
+      let new_seq = new Sequence();
841
+      const old_seq = sequences[0];
842
+
843
+      if (old_seq) {
844
+        new_seq.add(old_seq.last());
845
+      }
846
+
847
+      sequences = [new_seq];
848
+    }
849
+  }
850
+
851
+  pattern += sequencesToPattern(sequences, true);
852
+  return pattern;
853
+};
854
+
855
+/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */
856
+
857
+/**
858
+ * A property getter resolving dot-notation
859
+ * @param  {Object}  obj     The root object to fetch property on
860
+ * @param  {String}  name    The optionally dotted property name to fetch
861
+ * @return {Object}          The resolved property value
862
+ */
863
+const getAttr = (obj, name) => {
864
+  if (!obj) return;
865
+  return obj[name];
866
+};
867
+/**
868
+ * A property getter resolving dot-notation
869
+ * @param  {Object}  obj     The root object to fetch property on
870
+ * @param  {String}  name    The optionally dotted property name to fetch
871
+ * @return {Object}          The resolved property value
872
+ */
873
+
874
+const getAttrNesting = (obj, name) => {
875
+  if (!obj) return;
876
+  var part,
877
+      names = name.split(".");
878
+
879
+  while ((part = names.shift()) && (obj = obj[part]));
880
+
881
+  return obj;
882
+};
883
+/**
884
+ * Calculates how close of a match the
885
+ * given value is against a search token.
886
+ *
887
+ */
888
+
889
+const scoreValue = (value, token, weight) => {
890
+  var score, pos;
891
+  if (!value) return 0;
892
+  value = value + '';
893
+  if (token.regex == null) return 0;
894
+  pos = value.search(token.regex);
895
+  if (pos === -1) return 0;
896
+  score = token.string.length / value.length;
897
+  if (pos === 0) score += 0.5;
898
+  return score * weight;
899
+};
900
+/**
901
+ * Cast object property to an array if it exists and has a value
902
+ *
903
+ */
904
+
905
+const propToArray = (obj, key) => {
906
+  var value = obj[key];
907
+  if (typeof value == 'function') return value;
908
+
909
+  if (value && !Array.isArray(value)) {
910
+    obj[key] = [value];
911
+  }
912
+};
913
+/**
914
+ * Iterates over arrays and hashes.
915
+ *
916
+ * ```
917
+ * iterate(this.items, function(item, id) {
918
+ *    // invoked for each item
919
+ * });
920
+ * ```
921
+ *
922
+ */
923
+
924
+const iterate$1 = (object, callback) => {
925
+  if (Array.isArray(object)) {
926
+    object.forEach(callback);
927
+  } else {
928
+    for (var key in object) {
929
+      if (object.hasOwnProperty(key)) {
930
+        callback(object[key], key);
931
+      }
932
+    }
933
+  }
934
+};
935
+const cmp = (a, b) => {
936
+  if (typeof a === 'number' && typeof b === 'number') {
937
+    return a > b ? 1 : a < b ? -1 : 0;
938
+  }
939
+
940
+  a = asciifold(a + '').toLowerCase();
941
+  b = asciifold(b + '').toLowerCase();
942
+  if (a > b) return 1;
943
+  if (b > a) return -1;
944
+  return 0;
945
+};
946
+
947
+/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */
948
+
949
+/**
950
+ * sifter.js
951
+ * Copyright (c) 2013–2020 Brian Reavis & contributors
952
+ *
953
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
954
+ * file except in compliance with the License. You may obtain a copy of the License at:
955
+ * http://www.apache.org/licenses/LICENSE-2.0
956
+ *
957
+ * Unless required by applicable law or agreed to in writing, software distributed under
958
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
959
+ * ANY KIND, either express or implied. See the License for the specific language
960
+ * governing permissions and limitations under the License.
961
+ *
962
+ * @author Brian Reavis <brian@thirdroute.com>
963
+ */
964
+
965
+class Sifter {
966
+  // []|{};
967
+
968
+  /**
969
+   * Textually searches arrays and hashes of objects
970
+   * by property (or multiple properties). Designed
971
+   * specifically for autocomplete.
972
+   *
973
+   */
974
+  constructor(items, settings) {
975
+    this.items = void 0;
976
+    this.settings = void 0;
977
+    this.items = items;
978
+    this.settings = settings || {
979
+      diacritics: true
980
+    };
981
+  }
982
+
983
+  /**
984
+   * Splits a search string into an array of individual
985
+   * regexps to be used to match results.
986
+   *
987
+   */
988
+  tokenize(query, respect_word_boundaries, weights) {
989
+    if (!query || !query.length) return [];
990
+    const tokens = [];
991
+    const words = query.split(/\s+/);
992
+    var field_regex;
993
+
994
+    if (weights) {
995
+      field_regex = new RegExp('^(' + Object.keys(weights).map(escape_regex).join('|') + ')\:(.*)$');
996
+    }
997
+
998
+    words.forEach(word => {
999
+      let field_match;
1000
+      let field = null;
1001
+      let regex = null; // look for "field:query" tokens
1002
+
1003
+      if (field_regex && (field_match = word.match(field_regex))) {
1004
+        field = field_match[1];
1005
+        word = field_match[2];
1006
+      }
1007
+
1008
+      if (word.length > 0) {
1009
+        if (this.settings.diacritics) {
1010
+          regex = getPattern(word) || null;
1011
+        } else {
1012
+          regex = escape_regex(word);
1013
+        }
1014
+
1015
+        if (regex && respect_word_boundaries) regex = "\\b" + regex;
1016
+      }
1017
+
1018
+      tokens.push({
1019
+        string: word,
1020
+        regex: regex ? new RegExp(regex, 'iu') : null,
1021
+        field: field
1022
+      });
1023
+    });
1024
+    return tokens;
1025
+  }
1026
+
1027
+  /**
1028
+   * Returns a function to be used to score individual results.
1029
+   *
1030
+   * Good matches will have a higher score than poor matches.
1031
+   * If an item is not a match, 0 will be returned by the function.
1032
+   *
1033
+   * @returns {T.ScoreFn}
1034
+   */
1035
+  getScoreFunction(query, options) {
1036
+    var search = this.prepareSearch(query, options);
1037
+    return this._getScoreFunction(search);
1038
+  }
1039
+  /**
1040
+   * @returns {T.ScoreFn}
1041
+   *
1042
+   */
1043
+
1044
+
1045
+  _getScoreFunction(search) {
1046
+    const tokens = search.tokens,
1047
+          token_count = tokens.length;
1048
+
1049
+    if (!token_count) {
1050
+      return function () {
1051
+        return 0;
1052
+      };
1053
+    }
1054
+
1055
+    const fields = search.options.fields,
1056
+          weights = search.weights,
1057
+          field_count = fields.length,
1058
+          getAttrFn = search.getAttrFn;
1059
+
1060
+    if (!field_count) {
1061
+      return function () {
1062
+        return 1;
1063
+      };
1064
+    }
1065
+    /**
1066
+     * Calculates the score of an object
1067
+     * against the search query.
1068
+     *
1069
+     */
1070
+
1071
+
1072
+    const scoreObject = function () {
1073
+      if (field_count === 1) {
1074
+        return function (token, data) {
1075
+          const field = fields[0].field;
1076
+          return scoreValue(getAttrFn(data, field), token, weights[field] || 1);
1077
+        };
1078
+      }
1079
+
1080
+      return function (token, data) {
1081
+        var sum = 0; // is the token specific to a field?
1082
+
1083
+        if (token.field) {
1084
+          const value = getAttrFn(data, token.field);
1085
+
1086
+          if (!token.regex && value) {
1087
+            sum += 1 / field_count;
1088
+          } else {
1089
+            sum += scoreValue(value, token, 1);
1090
+          }
1091
+        } else {
1092
+          iterate$1(weights, (weight, field) => {
1093
+            sum += scoreValue(getAttrFn(data, field), token, weight);
1094
+          });
1095
+        }
1096
+
1097
+        return sum / field_count;
1098
+      };
1099
+    }();
1100
+
1101
+    if (token_count === 1) {
1102
+      return function (data) {
1103
+        return scoreObject(tokens[0], data);
1104
+      };
1105
+    }
1106
+
1107
+    if (search.options.conjunction === 'and') {
1108
+      return function (data) {
1109
+        var score,
1110
+            sum = 0;
1111
+
1112
+        for (let token of tokens) {
1113
+          score = scoreObject(token, data);
1114
+          if (score <= 0) return 0;
1115
+          sum += score;
1116
+        }
1117
+
1118
+        return sum / token_count;
1119
+      };
1120
+    } else {
1121
+      return function (data) {
1122
+        var sum = 0;
1123
+        iterate$1(tokens, token => {
1124
+          sum += scoreObject(token, data);
1125
+        });
1126
+        return sum / token_count;
1127
+      };
1128
+    }
1129
+  }
1130
+
1131
+  /**
1132
+   * Returns a function that can be used to compare two
1133
+   * results, for sorting purposes. If no sorting should
1134
+   * be performed, `null` will be returned.
1135
+   *
1136
+   * @return function(a,b)
1137
+   */
1138
+  getSortFunction(query, options) {
1139
+    var search = this.prepareSearch(query, options);
1140
+    return this._getSortFunction(search);
1141
+  }
1142
+
1143
+  _getSortFunction(search) {
1144
+    var implicit_score,
1145
+        sort_flds = [];
1146
+    const self = this,
1147
+          options = search.options,
1148
+          sort = !search.query && options.sort_empty ? options.sort_empty : options.sort;
1149
+
1150
+    if (typeof sort == 'function') {
1151
+      return sort.bind(this);
1152
+    }
1153
+    /**
1154
+     * Fetches the specified sort field value
1155
+     * from a search result item.
1156
+     *
1157
+     */
1158
+
1159
+
1160
+    const get_field = function get_field(name, result) {
1161
+      if (name === '$score') return result.score;
1162
+      return search.getAttrFn(self.items[result.id], name);
1163
+    }; // parse options
1164
+
1165
+
1166
+    if (sort) {
1167
+      for (let s of sort) {
1168
+        if (search.query || s.field !== '$score') {
1169
+          sort_flds.push(s);
1170
+        }
1171
+      }
1172
+    } // the "$score" field is implied to be the primary
1173
+    // sort field, unless it's manually specified
1174
+
1175
+
1176
+    if (search.query) {
1177
+      implicit_score = true;
1178
+
1179
+      for (let fld of sort_flds) {
1180
+        if (fld.field === '$score') {
1181
+          implicit_score = false;
1182
+          break;
1183
+        }
1184
+      }
1185
+
1186
+      if (implicit_score) {
1187
+        sort_flds.unshift({
1188
+          field: '$score',
1189
+          direction: 'desc'
1190
+        });
1191
+      } // without a search.query, all items will have the same score
1192
+
1193
+    } else {
1194
+      sort_flds = sort_flds.filter(fld => fld.field !== '$score');
1195
+    } // build function
1196
+
1197
+
1198
+    const sort_flds_count = sort_flds.length;
1199
+
1200
+    if (!sort_flds_count) {
1201
+      return null;
1202
+    }
1203
+
1204
+    return function (a, b) {
1205
+      var result, field;
1206
+
1207
+      for (let sort_fld of sort_flds) {
1208
+        field = sort_fld.field;
1209
+        let multiplier = sort_fld.direction === 'desc' ? -1 : 1;
1210
+        result = multiplier * cmp(get_field(field, a), get_field(field, b));
1211
+        if (result) return result;
1212
+      }
1213
+
1214
+      return 0;
1215
+    };
1216
+  }
1217
+
1218
+  /**
1219
+   * Parses a search query and returns an object
1220
+   * with tokens and fields ready to be populated
1221
+   * with results.
1222
+   *
1223
+   */
1224
+  prepareSearch(query, optsUser) {
1225
+    const weights = {};
1226
+    var options = Object.assign({}, optsUser);
1227
+    propToArray(options, 'sort');
1228
+    propToArray(options, 'sort_empty'); // convert fields to new format
1229
+
1230
+    if (options.fields) {
1231
+      propToArray(options, 'fields');
1232
+      const fields = [];
1233
+      options.fields.forEach(field => {
1234
+        if (typeof field == 'string') {
1235
+          field = {
1236
+            field: field,
1237
+            weight: 1
1238
+          };
1239
+        }
1240
+
1241
+        fields.push(field);
1242
+        weights[field.field] = 'weight' in field ? field.weight : 1;
1243
+      });
1244
+      options.fields = fields;
1245
+    }
1246
+
1247
+    return {
1248
+      options: options,
1249
+      query: query.toLowerCase().trim(),
1250
+      tokens: this.tokenize(query, options.respect_word_boundaries, weights),
1251
+      total: 0,
1252
+      items: [],
1253
+      weights: weights,
1254
+      getAttrFn: options.nesting ? getAttrNesting : getAttr
1255
+    };
1256
+  }
1257
+
1258
+  /**
1259
+   * Searches through all items and returns a sorted array of matches.
1260
+   *
1261
+   */
1262
+  search(query, options) {
1263
+    var self = this,
1264
+        score,
1265
+        search;
1266
+    search = this.prepareSearch(query, options);
1267
+    options = search.options;
1268
+    query = search.query; // generate result scoring function
1269
+
1270
+    const fn_score = options.score || self._getScoreFunction(search); // perform search and sort
1271
+
1272
+
1273
+    if (query.length) {
1274
+      iterate$1(self.items, (item, id) => {
1275
+        score = fn_score(item);
1276
+
1277
+        if (options.filter === false || score > 0) {
1278
+          search.items.push({
1279
+            'score': score,
1280
+            'id': id
1281
+          });
1282
+        }
1283
+      });
1284
+    } else {
1285
+      iterate$1(self.items, (_, id) => {
1286
+        search.items.push({
1287
+          'score': 1,
1288
+          'id': id
1289
+        });
1290
+      });
1291
+    }
1292
+
1293
+    const fn_sort = self._getSortFunction(search);
1294
+
1295
+    if (fn_sort) search.items.sort(fn_sort); // apply limits
1296
+
1297
+    search.total = search.items.length;
1298
+
1299
+    if (typeof options.limit === 'number') {
1300
+      search.items = search.items.slice(0, options.limit);
1301
+    }
1302
+
1303
+    return search;
1304
+  }
1305
+
1306
+}
1307
+
1308
+/**
1309
+ * Iterates over arrays and hashes.
1310
+ *
1311
+ * ```
1312
+ * iterate(this.items, function(item, id) {
1313
+ *    // invoked for each item
1314
+ * });
1315
+ * ```
1316
+ *
1317
+ */
1318
+
1319
+const iterate = (object, callback) => {
1320
+  if (Array.isArray(object)) {
1321
+    object.forEach(callback);
1322
+  } else {
1323
+    for (var key in object) {
1324
+      if (object.hasOwnProperty(key)) {
1325
+        callback(object[key], key);
1326
+      }
1327
+    }
1328
+  }
1329
+};
1330
+
1331
+/**
1332
+ * Return a dom element from either a dom query string, jQuery object, a dom element or html string
1333
+ * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
1334
+ *
1335
+ * param query should be {}
1336
+ */
1337
+
1338
+const getDom = query => {
1339
+  if (query.jquery) {
1340
+    return query[0];
1341
+  }
1342
+
1343
+  if (query instanceof HTMLElement) {
1344
+    return query;
1345
+  }
1346
+
1347
+  if (isHtmlString(query)) {
1348
+    var tpl = document.createElement('template');
1349
+    tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result
1350
+
1351
+    return tpl.content.firstChild;
1352
+  }
1353
+
1354
+  return document.querySelector(query);
1355
+};
1356
+const isHtmlString = arg => {
1357
+  if (typeof arg === 'string' && arg.indexOf('<') > -1) {
1358
+    return true;
1359
+  }
1360
+
1361
+  return false;
1362
+};
1363
+const escapeQuery = query => {
1364
+  return query.replace(/['"\\]/g, '\\$&');
1365
+};
1366
+/**
1367
+ * Dispatch an event
1368
+ *
1369
+ */
1370
+
1371
+const triggerEvent = (dom_el, event_name) => {
1372
+  var event = document.createEvent('HTMLEvents');
1373
+  event.initEvent(event_name, true, false);
1374
+  dom_el.dispatchEvent(event);
1375
+};
1376
+/**
1377
+ * Apply CSS rules to a dom element
1378
+ *
1379
+ */
1380
+
1381
+const applyCSS = (dom_el, css) => {
1382
+  Object.assign(dom_el.style, css);
1383
+};
1384
+/**
1385
+ * Add css classes
1386
+ *
1387
+ */
1388
+
1389
+const addClasses = (elmts, ...classes) => {
1390
+  var norm_classes = classesArray(classes);
1391
+  elmts = castAsArray(elmts);
1392
+  elmts.map(el => {
1393
+    norm_classes.map(cls => {
1394
+      el.classList.add(cls);
1395
+    });
1396
+  });
1397
+};
1398
+/**
1399
+ * Remove css classes
1400
+ *
1401
+ */
1402
+
1403
+const removeClasses = (elmts, ...classes) => {
1404
+  var norm_classes = classesArray(classes);
1405
+  elmts = castAsArray(elmts);
1406
+  elmts.map(el => {
1407
+    norm_classes.map(cls => {
1408
+      el.classList.remove(cls);
1409
+    });
1410
+  });
1411
+};
1412
+/**
1413
+ * Return arguments
1414
+ *
1415
+ */
1416
+
1417
+const classesArray = args => {
1418
+  var classes = [];
1419
+  iterate(args, _classes => {
1420
+    if (typeof _classes === 'string') {
1421
+      _classes = _classes.trim().split(/[\11\12\14\15\40]/);
1422
+    }
1423
+
1424
+    if (Array.isArray(_classes)) {
1425
+      classes = classes.concat(_classes);
1426
+    }
1427
+  });
1428
+  return classes.filter(Boolean);
1429
+};
1430
+/**
1431
+ * Create an array from arg if it's not already an array
1432
+ *
1433
+ */
1434
+
1435
+const castAsArray = arg => {
1436
+  if (!Array.isArray(arg)) {
1437
+    arg = [arg];
1438
+  }
1439
+
1440
+  return arg;
1441
+};
1442
+/**
1443
+ * Get the closest node to the evt.target matching the selector
1444
+ * Stops at wrapper
1445
+ *
1446
+ */
1447
+
1448
+const parentMatch = (target, selector, wrapper) => {
1449
+  if (wrapper && !wrapper.contains(target)) {
1450
+    return;
1451
+  }
1452
+
1453
+  while (target && target.matches) {
1454
+    if (target.matches(selector)) {
1455
+      return target;
1456
+    }
1457
+
1458
+    target = target.parentNode;
1459
+  }
1460
+};
1461
+/**
1462
+ * Get the first or last item from an array
1463
+ *
1464
+ * > 0 - right (last)
1465
+ * <= 0 - left (first)
1466
+ *
1467
+ */
1468
+
1469
+const getTail = (list, direction = 0) => {
1470
+  if (direction > 0) {
1471
+    return list[list.length - 1];
1472
+  }
1473
+
1474
+  return list[0];
1475
+};
1476
+/**
1477
+ * Return true if an object is empty
1478
+ *
1479
+ */
1480
+
1481
+const isEmptyObject = obj => {
1482
+  return Object.keys(obj).length === 0;
1483
+};
1484
+/**
1485
+ * Get the index of an element amongst sibling nodes of the same type
1486
+ *
1487
+ */
1488
+
1489
+const nodeIndex = (el, amongst) => {
1490
+  if (!el) return -1;
1491
+  amongst = amongst || el.nodeName;
1492
+  var i = 0;
1493
+
1494
+  while (el = el.previousElementSibling) {
1495
+    if (el.matches(amongst)) {
1496
+      i++;
1497
+    }
1498
+  }
1499
+
1500
+  return i;
1501
+};
1502
+/**
1503
+ * Set attributes of an element
1504
+ *
1505
+ */
1506
+
1507
+const setAttr = (el, attrs) => {
1508
+  iterate(attrs, (val, attr) => {
1509
+    if (val == null) {
1510
+      el.removeAttribute(attr);
1511
+    } else {
1512
+      el.setAttribute(attr, '' + val);
1513
+    }
1514
+  });
1515
+};
1516
+/**
1517
+ * Replace a node
1518
+ */
1519
+
1520
+const replaceNode = (existing, replacement) => {
1521
+  if (existing.parentNode) existing.parentNode.replaceChild(replacement, existing);
1522
+};
1523
+
1524
+/**
1525
+ * highlight v3 | MIT license | Johann Burkard <jb@eaio.com>
1526
+ * Highlights arbitrary terms in a node.
1527
+ *
1528
+ * - Modified by Marshal <beatgates@gmail.com> 2011-6-24 (added regex)
1529
+ * - Modified by Brian Reavis <brian@thirdroute.com> 2012-8-27 (cleanup)
1530
+ */
1531
+const highlight = (element, regex) => {
1532
+  if (regex === null) return; // convet string to regex
1533
+
1534
+  if (typeof regex === 'string') {
1535
+    if (!regex.length) return;
1536
+    regex = new RegExp(regex, 'i');
1537
+  } // Wrap matching part of text node with highlighting <span>, e.g.
1538
+  // Soccer  ->  <span class="highlight">Soc</span>cer  for regex = /soc/i
1539
+
1540
+
1541
+  const highlightText = node => {
1542
+    var match = node.data.match(regex);
1543
+
1544
+    if (match && node.data.length > 0) {
1545
+      var spannode = document.createElement('span');
1546
+      spannode.className = 'highlight';
1547
+      var middlebit = node.splitText(match.index);
1548
+      middlebit.splitText(match[0].length);
1549
+      var middleclone = middlebit.cloneNode(true);
1550
+      spannode.appendChild(middleclone);
1551
+      replaceNode(middlebit, spannode);
1552
+      return 1;
1553
+    }
1554
+
1555
+    return 0;
1556
+  }; // Recurse element node, looking for child text nodes to highlight, unless element
1557
+  // is childless, <script>, <style>, or already highlighted: <span class="hightlight">
1558
+
1559
+
1560
+  const highlightChildren = node => {
1561
+    if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && (node.className !== 'highlight' || node.tagName !== 'SPAN')) {
1562
+      Array.from(node.childNodes).forEach(element => {
1563
+        highlightRecursive(element);
1564
+      });
1565
+    }
1566
+  };
1567
+
1568
+  const highlightRecursive = node => {
1569
+    if (node.nodeType === 3) {
1570
+      return highlightText(node);
1571
+    }
1572
+
1573
+    highlightChildren(node);
1574
+    return 0;
1575
+  };
1576
+
1577
+  highlightRecursive(element);
1578
+};
1579
+/**
1580
+ * removeHighlight fn copied from highlight v5 and
1581
+ * edited to remove with(), pass js strict mode, and use without jquery
1582
+ */
1583
+
1584
+const removeHighlight = el => {
1585
+  var elements = el.querySelectorAll("span.highlight");
1586
+  Array.prototype.forEach.call(elements, function (el) {
1587
+    var parent = el.parentNode;
1588
+    parent.replaceChild(el.firstChild, el);
1589
+    parent.normalize();
1590
+  });
1591
+};
1592
+
1593
+const KEY_A = 65;
1594
+const KEY_RETURN = 13;
1595
+const KEY_ESC = 27;
1596
+const KEY_LEFT = 37;
1597
+const KEY_UP = 38;
1598
+const KEY_RIGHT = 39;
1599
+const KEY_DOWN = 40;
1600
+const KEY_BACKSPACE = 8;
1601
+const KEY_DELETE = 46;
1602
+const KEY_TAB = 9;
1603
+const IS_MAC = typeof navigator === 'undefined' ? false : /Mac/.test(navigator.userAgent);
1604
+const KEY_SHORTCUT = IS_MAC ? 'metaKey' : 'ctrlKey'; // ctrl key or apple key for ma
1605
+
1606
+var defaults = {
1607
+  options: [],
1608
+  optgroups: [],
1609
+  plugins: [],
1610
+  delimiter: ',',
1611
+  splitOn: null,
1612
+  // regexp or string for splitting up values from a paste command
1613
+  persist: true,
1614
+  diacritics: true,
1615
+  create: null,
1616
+  createOnBlur: false,
1617
+  createFilter: null,
1618
+  highlight: true,
1619
+  openOnFocus: true,
1620
+  shouldOpen: null,
1621
+  maxOptions: 50,
1622
+  maxItems: null,
1623
+  hideSelected: null,
1624
+  duplicates: false,
1625
+  addPrecedence: false,
1626
+  selectOnTab: false,
1627
+  preload: null,
1628
+  allowEmptyOption: false,
1629
+  //closeAfterSelect: false,
1630
+  loadThrottle: 300,
1631
+  loadingClass: 'loading',
1632
+  dataAttr: null,
1633
+  //'data-data',
1634
+  optgroupField: 'optgroup',
1635
+  valueField: 'value',
1636
+  labelField: 'text',
1637
+  disabledField: 'disabled',
1638
+  optgroupLabelField: 'label',
1639
+  optgroupValueField: 'value',
1640
+  lockOptgroupOrder: false,
1641
+  sortField: '$order',
1642
+  searchField: ['text'],
1643
+  searchConjunction: 'and',
1644
+  mode: null,
1645
+  wrapperClass: 'ts-wrapper',
1646
+  controlClass: 'ts-control',
1647
+  dropdownClass: 'ts-dropdown',
1648
+  dropdownContentClass: 'ts-dropdown-content',
1649
+  itemClass: 'item',
1650
+  optionClass: 'option',
1651
+  dropdownParent: null,
1652
+  controlInput: '<input type="text" autocomplete="off" size="1" />',
1653
+  copyClassesToDropdown: false,
1654
+  placeholder: null,
1655
+  hidePlaceholder: null,
1656
+  shouldLoad: function (query) {
1657
+    return query.length > 0;
1658
+  },
1659
+
1660
+  /*
1661
+  load                 : null, // function(query, callback) { ... }
1662
+  score                : null, // function(search) { ... }
1663
+  onInitialize         : null, // function() { ... }
1664
+  onChange             : null, // function(value) { ... }
1665
+  onItemAdd            : null, // function(value, $item) { ... }
1666
+  onItemRemove         : null, // function(value) { ... }
1667
+  onClear              : null, // function() { ... }
1668
+  onOptionAdd          : null, // function(value, data) { ... }
1669
+  onOptionRemove       : null, // function(value) { ... }
1670
+  onOptionClear        : null, // function() { ... }
1671
+  onOptionGroupAdd     : null, // function(id, data) { ... }
1672
+  onOptionGroupRemove  : null, // function(id) { ... }
1673
+  onOptionGroupClear   : null, // function() { ... }
1674
+  onDropdownOpen       : null, // function(dropdown) { ... }
1675
+  onDropdownClose      : null, // function(dropdown) { ... }
1676
+  onType               : null, // function(str) { ... }
1677
+  onDelete             : null, // function(values) { ... }
1678
+  */
1679
+  render: {
1680
+    /*
1681
+    item: null,
1682
+    optgroup: null,
1683
+    optgroup_header: null,
1684
+    option: null,
1685
+    option_create: null
1686
+    */
1687
+  }
1688
+};
1689
+
1690
+/**
1691
+ * Converts a scalar to its best string representation
1692
+ * for hash keys and HTML attribute values.
1693
+ *
1694
+ * Transformations:
1695
+ *   'str'     -> 'str'
1696
+ *   null      -> ''
1697
+ *   undefined -> ''
1698
+ *   true      -> '1'
1699
+ *   false     -> '0'
1700
+ *   0         -> '0'
1701
+ *   1         -> '1'
1702
+ *
1703
+ */
1704
+const hash_key = value => {
1705
+  if (typeof value === 'undefined' || value === null) return null;
1706
+  return get_hash(value);
1707
+};
1708
+const get_hash = value => {
1709
+  if (typeof value === 'boolean') return value ? '1' : '0';
1710
+  return value + '';
1711
+};
1712
+/**
1713
+ * Escapes a string for use within HTML.
1714
+ *
1715
+ */
1716
+
1717
+const escape_html = str => {
1718
+  return (str + '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1719
+};
1720
+/**
1721
+ * Debounce the user provided load function
1722
+ *
1723
+ */
1724
+
1725
+const loadDebounce = (fn, delay) => {
1726
+  var timeout;
1727
+  return function (value, callback) {
1728
+    var self = this;
1729
+
1730
+    if (timeout) {
1731
+      self.loading = Math.max(self.loading - 1, 0);
1732
+      clearTimeout(timeout);
1733
+    }
1734
+
1735
+    timeout = setTimeout(function () {
1736
+      timeout = null;
1737
+      self.loadedSearches[value] = true;
1738
+      fn.call(self, value, callback);
1739
+    }, delay);
1740
+  };
1741
+};
1742
+/**
1743
+ * Debounce all fired events types listed in `types`
1744
+ * while executing the provided `fn`.
1745
+ *
1746
+ */
1747
+
1748
+const debounce_events = (self, types, fn) => {
1749
+  var type;
1750
+  var trigger = self.trigger;
1751
+  var event_args = {}; // override trigger method
1752
+
1753
+  self.trigger = function () {
1754
+    var type = arguments[0];
1755
+
1756
+    if (types.indexOf(type) !== -1) {
1757
+      event_args[type] = arguments;
1758
+    } else {
1759
+      return trigger.apply(self, arguments);
1760
+    }
1761
+  }; // invoke provided function
1762
+
1763
+
1764
+  fn.apply(self, []);
1765
+  self.trigger = trigger; // trigger queued events
1766
+
1767
+  for (type of types) {
1768
+    if (type in event_args) {
1769
+      trigger.apply(self, event_args[type]);
1770
+    }
1771
+  }
1772
+};
1773
+/**
1774
+ * Determines the current selection within a text input control.
1775
+ * Returns an object containing:
1776
+ *   - start
1777
+ *   - length
1778
+ *
1779
+ */
1780
+
1781
+const getSelection = input => {
1782
+  return {
1783
+    start: input.selectionStart || 0,
1784
+    length: (input.selectionEnd || 0) - (input.selectionStart || 0)
1785
+  };
1786
+};
1787
+/**
1788
+ * Prevent default
1789
+ *
1790
+ */
1791
+
1792
+const preventDefault = (evt, stop = false) => {
1793
+  if (evt) {
1794
+    evt.preventDefault();
1795
+
1796
+    if (stop) {
1797
+      evt.stopPropagation();
1798
+    }
1799
+  }
1800
+};
1801
+/**
1802
+ * Add event helper
1803
+ *
1804
+ */
1805
+
1806
+const addEvent = (target, type, callback, options) => {
1807
+  target.addEventListener(type, callback, options);
1808
+};
1809
+/**
1810
+ * Return true if the requested key is down
1811
+ * Will return false if more than one control character is pressed ( when [ctrl+shift+a] != [ctrl+a] )
1812
+ * The current evt may not always set ( eg calling advanceSelection() )
1813
+ *
1814
+ */
1815
+
1816
+const isKeyDown = (key_name, evt) => {
1817
+  if (!evt) {
1818
+    return false;
1819
+  }
1820
+
1821
+  if (!evt[key_name]) {
1822
+    return false;
1823
+  }
1824
+
1825
+  var count = (evt.altKey ? 1 : 0) + (evt.ctrlKey ? 1 : 0) + (evt.shiftKey ? 1 : 0) + (evt.metaKey ? 1 : 0);
1826
+
1827
+  if (count === 1) {
1828
+    return true;
1829
+  }
1830
+
1831
+  return false;
1832
+};
1833
+/**
1834
+ * Get the id of an element
1835
+ * If the id attribute is not set, set the attribute with the given id
1836
+ *
1837
+ */
1838
+
1839
+const getId = (el, id) => {
1840
+  const existing_id = el.getAttribute('id');
1841
+
1842
+  if (existing_id) {
1843
+    return existing_id;
1844
+  }
1845
+
1846
+  el.setAttribute('id', id);
1847
+  return id;
1848
+};
1849
+/**
1850
+ * Returns a string with backslashes added before characters that need to be escaped.
1851
+ */
1852
+
1853
+const addSlashes = str => {
1854
+  return str.replace(/[\\"']/g, '\\$&');
1855
+};
1856
+/**
1857
+ *
1858
+ */
1859
+
1860
+const append = (parent, node) => {
1861
+  if (node) parent.append(node);
1862
+};
1863
+
1864
+function getSettings(input, settings_user) {
1865
+  var settings = Object.assign({}, defaults, settings_user);
1866
+  var attr_data = settings.dataAttr;
1867
+  var field_label = settings.labelField;
1868
+  var field_value = settings.valueField;
1869
+  var field_disabled = settings.disabledField;
1870
+  var field_optgroup = settings.optgroupField;
1871
+  var field_optgroup_label = settings.optgroupLabelField;
1872
+  var field_optgroup_value = settings.optgroupValueField;
1873
+  var tag_name = input.tagName.toLowerCase();
1874
+  var placeholder = input.getAttribute('placeholder') || input.getAttribute('data-placeholder');
1875
+
1876
+  if (!placeholder && !settings.allowEmptyOption) {
1877
+    let option = input.querySelector('option[value=""]');
1878
+
1879
+    if (option) {
1880
+      placeholder = option.textContent;
1881
+    }
1882
+  }
1883
+
1884
+  var settings_element = {
1885
+    placeholder: placeholder,
1886
+    options: [],
1887
+    optgroups: [],
1888
+    items: [],
1889
+    maxItems: null
1890
+  };
1891
+  /**
1892
+   * Initialize from a <select> element.
1893
+   *
1894
+   */
1895
+
1896
+  var init_select = () => {
1897
+    var tagName;
1898
+    var options = settings_element.options;
1899
+    var optionsMap = {};
1900
+    var group_count = 1;
1901
+
1902
+    var readData = el => {
1903
+      var data = Object.assign({}, el.dataset); // get plain object from DOMStringMap
1904
+
1905
+      var json = attr_data && data[attr_data];
1906
+
1907
+      if (typeof json === 'string' && json.length) {
1908
+        data = Object.assign(data, JSON.parse(json));
1909
+      }
1910
+
1911
+      return data;
1912
+    };
1913
+
1914
+    var addOption = (option, group) => {
1915
+      var value = hash_key(option.value);
1916
+      if (value == null) return;
1917
+      if (!value && !settings.allowEmptyOption) return; // if the option already exists, it's probably been
1918
+      // duplicated in another optgroup. in this case, push
1919
+      // the current group to the "optgroup" property on the
1920
+      // existing option so that it's rendered in both places.
1921
+
1922
+      if (optionsMap.hasOwnProperty(value)) {
1923
+        if (group) {
1924
+          var arr = optionsMap[value][field_optgroup];
1925
+
1926
+          if (!arr) {
1927
+            optionsMap[value][field_optgroup] = group;
1928
+          } else if (!Array.isArray(arr)) {
1929
+            optionsMap[value][field_optgroup] = [arr, group];
1930
+          } else {
1931
+            arr.push(group);
1932
+          }
1933
+        }
1934
+      } else {
1935
+        var option_data = readData(option);
1936
+        option_data[field_label] = option_data[field_label] || option.textContent;
1937
+        option_data[field_value] = option_data[field_value] || value;
1938
+        option_data[field_disabled] = option_data[field_disabled] || option.disabled;
1939
+        option_data[field_optgroup] = option_data[field_optgroup] || group;
1940
+        option_data.$option = option;
1941
+        optionsMap[value] = option_data;
1942
+        options.push(option_data);
1943
+      }
1944
+
1945
+      if (option.selected) {
1946
+        settings_element.items.push(value);
1947
+      }
1948
+    };
1949
+
1950
+    var addGroup = optgroup => {
1951
+      var id, optgroup_data;
1952
+      optgroup_data = readData(optgroup);
1953
+      optgroup_data[field_optgroup_label] = optgroup_data[field_optgroup_label] || optgroup.getAttribute('label') || '';
1954
+      optgroup_data[field_optgroup_value] = optgroup_data[field_optgroup_value] || group_count++;
1955
+      optgroup_data[field_disabled] = optgroup_data[field_disabled] || optgroup.disabled;
1956
+      settings_element.optgroups.push(optgroup_data);
1957
+      id = optgroup_data[field_optgroup_value];
1958
+      iterate(optgroup.children, option => {
1959
+        addOption(option, id);
1960
+      });
1961
+    };
1962
+
1963
+    settings_element.maxItems = input.hasAttribute('multiple') ? null : 1;
1964
+    iterate(input.children, child => {
1965
+      tagName = child.tagName.toLowerCase();
1966
+
1967
+      if (tagName === 'optgroup') {
1968
+        addGroup(child);
1969
+      } else if (tagName === 'option') {
1970
+        addOption(child);
1971
+      }
1972
+    });
1973
+  };
1974
+  /**
1975
+   * Initialize from a <input type="text"> element.
1976
+   *
1977
+   */
1978
+
1979
+
1980
+  var init_textbox = () => {
1981
+    const data_raw = input.getAttribute(attr_data);
1982
+
1983
+    if (!data_raw) {
1984
+      var value = input.value.trim() || '';
1985
+      if (!settings.allowEmptyOption && !value.length) return;
1986
+      const values = value.split(settings.delimiter);
1987
+      iterate(values, value => {
1988
+        const option = {};
1989
+        option[field_label] = value;
1990
+        option[field_value] = value;
1991
+        settings_element.options.push(option);
1992
+      });
1993
+      settings_element.items = values;
1994
+    } else {
1995
+      settings_element.options = JSON.parse(data_raw);
1996
+      iterate(settings_element.options, opt => {
1997
+        settings_element.items.push(opt[field_value]);
1998
+      });
1999
+    }
2000
+  };
2001
+
2002
+  if (tag_name === 'select') {
2003
+    init_select();
2004
+  } else {
2005
+    init_textbox();
2006
+  }
2007
+
2008
+  return Object.assign({}, defaults, settings_element, settings_user);
2009
+}
2010
+
2011
+var instance_i = 0;
2012
+class TomSelect extends MicroPlugin(MicroEvent) {
2013
+  // @deprecated 1.8
2014
+  constructor(input_arg, user_settings) {
2015
+    super();
2016
+    this.control_input = void 0;
2017
+    this.wrapper = void 0;
2018
+    this.dropdown = void 0;
2019
+    this.control = void 0;
2020
+    this.dropdown_content = void 0;
2021
+    this.focus_node = void 0;
2022
+    this.order = 0;
2023
+    this.settings = void 0;
2024
+    this.input = void 0;
2025
+    this.tabIndex = void 0;
2026
+    this.is_select_tag = void 0;
2027
+    this.rtl = void 0;
2028
+    this.inputId = void 0;
2029
+    this._destroy = void 0;
2030
+    this.sifter = void 0;
2031
+    this.isOpen = false;
2032
+    this.isDisabled = false;
2033
+    this.isRequired = void 0;
2034
+    this.isInvalid = false;
2035
+    this.isValid = true;
2036
+    this.isLocked = false;
2037
+    this.isFocused = false;
2038
+    this.isInputHidden = false;
2039
+    this.isSetup = false;
2040
+    this.ignoreFocus = false;
2041
+    this.ignoreHover = false;
2042
+    this.hasOptions = false;
2043
+    this.currentResults = void 0;
2044
+    this.lastValue = '';
2045
+    this.caretPos = 0;
2046
+    this.loading = 0;
2047
+    this.loadedSearches = {};
2048
+    this.activeOption = null;
2049
+    this.activeItems = [];
2050
+    this.optgroups = {};
2051
+    this.options = {};
2052
+    this.userOptions = {};
2053
+    this.items = [];
2054
+    instance_i++;
2055
+    var dir;
2056
+    var input = getDom(input_arg);
2057
+
2058
+    if (input.tomselect) {
2059
+      throw new Error('Tom Select already initialized on this element');
2060
+    }
2061
+
2062
+    input.tomselect = this; // detect rtl environment
2063
+
2064
+    var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);
2065
+    dir = computedStyle.getPropertyValue('direction'); // setup default state
2066
+
2067
+    const settings = getSettings(input, user_settings);
2068
+    this.settings = settings;
2069
+    this.input = input;
2070
+    this.tabIndex = input.tabIndex || 0;
2071
+    this.is_select_tag = input.tagName.toLowerCase() === 'select';
2072
+    this.rtl = /rtl/i.test(dir);
2073
+    this.inputId = getId(input, 'tomselect-' + instance_i);
2074
+    this.isRequired = input.required; // search system
2075
+
2076
+    this.sifter = new Sifter(this.options, {
2077
+      diacritics: settings.diacritics
2078
+    }); // option-dependent defaults
2079
+
2080
+    settings.mode = settings.mode || (settings.maxItems === 1 ? 'single' : 'multi');
2081
+
2082
+    if (typeof settings.hideSelected !== 'boolean') {
2083
+      settings.hideSelected = settings.mode === 'multi';
2084
+    }
2085
+
2086
+    if (typeof settings.hidePlaceholder !== 'boolean') {
2087
+      settings.hidePlaceholder = settings.mode !== 'multi';
2088
+    } // set up createFilter callback
2089
+
2090
+
2091
+    var filter = settings.createFilter;
2092
+
2093
+    if (typeof filter !== 'function') {
2094
+      if (typeof filter === 'string') {
2095
+        filter = new RegExp(filter);
2096
+      }
2097
+
2098
+      if (filter instanceof RegExp) {
2099
+        settings.createFilter = input => filter.test(input);
2100
+      } else {
2101
+        settings.createFilter = value => {
2102
+          return this.settings.duplicates || !this.options[value];
2103
+        };
2104
+      }
2105
+    }
2106
+
2107
+    this.initializePlugins(settings.plugins);
2108
+    this.setupCallbacks();
2109
+    this.setupTemplates(); // Create all elements
2110
+
2111
+    const wrapper = getDom('<div>');
2112
+    const control = getDom('<div>');
2113
+
2114
+    const dropdown = this._render('dropdown');
2115
+
2116
+    const dropdown_content = getDom(`<div role="listbox" tabindex="-1">`);
2117
+    const classes = this.input.getAttribute('class') || '';
2118
+    const inputMode = settings.mode;
2119
+    var control_input;
2120
+    addClasses(wrapper, settings.wrapperClass, classes, inputMode);
2121
+    addClasses(control, settings.controlClass);
2122
+    append(wrapper, control);
2123
+    addClasses(dropdown, settings.dropdownClass, inputMode);
2124
+
2125
+    if (settings.copyClassesToDropdown) {
2126
+      addClasses(dropdown, classes);
2127
+    }
2128
+
2129
+    addClasses(dropdown_content, settings.dropdownContentClass);
2130
+    append(dropdown, dropdown_content);
2131
+    getDom(settings.dropdownParent || wrapper).appendChild(dropdown); // default controlInput
2132
+
2133
+    if (isHtmlString(settings.controlInput)) {
2134
+      control_input = getDom(settings.controlInput); // set attributes
2135
+
2136
+      var attrs = ['autocorrect', 'autocapitalize', 'autocomplete'];
2137
+      iterate$1(attrs, attr => {
2138
+        if (input.getAttribute(attr)) {
2139
+          setAttr(control_input, {
2140
+            [attr]: input.getAttribute(attr)
2141
+          });
2142
+        }
2143
+      });
2144
+      control_input.tabIndex = -1;
2145
+      control.appendChild(control_input);
2146
+      this.focus_node = control_input; // dom element
2147
+    } else if (settings.controlInput) {
2148
+      control_input = getDom(settings.controlInput);
2149
+      this.focus_node = control_input;
2150
+    } else {
2151
+      control_input = getDom('<input/>');
2152
+      this.focus_node = control;
2153
+    }
2154
+
2155
+    this.wrapper = wrapper;
2156
+    this.dropdown = dropdown;
2157
+    this.dropdown_content = dropdown_content;
2158
+    this.control = control;
2159
+    this.control_input = control_input;
2160
+    this.setup();
2161
+  }
2162
+  /**
2163
+   * set up event bindings.
2164
+   *
2165
+   */
2166
+
2167
+
2168
+  setup() {
2169
+    const self = this;
2170
+    const settings = self.settings;
2171
+    const control_input = self.control_input;
2172
+    const dropdown = self.dropdown;
2173
+    const dropdown_content = self.dropdown_content;
2174
+    const wrapper = self.wrapper;
2175
+    const control = self.control;
2176
+    const input = self.input;
2177
+    const focus_node = self.focus_node;
2178
+    const passive_event = {
2179
+      passive: true
2180
+    };
2181
+    const listboxId = self.inputId + '-ts-dropdown';
2182
+    setAttr(dropdown_content, {
2183
+      id: listboxId
2184
+    });
2185
+    setAttr(focus_node, {
2186
+      role: 'combobox',
2187
+      'aria-haspopup': 'listbox',
2188
+      'aria-expanded': 'false',
2189
+      'aria-controls': listboxId
2190
+    });
2191
+    const control_id = getId(focus_node, self.inputId + '-ts-control');
2192
+    const query = "label[for='" + escapeQuery(self.inputId) + "']";
2193
+    const label = document.querySelector(query);
2194
+    const label_click = self.focus.bind(self);
2195
+
2196
+    if (label) {
2197
+      addEvent(label, 'click', label_click);
2198
+      setAttr(label, {
2199
+        for: control_id
2200
+      });
2201
+      const label_id = getId(label, self.inputId + '-ts-label');
2202
+      setAttr(focus_node, {
2203
+        'aria-labelledby': label_id
2204
+      });
2205
+      setAttr(dropdown_content, {
2206
+        'aria-labelledby': label_id
2207
+      });
2208
+    }
2209
+
2210
+    wrapper.style.width = input.style.width;
2211
+
2212
+    if (self.plugins.names.length) {
2213
+      const classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
2214
+      addClasses([wrapper, dropdown], classes_plugins);
2215
+    }
2216
+
2217
+    if ((settings.maxItems === null || settings.maxItems > 1) && self.is_select_tag) {
2218
+      setAttr(input, {
2219
+        multiple: 'multiple'
2220
+      });
2221
+    }
2222
+
2223
+    if (settings.placeholder) {
2224
+      setAttr(control_input, {
2225
+        placeholder: settings.placeholder
2226
+      });
2227
+    } // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
2228
+
2229
+
2230
+    if (!settings.splitOn && settings.delimiter) {
2231
+      settings.splitOn = new RegExp('\\s*' + escape_regex(settings.delimiter) + '+\\s*');
2232
+    } // debounce user defined load() if loadThrottle > 0
2233
+    // after initializePlugins() so plugins can create/modify user defined loaders
2234
+
2235
+
2236
+    if (settings.load && settings.loadThrottle) {
2237
+      settings.load = loadDebounce(settings.load, settings.loadThrottle);
2238
+    }
2239
+
2240
+    self.control_input.type = input.type;
2241
+    addEvent(dropdown, 'mousemove', () => {
2242
+      self.ignoreHover = false;
2243
+    });
2244
+    addEvent(dropdown, 'mouseenter', e => {
2245
+      var target_match = parentMatch(e.target, '[data-selectable]', dropdown);
2246
+      if (target_match) self.onOptionHover(e, target_match);
2247
+    }, {
2248
+      capture: true
2249
+    }); // clicking on an option should select it
2250
+
2251
+    addEvent(dropdown, 'click', evt => {
2252
+      const option = parentMatch(evt.target, '[data-selectable]');
2253
+
2254
+      if (option) {
2255
+        self.onOptionSelect(evt, option);
2256
+        preventDefault(evt, true);
2257
+      }
2258
+    });
2259
+    addEvent(control, 'click', evt => {
2260
+      var target_match = parentMatch(evt.target, '[data-ts-item]', control);
2261
+
2262
+      if (target_match && self.onItemSelect(evt, target_match)) {
2263
+        preventDefault(evt, true);
2264
+        return;
2265
+      } // retain focus (see control_input mousedown)
2266
+
2267
+
2268
+      if (control_input.value != '') {
2269
+        return;
2270
+      }
2271
+
2272
+      self.onClick();
2273
+      preventDefault(evt, true);
2274
+    }); // keydown on focus_node for arrow_down/arrow_up
2275
+
2276
+    addEvent(focus_node, 'keydown', e => self.onKeyDown(e)); // keypress and input/keyup
2277
+
2278
+    addEvent(control_input, 'keypress', e => self.onKeyPress(e));
2279
+    addEvent(control_input, 'input', e => self.onInput(e));
2280
+    addEvent(focus_node, 'blur', e => self.onBlur(e));
2281
+    addEvent(focus_node, 'focus', e => self.onFocus(e));
2282
+    addEvent(control_input, 'paste', e => self.onPaste(e));
2283
+
2284
+    const doc_mousedown = evt => {
2285
+      // blur if target is outside of this instance
2286
+      // dropdown is not always inside wrapper
2287
+      const target = evt.composedPath()[0];
2288
+
2289
+      if (!wrapper.contains(target) && !dropdown.contains(target)) {
2290
+        if (self.isFocused) {
2291
+          self.blur();
2292
+        }
2293
+
2294
+        self.inputState();
2295
+        return;
2296
+      } // retain focus by preventing native handling. if the
2297
+      // event target is the input it should not be modified.
2298
+      // otherwise, text selection within the input won't work.
2299
+      // Fixes bug #212 which is no covered by tests
2300
+
2301
+
2302
+      if (target == control_input && self.isOpen) {
2303
+        evt.stopPropagation(); // clicking anywhere in the control should not blur the control_input (which would close the dropdown)
2304
+      } else {
2305
+        preventDefault(evt, true);
2306
+      }
2307
+    };
2308
+
2309
+    const win_scroll = () => {
2310
+      if (self.isOpen) {
2311
+        self.positionDropdown();
2312
+      }
2313
+    };
2314
+
2315
+    addEvent(document, 'mousedown', doc_mousedown);
2316
+    addEvent(window, 'scroll', win_scroll, passive_event);
2317
+    addEvent(window, 'resize', win_scroll, passive_event);
2318
+
2319
+    this._destroy = () => {
2320
+      document.removeEventListener('mousedown', doc_mousedown);
2321
+      window.removeEventListener('scroll', win_scroll);
2322
+      window.removeEventListener('resize', win_scroll);
2323
+      if (label) label.removeEventListener('click', label_click);
2324
+    }; // store original html and tab index so that they can be
2325
+    // restored when the destroy() method is called.
2326
+
2327
+
2328
+    this.revertSettings = {
2329
+      innerHTML: input.innerHTML,
2330
+      tabIndex: input.tabIndex
2331
+    };
2332
+    input.tabIndex = -1;
2333
+    input.insertAdjacentElement('afterend', self.wrapper);
2334
+    self.sync(false);
2335
+    settings.items = [];
2336
+    delete settings.optgroups;
2337
+    delete settings.options;
2338
+    addEvent(input, 'invalid', () => {
2339
+      if (self.isValid) {
2340
+        self.isValid = false;
2341
+        self.isInvalid = true;
2342
+        self.refreshState();
2343
+      }
2344
+    });
2345
+    self.updateOriginalInput();
2346
+    self.refreshItems();
2347
+    self.close(false);
2348
+    self.inputState();
2349
+    self.isSetup = true;
2350
+
2351
+    if (input.disabled) {
2352
+      self.disable();
2353
+    } else {
2354
+      self.enable(); //sets tabIndex
2355
+    }
2356
+
2357
+    self.on('change', this.onChange);
2358
+    addClasses(input, 'tomselected', 'ts-hidden-accessible');
2359
+    self.trigger('initialize'); // preload options
2360
+
2361
+    if (settings.preload === true) {
2362
+      self.preload();
2363
+    }
2364
+  }
2365
+  /**
2366
+   * Register options and optgroups
2367
+   *
2368
+   */
2369
+
2370
+
2371
+  setupOptions(options = [], optgroups = []) {
2372
+    // build options table
2373
+    this.addOptions(options); // build optgroup table
2374
+
2375
+    iterate$1(optgroups, optgroup => {
2376
+      this.registerOptionGroup(optgroup);
2377
+    });
2378
+  }
2379
+  /**
2380
+   * Sets up default rendering functions.
2381
+   */
2382
+
2383
+
2384
+  setupTemplates() {
2385
+    var self = this;
2386
+    var field_label = self.settings.labelField;
2387
+    var field_optgroup = self.settings.optgroupLabelField;
2388
+    var templates = {
2389
+      'optgroup': data => {
2390
+        let optgroup = document.createElement('div');
2391
+        optgroup.className = 'optgroup';
2392
+        optgroup.appendChild(data.options);
2393
+        return optgroup;
2394
+      },
2395
+      'optgroup_header': (data, escape) => {
2396
+        return '<div class="optgroup-header">' + escape(data[field_optgroup]) + '</div>';
2397
+      },
2398
+      'option': (data, escape) => {
2399
+        return '<div>' + escape(data[field_label]) + '</div>';
2400
+      },
2401
+      'item': (data, escape) => {
2402
+        return '<div>' + escape(data[field_label]) + '</div>';
2403
+      },
2404
+      'option_create': (data, escape) => {
2405
+        return '<div class="create">Add <strong>' + escape(data.input) + '</strong>&hellip;</div>';
2406
+      },
2407
+      'no_results': () => {
2408
+        return '<div class="no-results">No results found</div>';
2409
+      },
2410
+      'loading': () => {
2411
+        return '<div class="spinner"></div>';
2412
+      },
2413
+      'not_loading': () => {},
2414
+      'dropdown': () => {
2415
+        return '<div></div>';
2416
+      }
2417
+    };
2418
+    self.settings.render = Object.assign({}, templates, self.settings.render);
2419
+  }
2420
+  /**
2421
+   * Maps fired events to callbacks provided
2422
+   * in the settings used when creating the control.
2423
+   */
2424
+
2425
+
2426
+  setupCallbacks() {
2427
+    var key, fn;
2428
+    var callbacks = {
2429
+      'initialize': 'onInitialize',
2430
+      'change': 'onChange',
2431
+      'item_add': 'onItemAdd',
2432
+      'item_remove': 'onItemRemove',
2433
+      'item_select': 'onItemSelect',
2434
+      'clear': 'onClear',
2435
+      'option_add': 'onOptionAdd',
2436
+      'option_remove': 'onOptionRemove',
2437
+      'option_clear': 'onOptionClear',
2438
+      'optgroup_add': 'onOptionGroupAdd',
2439
+      'optgroup_remove': 'onOptionGroupRemove',
2440
+      'optgroup_clear': 'onOptionGroupClear',
2441
+      'dropdown_open': 'onDropdownOpen',
2442
+      'dropdown_close': 'onDropdownClose',
2443
+      'type': 'onType',
2444
+      'load': 'onLoad',
2445
+      'focus': 'onFocus',
2446
+      'blur': 'onBlur'
2447
+    };
2448
+
2449
+    for (key in callbacks) {
2450
+      fn = this.settings[callbacks[key]];
2451
+      if (fn) this.on(key, fn);
2452
+    }
2453
+  }
2454
+  /**
2455
+   * Sync the Tom Select instance with the original input or select
2456
+   *
2457
+   */
2458
+
2459
+
2460
+  sync(get_settings = true) {
2461
+    const self = this;
2462
+    const settings = get_settings ? getSettings(self.input, {
2463
+      delimiter: self.settings.delimiter
2464
+    }) : self.settings;
2465
+    self.setupOptions(settings.options, settings.optgroups);
2466
+    self.setValue(settings.items || [], true); // silent prevents recursion
2467
+
2468
+    self.lastQuery = null; // so updated options will be displayed in dropdown
2469
+  }
2470
+  /**
2471
+   * Triggered when the main control element
2472
+   * has a click event.
2473
+   *
2474
+   */
2475
+
2476
+
2477
+  onClick() {
2478
+    var self = this;
2479
+
2480
+    if (self.activeItems.length > 0) {
2481
+      self.clearActiveItems();
2482
+      self.focus();
2483
+      return;
2484
+    }
2485
+
2486
+    if (self.isFocused && self.isOpen) {
2487
+      self.blur();
2488
+    } else {
2489
+      self.focus();
2490
+    }
2491
+  }
2492
+  /**
2493
+   * @deprecated v1.7
2494
+   *
2495
+   */
2496
+
2497
+
2498
+  onMouseDown() {}
2499
+  /**
2500
+   * Triggered when the value of the control has been changed.
2501
+   * This should propagate the event to the original DOM
2502
+   * input / select element.
2503
+   */
2504
+
2505
+
2506
+  onChange() {
2507
+    triggerEvent(this.input, 'input');
2508
+    triggerEvent(this.input, 'change');
2509
+  }
2510
+  /**
2511
+   * Triggered on <input> paste.
2512
+   *
2513
+   */
2514
+
2515
+
2516
+  onPaste(e) {
2517
+    var self = this;
2518
+
2519
+    if (self.isInputHidden || self.isLocked) {
2520
+      preventDefault(e);
2521
+      return;
2522
+    } // If a regex or string is included, this will split the pasted
2523
+    // input and create Items for each separate value
2524
+
2525
+
2526
+    if (!self.settings.splitOn) {
2527
+      return;
2528
+    } // Wait for pasted text to be recognized in value
2529
+
2530
+
2531
+    setTimeout(() => {
2532
+      var pastedText = self.inputValue();
2533
+
2534
+      if (!pastedText.match(self.settings.splitOn)) {
2535
+        return;
2536
+      }
2537
+
2538
+      var splitInput = pastedText.trim().split(self.settings.splitOn);
2539
+      iterate$1(splitInput, piece => {
2540
+        const hash = hash_key(piece);
2541
+
2542
+        if (hash) {
2543
+          if (this.options[piece]) {
2544
+            self.addItem(piece);
2545
+          } else {
2546
+            self.createItem(piece);
2547
+          }
2548
+        }
2549
+      });
2550
+    }, 0);
2551
+  }
2552
+  /**
2553
+   * Triggered on <input> keypress.
2554
+   *
2555
+   */
2556
+
2557
+
2558
+  onKeyPress(e) {
2559
+    var self = this;
2560
+
2561
+    if (self.isLocked) {
2562
+      preventDefault(e);
2563
+      return;
2564
+    }
2565
+
2566
+    var character = String.fromCharCode(e.keyCode || e.which);
2567
+
2568
+    if (self.settings.create && self.settings.mode === 'multi' && character === self.settings.delimiter) {
2569
+      self.createItem();
2570
+      preventDefault(e);
2571
+      return;
2572
+    }
2573
+  }
2574
+  /**
2575
+   * Triggered on <input> keydown.
2576
+   *
2577
+   */
2578
+
2579
+
2580
+  onKeyDown(e) {
2581
+    var self = this;
2582
+    self.ignoreHover = true;
2583
+
2584
+    if (self.isLocked) {
2585
+      if (e.keyCode !== KEY_TAB) {
2586
+        preventDefault(e);
2587
+      }
2588
+
2589
+      return;
2590
+    }
2591
+
2592
+    switch (e.keyCode) {
2593
+      // ctrl+A: select all
2594
+      case KEY_A:
2595
+        if (isKeyDown(KEY_SHORTCUT, e)) {
2596
+          if (self.control_input.value == '') {
2597
+            preventDefault(e);
2598
+            self.selectAll();
2599
+            return;
2600
+          }
2601
+        }
2602
+
2603
+        break;
2604
+      // esc: close dropdown
2605
+
2606
+      case KEY_ESC:
2607
+        if (self.isOpen) {
2608
+          preventDefault(e, true);
2609
+          self.close();
2610
+        }
2611
+
2612
+        self.clearActiveItems();
2613
+        return;
2614
+      // down: open dropdown or move selection down
2615
+
2616
+      case KEY_DOWN:
2617
+        if (!self.isOpen && self.hasOptions) {
2618
+          self.open();
2619
+        } else if (self.activeOption) {
2620
+          let next = self.getAdjacent(self.activeOption, 1);
2621
+          if (next) self.setActiveOption(next);
2622
+        }
2623
+
2624
+        preventDefault(e);
2625
+        return;
2626
+      // up: move selection up
2627
+
2628
+      case KEY_UP:
2629
+        if (self.activeOption) {
2630
+          let prev = self.getAdjacent(self.activeOption, -1);
2631
+          if (prev) self.setActiveOption(prev);
2632
+        }
2633
+
2634
+        preventDefault(e);
2635
+        return;
2636
+      // return: select active option
2637
+
2638
+      case KEY_RETURN:
2639
+        if (self.canSelect(self.activeOption)) {
2640
+          self.onOptionSelect(e, self.activeOption);
2641
+          preventDefault(e); // if the option_create=null, the dropdown might be closed
2642
+        } else if (self.settings.create && self.createItem()) {
2643
+          preventDefault(e); // don't submit form when searching for a value
2644
+        } else if (document.activeElement == self.control_input && self.isOpen) {
2645
+          preventDefault(e);
2646
+        }
2647
+
2648
+        return;
2649
+      // left: modifiy item selection to the left
2650
+
2651
+      case KEY_LEFT:
2652
+        self.advanceSelection(-1, e);
2653
+        return;
2654
+      // right: modifiy item selection to the right
2655
+
2656
+      case KEY_RIGHT:
2657
+        self.advanceSelection(1, e);
2658
+        return;
2659
+      // tab: select active option and/or create item
2660
+
2661
+      case KEY_TAB:
2662
+        if (self.settings.selectOnTab) {
2663
+          if (self.canSelect(self.activeOption)) {
2664
+            self.onOptionSelect(e, self.activeOption); // prevent default [tab] behaviour of jump to the next field
2665
+            // if select isFull, then the dropdown won't be open and [tab] will work normally
2666
+
2667
+            preventDefault(e);
2668
+          }
2669
+
2670
+          if (self.settings.create && self.createItem()) {
2671
+            preventDefault(e);
2672
+          }
2673
+        }
2674
+
2675
+        return;
2676
+      // delete|backspace: delete items
2677
+
2678
+      case KEY_BACKSPACE:
2679
+      case KEY_DELETE:
2680
+        self.deleteSelection(e);
2681
+        return;
2682
+    } // don't enter text in the control_input when active items are selected
2683
+
2684
+
2685
+    if (self.isInputHidden && !isKeyDown(KEY_SHORTCUT, e)) {
2686
+      preventDefault(e);
2687
+    }
2688
+  }
2689
+  /**
2690
+   * Triggered on <input> keyup.
2691
+   *
2692
+   */
2693
+
2694
+
2695
+  onInput(e) {
2696
+    var self = this;
2697
+
2698
+    if (self.isLocked) {
2699
+      return;
2700
+    }
2701
+
2702
+    var value = self.inputValue();
2703
+
2704
+    if (self.lastValue !== value) {
2705
+      self.lastValue = value;
2706
+
2707
+      if (self.settings.shouldLoad.call(self, value)) {
2708
+        self.load(value);
2709
+      }
2710
+
2711
+      self.refreshOptions();
2712
+      self.trigger('type', value);
2713
+    }
2714
+  }
2715
+  /**
2716
+   * Triggered when the user rolls over
2717
+   * an option in the autocomplete dropdown menu.
2718
+   *
2719
+   */
2720
+
2721
+
2722
+  onOptionHover(evt, option) {
2723
+    if (this.ignoreHover) return;
2724
+    this.setActiveOption(option, false);
2725
+  }
2726
+  /**
2727
+   * Triggered on <input> focus.
2728
+   *
2729
+   */
2730
+
2731
+
2732
+  onFocus(e) {
2733
+    var self = this;
2734
+    var wasFocused = self.isFocused;
2735
+
2736
+    if (self.isDisabled) {
2737
+      self.blur();
2738
+      preventDefault(e);
2739
+      return;
2740
+    }
2741
+
2742
+    if (self.ignoreFocus) return;
2743
+    self.isFocused = true;
2744
+    if (self.settings.preload === 'focus') self.preload();
2745
+    if (!wasFocused) self.trigger('focus');
2746
+
2747
+    if (!self.activeItems.length) {
2748
+      self.showInput();
2749
+      self.refreshOptions(!!self.settings.openOnFocus);
2750
+    }
2751
+
2752
+    self.refreshState();
2753
+  }
2754
+  /**
2755
+   * Triggered on <input> blur.
2756
+   *
2757
+   */
2758
+
2759
+
2760
+  onBlur(e) {
2761
+    if (document.hasFocus() === false) return;
2762
+    var self = this;
2763
+    if (!self.isFocused) return;
2764
+    self.isFocused = false;
2765
+    self.ignoreFocus = false;
2766
+
2767
+    var deactivate = () => {
2768
+      self.close();
2769
+      self.setActiveItem();
2770
+      self.setCaret(self.items.length);
2771
+      self.trigger('blur');
2772
+    };
2773
+
2774
+    if (self.settings.create && self.settings.createOnBlur) {
2775
+      self.createItem(null, deactivate);
2776
+    } else {
2777
+      deactivate();
2778
+    }
2779
+  }
2780
+  /**
2781
+   * Triggered when the user clicks on an option
2782
+   * in the autocomplete dropdown menu.
2783
+   *
2784
+   */
2785
+
2786
+
2787
+  onOptionSelect(evt, option) {
2788
+    var value,
2789
+        self = this; // should not be possible to trigger a option under a disabled optgroup
2790
+
2791
+    if (option.parentElement && option.parentElement.matches('[data-disabled]')) {
2792
+      return;
2793
+    }
2794
+
2795
+    if (option.classList.contains('create')) {
2796
+      self.createItem(null, () => {
2797
+        if (self.settings.closeAfterSelect) {
2798
+          self.close();
2799
+        }
2800
+      });
2801
+    } else {
2802
+      value = option.dataset.value;
2803
+
2804
+      if (typeof value !== 'undefined') {
2805
+        self.lastQuery = null;
2806
+        self.addItem(value);
2807
+
2808
+        if (self.settings.closeAfterSelect) {
2809
+          self.close();
2810
+        }
2811
+
2812
+        if (!self.settings.hideSelected && evt.type && /click/.test(evt.type)) {
2813
+          self.setActiveOption(option);
2814
+        }
2815
+      }
2816
+    }
2817
+  }
2818
+  /**
2819
+   * Return true if the given option can be selected
2820
+   *
2821
+   */
2822
+
2823
+
2824
+  canSelect(option) {
2825
+    if (this.isOpen && option && this.dropdown_content.contains(option)) {
2826
+      return true;
2827
+    }
2828
+
2829
+    return false;
2830
+  }
2831
+  /**
2832
+   * Triggered when the user clicks on an item
2833
+   * that has been selected.
2834
+   *
2835
+   */
2836
+
2837
+
2838
+  onItemSelect(evt, item) {
2839
+    var self = this;
2840
+
2841
+    if (!self.isLocked && self.settings.mode === 'multi') {
2842
+      preventDefault(evt);
2843
+      self.setActiveItem(item, evt);
2844
+      return true;
2845
+    }
2846
+
2847
+    return false;
2848
+  }
2849
+  /**
2850
+   * Determines whether or not to invoke
2851
+   * the user-provided option provider / loader
2852
+   *
2853
+   * Note, there is a subtle difference between
2854
+   * this.canLoad() and this.settings.shouldLoad();
2855
+   *
2856
+   *	- settings.shouldLoad() is a user-input validator.
2857
+   *	When false is returned, the not_loading template
2858
+   *	will be added to the dropdown
2859
+   *
2860
+   *	- canLoad() is lower level validator that checks
2861
+   * 	the Tom Select instance. There is no inherent user
2862
+   *	feedback when canLoad returns false
2863
+   *
2864
+   */
2865
+
2866
+
2867
+  canLoad(value) {
2868
+    if (!this.settings.load) return false;
2869
+    if (this.loadedSearches.hasOwnProperty(value)) return false;
2870
+    return true;
2871
+  }
2872
+  /**
2873
+   * Invokes the user-provided option provider / loader.
2874
+   *
2875
+   */
2876
+
2877
+
2878
+  load(value) {
2879
+    const self = this;
2880
+    if (!self.canLoad(value)) return;
2881
+    addClasses(self.wrapper, self.settings.loadingClass);
2882
+    self.loading++;
2883
+    const callback = self.loadCallback.bind(self);
2884
+    self.settings.load.call(self, value, callback);
2885
+  }
2886
+  /**
2887
+   * Invoked by the user-provided option provider
2888
+   *
2889
+   */
2890
+
2891
+
2892
+  loadCallback(options, optgroups) {
2893
+    const self = this;
2894
+    self.loading = Math.max(self.loading - 1, 0);
2895
+    self.lastQuery = null;
2896
+    self.clearActiveOption(); // when new results load, focus should be on first option
2897
+
2898
+    self.setupOptions(options, optgroups);
2899
+    self.refreshOptions(self.isFocused && !self.isInputHidden);
2900
+
2901
+    if (!self.loading) {
2902
+      removeClasses(self.wrapper, self.settings.loadingClass);
2903
+    }
2904
+
2905
+    self.trigger('load', options, optgroups);
2906
+  }
2907
+
2908
+  preload() {
2909
+    var classList = this.wrapper.classList;
2910
+    if (classList.contains('preloaded')) return;
2911
+    classList.add('preloaded');
2912
+    this.load('');
2913
+  }
2914
+  /**
2915
+   * Sets the input field of the control to the specified value.
2916
+   *
2917
+   */
2918
+
2919
+
2920
+  setTextboxValue(value = '') {
2921
+    var input = this.control_input;
2922
+    var changed = input.value !== value;
2923
+
2924
+    if (changed) {
2925
+      input.value = value;
2926
+      triggerEvent(input, 'update');
2927
+      this.lastValue = value;
2928
+    }
2929
+  }
2930
+  /**
2931
+   * Returns the value of the control. If multiple items
2932
+   * can be selected (e.g. <select multiple>), this returns
2933
+   * an array. If only one item can be selected, this
2934
+   * returns a string.
2935
+   *
2936
+   */
2937
+
2938
+
2939
+  getValue() {
2940
+    if (this.is_select_tag && this.input.hasAttribute('multiple')) {
2941
+      return this.items;
2942
+    }
2943
+
2944
+    return this.items.join(this.settings.delimiter);
2945
+  }
2946
+  /**
2947
+   * Resets the selected items to the given value.
2948
+   *
2949
+   */
2950
+
2951
+
2952
+  setValue(value, silent) {
2953
+    var events = silent ? [] : ['change'];
2954
+    debounce_events(this, events, () => {
2955
+      this.clear(silent);
2956
+      this.addItems(value, silent);
2957
+    });
2958
+  }
2959
+  /**
2960
+   * Resets the number of max items to the given value
2961
+   *
2962
+   */
2963
+
2964
+
2965
+  setMaxItems(value) {
2966
+    if (value === 0) value = null; //reset to unlimited items.
2967
+
2968
+    this.settings.maxItems = value;
2969
+    this.refreshState();
2970
+  }
2971
+  /**
2972
+   * Sets the selected item.
2973
+   *
2974
+   */
2975
+
2976
+
2977
+  setActiveItem(item, e) {
2978
+    var self = this;
2979
+    var eventName;
2980
+    var i, begin, end, swap;
2981
+    var last;
2982
+    if (self.settings.mode === 'single') return; // clear the active selection
2983
+
2984
+    if (!item) {
2985
+      self.clearActiveItems();
2986
+
2987
+      if (self.isFocused) {
2988
+        self.showInput();
2989
+      }
2990
+
2991
+      return;
2992
+    } // modify selection
2993
+
2994
+
2995
+    eventName = e && e.type.toLowerCase();
2996
+
2997
+    if (eventName === 'click' && isKeyDown('shiftKey', e) && self.activeItems.length) {
2998
+      last = self.getLastActive();
2999
+      begin = Array.prototype.indexOf.call(self.control.children, last);
3000
+      end = Array.prototype.indexOf.call(self.control.children, item);
3001
+
3002
+      if (begin > end) {
3003
+        swap = begin;
3004
+        begin = end;
3005
+        end = swap;
3006
+      }
3007
+
3008
+      for (i = begin; i <= end; i++) {
3009
+        item = self.control.children[i];
3010
+
3011
+        if (self.activeItems.indexOf(item) === -1) {
3012
+          self.setActiveItemClass(item);
3013
+        }
3014
+      }
3015
+
3016
+      preventDefault(e);
3017
+    } else if (eventName === 'click' && isKeyDown(KEY_SHORTCUT, e) || eventName === 'keydown' && isKeyDown('shiftKey', e)) {
3018
+      if (item.classList.contains('active')) {
3019
+        self.removeActiveItem(item);
3020
+      } else {
3021
+        self.setActiveItemClass(item);
3022
+      }
3023
+    } else {
3024
+      self.clearActiveItems();
3025
+      self.setActiveItemClass(item);
3026
+    } // ensure control has focus
3027
+
3028
+
3029
+    self.hideInput();
3030
+
3031
+    if (!self.isFocused) {
3032
+      self.focus();
3033
+    }
3034
+  }
3035
+  /**
3036
+   * Set the active and last-active classes
3037
+   *
3038
+   */
3039
+
3040
+
3041
+  setActiveItemClass(item) {
3042
+    const self = this;
3043
+    const last_active = self.control.querySelector('.last-active');
3044
+    if (last_active) removeClasses(last_active, 'last-active');
3045
+    addClasses(item, 'active last-active');
3046
+    self.trigger('item_select', item);
3047
+
3048
+    if (self.activeItems.indexOf(item) == -1) {
3049
+      self.activeItems.push(item);
3050
+    }
3051
+  }
3052
+  /**
3053
+   * Remove active item
3054
+   *
3055
+   */
3056
+
3057
+
3058
+  removeActiveItem(item) {
3059
+    var idx = this.activeItems.indexOf(item);
3060
+    this.activeItems.splice(idx, 1);
3061
+    removeClasses(item, 'active');
3062
+  }
3063
+  /**
3064
+   * Clears all the active items
3065
+   *
3066
+   */
3067
+
3068
+
3069
+  clearActiveItems() {
3070
+    removeClasses(this.activeItems, 'active');
3071
+    this.activeItems = [];
3072
+  }
3073
+  /**
3074
+   * Sets the selected item in the dropdown menu
3075
+   * of available options.
3076
+   *
3077
+   */
3078
+
3079
+
3080
+  setActiveOption(option, scroll = true) {
3081
+    if (option === this.activeOption) {
3082
+      return;
3083
+    }
3084
+
3085
+    this.clearActiveOption();
3086
+    if (!option) return;
3087
+    this.activeOption = option;
3088
+    setAttr(this.focus_node, {
3089
+      'aria-activedescendant': option.getAttribute('id')
3090
+    });
3091
+    setAttr(option, {
3092
+      'aria-selected': 'true'
3093
+    });
3094
+    addClasses(option, 'active');
3095
+    if (scroll) this.scrollToOption(option);
3096
+  }
3097
+  /**
3098
+   * Sets the dropdown_content scrollTop to display the option
3099
+   *
3100
+   */
3101
+
3102
+
3103
+  scrollToOption(option, behavior) {
3104
+    if (!option) return;
3105
+    const content = this.dropdown_content;
3106
+    const height_menu = content.clientHeight;
3107
+    const scrollTop = content.scrollTop || 0;
3108
+    const height_item = option.offsetHeight;
3109
+    const y = option.getBoundingClientRect().top - content.getBoundingClientRect().top + scrollTop;
3110
+
3111
+    if (y + height_item > height_menu + scrollTop) {
3112
+      this.scroll(y - height_menu + height_item, behavior);
3113
+    } else if (y < scrollTop) {
3114
+      this.scroll(y, behavior);
3115
+    }
3116
+  }
3117
+  /**
3118
+   * Scroll the dropdown to the given position
3119
+   *
3120
+   */
3121
+
3122
+
3123
+  scroll(scrollTop, behavior) {
3124
+    const content = this.dropdown_content;
3125
+
3126
+    if (behavior) {
3127
+      content.style.scrollBehavior = behavior;
3128
+    }
3129
+
3130
+    content.scrollTop = scrollTop;
3131
+    content.style.scrollBehavior = '';
3132
+  }
3133
+  /**
3134
+   * Clears the active option
3135
+   *
3136
+   */
3137
+
3138
+
3139
+  clearActiveOption() {
3140
+    if (this.activeOption) {
3141
+      removeClasses(this.activeOption, 'active');
3142
+      setAttr(this.activeOption, {
3143
+        'aria-selected': null
3144
+      });
3145
+    }
3146
+
3147
+    this.activeOption = null;
3148
+    setAttr(this.focus_node, {
3149
+      'aria-activedescendant': null
3150
+    });
3151
+  }
3152
+  /**
3153
+   * Selects all items (CTRL + A).
3154
+   */
3155
+
3156
+
3157
+  selectAll() {
3158
+    const self = this;
3159
+    if (self.settings.mode === 'single') return;
3160
+    const activeItems = self.controlChildren();
3161
+    if (!activeItems.length) return;
3162
+    self.hideInput();
3163
+    self.close();
3164
+    self.activeItems = activeItems;
3165
+    iterate$1(activeItems, item => {
3166
+      self.setActiveItemClass(item);
3167
+    });
3168
+  }
3169
+  /**
3170
+   * Determines if the control_input should be in a hidden or visible state
3171
+   *
3172
+   */
3173
+
3174
+
3175
+  inputState() {
3176
+    var self = this;
3177
+    if (!self.control.contains(self.control_input)) return;
3178
+    setAttr(self.control_input, {
3179
+      placeholder: self.settings.placeholder
3180
+    });
3181
+
3182
+    if (self.activeItems.length > 0 || !self.isFocused && self.settings.hidePlaceholder && self.items.length > 0) {
3183
+      self.setTextboxValue();
3184
+      self.isInputHidden = true;
3185
+    } else {
3186
+      if (self.settings.hidePlaceholder && self.items.length > 0) {
3187
+        setAttr(self.control_input, {
3188
+          placeholder: ''
3189
+        });
3190
+      }
3191
+
3192
+      self.isInputHidden = false;
3193
+    }
3194
+
3195
+    self.wrapper.classList.toggle('input-hidden', self.isInputHidden);
3196
+  }
3197
+  /**
3198
+   * Hides the input element out of view, while
3199
+   * retaining its focus.
3200
+   * @deprecated 1.3
3201
+   */
3202
+
3203
+
3204
+  hideInput() {
3205
+    this.inputState();
3206
+  }
3207
+  /**
3208
+   * Restores input visibility.
3209
+   * @deprecated 1.3
3210
+   */
3211
+
3212
+
3213
+  showInput() {
3214
+    this.inputState();
3215
+  }
3216
+  /**
3217
+   * Get the input value
3218
+   */
3219
+
3220
+
3221
+  inputValue() {
3222
+    return this.control_input.value.trim();
3223
+  }
3224
+  /**
3225
+   * Gives the control focus.
3226
+   */
3227
+
3228
+
3229
+  focus() {
3230
+    var self = this;
3231
+    if (self.isDisabled) return;
3232
+    self.ignoreFocus = true;
3233
+
3234
+    if (self.control_input.offsetWidth) {
3235
+      self.control_input.focus();
3236
+    } else {
3237
+      self.focus_node.focus();
3238
+    }
3239
+
3240
+    setTimeout(() => {
3241
+      self.ignoreFocus = false;
3242
+      self.onFocus();
3243
+    }, 0);
3244
+  }
3245
+  /**
3246
+   * Forces the control out of focus.
3247
+   *
3248
+   */
3249
+
3250
+
3251
+  blur() {
3252
+    this.focus_node.blur();
3253
+    this.onBlur();
3254
+  }
3255
+  /**
3256
+   * Returns a function that scores an object
3257
+   * to show how good of a match it is to the
3258
+   * provided query.
3259
+   *
3260
+   * @return {function}
3261
+   */
3262
+
3263
+
3264
+  getScoreFunction(query) {
3265
+    return this.sifter.getScoreFunction(query, this.getSearchOptions());
3266
+  }
3267
+  /**
3268
+   * Returns search options for sifter (the system
3269
+   * for scoring and sorting results).
3270
+   *
3271
+   * @see https://github.com/orchidjs/sifter.js
3272
+   * @return {object}
3273
+   */
3274
+
3275
+
3276
+  getSearchOptions() {
3277
+    var settings = this.settings;
3278
+    var sort = settings.sortField;
3279
+
3280
+    if (typeof settings.sortField === 'string') {
3281
+      sort = [{
3282
+        field: settings.sortField
3283
+      }];
3284
+    }
3285
+
3286
+    return {
3287
+      fields: settings.searchField,
3288
+      conjunction: settings.searchConjunction,
3289
+      sort: sort,
3290
+      nesting: settings.nesting
3291
+    };
3292
+  }
3293
+  /**
3294
+   * Searches through available options and returns
3295
+   * a sorted array of matches.
3296
+   *
3297
+   */
3298
+
3299
+
3300
+  search(query) {
3301
+    var result, calculateScore;
3302
+    var self = this;
3303
+    var options = this.getSearchOptions(); // validate user-provided result scoring function
3304
+
3305
+    if (self.settings.score) {
3306
+      calculateScore = self.settings.score.call(self, query);
3307
+
3308
+      if (typeof calculateScore !== 'function') {
3309
+        throw new Error('Tom Select "score" setting must be a function that returns a function');
3310
+      }
3311
+    } // perform search
3312
+
3313
+
3314
+    if (query !== self.lastQuery) {
3315
+      self.lastQuery = query;
3316
+      result = self.sifter.search(query, Object.assign(options, {
3317
+        score: calculateScore
3318
+      }));
3319
+      self.currentResults = result;
3320
+    } else {
3321
+      result = Object.assign({}, self.currentResults);
3322
+    } // filter out selected items
3323
+
3324
+
3325
+    if (self.settings.hideSelected) {
3326
+      result.items = result.items.filter(item => {
3327
+        let hashed = hash_key(item.id);
3328
+        return !(hashed && self.items.indexOf(hashed) !== -1);
3329
+      });
3330
+    }
3331
+
3332
+    return result;
3333
+  }
3334
+  /**
3335
+   * Refreshes the list of available options shown
3336
+   * in the autocomplete dropdown menu.
3337
+   *
3338
+   */
3339
+
3340
+
3341
+  refreshOptions(triggerDropdown = true) {
3342
+    var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;
3343
+    var create;
3344
+    const groups = {};
3345
+    const groups_order = [];
3346
+    var self = this;
3347
+    var query = self.inputValue();
3348
+    const same_query = query === self.lastQuery || query == '' && self.lastQuery == null;
3349
+    var results = self.search(query);
3350
+    var active_option = null;
3351
+    var show_dropdown = self.settings.shouldOpen || false;
3352
+    var dropdown_content = self.dropdown_content;
3353
+
3354
+    if (same_query) {
3355
+      active_option = self.activeOption;
3356
+
3357
+      if (active_option) {
3358
+        active_group = active_option.closest('[data-group]');
3359
+      }
3360
+    } // build markup
3361
+
3362
+
3363
+    n = results.items.length;
3364
+
3365
+    if (typeof self.settings.maxOptions === 'number') {
3366
+      n = Math.min(n, self.settings.maxOptions);
3367
+    }
3368
+
3369
+    if (n > 0) {
3370
+      show_dropdown = true;
3371
+    } // render and group available options individually
3372
+
3373
+
3374
+    for (i = 0; i < n; i++) {
3375
+      // get option dom element
3376
+      let item = results.items[i];
3377
+      if (!item) continue;
3378
+      let opt_value = item.id;
3379
+      let option = self.options[opt_value];
3380
+      if (option === undefined) continue;
3381
+      let opt_hash = get_hash(opt_value);
3382
+      let option_el = self.getOption(opt_hash, true); // toggle 'selected' class
3383
+
3384
+      if (!self.settings.hideSelected) {
3385
+        option_el.classList.toggle('selected', self.items.includes(opt_hash));
3386
+      }
3387
+
3388
+      optgroup = option[self.settings.optgroupField] || '';
3389
+      optgroups = Array.isArray(optgroup) ? optgroup : [optgroup];
3390
+
3391
+      for (j = 0, k = optgroups && optgroups.length; j < k; j++) {
3392
+        optgroup = optgroups[j];
3393
+
3394
+        if (!self.optgroups.hasOwnProperty(optgroup)) {
3395
+          optgroup = '';
3396
+        }
3397
+
3398
+        let group_fragment = groups[optgroup];
3399
+
3400
+        if (group_fragment === undefined) {
3401
+          group_fragment = document.createDocumentFragment();
3402
+          groups_order.push(optgroup);
3403
+        } // nodes can only have one parent, so if the option is in mutple groups, we need a clone
3404
+
3405
+
3406
+        if (j > 0) {
3407
+          option_el = option_el.cloneNode(true);
3408
+          setAttr(option_el, {
3409
+            id: option.$id + '-clone-' + j,
3410
+            'aria-selected': null
3411
+          });
3412
+          option_el.classList.add('ts-cloned');
3413
+          removeClasses(option_el, 'active'); // make sure we keep the activeOption in the same group
3414
+
3415
+          if (self.activeOption && self.activeOption.dataset.value == opt_value) {
3416
+            if (active_group && active_group.dataset.group === optgroup.toString()) {
3417
+              active_option = option_el;
3418
+            }
3419
+          }
3420
+        }
3421
+
3422
+        group_fragment.appendChild(option_el);
3423
+        groups[optgroup] = group_fragment;
3424
+      }
3425
+    } // sort optgroups
3426
+
3427
+
3428
+    if (self.settings.lockOptgroupOrder) {
3429
+      groups_order.sort((a, b) => {
3430
+        const grp_a = self.optgroups[a];
3431
+        const grp_b = self.optgroups[b];
3432
+        const a_order = grp_a && grp_a.$order || 0;
3433
+        const b_order = grp_b && grp_b.$order || 0;
3434
+        return a_order - b_order;
3435
+      });
3436
+    } // render optgroup headers & join groups
3437
+
3438
+
3439
+    html = document.createDocumentFragment();
3440
+    iterate$1(groups_order, optgroup => {
3441
+      let group_fragment = groups[optgroup];
3442
+      if (!group_fragment || !group_fragment.children.length) return;
3443
+      let group_heading = self.optgroups[optgroup];
3444
+
3445
+      if (group_heading !== undefined) {
3446
+        let group_options = document.createDocumentFragment();
3447
+        let header = self.render('optgroup_header', group_heading);
3448
+        append(group_options, header);
3449
+        append(group_options, group_fragment);
3450
+        let group_html = self.render('optgroup', {
3451
+          group: group_heading,
3452
+          options: group_options
3453
+        });
3454
+        append(html, group_html);
3455
+      } else {
3456
+        append(html, group_fragment);
3457
+      }
3458
+    });
3459
+    dropdown_content.innerHTML = '';
3460
+    append(dropdown_content, html); // highlight matching terms inline
3461
+
3462
+    if (self.settings.highlight) {
3463
+      removeHighlight(dropdown_content);
3464
+
3465
+      if (results.query.length && results.tokens.length) {
3466
+        iterate$1(results.tokens, tok => {
3467
+          highlight(dropdown_content, tok.regex);
3468
+        });
3469
+      }
3470
+    } // helper method for adding templates to dropdown
3471
+
3472
+
3473
+    var add_template = template => {
3474
+      let content = self.render(template, {
3475
+        input: query
3476
+      });
3477
+
3478
+      if (content) {
3479
+        show_dropdown = true;
3480
+        dropdown_content.insertBefore(content, dropdown_content.firstChild);
3481
+      }
3482
+
3483
+      return content;
3484
+    }; // add loading message
3485
+
3486
+
3487
+    if (self.loading) {
3488
+      add_template('loading'); // invalid query
3489
+    } else if (!self.settings.shouldLoad.call(self, query)) {
3490
+      add_template('not_loading'); // add no_results message
3491
+    } else if (results.items.length === 0) {
3492
+      add_template('no_results');
3493
+    } // add create option
3494
+
3495
+
3496
+    has_create_option = self.canCreate(query);
3497
+
3498
+    if (has_create_option) {
3499
+      create = add_template('option_create');
3500
+    } // activate
3501
+
3502
+
3503
+    self.hasOptions = results.items.length > 0 || has_create_option;
3504
+
3505
+    if (show_dropdown) {
3506
+      if (results.items.length > 0) {
3507
+        if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {
3508
+          active_option = self.getOption(self.items[0]);
3509
+        }
3510
+
3511
+        if (!dropdown_content.contains(active_option)) {
3512
+          let active_index = 0;
3513
+
3514
+          if (create && !self.settings.addPrecedence) {
3515
+            active_index = 1;
3516
+          }
3517
+
3518
+          active_option = self.selectable()[active_index];
3519
+        }
3520
+      } else if (create) {
3521
+        active_option = create;
3522
+      }
3523
+
3524
+      if (triggerDropdown && !self.isOpen) {
3525
+        self.open();
3526
+        self.scrollToOption(active_option, 'auto');
3527
+      }
3528
+
3529
+      self.setActiveOption(active_option);
3530
+    } else {
3531
+      self.clearActiveOption();
3532
+
3533
+      if (triggerDropdown && self.isOpen) {
3534
+        self.close(false); // if create_option=null, we want the dropdown to close but not reset the textbox value
3535
+      }
3536
+    }
3537
+  }
3538
+  /**
3539
+   * Return list of selectable options
3540
+   *
3541
+   */
3542
+
3543
+
3544
+  selectable() {
3545
+    return this.dropdown_content.querySelectorAll('[data-selectable]');
3546
+  }
3547
+  /**
3548
+   * Adds an available option. If it already exists,
3549
+   * nothing will happen. Note: this does not refresh
3550
+   * the options list dropdown (use `refreshOptions`
3551
+   * for that).
3552
+   *
3553
+   * Usage:
3554
+   *
3555
+   *   this.addOption(data)
3556
+   *
3557
+   */
3558
+
3559
+
3560
+  addOption(data, user_created = false) {
3561
+    const self = this; // @deprecated 1.7.7
3562
+    // use addOptions( array, user_created ) for adding multiple options
3563
+
3564
+    if (Array.isArray(data)) {
3565
+      self.addOptions(data, user_created);
3566
+      return false;
3567
+    }
3568
+
3569
+    const key = hash_key(data[self.settings.valueField]);
3570
+
3571
+    if (key === null || self.options.hasOwnProperty(key)) {
3572
+      return false;
3573
+    }
3574
+
3575
+    data.$order = data.$order || ++self.order;
3576
+    data.$id = self.inputId + '-opt-' + data.$order;
3577
+    self.options[key] = data;
3578
+    self.lastQuery = null;
3579
+
3580
+    if (user_created) {
3581
+      self.userOptions[key] = user_created;
3582
+      self.trigger('option_add', key, data);
3583
+    }
3584
+
3585
+    return key;
3586
+  }
3587
+  /**
3588
+   * Add multiple options
3589
+   *
3590
+   */
3591
+
3592
+
3593
+  addOptions(data, user_created = false) {
3594
+    iterate$1(data, dat => {
3595
+      this.addOption(dat, user_created);
3596
+    });
3597
+  }
3598
+  /**
3599
+   * @deprecated 1.7.7
3600
+   */
3601
+
3602
+
3603
+  registerOption(data) {
3604
+    return this.addOption(data);
3605
+  }
3606
+  /**
3607
+   * Registers an option group to the pool of option groups.
3608
+   *
3609
+   * @return {boolean|string}
3610
+   */
3611
+
3612
+
3613
+  registerOptionGroup(data) {
3614
+    var key = hash_key(data[this.settings.optgroupValueField]);
3615
+    if (key === null) return false;
3616
+    data.$order = data.$order || ++this.order;
3617
+    this.optgroups[key] = data;
3618
+    return key;
3619
+  }
3620
+  /**
3621
+   * Registers a new optgroup for options
3622
+   * to be bucketed into.
3623
+   *
3624
+   */
3625
+
3626
+
3627
+  addOptionGroup(id, data) {
3628
+    var hashed_id;
3629
+    data[this.settings.optgroupValueField] = id;
3630
+
3631
+    if (hashed_id = this.registerOptionGroup(data)) {
3632
+      this.trigger('optgroup_add', hashed_id, data);
3633
+    }
3634
+  }
3635
+  /**
3636
+   * Removes an existing option group.
3637
+   *
3638
+   */
3639
+
3640
+
3641
+  removeOptionGroup(id) {
3642
+    if (this.optgroups.hasOwnProperty(id)) {
3643
+      delete this.optgroups[id];
3644
+      this.clearCache();
3645
+      this.trigger('optgroup_remove', id);
3646
+    }
3647
+  }
3648
+  /**
3649
+   * Clears all existing option groups.
3650
+   */
3651
+
3652
+
3653
+  clearOptionGroups() {
3654
+    this.optgroups = {};
3655
+    this.clearCache();
3656
+    this.trigger('optgroup_clear');
3657
+  }
3658
+  /**
3659
+   * Updates an option available for selection. If
3660
+   * it is visible in the selected items or options
3661
+   * dropdown, it will be re-rendered automatically.
3662
+   *
3663
+   */
3664
+
3665
+
3666
+  updateOption(value, data) {
3667
+    const self = this;
3668
+    var item_new;
3669
+    var index_item;
3670
+    const value_old = hash_key(value);
3671
+    const value_new = hash_key(data[self.settings.valueField]); // sanity checks
3672
+
3673
+    if (value_old === null) return;
3674
+    const data_old = self.options[value_old];
3675
+    if (data_old == undefined) return;
3676
+    if (typeof value_new !== 'string') throw new Error('Value must be set in option data');
3677
+    const option = self.getOption(value_old);
3678
+    const item = self.getItem(value_old);
3679
+    data.$order = data.$order || data_old.$order;
3680
+    delete self.options[value_old]; // invalidate render cache
3681
+    // don't remove existing node yet, we'll remove it after replacing it
3682
+
3683
+    self.uncacheValue(value_new);
3684
+    self.options[value_new] = data; // update the option if it's in the dropdown
3685
+
3686
+    if (option) {
3687
+      if (self.dropdown_content.contains(option)) {
3688
+        const option_new = self._render('option', data);
3689
+
3690
+        replaceNode(option, option_new);
3691
+
3692
+        if (self.activeOption === option) {
3693
+          self.setActiveOption(option_new);
3694
+        }
3695
+      }
3696
+
3697
+      option.remove();
3698
+    } // update the item if we have one
3699
+
3700
+
3701
+    if (item) {
3702
+      index_item = self.items.indexOf(value_old);
3703
+
3704
+      if (index_item !== -1) {
3705
+        self.items.splice(index_item, 1, value_new);
3706
+      }
3707
+
3708
+      item_new = self._render('item', data);
3709
+      if (item.classList.contains('active')) addClasses(item_new, 'active');
3710
+      replaceNode(item, item_new);
3711
+    } // invalidate last query because we might have updated the sortField
3712
+
3713
+
3714
+    self.lastQuery = null;
3715
+  }
3716
+  /**
3717
+   * Removes a single option.
3718
+   *
3719
+   */
3720
+
3721
+
3722
+  removeOption(value, silent) {
3723
+    const self = this;
3724
+    value = get_hash(value);
3725
+    self.uncacheValue(value);
3726
+    delete self.userOptions[value];
3727
+    delete self.options[value];
3728
+    self.lastQuery = null;
3729
+    self.trigger('option_remove', value);
3730
+    self.removeItem(value, silent);
3731
+  }
3732
+  /**
3733
+   * Clears all options.
3734
+   */
3735
+
3736
+
3737
+  clearOptions(filter) {
3738
+    const boundFilter = (filter || this.clearFilter).bind(this);
3739
+    this.loadedSearches = {};
3740
+    this.userOptions = {};
3741
+    this.clearCache();
3742
+    const selected = {};
3743
+    iterate$1(this.options, (option, key) => {
3744
+      if (boundFilter(option, key)) {
3745
+        selected[key] = option;
3746
+      }
3747
+    });
3748
+    this.options = this.sifter.items = selected;
3749
+    this.lastQuery = null;
3750
+    this.trigger('option_clear');
3751
+  }
3752
+  /**
3753
+   * Used by clearOptions() to decide whether or not an option should be removed
3754
+   * Return true to keep an option, false to remove
3755
+   *
3756
+   */
3757
+
3758
+
3759
+  clearFilter(option, value) {
3760
+    if (this.items.indexOf(value) >= 0) {
3761
+      return true;
3762
+    }
3763
+
3764
+    return false;
3765
+  }
3766
+  /**
3767
+   * Returns the dom element of the option
3768
+   * matching the given value.
3769
+   *
3770
+   */
3771
+
3772
+
3773
+  getOption(value, create = false) {
3774
+    const hashed = hash_key(value);
3775
+    if (hashed === null) return null;
3776
+    const option = this.options[hashed];
3777
+
3778
+    if (option != undefined) {
3779
+      if (option.$div) {
3780
+        return option.$div;
3781
+      }
3782
+
3783
+      if (create) {
3784
+        return this._render('option', option);
3785
+      }
3786
+    }
3787
+
3788
+    return null;
3789
+  }
3790
+  /**
3791
+   * Returns the dom element of the next or previous dom element of the same type
3792
+   * Note: adjacent options may not be adjacent DOM elements (optgroups)
3793
+   *
3794
+   */
3795
+
3796
+
3797
+  getAdjacent(option, direction, type = 'option') {
3798
+    var self = this,
3799
+        all;
3800
+
3801
+    if (!option) {
3802
+      return null;
3803
+    }
3804
+
3805
+    if (type == 'item') {
3806
+      all = self.controlChildren();
3807
+    } else {
3808
+      all = self.dropdown_content.querySelectorAll('[data-selectable]');
3809
+    }
3810
+
3811
+    for (let i = 0; i < all.length; i++) {
3812
+      if (all[i] != option) {
3813
+        continue;
3814
+      }
3815
+
3816
+      if (direction > 0) {
3817
+        return all[i + 1];
3818
+      }
3819
+
3820
+      return all[i - 1];
3821
+    }
3822
+
3823
+    return null;
3824
+  }
3825
+  /**
3826
+   * Returns the dom element of the item
3827
+   * matching the given value.
3828
+   *
3829
+   */
3830
+
3831
+
3832
+  getItem(item) {
3833
+    if (typeof item == 'object') {
3834
+      return item;
3835
+    }
3836
+
3837
+    var value = hash_key(item);
3838
+    return value !== null ? this.control.querySelector(`[data-value="${addSlashes(value)}"]`) : null;
3839
+  }
3840
+  /**
3841
+   * "Selects" multiple items at once. Adds them to the list
3842
+   * at the current caret position.
3843
+   *
3844
+   */
3845
+
3846
+
3847
+  addItems(values, silent) {
3848
+    var self = this;
3849
+    var items = Array.isArray(values) ? values : [values];
3850
+    items = items.filter(x => self.items.indexOf(x) === -1);
3851
+    const last_item = items[items.length - 1];
3852
+    items.forEach(item => {
3853
+      self.isPending = item !== last_item;
3854
+      self.addItem(item, silent);
3855
+    });
3856
+  }
3857
+  /**
3858
+   * "Selects" an item. Adds it to the list
3859
+   * at the current caret position.
3860
+   *
3861
+   */
3862
+
3863
+
3864
+  addItem(value, silent) {
3865
+    var events = silent ? [] : ['change', 'dropdown_close'];
3866
+    debounce_events(this, events, () => {
3867
+      var item, wasFull;
3868
+      const self = this;
3869
+      const inputMode = self.settings.mode;
3870
+      const hashed = hash_key(value);
3871
+
3872
+      if (hashed && self.items.indexOf(hashed) !== -1) {
3873
+        if (inputMode === 'single') {
3874
+          self.close();
3875
+        }
3876
+
3877
+        if (inputMode === 'single' || !self.settings.duplicates) {
3878
+          return;
3879
+        }
3880
+      }
3881
+
3882
+      if (hashed === null || !self.options.hasOwnProperty(hashed)) return;
3883
+      if (inputMode === 'single') self.clear(silent);
3884
+      if (inputMode === 'multi' && self.isFull()) return;
3885
+      item = self._render('item', self.options[hashed]);
3886
+
3887
+      if (self.control.contains(item)) {
3888
+        // duplicates
3889
+        item = item.cloneNode(true);
3890
+      }
3891
+
3892
+      wasFull = self.isFull();
3893
+      self.items.splice(self.caretPos, 0, hashed);
3894
+      self.insertAtCaret(item);
3895
+
3896
+      if (self.isSetup) {
3897
+        // update menu / remove the option (if this is not one item being added as part of series)
3898
+        if (!self.isPending && self.settings.hideSelected) {
3899
+          let option = self.getOption(hashed);
3900
+          let next = self.getAdjacent(option, 1);
3901
+
3902
+          if (next) {
3903
+            self.setActiveOption(next);
3904
+          }
3905
+        } // refreshOptions after setActiveOption(),
3906
+        // otherwise setActiveOption() will be called by refreshOptions() with the wrong value
3907
+
3908
+
3909
+        if (!self.isPending && !self.settings.closeAfterSelect) {
3910
+          self.refreshOptions(self.isFocused && inputMode !== 'single');
3911
+        } // hide the menu if the maximum number of items have been selected or no options are left
3912
+
3913
+
3914
+        if (self.settings.closeAfterSelect != false && self.isFull()) {
3915
+          self.close();
3916
+        } else if (!self.isPending) {
3917
+          self.positionDropdown();
3918
+        }
3919
+
3920
+        self.trigger('item_add', hashed, item);
3921
+
3922
+        if (!self.isPending) {
3923
+          self.updateOriginalInput({
3924
+            silent: silent
3925
+          });
3926
+        }
3927
+      }
3928
+
3929
+      if (!self.isPending || !wasFull && self.isFull()) {
3930
+        self.inputState();
3931
+        self.refreshState();
3932
+      }
3933
+    });
3934
+  }
3935
+  /**
3936
+   * Removes the selected item matching
3937
+   * the provided value.
3938
+   *
3939
+   */
3940
+
3941
+
3942
+  removeItem(item = null, silent) {
3943
+    const self = this;
3944
+    item = self.getItem(item);
3945
+    if (!item) return;
3946
+    var i, idx;
3947
+    const value = item.dataset.value;
3948
+    i = nodeIndex(item);
3949
+    item.remove();
3950
+
3951
+    if (item.classList.contains('active')) {
3952
+      idx = self.activeItems.indexOf(item);
3953
+      self.activeItems.splice(idx, 1);
3954
+      removeClasses(item, 'active');
3955
+    }
3956
+
3957
+    self.items.splice(i, 1);
3958
+    self.lastQuery = null;
3959
+
3960
+    if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
3961
+      self.removeOption(value, silent);
3962
+    }
3963
+
3964
+    if (i < self.caretPos) {
3965
+      self.setCaret(self.caretPos - 1);
3966
+    }
3967
+
3968
+    self.updateOriginalInput({
3969
+      silent: silent
3970
+    });
3971
+    self.refreshState();
3972
+    self.positionDropdown();
3973
+    self.trigger('item_remove', value, item);
3974
+  }
3975
+  /**
3976
+   * Invokes the `create` method provided in the
3977
+   * TomSelect options that should provide the data
3978
+   * for the new item, given the user input.
3979
+   *
3980
+   * Once this completes, it will be added
3981
+   * to the item list.
3982
+   *
3983
+   */
3984
+
3985
+
3986
+  createItem(input = null, callback = () => {}) {
3987
+    // triggerDropdown parameter @deprecated 2.1.1
3988
+    if (arguments.length === 3) {
3989
+      callback = arguments[2];
3990
+    }
3991
+
3992
+    if (typeof callback != 'function') {
3993
+      callback = () => {};
3994
+    }
3995
+
3996
+    var self = this;
3997
+    var caret = self.caretPos;
3998
+    var output;
3999
+    input = input || self.inputValue();
4000
+
4001
+    if (!self.canCreate(input)) {
4002
+      callback();
4003
+      return false;
4004
+    }
4005
+
4006
+    self.lock();
4007
+    var created = false;
4008
+
4009
+    var create = data => {
4010
+      self.unlock();
4011
+      if (!data || typeof data !== 'object') return callback();
4012
+      var value = hash_key(data[self.settings.valueField]);
4013
+
4014
+      if (typeof value !== 'string') {
4015
+        return callback();
4016
+      }
4017
+
4018
+      self.setTextboxValue();
4019
+      self.addOption(data, true);
4020
+      self.setCaret(caret);
4021
+      self.addItem(value);
4022
+      callback(data);
4023
+      created = true;
4024
+    };
4025
+
4026
+    if (typeof self.settings.create === 'function') {
4027
+      output = self.settings.create.call(this, input, create);
4028
+    } else {
4029
+      output = {
4030
+        [self.settings.labelField]: input,
4031
+        [self.settings.valueField]: input
4032
+      };
4033
+    }
4034
+
4035
+    if (!created) {
4036
+      create(output);
4037
+    }
4038
+
4039
+    return true;
4040
+  }
4041
+  /**
4042
+   * Re-renders the selected item lists.
4043
+   */
4044
+
4045
+
4046
+  refreshItems() {
4047
+    var self = this;
4048
+    self.lastQuery = null;
4049
+
4050
+    if (self.isSetup) {
4051
+      self.addItems(self.items);
4052
+    }
4053
+
4054
+    self.updateOriginalInput();
4055
+    self.refreshState();
4056
+  }
4057
+  /**
4058
+   * Updates all state-dependent attributes
4059
+   * and CSS classes.
4060
+   */
4061
+
4062
+
4063
+  refreshState() {
4064
+    const self = this;
4065
+    self.refreshValidityState();
4066
+    const isFull = self.isFull();
4067
+    const isLocked = self.isLocked;
4068
+    self.wrapper.classList.toggle('rtl', self.rtl);
4069
+    const wrap_classList = self.wrapper.classList;
4070
+    wrap_classList.toggle('focus', self.isFocused);
4071
+    wrap_classList.toggle('disabled', self.isDisabled);
4072
+    wrap_classList.toggle('required', self.isRequired);
4073
+    wrap_classList.toggle('invalid', !self.isValid);
4074
+    wrap_classList.toggle('locked', isLocked);
4075
+    wrap_classList.toggle('full', isFull);
4076
+    wrap_classList.toggle('input-active', self.isFocused && !self.isInputHidden);
4077
+    wrap_classList.toggle('dropdown-active', self.isOpen);
4078
+    wrap_classList.toggle('has-options', isEmptyObject(self.options));
4079
+    wrap_classList.toggle('has-items', self.items.length > 0);
4080
+  }
4081
+  /**
4082
+   * Update the `required` attribute of both input and control input.
4083
+   *
4084
+   * The `required` property needs to be activated on the control input
4085
+   * for the error to be displayed at the right place. `required` also
4086
+   * needs to be temporarily deactivated on the input since the input is
4087
+   * hidden and can't show errors.
4088
+   */
4089
+
4090
+
4091
+  refreshValidityState() {
4092
+    var self = this;
4093
+
4094
+    if (!self.input.validity) {
4095
+      return;
4096
+    }
4097
+
4098
+    self.isValid = self.input.validity.valid;
4099
+    self.isInvalid = !self.isValid;
4100
+  }
4101
+  /**
4102
+   * Determines whether or not more items can be added
4103
+   * to the control without exceeding the user-defined maximum.
4104
+   *
4105
+   * @returns {boolean}
4106
+   */
4107
+
4108
+
4109
+  isFull() {
4110
+    return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
4111
+  }
4112
+  /**
4113
+   * Refreshes the original <select> or <input>
4114
+   * element to reflect the current state.
4115
+   *
4116
+   */
4117
+
4118
+
4119
+  updateOriginalInput(opts = {}) {
4120
+    const self = this;
4121
+    var option, label;
4122
+    const empty_option = self.input.querySelector('option[value=""]');
4123
+
4124
+    if (self.is_select_tag) {
4125
+      const selected = [];
4126
+      const has_selected = self.input.querySelectorAll('option:checked').length;
4127
+
4128
+      function AddSelected(option_el, value, label) {
4129
+        if (!option_el) {
4130
+          option_el = getDom('<option value="' + escape_html(value) + '">' + escape_html(label) + '</option>');
4131
+        } // don't move empty option from top of list
4132
+        // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293
4133
+
4134
+
4135
+        if (option_el != empty_option) {
4136
+          self.input.append(option_el);
4137
+        }
4138
+
4139
+        selected.push(option_el); // marking empty option as selected can break validation
4140
+        // fixes https://github.com/orchidjs/tom-select/issues/303
4141
+
4142
+        if (option_el != empty_option || has_selected > 0) {
4143
+          option_el.selected = true;
4144
+        }
4145
+
4146
+        return option_el;
4147
+      } // unselect all selected options
4148
+
4149
+
4150
+      self.input.querySelectorAll('option:checked').forEach(option_el => {
4151
+        option_el.selected = false;
4152
+      }); // nothing selected?
4153
+
4154
+      if (self.items.length == 0 && self.settings.mode == 'single') {
4155
+        AddSelected(empty_option, "", ""); // order selected <option> tags for values in self.items
4156
+      } else {
4157
+        self.items.forEach(value => {
4158
+          option = self.options[value];
4159
+          label = option[self.settings.labelField] || '';
4160
+
4161
+          if (selected.includes(option.$option)) {
4162
+            const reuse_opt = self.input.querySelector(`option[value="${addSlashes(value)}"]:not(:checked)`);
4163
+            AddSelected(reuse_opt, value, label);
4164
+          } else {
4165
+            option.$option = AddSelected(option.$option, value, label);
4166
+          }
4167
+        });
4168
+      }
4169
+    } else {
4170
+      self.input.value = self.getValue();
4171
+    }
4172
+
4173
+    if (self.isSetup) {
4174
+      if (!opts.silent) {
4175
+        self.trigger('change', self.getValue());
4176
+      }
4177
+    }
4178
+  }
4179
+  /**
4180
+   * Shows the autocomplete dropdown containing
4181
+   * the available options.
4182
+   */
4183
+
4184
+
4185
+  open() {
4186
+    var self = this;
4187
+    if (self.isLocked || self.isOpen || self.settings.mode === 'multi' && self.isFull()) return;
4188
+    self.isOpen = true;
4189
+    setAttr(self.focus_node, {
4190
+      'aria-expanded': 'true'
4191
+    });
4192
+    self.refreshState();
4193
+    applyCSS(self.dropdown, {
4194
+      visibility: 'hidden',
4195
+      display: 'block'
4196
+    });
4197
+    self.positionDropdown();
4198
+    applyCSS(self.dropdown, {
4199
+      visibility: 'visible',
4200
+      display: 'block'
4201
+    });
4202
+    self.focus();
4203
+    self.trigger('dropdown_open', self.dropdown);
4204
+  }
4205
+  /**
4206
+   * Closes the autocomplete dropdown menu.
4207
+   */
4208
+
4209
+
4210
+  close(setTextboxValue = true) {
4211
+    var self = this;
4212
+    var trigger = self.isOpen;
4213
+
4214
+    if (setTextboxValue) {
4215
+      // before blur() to prevent form onchange event
4216
+      self.setTextboxValue();
4217
+
4218
+      if (self.settings.mode === 'single' && self.items.length) {
4219
+        self.hideInput();
4220
+      }
4221
+    }
4222
+
4223
+    self.isOpen = false;
4224
+    setAttr(self.focus_node, {
4225
+      'aria-expanded': 'false'
4226
+    });
4227
+    applyCSS(self.dropdown, {
4228
+      display: 'none'
4229
+    });
4230
+
4231
+    if (self.settings.hideSelected) {
4232
+      self.clearActiveOption();
4233
+    }
4234
+
4235
+    self.refreshState();
4236
+    if (trigger) self.trigger('dropdown_close', self.dropdown);
4237
+  }
4238
+  /**
4239
+   * Calculates and applies the appropriate
4240
+   * position of the dropdown if dropdownParent = 'body'.
4241
+   * Otherwise, position is determined by css
4242
+   */
4243
+
4244
+
4245
+  positionDropdown() {
4246
+    if (this.settings.dropdownParent !== 'body') {
4247
+      return;
4248
+    }
4249
+
4250
+    var context = this.control;
4251
+    var rect = context.getBoundingClientRect();
4252
+    var top = context.offsetHeight + rect.top + window.scrollY;
4253
+    var left = rect.left + window.scrollX;
4254
+    applyCSS(this.dropdown, {
4255
+      width: rect.width + 'px',
4256
+      top: top + 'px',
4257
+      left: left + 'px'
4258
+    });
4259
+  }
4260
+  /**
4261
+   * Resets / clears all selected items
4262
+   * from the control.
4263
+   *
4264
+   */
4265
+
4266
+
4267
+  clear(silent) {
4268
+    var self = this;
4269
+    if (!self.items.length) return;
4270
+    var items = self.controlChildren();
4271
+    iterate$1(items, item => {
4272
+      self.removeItem(item, true);
4273
+    });
4274
+    self.showInput();
4275
+    if (!silent) self.updateOriginalInput();
4276
+    self.trigger('clear');
4277
+  }
4278
+  /**
4279
+   * A helper method for inserting an element
4280
+   * at the current caret position.
4281
+   *
4282
+   */
4283
+
4284
+
4285
+  insertAtCaret(el) {
4286
+    const self = this;
4287
+    const caret = self.caretPos;
4288
+    const target = self.control;
4289
+    target.insertBefore(el, target.children[caret] || null);
4290
+    self.setCaret(caret + 1);
4291
+  }
4292
+  /**
4293
+   * Removes the current selected item(s).
4294
+   *
4295
+   */
4296
+
4297
+
4298
+  deleteSelection(e) {
4299
+    var direction, selection, caret, tail;
4300
+    var self = this;
4301
+    direction = e && e.keyCode === KEY_BACKSPACE ? -1 : 1;
4302
+    selection = getSelection(self.control_input); // determine items that will be removed
4303
+
4304
+    const rm_items = [];
4305
+
4306
+    if (self.activeItems.length) {
4307
+      tail = getTail(self.activeItems, direction);
4308
+      caret = nodeIndex(tail);
4309
+
4310
+      if (direction > 0) {
4311
+        caret++;
4312
+      }
4313
+
4314
+      iterate$1(self.activeItems, item => rm_items.push(item));
4315
+    } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
4316
+      const items = self.controlChildren();
4317
+      let rm_item;
4318
+
4319
+      if (direction < 0 && selection.start === 0 && selection.length === 0) {
4320
+        rm_item = items[self.caretPos - 1];
4321
+      } else if (direction > 0 && selection.start === self.inputValue().length) {
4322
+        rm_item = items[self.caretPos];
4323
+      }
4324
+
4325
+      if (rm_item !== undefined) {
4326
+        rm_items.push(rm_item);
4327
+      }
4328
+    }
4329
+
4330
+    if (!self.shouldDelete(rm_items, e)) {
4331
+      return false;
4332
+    }
4333
+
4334
+    preventDefault(e, true); // perform removal
4335
+
4336
+    if (typeof caret !== 'undefined') {
4337
+      self.setCaret(caret);
4338
+    }
4339
+
4340
+    while (rm_items.length) {
4341
+      self.removeItem(rm_items.pop());
4342
+    }
4343
+
4344
+    self.showInput();
4345
+    self.positionDropdown();
4346
+    self.refreshOptions(false);
4347
+    return true;
4348
+  }
4349
+  /**
4350
+   * Return true if the items should be deleted
4351
+   */
4352
+
4353
+
4354
+  shouldDelete(items, evt) {
4355
+    const values = items.map(item => item.dataset.value); // allow the callback to abort
4356
+
4357
+    if (!values.length || typeof this.settings.onDelete === 'function' && this.settings.onDelete(values, evt) === false) {
4358
+      return false;
4359
+    }
4360
+
4361
+    return true;
4362
+  }
4363
+  /**
4364
+   * Selects the previous / next item (depending on the `direction` argument).
4365
+   *
4366
+   * > 0 - right
4367
+   * < 0 - left
4368
+   *
4369
+   */
4370
+
4371
+
4372
+  advanceSelection(direction, e) {
4373
+    var last_active,
4374
+        adjacent,
4375
+        self = this;
4376
+    if (self.rtl) direction *= -1;
4377
+    if (self.inputValue().length) return; // add or remove to active items
4378
+
4379
+    if (isKeyDown(KEY_SHORTCUT, e) || isKeyDown('shiftKey', e)) {
4380
+      last_active = self.getLastActive(direction);
4381
+
4382
+      if (last_active) {
4383
+        if (!last_active.classList.contains('active')) {
4384
+          adjacent = last_active;
4385
+        } else {
4386
+          adjacent = self.getAdjacent(last_active, direction, 'item');
4387
+        } // if no active item, get items adjacent to the control input
4388
+
4389
+      } else if (direction > 0) {
4390
+        adjacent = self.control_input.nextElementSibling;
4391
+      } else {
4392
+        adjacent = self.control_input.previousElementSibling;
4393
+      }
4394
+
4395
+      if (adjacent) {
4396
+        if (adjacent.classList.contains('active')) {
4397
+          self.removeActiveItem(last_active);
4398
+        }
4399
+
4400
+        self.setActiveItemClass(adjacent); // mark as last_active !! after removeActiveItem() on last_active
4401
+      } // move caret to the left or right
4402
+
4403
+    } else {
4404
+      self.moveCaret(direction);
4405
+    }
4406
+  }
4407
+
4408
+  moveCaret(direction) {}
4409
+  /**
4410
+   * Get the last active item
4411
+   *
4412
+   */
4413
+
4414
+
4415
+  getLastActive(direction) {
4416
+    let last_active = this.control.querySelector('.last-active');
4417
+
4418
+    if (last_active) {
4419
+      return last_active;
4420
+    }
4421
+
4422
+    var result = this.control.querySelectorAll('.active');
4423
+
4424
+    if (result) {
4425
+      return getTail(result, direction);
4426
+    }
4427
+  }
4428
+  /**
4429
+   * Moves the caret to the specified index.
4430
+   *
4431
+   * The input must be moved by leaving it in place and moving the
4432
+   * siblings, due to the fact that focus cannot be restored once lost
4433
+   * on mobile webkit devices
4434
+   *
4435
+   */
4436
+
4437
+
4438
+  setCaret(new_pos) {
4439
+    this.caretPos = this.items.length;
4440
+  }
4441
+  /**
4442
+   * Return list of item dom elements
4443
+   *
4444
+   */
4445
+
4446
+
4447
+  controlChildren() {
4448
+    return Array.from(this.control.querySelectorAll('[data-ts-item]'));
4449
+  }
4450
+  /**
4451
+   * Disables user input on the control. Used while
4452
+   * items are being asynchronously created.
4453
+   */
4454
+
4455
+
4456
+  lock() {
4457
+    this.isLocked = true;
4458
+    this.refreshState();
4459
+  }
4460
+  /**
4461
+   * Re-enables user input on the control.
4462
+   */
4463
+
4464
+
4465
+  unlock() {
4466
+    this.isLocked = false;
4467
+    this.refreshState();
4468
+  }
4469
+  /**
4470
+   * Disables user input on the control completely.
4471
+   * While disabled, it cannot receive focus.
4472
+   */
4473
+
4474
+
4475
+  disable() {
4476
+    var self = this;
4477
+    self.input.disabled = true;
4478
+    self.control_input.disabled = true;
4479
+    self.focus_node.tabIndex = -1;
4480
+    self.isDisabled = true;
4481
+    this.close();
4482
+    self.lock();
4483
+  }
4484
+  /**
4485
+   * Enables the control so that it can respond
4486
+   * to focus and user input.
4487
+   */
4488
+
4489
+
4490
+  enable() {
4491
+    var self = this;
4492
+    self.input.disabled = false;
4493
+    self.control_input.disabled = false;
4494
+    self.focus_node.tabIndex = self.tabIndex;
4495
+    self.isDisabled = false;
4496
+    self.unlock();
4497
+  }
4498
+  /**
4499
+   * Completely destroys the control and
4500
+   * unbinds all event listeners so that it can
4501
+   * be garbage collected.
4502
+   */
4503
+
4504
+
4505
+  destroy() {
4506
+    var self = this;
4507
+    var revertSettings = self.revertSettings;
4508
+    self.trigger('destroy');
4509
+    self.off();
4510
+    self.wrapper.remove();
4511
+    self.dropdown.remove();
4512
+    self.input.innerHTML = revertSettings.innerHTML;
4513
+    self.input.tabIndex = revertSettings.tabIndex;
4514
+    removeClasses(self.input, 'tomselected', 'ts-hidden-accessible');
4515
+
4516
+    self._destroy();
4517
+
4518
+    delete self.input.tomselect;
4519
+  }
4520
+  /**
4521
+   * A helper method for rendering "item" and
4522
+   * "option" templates, given the data.
4523
+   *
4524
+   */
4525
+
4526
+
4527
+  render(templateName, data) {
4528
+    var id, html;
4529
+    const self = this;
4530
+
4531
+    if (typeof this.settings.render[templateName] !== 'function') {
4532
+      return null;
4533
+    } // render markup
4534
+
4535
+
4536
+    html = self.settings.render[templateName].call(this, data, escape_html);
4537
+
4538
+    if (!html) {
4539
+      return null;
4540
+    }
4541
+
4542
+    html = getDom(html); // add mandatory attributes
4543
+
4544
+    if (templateName === 'option' || templateName === 'option_create') {
4545
+      if (data[self.settings.disabledField]) {
4546
+        setAttr(html, {
4547
+          'aria-disabled': 'true'
4548
+        });
4549
+      } else {
4550
+        setAttr(html, {
4551
+          'data-selectable': ''
4552
+        });
4553
+      }
4554
+    } else if (templateName === 'optgroup') {
4555
+      id = data.group[self.settings.optgroupValueField];
4556
+      setAttr(html, {
4557
+        'data-group': id
4558
+      });
4559
+
4560
+      if (data.group[self.settings.disabledField]) {
4561
+        setAttr(html, {
4562
+          'data-disabled': ''
4563
+        });
4564
+      }
4565
+    }
4566
+
4567
+    if (templateName === 'option' || templateName === 'item') {
4568
+      const value = get_hash(data[self.settings.valueField]);
4569
+      setAttr(html, {
4570
+        'data-value': value
4571
+      }); // make sure we have some classes if a template is overwritten
4572
+
4573
+      if (templateName === 'item') {
4574
+        addClasses(html, self.settings.itemClass);
4575
+        setAttr(html, {
4576
+          'data-ts-item': ''
4577
+        });
4578
+      } else {
4579
+        addClasses(html, self.settings.optionClass);
4580
+        setAttr(html, {
4581
+          role: 'option',
4582
+          id: data.$id
4583
+        }); // update cache
4584
+
4585
+        data.$div = html;
4586
+        self.options[value] = data;
4587
+      }
4588
+    }
4589
+
4590
+    return html;
4591
+  }
4592
+  /**
4593
+   * Type guarded rendering
4594
+   *
4595
+   */
4596
+
4597
+
4598
+  _render(templateName, data) {
4599
+    const html = this.render(templateName, data);
4600
+
4601
+    if (html == null) {
4602
+      throw 'HTMLElement expected';
4603
+    }
4604
+
4605
+    return html;
4606
+  }
4607
+  /**
4608
+   * Clears the render cache for a template. If
4609
+   * no template is given, clears all render
4610
+   * caches.
4611
+   *
4612
+   */
4613
+
4614
+
4615
+  clearCache() {
4616
+    iterate$1(this.options, option => {
4617
+      if (option.$div) {
4618
+        option.$div.remove();
4619
+        delete option.$div;
4620
+      }
4621
+    });
4622
+  }
4623
+  /**
4624
+   * Removes a value from item and option caches
4625
+   *
4626
+   */
4627
+
4628
+
4629
+  uncacheValue(value) {
4630
+    const option_el = this.getOption(value);
4631
+    if (option_el) option_el.remove();
4632
+  }
4633
+  /**
4634
+   * Determines whether or not to display the
4635
+   * create item prompt, given a user input.
4636
+   *
4637
+   */
4638
+
4639
+
4640
+  canCreate(input) {
4641
+    return this.settings.create && input.length > 0 && this.settings.createFilter.call(this, input);
4642
+  }
4643
+  /**
4644
+   * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method
4645
+   *
4646
+   * this.hook('instead','onKeyDown',function( arg1, arg2 ...){
4647
+   *
4648
+   * });
4649
+   */
4650
+
4651
+
4652
+  hook(when, method, new_fn) {
4653
+    var self = this;
4654
+    var orig_method = self[method];
4655
+
4656
+    self[method] = function () {
4657
+      var result, result_new;
4658
+
4659
+      if (when === 'after') {
4660
+        result = orig_method.apply(self, arguments);
4661
+      }
4662
+
4663
+      result_new = new_fn.apply(self, arguments);
4664
+
4665
+      if (when === 'instead') {
4666
+        return result_new;
4667
+      }
4668
+
4669
+      if (when === 'before') {
4670
+        result = orig_method.apply(self, arguments);
4671
+      }
4672
+
4673
+      return result;
4674
+    };
4675
+  }
4676
+
4677
+}
4678
+
4679
+module.exports = TomSelect;
4680
+//# sourceMappingURL=tom-select.js.map