PageSourceSearch

https://www.myticket.de/assets/myticket/libs/tom-select/dist/js/to…?v=9ce997f9af56631057555b829a79747b9a293c6a

js myticket.de collected 2026-10-01 14:31:19 UTC 151,226 bytes, 5,021 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.