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