tom-select-rails 0.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tom-select-rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.complete.js +882 -310
  4. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.complete.js.map +1 -1
  5. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.js +838 -281
  6. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.js.map +1 -1
  7. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.popular.js +846 -287
  8. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.popular.js.map +1 -1
  9. data/vendor/assets/javascripts/tom-select-rails/cjs/utils.js +1 -1
  10. data/vendor/assets/javascripts/tom-select-rails/cjs/utils.js.map +1 -1
  11. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/caret_position/plugin.js +9 -5
  12. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/caret_position/plugin.js.map +1 -1
  13. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/change_listener/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/change_listener/plugin.js.map +1 -1
  15. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/checkbox_options/plugin.js +18 -11
  16. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/checkbox_options/plugin.js.map +1 -1
  17. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/clear_button/plugin.js +13 -8
  18. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/clear_button/plugin.js.map +1 -1
  19. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/drag_drop/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/drag_drop/plugin.js.map +1 -1
  21. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_header/plugin.js +12 -7
  22. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_header/plugin.js.map +1 -1
  23. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_input/plugin.js +15 -9
  24. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_input/plugin.js.map +1 -1
  25. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/input_autogrow/plugin.js +3 -7
  26. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/input_autogrow/plugin.js.map +1 -1
  27. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_active_items/plugin.js +1 -1
  28. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_active_items/plugin.js.map +1 -1
  29. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_backspace_delete/plugin.js +1 -1
  30. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_backspace_delete/plugin.js.map +1 -1
  31. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/optgroup_columns/plugin.js +10 -4
  32. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/optgroup_columns/plugin.js.map +1 -1
  33. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/remove_button/plugin.js +17 -12
  34. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/remove_button/plugin.js.map +1 -1
  35. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/restore_on_backspace/plugin.js +1 -1
  36. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/restore_on_backspace/plugin.js.map +1 -1
  37. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/virtual_scroll/plugin.js +35 -17
  38. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/virtual_scroll/plugin.js.map +1 -1
  39. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.complete.js +882 -310
  40. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.complete.js.map +1 -1
  41. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.js +838 -281
  42. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.js.map +1 -1
  43. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.popular.js +846 -287
  44. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.popular.js.map +1 -1
  45. data/vendor/assets/javascripts/tom-select-rails/esm/utils.js +1 -1
  46. data/vendor/assets/javascripts/tom-select-rails/esm/utils.js.map +1 -1
  47. data/vendor/assets/javascripts/tom-select-rails/js/plugins/caret_position.js +164 -160
  48. data/vendor/assets/javascripts/tom-select-rails/js/plugins/caret_position.js.map +1 -1
  49. data/vendor/assets/javascripts/tom-select-rails/js/plugins/change_listener.js +1 -1
  50. data/vendor/assets/javascripts/tom-select-rails/js/plugins/change_listener.js.map +1 -1
  51. data/vendor/assets/javascripts/tom-select-rails/js/plugins/checkbox_options.js +18 -11
  52. data/vendor/assets/javascripts/tom-select-rails/js/plugins/checkbox_options.js.map +1 -1
  53. data/vendor/assets/javascripts/tom-select-rails/js/plugins/clear_button.js +94 -89
  54. data/vendor/assets/javascripts/tom-select-rails/js/plugins/clear_button.js.map +1 -1
  55. data/vendor/assets/javascripts/tom-select-rails/js/plugins/drag_drop.js +1 -1
  56. data/vendor/assets/javascripts/tom-select-rails/js/plugins/drag_drop.js.map +1 -1
  57. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_header.js +121 -116
  58. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_header.js.map +1 -1
  59. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_input.js +234 -228
  60. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_input.js.map +1 -1
  61. data/vendor/assets/javascripts/tom-select-rails/js/plugins/input_autogrow.js +3 -7
  62. data/vendor/assets/javascripts/tom-select-rails/js/plugins/input_autogrow.js.map +1 -1
  63. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_active_items.js +1 -1
  64. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_active_items.js.map +1 -1
  65. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_backspace_delete.js +1 -1
  66. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_backspace_delete.js.map +1 -1
  67. data/vendor/assets/javascripts/tom-select-rails/js/plugins/optgroup_columns.js +112 -106
  68. data/vendor/assets/javascripts/tom-select-rails/js/plugins/optgroup_columns.js.map +1 -1
  69. data/vendor/assets/javascripts/tom-select-rails/js/plugins/remove_button.js +149 -144
  70. data/vendor/assets/javascripts/tom-select-rails/js/plugins/remove_button.js.map +1 -1
  71. data/vendor/assets/javascripts/tom-select-rails/js/plugins/restore_on_backspace.js +1 -1
  72. data/vendor/assets/javascripts/tom-select-rails/js/plugins/restore_on_backspace.js.map +1 -1
  73. data/vendor/assets/javascripts/tom-select-rails/js/plugins/virtual_scroll.js +277 -259
  74. data/vendor/assets/javascripts/tom-select-rails/js/plugins/virtual_scroll.js.map +1 -1
  75. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.js +838 -281
  76. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.js.map +1 -1
  77. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.min.js +331 -274
  78. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.min.js.map +1 -1
  79. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.js +882 -310
  80. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.js.map +1 -1
  81. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.min.js +281 -221
  82. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.min.js.map +1 -1
  83. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.js +846 -287
  84. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.js.map +1 -1
  85. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.min.js +350 -294
  86. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.min.js.map +1 -1
  87. data/vendor/assets/javascripts/tom-select-rails/types/tom-select.d.ts +26 -9
  88. data/vendor/assets/javascripts/tom-select-rails/types/types/core.d.ts +2 -1
  89. data/vendor/assets/javascripts/tom-select-rails/types/types/settings.d.ts +19 -22
  90. data/vendor/assets/javascripts/tom-select-rails/types/utils.d.ts +5 -5
  91. data/vendor/assets/javascripts/tom-select-rails/types/vanilla.d.ts +2 -2
  92. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css +43 -25
  93. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css.map +1 -1
  94. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css +1 -1
  95. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css.map +1 -1
  96. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css +63 -40
  97. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css.map +1 -1
  98. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css +1 -1
  99. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css.map +1 -1
  100. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css +45 -27
  101. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css.map +1 -1
  102. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css +43 -25
  103. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css.map +1 -1
  104. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css +1 -1
  105. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css.map +1 -1
  106. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css +1 -1
  107. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css.map +1 -1
  108. data/vendor/assets/stylesheets/tom-select-rails/scss/_dropdown.scss +0 -2
  109. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/clear_button.scss +12 -5
  110. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/remove_button.scss +34 -8
  111. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap4.scss +1 -1
  112. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap5.scss +20 -10
  113. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.default.scss +1 -1
  114. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.scss +14 -5
  115. metadata +3 -3
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tom Select v2.0.3
2
+ * Tom Select v2.2.0
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  */
5
5
 
@@ -37,9 +37,9 @@
37
37
 
38
38
  on(events, fct) {
39
39
  forEvents(events, event => {
40
- this._events[event] = this._events[event] || [];
41
-
42
- this._events[event].push(fct);
40
+ const event_array = this._events[event] || [];
41
+ event_array.push(fct);
42
+ this._events[event] = event_array;
43
43
  });
44
44
  }
45
45
 
@@ -52,21 +52,26 @@
52
52
  }
53
53
 
54
54
  forEvents(events, event => {
55
- if (n === 1) return delete this._events[event];
56
- if (event in this._events === false) return;
55
+ if (n === 1) {
56
+ delete this._events[event];
57
+ return;
58
+ }
57
59
 
58
- this._events[event].splice(this._events[event].indexOf(fct), 1);
60
+ const event_array = this._events[event];
61
+ if (event_array === undefined) return;
62
+ event_array.splice(event_array.indexOf(fct), 1);
63
+ this._events[event] = event_array;
59
64
  });
60
65
  }
61
66
 
62
67
  trigger(events, ...args) {
63
68
  var self = this;
64
69
  forEvents(events, event => {
65
- if (event in self._events === false) return;
66
-
67
- for (let fct of self._events[event]) {
70
+ const event_array = self._events[event];
71
+ if (event_array === undefined) return;
72
+ event_array.forEach(fct => {
68
73
  fct.apply(self, args);
69
- }
74
+ });
70
75
  });
71
76
  }
72
77
 
@@ -193,70 +198,124 @@
193
198
  };
194
199
  }
195
200
 
196
- // https://github.com/andrewrk/node-diacritics/blob/master/index.js
197
- var latin_pat;
198
- const accent_pat = '[\u0300-\u036F\u{b7}\u{2be}]'; // \u{2bc}
199
-
200
- const accent_reg = new RegExp(accent_pat, 'g');
201
- var diacritic_patterns;
202
- const latin_convert = {
203
- 'æ': 'ae',
204
- 'ⱥ': 'a',
205
- 'ø': 'o'
206
- };
207
- const convert_pat = new RegExp(Object.keys(latin_convert).join('|'), 'g');
201
+ /*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
208
202
  /**
209
- * code points generated from toCodePoints();
210
- * removed 65339 to 65345
203
+ * Convert array of strings to a regular expression
204
+ * ex ['ab','a'] => (?:ab|a)
205
+ * ex ['a','b'] => [ab]
206
+ * @param {string[]} chars
207
+ * @return {string}
211
208
  */
209
+ const arrayToPattern = chars => {
210
+ chars = chars.filter(Boolean);
212
211
 
213
- const code_points = [[67, 67], [160, 160], [192, 438], [452, 652], [961, 961], [1019, 1019], [1083, 1083], [1281, 1289], [1984, 1984], [5095, 5095], [7429, 7441], [7545, 7549], [7680, 7935], [8580, 8580], [9398, 9449], [11360, 11391], [42792, 42793], [42802, 42851], [42873, 42897], [42912, 42922], [64256, 64260], [65313, 65338], [65345, 65370]];
212
+ if (chars.length < 2) {
213
+ return chars[0] || '';
214
+ }
215
+
216
+ return maxValueLength(chars) == 1 ? '[' + chars.join('') + ']' : '(?:' + chars.join('|') + ')';
217
+ };
214
218
  /**
215
- * Remove accents
216
- * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703
217
- *
219
+ * @param {string[]} array
220
+ * @return {string}
218
221
  */
219
222
 
220
- const asciifold = str => {
221
- return str.normalize('NFKD').replace(accent_reg, '').toLowerCase().replace(convert_pat, function (foreignletter) {
222
- return latin_convert[foreignletter];
223
+ const sequencePattern = array => {
224
+ if (!hasDuplicates(array)) {
225
+ return array.join('');
226
+ }
227
+
228
+ let pattern = '';
229
+ let prev_char_count = 0;
230
+
231
+ const prev_pattern = () => {
232
+ if (prev_char_count > 1) {
233
+ pattern += '{' + prev_char_count + '}';
234
+ }
235
+ };
236
+
237
+ array.forEach((char, i) => {
238
+ if (char === array[i - 1]) {
239
+ prev_char_count++;
240
+ return;
241
+ }
242
+
243
+ prev_pattern();
244
+ pattern += char;
245
+ prev_char_count = 1;
223
246
  });
247
+ prev_pattern();
248
+ return pattern;
224
249
  };
225
250
  /**
226
251
  * Convert array of strings to a regular expression
227
252
  * ex ['ab','a'] => (?:ab|a)
228
253
  * ex ['a','b'] => [ab]
229
- *
254
+ * @param {Set<string>} chars
255
+ * @return {string}
230
256
  */
231
257
 
258
+ const setToPattern = chars => {
259
+ let array = toArray(chars);
260
+ return arrayToPattern(array);
261
+ };
262
+ /**
263
+ *
264
+ * https://stackoverflow.com/questions/7376598/in-javascript-how-do-i-check-if-an-array-has-duplicate-values
265
+ * @param {any[]} array
266
+ */
232
267
 
233
- const arrayToPattern = (chars, glue = '|') => {
234
- if (chars.length == 1) {
235
- return chars[0];
236
- }
268
+ const hasDuplicates = array => {
269
+ return new Set(array).size !== array.length;
270
+ };
271
+ /**
272
+ * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error
273
+ * @param {string} str
274
+ * @return {string}
275
+ */
237
276
 
238
- var longest = 1;
239
- chars.forEach(a => {
240
- longest = Math.max(longest, a.length);
241
- });
277
+ const escape_regex = str => {
278
+ return (str + '').replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu, '\\$1');
279
+ };
280
+ /**
281
+ * Return the max length of array values
282
+ * @param {string[]} array
283
+ *
284
+ */
242
285
 
243
- if (longest == 1) {
244
- return '[' + chars.join('') + ']';
245
- }
286
+ const maxValueLength = array => {
287
+ return array.reduce((longest, value) => Math.max(longest, unicodeLength(value)), 0);
288
+ };
289
+ /**
290
+ * @param {string} str
291
+ */
246
292
 
247
- return '(?:' + chars.join(glue) + ')';
293
+ const unicodeLength = str => {
294
+ return toArray(str).length;
248
295
  };
296
+ /**
297
+ * @param {any} p
298
+ * @return {any[]}
299
+ */
300
+
301
+ const toArray = p => Array.from(p);
302
+
303
+ /*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
249
304
  /**
250
305
  * Get all possible combinations of substrings that add up to the given string
251
306
  * https://stackoverflow.com/questions/30169587/find-all-the-combination-of-substrings-that-add-up-to-the-given-string
252
- *
307
+ * @param {string} input
308
+ * @return {string[][]}
253
309
  */
254
-
255
310
  const allSubstrings = input => {
256
311
  if (input.length === 1) return [[input]];
257
- var result = [];
258
- allSubstrings(input.substring(1)).forEach(function (subresult) {
259
- var tmp = subresult.slice(0);
312
+ /** @type {string[][]} */
313
+
314
+ let result = [];
315
+ const start = input.substring(1);
316
+ const suba = allSubstrings(start);
317
+ suba.forEach(function (subresult) {
318
+ let tmp = subresult.slice(0);
260
319
  tmp[0] = input.charAt(0) + tmp[0];
261
320
  result.push(tmp);
262
321
  tmp = subresult.slice(0);
@@ -265,96 +324,500 @@
265
324
  });
266
325
  return result;
267
326
  };
327
+
328
+ /*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */
329
+
330
+ /**
331
+ * @typedef {{[key:string]:string}} TUnicodeMap
332
+ * @typedef {{[key:string]:Set<string>}} TUnicodeSets
333
+ * @typedef {[[number,number]]} TCodePoints
334
+ * @typedef {{folded:string,composed:string,code_point:number}} TCodePointObj
335
+ * @typedef {{start:number,end:number,length:number,substr:string}} TSequencePart
336
+ */
337
+ /** @type {TCodePoints} */
338
+
339
+ const code_points = [[0, 65535]];
340
+ const accent_pat = '[\u0300-\u036F\u{b7}\u{2be}]'; // \u{2bc}
341
+
342
+ /** @type {TUnicodeMap} */
343
+
344
+ let unicode_map;
345
+ /** @type {RegExp} */
346
+
347
+ let multi_char_reg;
348
+ const max_char_length = 3;
349
+ /** @type {TUnicodeMap} */
350
+
351
+ const latin_convert = {
352
+ 'æ': 'ae',
353
+ 'ⱥ': 'a',
354
+ 'ø': 'o',
355
+ '⁄': '/',
356
+ '∕': '/'
357
+ };
358
+ const convert_pat = new RegExp(Object.keys(latin_convert).join('|') + '|' + accent_pat, 'gu');
268
359
  /**
269
- * Generate a list of diacritics from the list of code points
360
+ * Initialize the unicode_map from the give code point ranges
270
361
  *
362
+ * @param {TCodePoints=} _code_points
363
+ */
364
+
365
+ const initialize = _code_points => {
366
+ if (unicode_map !== undefined) return;
367
+ unicode_map = generateMap(_code_points || code_points);
368
+ };
369
+ /**
370
+ * Helper method for normalize a string
371
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
372
+ * @param {string} str
373
+ * @param {string} form
374
+ */
375
+
376
+ const normalize = (str, form = 'NFKD') => str.normalize(form);
377
+ /**
378
+ * Compatibility Decomposition without reordering string
379
+ * calling str.normalize('NFKD') on \u{594}\u{595}\u{596} becomes \u{596}\u{594}\u{595}
380
+ * @param {string} str
381
+ */
382
+
383
+ const decompose = str => {
384
+ if (str.match(/[\u0f71-\u0f81]/)) {
385
+ return toArray(str).reduce(
386
+ /**
387
+ * @param {string} result
388
+ * @param {string} char
389
+ */
390
+ (result, char) => {
391
+ return result + normalize(char);
392
+ }, '');
393
+ }
394
+
395
+ return normalize(str);
396
+ };
397
+ /**
398
+ * Remove accents
399
+ * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703
400
+ * @param {string} str
401
+ * @return {string}
402
+ */
403
+
404
+ const asciifold = str => {
405
+ return decompose(str).toLowerCase().replace(convert_pat, (
406
+ /** @type {string} */
407
+ char) => {
408
+ return latin_convert[char] || '';
409
+ });
410
+ };
411
+ /**
412
+ * Generate a list of unicode variants from the list of code points
413
+ * @param {TCodePoints} code_points
414
+ * @yield {TCodePointObj}
271
415
  */
272
416
 
273
- const generateDiacritics = () => {
274
- var diacritics = {};
275
- code_points.forEach(code_range => {
276
- for (let i = code_range[0]; i <= code_range[1]; i++) {
277
- let diacritic = String.fromCharCode(i);
278
- let latin = asciifold(diacritic);
417
+ function* generator(code_points) {
418
+ for (const [code_point_min, code_point_max] of code_points) {
419
+ for (let i = code_point_min; i <= code_point_max; i++) {
420
+ let composed = String.fromCharCode(i);
421
+ let folded = asciifold(composed);
279
422
 
280
- if (latin == diacritic.toLowerCase()) {
423
+ if (folded == composed.toLowerCase()) {
424
+ continue;
425
+ } // skip when folded is a string longer than 3 characters long
426
+ // bc the resulting regex patterns will be long
427
+ // eg:
428
+ // folded صلى الله عليه وسلم length 18 code point 65018
429
+ // folded جل جلاله length 8 code point 65019
430
+
431
+
432
+ if (folded.length > max_char_length) {
281
433
  continue;
282
434
  }
283
435
 
284
- if (!(latin in diacritics)) {
285
- diacritics[latin] = [latin];
436
+ if (folded.length == 0) {
437
+ continue;
286
438
  }
287
439
 
288
- var patt = new RegExp(arrayToPattern(diacritics[latin]), 'iu');
440
+ let decomposed = normalize(composed);
441
+ let recomposed = normalize(decomposed, 'NFC');
289
442
 
290
- if (diacritic.match(patt)) {
443
+ if (recomposed === composed && folded === decomposed) {
291
444
  continue;
292
445
  }
293
446
 
294
- diacritics[latin].push(diacritic);
447
+ yield {
448
+ folded: folded,
449
+ composed: composed,
450
+ code_point: i
451
+ };
452
+ }
453
+ }
454
+ }
455
+ /**
456
+ * Generate a unicode map from the list of code points
457
+ * @param {TCodePoints} code_points
458
+ * @return {TUnicodeSets}
459
+ */
460
+
461
+ const generateSets = code_points => {
462
+ /** @type {{[key:string]:Set<string>}} */
463
+ const unicode_sets = {};
464
+ /**
465
+ * @param {string} folded
466
+ * @param {string} to_add
467
+ */
468
+
469
+ const addMatching = (folded, to_add) => {
470
+ /** @type {Set<string>} */
471
+ const folded_set = unicode_sets[folded] || new Set();
472
+ const patt = new RegExp('^' + setToPattern(folded_set) + '$', 'iu');
473
+
474
+ if (to_add.match(patt)) {
475
+ return;
476
+ }
477
+
478
+ folded_set.add(escape_regex(to_add));
479
+ unicode_sets[folded] = folded_set;
480
+ };
481
+
482
+ for (let value of generator(code_points)) {
483
+ addMatching(value.folded, value.folded);
484
+ addMatching(value.folded, value.composed);
485
+ }
486
+
487
+ return unicode_sets;
488
+ };
489
+ /**
490
+ * Generate a unicode map from the list of code points
491
+ * ae => (?:(?:ae|Æ|Ǽ|Ǣ)|(?:A|Ⓐ|A...)(?:E|ɛ|Ⓔ...))
492
+ *
493
+ * @param {TCodePoints} code_points
494
+ * @return {TUnicodeMap}
495
+ */
496
+
497
+ const generateMap = code_points => {
498
+ /** @type {TUnicodeSets} */
499
+ const unicode_sets = generateSets(code_points);
500
+ /** @type {TUnicodeMap} */
501
+
502
+ const unicode_map = {};
503
+ /** @type {string[]} */
504
+
505
+ let multi_char = [];
506
+
507
+ for (let folded in unicode_sets) {
508
+ let set = unicode_sets[folded];
509
+
510
+ if (set) {
511
+ unicode_map[folded] = setToPattern(set);
512
+ }
513
+
514
+ if (folded.length > 1) {
515
+ multi_char.push(escape_regex(folded));
516
+ }
517
+ }
518
+
519
+ multi_char.sort((a, b) => b.length - a.length);
520
+ const multi_char_patt = arrayToPattern(multi_char);
521
+ multi_char_reg = new RegExp('^' + multi_char_patt, 'u');
522
+ return unicode_map;
523
+ };
524
+ /**
525
+ * Map each element of an array from it's folded value to all possible unicode matches
526
+ * @param {string[]} strings
527
+ * @param {number} min_replacement
528
+ * @return {string}
529
+ */
530
+
531
+ const mapSequence = (strings, min_replacement = 1) => {
532
+ let chars_replaced = 0;
533
+ strings = strings.map(str => {
534
+ if (unicode_map[str]) {
535
+ chars_replaced += str.length;
295
536
  }
537
+
538
+ return unicode_map[str] || str;
296
539
  });
297
- var latin_chars = Object.keys(diacritics); // latin character pattern
298
- // match longer substrings first
299
-
300
- latin_chars = latin_chars.sort((a, b) => b.length - a.length);
301
- latin_pat = new RegExp('(' + arrayToPattern(latin_chars) + accent_pat + '*)', 'g'); // build diacritic patterns
302
- // ae needs:
303
- // (?:(?:ae|Æ|Ǽ|Ǣ)|(?:A|Ⓐ|A...)(?:E|ɛ|Ⓔ...))
304
-
305
- var diacritic_patterns = {};
306
- latin_chars.sort((a, b) => a.length - b.length).forEach(latin => {
307
- var substrings = allSubstrings(latin);
308
- var pattern = substrings.map(sub_pat => {
309
- sub_pat = sub_pat.map(l => {
310
- if (diacritics.hasOwnProperty(l)) {
311
- return arrayToPattern(diacritics[l]);
540
+
541
+ if (chars_replaced >= min_replacement) {
542
+ return sequencePattern(strings);
543
+ }
544
+
545
+ return '';
546
+ };
547
+ /**
548
+ * Convert a short string and split it into all possible patterns
549
+ * Keep a pattern only if min_replacement is met
550
+ *
551
+ * 'abc'
552
+ * => [['abc'],['ab','c'],['a','bc'],['a','b','c']]
553
+ * => ['abc-pattern','ab-c-pattern'...]
554
+ *
555
+ *
556
+ * @param {string} str
557
+ * @param {number} min_replacement
558
+ * @return {string}
559
+ */
560
+
561
+ const substringsToPattern = (str, min_replacement = 1) => {
562
+ min_replacement = Math.max(min_replacement, str.length - 1);
563
+ return arrayToPattern(allSubstrings(str).map(sub_pat => {
564
+ return mapSequence(sub_pat, min_replacement);
565
+ }));
566
+ };
567
+ /**
568
+ * Convert an array of sequences into a pattern
569
+ * [{start:0,end:3,length:3,substr:'iii'}...] => (?:iii...)
570
+ *
571
+ * @param {Sequence[]} sequences
572
+ * @param {boolean} all
573
+ */
574
+
575
+ const sequencesToPattern = (sequences, all = true) => {
576
+ let min_replacement = sequences.length > 1 ? 1 : 0;
577
+ return arrayToPattern(sequences.map(sequence => {
578
+ let seq = [];
579
+ const len = all ? sequence.length() : sequence.length() - 1;
580
+
581
+ for (let j = 0; j < len; j++) {
582
+ seq.push(substringsToPattern(sequence.substrs[j] || '', min_replacement));
583
+ }
584
+
585
+ return sequencePattern(seq);
586
+ }));
587
+ };
588
+ /**
589
+ * Return true if the sequence is already in the sequences
590
+ * @param {Sequence} needle_seq
591
+ * @param {Sequence[]} sequences
592
+ */
593
+
594
+
595
+ const inSequences = (needle_seq, sequences) => {
596
+ for (const seq of sequences) {
597
+ if (seq.start != needle_seq.start || seq.end != needle_seq.end) {
598
+ continue;
599
+ }
600
+
601
+ if (seq.substrs.join('') !== needle_seq.substrs.join('')) {
602
+ continue;
603
+ }
604
+
605
+ let needle_parts = needle_seq.parts;
606
+ /**
607
+ * @param {TSequencePart} part
608
+ */
609
+
610
+ const filter = part => {
611
+ for (const needle_part of needle_parts) {
612
+ if (needle_part.start === part.start && needle_part.substr === part.substr) {
613
+ return false;
312
614
  }
313
615
 
314
- return l;
315
- });
316
- return arrayToPattern(sub_pat, '');
317
- });
318
- diacritic_patterns[latin] = arrayToPattern(pattern);
319
- });
320
- return diacritic_patterns;
616
+ if (part.length == 1 || needle_part.length == 1) {
617
+ continue;
618
+ } // check for overlapping parts
619
+ // a = ['::=','==']
620
+ // b = ['::','===']
621
+ // a = ['r','sm']
622
+ // b = ['rs','m']
623
+
624
+
625
+ if (part.start < needle_part.start && part.end > needle_part.start) {
626
+ return true;
627
+ }
628
+
629
+ if (needle_part.start < part.start && needle_part.end > part.start) {
630
+ return true;
631
+ }
632
+ }
633
+
634
+ return false;
635
+ };
636
+
637
+ let filtered = seq.parts.filter(filter);
638
+
639
+ if (filtered.length > 0) {
640
+ continue;
641
+ }
642
+
643
+ return true;
644
+ }
645
+
646
+ return false;
321
647
  };
648
+
649
+ class Sequence {
650
+ constructor() {
651
+ /** @type {TSequencePart[]} */
652
+ this.parts = [];
653
+ /** @type {string[]} */
654
+
655
+ this.substrs = [];
656
+ this.start = 0;
657
+ this.end = 0;
658
+ }
659
+ /**
660
+ * @param {TSequencePart|undefined} part
661
+ */
662
+
663
+
664
+ add(part) {
665
+ if (part) {
666
+ this.parts.push(part);
667
+ this.substrs.push(part.substr);
668
+ this.start = Math.min(part.start, this.start);
669
+ this.end = Math.max(part.end, this.end);
670
+ }
671
+ }
672
+
673
+ last() {
674
+ return this.parts[this.parts.length - 1];
675
+ }
676
+
677
+ length() {
678
+ return this.parts.length;
679
+ }
680
+ /**
681
+ * @param {number} position
682
+ * @param {TSequencePart} last_piece
683
+ */
684
+
685
+
686
+ clone(position, last_piece) {
687
+ let clone = new Sequence();
688
+ let parts = JSON.parse(JSON.stringify(this.parts));
689
+ let last_part = parts.pop();
690
+
691
+ for (const part of parts) {
692
+ clone.add(part);
693
+ }
694
+
695
+ let last_substr = last_piece.substr.substring(0, position - last_part.start);
696
+ let clone_last_len = last_substr.length;
697
+ clone.add({
698
+ start: last_part.start,
699
+ end: last_part.start + clone_last_len,
700
+ length: clone_last_len,
701
+ substr: last_substr
702
+ });
703
+ return clone;
704
+ }
705
+
706
+ }
322
707
  /**
323
- * Expand a regular expression pattern to include diacritics
708
+ * Expand a regular expression pattern to include unicode variants
324
709
  * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/
325
710
  *
711
+ * Issue:
712
+ * ﺊﺋ [ 'ﺊ = \\u{fe8a}', 'ﺋ = \\u{fe8b}' ]
713
+ * becomes: ئئ [ 'ي = \\u{64a}', 'ٔ = \\u{654}', 'ي = \\u{64a}', 'ٔ = \\u{654}' ]
714
+ *
715
+ * İIJ = IIJ = ⅡJ
716
+ *
717
+ * 1/2/4
718
+ *
719
+ * @param {string} str
720
+ * @return {string|undefined}
326
721
  */
327
722
 
328
- const diacriticRegexPoints = regex => {
329
- if (diacritic_patterns === undefined) {
330
- diacritic_patterns = generateDiacritics();
331
- }
332
723
 
333
- const decomposed = regex.normalize('NFKD').toLowerCase();
334
- return decomposed.split(latin_pat).map(part => {
335
- if (part == '') {
336
- return '';
337
- } // "ffl" or "ffl"
724
+ const getPattern = str => {
725
+ initialize();
726
+ str = asciifold(str);
727
+ let pattern = '';
728
+ let sequences = [new Sequence()];
729
+
730
+ for (let i = 0; i < str.length; i++) {
731
+ let substr = str.substring(i);
732
+ let match = substr.match(multi_char_reg);
733
+ const char = str.substring(i, i + 1);
734
+ const match_str = match ? match[0] : null; // loop through sequences
735
+ // add either the char or multi_match
736
+
737
+ let overlapping = [];
738
+ let added_types = new Set();
739
+
740
+ for (const sequence of sequences) {
741
+ const last_piece = sequence.last();
742
+
743
+ if (!last_piece || last_piece.length == 1 || last_piece.end <= i) {
744
+ // if we have a multi match
745
+ if (match_str) {
746
+ const len = match_str.length;
747
+ sequence.add({
748
+ start: i,
749
+ end: i + len,
750
+ length: len,
751
+ substr: match_str
752
+ });
753
+ added_types.add('1');
754
+ } else {
755
+ sequence.add({
756
+ start: i,
757
+ end: i + 1,
758
+ length: 1,
759
+ substr: char
760
+ });
761
+ added_types.add('2');
762
+ }
763
+ } else if (match_str) {
764
+ let clone = sequence.clone(i, last_piece);
765
+ const len = match_str.length;
766
+ clone.add({
767
+ start: i,
768
+ end: i + len,
769
+ length: len,
770
+ substr: match_str
771
+ });
772
+ overlapping.push(clone);
773
+ } else {
774
+ // don't add char
775
+ // adding would create invalid patterns: 234 => [2,34,4]
776
+ added_types.add('3');
777
+ }
778
+ } // if we have overlapping
779
+
780
+
781
+ if (overlapping.length > 0) {
782
+ // ['ii','iii'] before ['i','i','iii']
783
+ overlapping = overlapping.sort((a, b) => {
784
+ return a.length() - b.length();
785
+ });
786
+
787
+ for (let clone of overlapping) {
788
+ // don't add if we already have an equivalent sequence
789
+ if (inSequences(clone, sequences)) {
790
+ continue;
791
+ }
338
792
 
793
+ sequences.push(clone);
794
+ }
339
795
 
340
- const no_accent = asciifold(part);
796
+ continue;
797
+ } // if we haven't done anything unique
798
+ // clean up the patterns
799
+ // helps keep patterns smaller
800
+ // if str = 'r₨㎧aarss', pattern will be 446 instead of 655
341
801
 
342
- if (diacritic_patterns.hasOwnProperty(no_accent)) {
343
- return diacritic_patterns[no_accent];
344
- } // 'أهلا' (\u{623}\u{647}\u{644}\u{627}) or 'أهلا' (\u{627}\u{654}\u{647}\u{644}\u{627})
345
802
 
803
+ if (i > 0 && added_types.size == 1 && !added_types.has('3')) {
804
+ pattern += sequencesToPattern(sequences, false);
805
+ let new_seq = new Sequence();
806
+ const old_seq = sequences[0];
346
807
 
347
- const composed_part = part.normalize('NFC');
808
+ if (old_seq) {
809
+ new_seq.add(old_seq.last());
810
+ }
348
811
 
349
- if (composed_part != part) {
350
- return arrayToPattern([part, composed_part]);
812
+ sequences = [new_seq];
351
813
  }
814
+ }
352
815
 
353
- return part;
354
- }).join('');
816
+ pattern += sequencesToPattern(sequences, true);
817
+ return pattern;
355
818
  };
356
819
 
357
- // @ts-ignore TS2691 "An import path cannot end with a '.ts' extension"
820
+ /*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */
358
821
 
359
822
  /**
360
823
  * A property getter resolving dot-notation
@@ -392,20 +855,13 @@
392
855
  var score, pos;
393
856
  if (!value) return 0;
394
857
  value = value + '';
858
+ if (token.regex == null) return 0;
395
859
  pos = value.search(token.regex);
396
860
  if (pos === -1) return 0;
397
861
  score = token.string.length / value.length;
398
862
  if (pos === 0) score += 0.5;
399
863
  return score * weight;
400
864
  };
401
- /**
402
- *
403
- * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error
404
- */
405
-
406
- const escape_regex = str => {
407
- return (str + '').replace(/([\$\(-\+\.\?\[-\^\{-\}])/g, '\\$1');
408
- };
409
865
  /**
410
866
  * Cast object property to an array if it exists and has a value
411
867
  *
@@ -430,7 +886,7 @@
430
886
  *
431
887
  */
432
888
 
433
- const iterate = (object, callback) => {
889
+ const iterate$1 = (object, callback) => {
434
890
  if (Array.isArray(object)) {
435
891
  object.forEach(callback);
436
892
  } else {
@@ -453,6 +909,8 @@
453
909
  return 0;
454
910
  };
455
911
 
912
+ /*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */
913
+
456
914
  /**
457
915
  * sifter.js
458
916
  * Copyright (c) 2013–2020 Brian Reavis & contributors
@@ -513,13 +971,13 @@
513
971
  }
514
972
 
515
973
  if (word.length > 0) {
516
- regex = escape_regex(word);
517
-
518
974
  if (this.settings.diacritics) {
519
- regex = diacriticRegexPoints(regex);
975
+ regex = getPattern(word) || null;
976
+ } else {
977
+ regex = escape_regex(word);
520
978
  }
521
979
 
522
- if (respect_word_boundaries) regex = "\\b" + regex;
980
+ if (regex && respect_word_boundaries) regex = "\\b" + regex;
523
981
  }
524
982
 
525
983
  tokens.push({
@@ -537,12 +995,17 @@
537
995
  * Good matches will have a higher score than poor matches.
538
996
  * If an item is not a match, 0 will be returned by the function.
539
997
  *
540
- * @returns {function}
998
+ * @returns {T.ScoreFn}
541
999
  */
542
1000
  getScoreFunction(query, options) {
543
1001
  var search = this.prepareSearch(query, options);
544
1002
  return this._getScoreFunction(search);
545
1003
  }
1004
+ /**
1005
+ * @returns {T.ScoreFn}
1006
+ *
1007
+ */
1008
+
546
1009
 
547
1010
  _getScoreFunction(search) {
548
1011
  const tokens = search.tokens,
@@ -575,7 +1038,7 @@
575
1038
  if (field_count === 1) {
576
1039
  return function (token, data) {
577
1040
  const field = fields[0].field;
578
- return scoreValue(getAttrFn(data, field), token, weights[field]);
1041
+ return scoreValue(getAttrFn(data, field), token, weights[field] || 1);
579
1042
  };
580
1043
  }
581
1044
 
@@ -591,7 +1054,7 @@
591
1054
  sum += scoreValue(value, token, 1);
592
1055
  }
593
1056
  } else {
594
- iterate(weights, (weight, field) => {
1057
+ iterate$1(weights, (weight, field) => {
595
1058
  sum += scoreValue(getAttrFn(data, field), token, weight);
596
1059
  });
597
1060
  }
@@ -608,12 +1071,11 @@
608
1071
 
609
1072
  if (search.options.conjunction === 'and') {
610
1073
  return function (data) {
611
- var i = 0,
612
- score,
1074
+ var score,
613
1075
  sum = 0;
614
1076
 
615
- for (; i < token_count; i++) {
616
- score = scoreObject(tokens[i], data);
1077
+ for (let token of tokens) {
1078
+ score = scoreObject(token, data);
617
1079
  if (score <= 0) return 0;
618
1080
  sum += score;
619
1081
  }
@@ -623,7 +1085,7 @@
623
1085
  } else {
624
1086
  return function (data) {
625
1087
  var sum = 0;
626
- iterate(tokens, token => {
1088
+ iterate$1(tokens, token => {
627
1089
  sum += scoreObject(token, data);
628
1090
  });
629
1091
  return sum / token_count;
@@ -644,12 +1106,11 @@
644
1106
  }
645
1107
 
646
1108
  _getSortFunction(search) {
647
- var i, n, implicit_score;
1109
+ var implicit_score,
1110
+ sort_flds = [];
648
1111
  const self = this,
649
1112
  options = search.options,
650
- sort = !search.query && options.sort_empty ? options.sort_empty : options.sort,
651
- sort_flds = [],
652
- multipliers = [];
1113
+ sort = !search.query && options.sort_empty ? options.sort_empty : options.sort;
653
1114
 
654
1115
  if (typeof sort == 'function') {
655
1116
  return sort.bind(this);
@@ -668,9 +1129,9 @@
668
1129
 
669
1130
 
670
1131
  if (sort) {
671
- for (i = 0, n = sort.length; i < n; i++) {
672
- if (search.query || sort[i].field !== '$score') {
673
- sort_flds.push(sort[i]);
1132
+ for (let s of sort) {
1133
+ if (search.query || s.field !== '$score') {
1134
+ sort_flds.push(s);
674
1135
  }
675
1136
  }
676
1137
  } // the "$score" field is implied to be the primary
@@ -680,8 +1141,8 @@
680
1141
  if (search.query) {
681
1142
  implicit_score = true;
682
1143
 
683
- for (i = 0, n = sort_flds.length; i < n; i++) {
684
- if (sort_flds[i].field === '$score') {
1144
+ for (let fld of sort_flds) {
1145
+ if (fld.field === '$score') {
685
1146
  implicit_score = false;
686
1147
  break;
687
1148
  }
@@ -692,18 +1153,10 @@
692
1153
  field: '$score',
693
1154
  direction: 'desc'
694
1155
  });
695
- }
696
- } else {
697
- for (i = 0, n = sort_flds.length; i < n; i++) {
698
- if (sort_flds[i].field === '$score') {
699
- sort_flds.splice(i, 1);
700
- break;
701
- }
702
- }
703
- }
1156
+ } // without a search.query, all items will have the same score
704
1157
 
705
- for (i = 0, n = sort_flds.length; i < n; i++) {
706
- multipliers.push(sort_flds[i].direction === 'desc' ? -1 : 1);
1158
+ } else {
1159
+ sort_flds = sort_flds.filter(fld => fld.field !== '$score');
707
1160
  } // build function
708
1161
 
709
1162
 
@@ -711,25 +1164,20 @@
711
1164
 
712
1165
  if (!sort_flds_count) {
713
1166
  return null;
714
- } else if (sort_flds_count === 1) {
715
- const sort_fld = sort_flds[0].field;
716
- const multiplier = multipliers[0];
717
- return function (a, b) {
718
- return multiplier * cmp(get_field(sort_fld, a), get_field(sort_fld, b));
719
- };
720
- } else {
721
- return function (a, b) {
722
- var i, result, field;
1167
+ }
723
1168
 
724
- for (i = 0; i < sort_flds_count; i++) {
725
- field = sort_flds[i].field;
726
- result = multipliers[i] * cmp(get_field(field, a), get_field(field, b));
727
- if (result) return result;
728
- }
1169
+ return function (a, b) {
1170
+ var result, field;
729
1171
 
730
- return 0;
731
- };
732
- }
1172
+ for (let sort_fld of sort_flds) {
1173
+ field = sort_fld.field;
1174
+ let multiplier = sort_fld.direction === 'desc' ? -1 : 1;
1175
+ result = multiplier * cmp(get_field(field, a), get_field(field, b));
1176
+ if (result) return result;
1177
+ }
1178
+
1179
+ return 0;
1180
+ };
733
1181
  }
734
1182
 
735
1183
  /**
@@ -788,7 +1236,7 @@
788
1236
 
789
1237
 
790
1238
  if (query.length) {
791
- iterate(self.items, (item, id) => {
1239
+ iterate$1(self.items, (item, id) => {
792
1240
  score = fn_score(item);
793
1241
 
794
1242
  if (options.filter === false || score > 0) {
@@ -799,7 +1247,7 @@
799
1247
  }
800
1248
  });
801
1249
  } else {
802
- iterate(self.items, (_, id) => {
1250
+ iterate$1(self.items, (_, id) => {
803
1251
  search.items.push({
804
1252
  'score': 1,
805
1253
  'id': id
@@ -822,6 +1270,29 @@
822
1270
 
823
1271
  }
824
1272
 
1273
+ /**
1274
+ * Iterates over arrays and hashes.
1275
+ *
1276
+ * ```
1277
+ * iterate(this.items, function(item, id) {
1278
+ * // invoked for each item
1279
+ * });
1280
+ * ```
1281
+ *
1282
+ */
1283
+
1284
+ const iterate = (object, callback) => {
1285
+ if (Array.isArray(object)) {
1286
+ object.forEach(callback);
1287
+ } else {
1288
+ for (var key in object) {
1289
+ if (object.hasOwnProperty(key)) {
1290
+ callback(object[key], key);
1291
+ }
1292
+ }
1293
+ }
1294
+ };
1295
+
825
1296
  /**
826
1297
  * Return a dom element from either a dom query string, jQuery object, a dom element or html string
827
1298
  * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
@@ -839,10 +1310,10 @@
839
1310
  }
840
1311
 
841
1312
  if (isHtmlString(query)) {
842
- let div = document.createElement('div');
843
- div.innerHTML = query.trim(); // Never return a text node of whitespace as the result
1313
+ var tpl = document.createElement('template');
1314
+ tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result
844
1315
 
845
- return div.firstChild;
1316
+ return tpl.content.firstChild;
846
1317
  }
847
1318
 
848
1319
  return document.querySelector(query);
@@ -1053,9 +1524,9 @@
1053
1524
 
1054
1525
  const highlightChildren = node => {
1055
1526
  if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && (node.className !== 'highlight' || node.tagName !== 'SPAN')) {
1056
- for (var i = 0; i < node.childNodes.length; ++i) {
1057
- i += highlightRecursive(node.childNodes[i]);
1058
- }
1527
+ Array.from(node.childNodes).forEach(element => {
1528
+ highlightRecursive(element);
1529
+ });
1059
1530
  }
1060
1531
  };
1061
1532
 
@@ -1532,6 +2003,7 @@
1532
2003
  this.isInputHidden = false;
1533
2004
  this.isSetup = false;
1534
2005
  this.ignoreFocus = false;
2006
+ this.ignoreHover = false;
1535
2007
  this.hasOptions = false;
1536
2008
  this.currentResults = void 0;
1537
2009
  this.lastValue = '';
@@ -1627,7 +2099,7 @@
1627
2099
  control_input = getDom(settings.controlInput); // set attributes
1628
2100
 
1629
2101
  var attrs = ['autocorrect', 'autocapitalize', 'autocomplete'];
1630
- iterate(attrs, attr => {
2102
+ iterate$1(attrs, attr => {
1631
2103
  if (input.getAttribute(attr)) {
1632
2104
  setAttr(control_input, {
1633
2105
  [attr]: input.getAttribute(attr)
@@ -1730,7 +2202,16 @@
1730
2202
  settings.load = loadDebounce(settings.load, settings.loadThrottle);
1731
2203
  }
1732
2204
 
1733
- self.control_input.type = input.type; // clicking on an option should select it
2205
+ self.control_input.type = input.type;
2206
+ addEvent(dropdown, 'mousemove', () => {
2207
+ self.ignoreHover = false;
2208
+ });
2209
+ addEvent(dropdown, 'mouseenter', e => {
2210
+ var target_match = parentMatch(e.target, '[data-selectable]', dropdown);
2211
+ if (target_match) self.onOptionHover(e, target_match);
2212
+ }, {
2213
+ capture: true
2214
+ }); // clicking on an option should select it
1734
2215
 
1735
2216
  addEvent(dropdown, 'click', evt => {
1736
2217
  const option = parentMatch(evt.target, '[data-selectable]');
@@ -1764,7 +2245,7 @@
1764
2245
  addEvent(focus_node, 'resize', () => self.positionDropdown(), passive_event);
1765
2246
  addEvent(focus_node, 'blur', e => self.onBlur(e));
1766
2247
  addEvent(focus_node, 'focus', e => self.onFocus(e));
1767
- addEvent(focus_node, 'paste', e => self.onPaste(e));
2248
+ addEvent(control_input, 'paste', e => self.onPaste(e));
1768
2249
 
1769
2250
  const doc_mousedown = evt => {
1770
2251
  // blur if target is outside of this instance
@@ -1791,7 +2272,7 @@
1791
2272
  }
1792
2273
  };
1793
2274
 
1794
- var win_scroll = () => {
2275
+ const win_scroll = () => {
1795
2276
  if (self.isOpen) {
1796
2277
  self.positionDropdown();
1797
2278
  }
@@ -1820,7 +2301,7 @@
1820
2301
  settings.items = [];
1821
2302
  delete settings.optgroups;
1822
2303
  delete settings.options;
1823
- addEvent(input, 'invalid', e => {
2304
+ addEvent(input, 'invalid', () => {
1824
2305
  if (self.isValid) {
1825
2306
  self.isValid = false;
1826
2307
  self.isInvalid = true;
@@ -1857,7 +2338,7 @@
1857
2338
  // build options table
1858
2339
  this.addOptions(options); // build optgroup table
1859
2340
 
1860
- iterate(optgroups, optgroup => {
2341
+ iterate$1(optgroups, optgroup => {
1861
2342
  this.registerOptionGroup(optgroup);
1862
2343
  });
1863
2344
  }
@@ -2008,21 +2489,31 @@
2008
2489
  // input and create Items for each separate value
2009
2490
 
2010
2491
 
2011
- if (self.settings.splitOn) {
2012
- // Wait for pasted text to be recognized in value
2013
- setTimeout(() => {
2014
- var pastedText = self.inputValue();
2492
+ if (!self.settings.splitOn) {
2493
+ return;
2494
+ } // Wait for pasted text to be recognized in value
2015
2495
 
2016
- if (!pastedText.match(self.settings.splitOn)) {
2017
- return;
2018
- }
2019
2496
 
2020
- var splitInput = pastedText.trim().split(self.settings.splitOn);
2021
- iterate(splitInput, piece => {
2022
- self.createItem(piece);
2023
- });
2024
- }, 0);
2025
- }
2497
+ setTimeout(() => {
2498
+ var pastedText = self.inputValue();
2499
+
2500
+ if (!pastedText.match(self.settings.splitOn)) {
2501
+ return;
2502
+ }
2503
+
2504
+ var splitInput = pastedText.trim().split(self.settings.splitOn);
2505
+ iterate$1(splitInput, piece => {
2506
+ const hash = hash_key(piece);
2507
+
2508
+ if (hash) {
2509
+ if (this.options[piece]) {
2510
+ self.addItem(piece);
2511
+ } else {
2512
+ self.createItem(piece);
2513
+ }
2514
+ }
2515
+ });
2516
+ }, 0);
2026
2517
  }
2027
2518
  /**
2028
2519
  * Triggered on <input> keypress.
@@ -2054,6 +2545,7 @@
2054
2545
 
2055
2546
  onKeyDown(e) {
2056
2547
  var self = this;
2548
+ self.ignoreHover = true;
2057
2549
 
2058
2550
  if (self.isLocked) {
2059
2551
  if (e.keyCode !== KEY_TAB) {
@@ -2114,6 +2606,8 @@
2114
2606
  self.onOptionSelect(e, self.activeOption);
2115
2607
  preventDefault(e); // if the option_create=null, the dropdown might be closed
2116
2608
  } else if (self.settings.create && self.createItem()) {
2609
+ preventDefault(e); // don't submit form when searching for a value
2610
+ } else if (document.activeElement == self.control_input && self.isOpen) {
2117
2611
  preventDefault(e);
2118
2612
  }
2119
2613
 
@@ -2184,6 +2678,17 @@
2184
2678
  self.trigger('type', value);
2185
2679
  }
2186
2680
  }
2681
+ /**
2682
+ * Triggered when the user rolls over
2683
+ * an option in the autocomplete dropdown menu.
2684
+ *
2685
+ */
2686
+
2687
+
2688
+ onOptionHover(evt, option) {
2689
+ if (this.ignoreHover) return;
2690
+ this.setActiveOption(option, false);
2691
+ }
2187
2692
  /**
2188
2693
  * Triggered on <input> focus.
2189
2694
  *
@@ -2233,7 +2738,7 @@
2233
2738
  };
2234
2739
 
2235
2740
  if (self.settings.create && self.settings.createOnBlur) {
2236
- self.createItem(null, false, deactivate);
2741
+ self.createItem(null, deactivate);
2237
2742
  } else {
2238
2743
  deactivate();
2239
2744
  }
@@ -2254,7 +2759,7 @@
2254
2759
  }
2255
2760
 
2256
2761
  if (option.classList.contains('create')) {
2257
- self.createItem(null, true, () => {
2762
+ self.createItem(null, () => {
2258
2763
  if (self.settings.closeAfterSelect) {
2259
2764
  self.close();
2260
2765
  }
@@ -2538,7 +3043,7 @@
2538
3043
  */
2539
3044
 
2540
3045
 
2541
- setActiveOption(option) {
3046
+ setActiveOption(option, scroll = true) {
2542
3047
  if (option === this.activeOption) {
2543
3048
  return;
2544
3049
  }
@@ -2553,7 +3058,7 @@
2553
3058
  'aria-selected': 'true'
2554
3059
  });
2555
3060
  addClasses(option, 'active');
2556
- this.scrollToOption(option);
3061
+ if (scroll) this.scrollToOption(option);
2557
3062
  }
2558
3063
  /**
2559
3064
  * Sets the dropdown_content scrollTop to display the option
@@ -2623,7 +3128,7 @@
2623
3128
  self.hideInput();
2624
3129
  self.close();
2625
3130
  self.activeItems = activeItems;
2626
- iterate(activeItems, item => {
3131
+ iterate$1(activeItems, item => {
2627
3132
  self.setActiveItemClass(item);
2628
3133
  });
2629
3134
  }
@@ -2759,7 +3264,7 @@
2759
3264
 
2760
3265
 
2761
3266
  search(query) {
2762
- var i, result, calculateScore;
3267
+ var result, calculateScore;
2763
3268
  var self = this;
2764
3269
  var options = this.getSearchOptions(); // validate user-provided result scoring function
2765
3270
 
@@ -2784,13 +3289,10 @@
2784
3289
 
2785
3290
 
2786
3291
  if (self.settings.hideSelected) {
2787
- for (i = result.items.length - 1; i >= 0; i--) {
2788
- let hashed = hash_key(result.items[i].id);
2789
-
2790
- if (hashed && self.items.indexOf(hashed) !== -1) {
2791
- result.items.splice(i, 1);
2792
- }
2793
- }
3292
+ result.items = result.items.filter(item => {
3293
+ let hashed = hash_key(item.id);
3294
+ return !(hashed && self.items.indexOf(hashed) !== -1);
3295
+ });
2794
3296
  }
2795
3297
 
2796
3298
  return result;
@@ -2803,21 +3305,24 @@
2803
3305
 
2804
3306
 
2805
3307
  refreshOptions(triggerDropdown = true) {
2806
- var i, j, k, n, optgroup, optgroups, html, has_create_option, active_value, active_group;
3308
+ var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;
2807
3309
  var create;
2808
3310
  const groups = {};
2809
3311
  const groups_order = [];
2810
3312
  var self = this;
2811
3313
  var query = self.inputValue();
3314
+ const same_query = query === self.lastQuery || query == '' && self.lastQuery == null;
2812
3315
  var results = self.search(query);
2813
- var active_option = null; //self.activeOption;
2814
-
3316
+ var active_option = null;
2815
3317
  var show_dropdown = self.settings.shouldOpen || false;
2816
3318
  var dropdown_content = self.dropdown_content;
2817
3319
 
2818
- if (self.activeOption) {
2819
- active_value = self.activeOption.dataset.value;
2820
- active_group = self.activeOption.closest('[data-group]');
3320
+ if (same_query) {
3321
+ active_option = self.activeOption;
3322
+
3323
+ if (active_option) {
3324
+ active_group = active_option.closest('[data-group]');
3325
+ }
2821
3326
  } // build markup
2822
3327
 
2823
3328
 
@@ -2834,12 +3339,16 @@
2834
3339
 
2835
3340
  for (i = 0; i < n; i++) {
2836
3341
  // get option dom element
2837
- let opt_value = results.items[i].id;
3342
+ let item = results.items[i];
3343
+ if (!item) continue;
3344
+ let opt_value = item.id;
2838
3345
  let option = self.options[opt_value];
2839
- let option_el = self.getOption(opt_value, true); // toggle 'selected' class
3346
+ if (option === undefined) continue;
3347
+ let opt_hash = get_hash(opt_value);
3348
+ let option_el = self.getOption(opt_hash, true); // toggle 'selected' class
2840
3349
 
2841
3350
  if (!self.settings.hideSelected) {
2842
- option_el.classList.toggle('selected', self.items.includes(opt_value));
3351
+ option_el.classList.toggle('selected', self.items.includes(opt_hash));
2843
3352
  }
2844
3353
 
2845
3354
  optgroup = option[self.settings.optgroupField] || '';
@@ -2852,8 +3361,10 @@
2852
3361
  optgroup = '';
2853
3362
  }
2854
3363
 
2855
- if (!groups.hasOwnProperty(optgroup)) {
2856
- groups[optgroup] = document.createDocumentFragment();
3364
+ let group_fragment = groups[optgroup];
3365
+
3366
+ if (group_fragment === undefined) {
3367
+ group_fragment = document.createDocumentFragment();
2857
3368
  groups_order.push(optgroup);
2858
3369
  } // nodes can only have one parent, so if the option is in mutple groups, we need a clone
2859
3370
 
@@ -2865,48 +3376,50 @@
2865
3376
  'aria-selected': null
2866
3377
  });
2867
3378
  option_el.classList.add('ts-cloned');
2868
- removeClasses(option_el, 'active');
2869
- } // make sure we keep the activeOption in the same group
3379
+ removeClasses(option_el, 'active'); // make sure we keep the activeOption in the same group
2870
3380
 
2871
-
2872
- if (!active_option && active_value == opt_value) {
2873
- if (active_group) {
2874
- if (active_group.dataset.group === optgroup) {
3381
+ if (self.activeOption && self.activeOption.dataset.value == opt_value) {
3382
+ if (active_group && active_group.dataset.group === optgroup.toString()) {
2875
3383
  active_option = option_el;
2876
3384
  }
2877
- } else {
2878
- active_option = option_el;
2879
3385
  }
2880
3386
  }
2881
3387
 
2882
- groups[optgroup].appendChild(option_el);
3388
+ group_fragment.appendChild(option_el);
3389
+ groups[optgroup] = group_fragment;
2883
3390
  }
2884
3391
  } // sort optgroups
2885
3392
 
2886
3393
 
2887
- if (this.settings.lockOptgroupOrder) {
3394
+ if (self.settings.lockOptgroupOrder) {
2888
3395
  groups_order.sort((a, b) => {
2889
- var a_order = self.optgroups[a] && self.optgroups[a].$order || 0;
2890
- var b_order = self.optgroups[b] && self.optgroups[b].$order || 0;
3396
+ const grp_a = self.optgroups[a];
3397
+ const grp_b = self.optgroups[b];
3398
+ const a_order = grp_a && grp_a.$order || 0;
3399
+ const b_order = grp_b && grp_b.$order || 0;
2891
3400
  return a_order - b_order;
2892
3401
  });
2893
3402
  } // render optgroup headers & join groups
2894
3403
 
2895
3404
 
2896
3405
  html = document.createDocumentFragment();
2897
- iterate(groups_order, optgroup => {
2898
- if (self.optgroups.hasOwnProperty(optgroup) && groups[optgroup].children.length) {
3406
+ iterate$1(groups_order, optgroup => {
3407
+ let group_fragment = groups[optgroup];
3408
+ if (!group_fragment || !group_fragment.children.length) return;
3409
+ let group_heading = self.optgroups[optgroup];
3410
+
3411
+ if (group_heading !== undefined) {
2899
3412
  let group_options = document.createDocumentFragment();
2900
- let header = self.render('optgroup_header', self.optgroups[optgroup]);
3413
+ let header = self.render('optgroup_header', group_heading);
2901
3414
  append(group_options, header);
2902
- append(group_options, groups[optgroup]);
3415
+ append(group_options, group_fragment);
2903
3416
  let group_html = self.render('optgroup', {
2904
- group: self.optgroups[optgroup],
3417
+ group: group_heading,
2905
3418
  options: group_options
2906
3419
  });
2907
3420
  append(html, group_html);
2908
3421
  } else {
2909
- append(html, groups[optgroup]);
3422
+ append(html, group_fragment);
2910
3423
  }
2911
3424
  });
2912
3425
  dropdown_content.innerHTML = '';
@@ -2916,7 +3429,7 @@
2916
3429
  removeHighlight(dropdown_content);
2917
3430
 
2918
3431
  if (results.query.length && results.tokens.length) {
2919
- iterate(results.tokens, tok => {
3432
+ iterate$1(results.tokens, tok => {
2920
3433
  highlight(dropdown_content, tok.regex);
2921
3434
  });
2922
3435
  }
@@ -2957,7 +3470,7 @@
2957
3470
 
2958
3471
  if (show_dropdown) {
2959
3472
  if (results.items.length > 0) {
2960
- if (!active_option && self.settings.mode === 'single' && self.items.length) {
3473
+ if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {
2961
3474
  active_option = self.getOption(self.items[0]);
2962
3475
  }
2963
3476
 
@@ -3044,7 +3557,7 @@
3044
3557
 
3045
3558
 
3046
3559
  addOptions(data, user_created = false) {
3047
- iterate(data, dat => {
3560
+ iterate$1(data, dat => {
3048
3561
  this.addOption(dat, user_created);
3049
3562
  });
3050
3563
  }
@@ -3124,11 +3637,12 @@
3124
3637
  const value_new = hash_key(data[self.settings.valueField]); // sanity checks
3125
3638
 
3126
3639
  if (value_old === null) return;
3127
- if (!self.options.hasOwnProperty(value_old)) return;
3640
+ const data_old = self.options[value_old];
3641
+ if (data_old == undefined) return;
3128
3642
  if (typeof value_new !== 'string') throw new Error('Value must be set in option data');
3129
3643
  const option = self.getOption(value_old);
3130
3644
  const item = self.getItem(value_old);
3131
- data.$order = data.$order || self.options[value_old].$order;
3645
+ data.$order = data.$order || data_old.$order;
3132
3646
  delete self.options[value_old]; // invalidate render cache
3133
3647
  // don't remove existing node yet, we'll remove it after replacing it
3134
3648
 
@@ -3186,20 +3700,35 @@
3186
3700
  */
3187
3701
 
3188
3702
 
3189
- clearOptions() {
3703
+ clearOptions(filter) {
3704
+ const boundFilter = (filter || this.clearFilter).bind(this);
3190
3705
  this.loadedSearches = {};
3191
3706
  this.userOptions = {};
3192
3707
  this.clearCache();
3193
- var selected = {};
3194
- iterate(this.options, (option, key) => {
3195
- if (this.items.indexOf(key) >= 0) {
3196
- selected[key] = this.options[key];
3708
+ const selected = {};
3709
+ iterate$1(this.options, (option, key) => {
3710
+ if (boundFilter(option, key)) {
3711
+ selected[key] = option;
3197
3712
  }
3198
3713
  });
3199
3714
  this.options = this.sifter.items = selected;
3200
3715
  this.lastQuery = null;
3201
3716
  this.trigger('option_clear');
3202
3717
  }
3718
+ /**
3719
+ * Used by clearOptions() to decide whether or not an option should be removed
3720
+ * Return true to keep an option, false to remove
3721
+ *
3722
+ */
3723
+
3724
+
3725
+ clearFilter(option, value) {
3726
+ if (this.items.indexOf(value) >= 0) {
3727
+ return true;
3728
+ }
3729
+
3730
+ return false;
3731
+ }
3203
3732
  /**
3204
3733
  * Returns the dom element of the option
3205
3734
  * matching the given value.
@@ -3209,10 +3738,10 @@
3209
3738
 
3210
3739
  getOption(value, create = false) {
3211
3740
  const hashed = hash_key(value);
3741
+ if (hashed === null) return null;
3742
+ const option = this.options[hashed];
3212
3743
 
3213
- if (hashed !== null && this.options.hasOwnProperty(hashed)) {
3214
- const option = this.options[hashed];
3215
-
3744
+ if (option != undefined) {
3216
3745
  if (option.$div) {
3217
3746
  return option.$div;
3218
3747
  }
@@ -3285,11 +3814,11 @@
3285
3814
  var self = this;
3286
3815
  var items = Array.isArray(values) ? values : [values];
3287
3816
  items = items.filter(x => self.items.indexOf(x) === -1);
3288
-
3289
- for (let i = 0, n = items.length; i < n; i++) {
3290
- self.isPending = i < n - 1;
3291
- self.addItem(items[i], silent);
3292
- }
3817
+ const last_item = items[items.length - 1];
3818
+ items.forEach(item => {
3819
+ self.isPending = item !== last_item;
3820
+ self.addItem(item, silent);
3821
+ });
3293
3822
  }
3294
3823
  /**
3295
3824
  * "Selects" an item. Adds it to the list
@@ -3420,7 +3949,16 @@
3420
3949
  */
3421
3950
 
3422
3951
 
3423
- createItem(input = null, triggerDropdown = true, callback = () => {}) {
3952
+ createItem(input = null, callback = () => {}) {
3953
+ // triggerDropdown parameter @deprecated 2.1.1
3954
+ if (arguments.length === 3) {
3955
+ callback = arguments[2];
3956
+ }
3957
+
3958
+ if (typeof callback != 'function') {
3959
+ callback = () => {};
3960
+ }
3961
+
3424
3962
  var self = this;
3425
3963
  var caret = self.caretPos;
3426
3964
  var output;
@@ -3519,11 +4057,11 @@
3519
4057
  refreshValidityState() {
3520
4058
  var self = this;
3521
4059
 
3522
- if (!self.input.checkValidity) {
4060
+ if (!self.input.validity) {
3523
4061
  return;
3524
4062
  }
3525
4063
 
3526
- self.isValid = self.input.checkValidity();
4064
+ self.isValid = self.input.validity.valid;
3527
4065
  self.isInvalid = !self.isValid;
3528
4066
  }
3529
4067
  /**
@@ -3696,7 +4234,7 @@
3696
4234
  var self = this;
3697
4235
  if (!self.items.length) return;
3698
4236
  var items = self.controlChildren();
3699
- iterate(items, item => {
4237
+ iterate$1(items, item => {
3700
4238
  self.removeItem(item, true);
3701
4239
  });
3702
4240
  self.showInput();
@@ -3714,7 +4252,7 @@
3714
4252
  const self = this;
3715
4253
  const caret = self.caretPos;
3716
4254
  const target = self.control;
3717
- target.insertBefore(el, target.children[caret]);
4255
+ target.insertBefore(el, target.children[caret] || null);
3718
4256
  self.setCaret(caret + 1);
3719
4257
  }
3720
4258
  /**
@@ -3739,20 +4277,23 @@
3739
4277
  caret++;
3740
4278
  }
3741
4279
 
3742
- iterate(self.activeItems, item => rm_items.push(item));
4280
+ iterate$1(self.activeItems, item => rm_items.push(item));
3743
4281
  } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
3744
4282
  const items = self.controlChildren();
4283
+ let rm_item;
3745
4284
 
3746
4285
  if (direction < 0 && selection.start === 0 && selection.length === 0) {
3747
- rm_items.push(items[self.caretPos - 1]);
4286
+ rm_item = items[self.caretPos - 1];
3748
4287
  } else if (direction > 0 && selection.start === self.inputValue().length) {
3749
- rm_items.push(items[self.caretPos]);
4288
+ rm_item = items[self.caretPos];
3750
4289
  }
3751
- }
3752
4290
 
3753
- const values = rm_items.map(item => item.dataset.value); // allow the callback to abort
4291
+ if (rm_item !== undefined) {
4292
+ rm_items.push(rm_item);
4293
+ }
4294
+ }
3754
4295
 
3755
- if (!values.length || typeof self.settings.onDelete === 'function' && self.settings.onDelete.call(self, values, e) === false) {
4296
+ if (!self.shouldDelete(rm_items, e)) {
3756
4297
  return false;
3757
4298
  }
3758
4299
 
@@ -3771,6 +4312,20 @@
3771
4312
  self.refreshOptions(false);
3772
4313
  return true;
3773
4314
  }
4315
+ /**
4316
+ * Return true if the items should be deleted
4317
+ */
4318
+
4319
+
4320
+ shouldDelete(items, evt) {
4321
+ const values = items.map(item => item.dataset.value); // allow the callback to abort
4322
+
4323
+ if (!values.length || typeof this.settings.onDelete === 'function' && this.settings.onDelete(values, evt) === false) {
4324
+ return false;
4325
+ }
4326
+
4327
+ return true;
4328
+ }
3774
4329
  /**
3775
4330
  * Selects the previous / next item (depending on the `direction` argument).
3776
4331
  *
@@ -3936,26 +4491,11 @@
3936
4491
 
3937
4492
 
3938
4493
  render(templateName, data) {
3939
- if (typeof this.settings.render[templateName] !== 'function') {
3940
- return null;
3941
- }
3942
-
3943
- return this._render(templateName, data);
3944
- }
3945
- /**
3946
- * _render() can be called directly when we know we don't want to hit the cache
3947
- * return type could be null for some templates, we need https://github.com/microsoft/TypeScript/issues/33014
3948
- */
3949
-
3950
-
3951
- _render(templateName, data) {
3952
- var value = '',
3953
- id,
3954
- html;
4494
+ var id, html;
3955
4495
  const self = this;
3956
4496
 
3957
- if (templateName === 'option' || templateName == 'item') {
3958
- value = get_hash(data[self.settings.valueField]);
4497
+ if (typeof this.settings.render[templateName] !== 'function') {
4498
+ return null;
3959
4499
  } // render markup
3960
4500
 
3961
4501
 
@@ -3991,6 +4531,7 @@
3991
4531
  }
3992
4532
 
3993
4533
  if (templateName === 'option' || templateName === 'item') {
4534
+ const value = get_hash(data[self.settings.valueField]);
3994
4535
  setAttr(html, {
3995
4536
  'data-value': value
3996
4537
  }); // make sure we have some classes if a template is overwritten
@@ -4007,12 +4548,28 @@
4007
4548
  id: data.$id
4008
4549
  }); // update cache
4009
4550
 
4010
- self.options[value].$div = html;
4551
+ data.$div = html;
4552
+ self.options[value] = data;
4011
4553
  }
4012
4554
  }
4013
4555
 
4014
4556
  return html;
4015
4557
  }
4558
+ /**
4559
+ * Type guarded rendering
4560
+ *
4561
+ */
4562
+
4563
+
4564
+ _render(templateName, data) {
4565
+ const html = this.render(templateName, data);
4566
+
4567
+ if (html == null) {
4568
+ throw 'HTMLElement expected';
4569
+ }
4570
+
4571
+ return html;
4572
+ }
4016
4573
  /**
4017
4574
  * Clears the render cache for a template. If
4018
4575
  * no template is given, clears all render
@@ -4022,7 +4579,7 @@
4022
4579
 
4023
4580
 
4024
4581
  clearCache() {
4025
- iterate(this.options, (option, value) => {
4582
+ iterate$1(this.options, option => {
4026
4583
  if (option.$div) {
4027
4584
  option.$div.remove();
4028
4585
  delete option.$div;
@@ -4212,7 +4769,9 @@
4212
4769
 
4213
4770
  self.hook('before', 'close', () => {
4214
4771
  if (!self.isOpen) return;
4215
- self.focus_node.focus();
4772
+ self.focus_node.focus({
4773
+ preventScroll: true
4774
+ });
4216
4775
  });
4217
4776
  });
4218
4777
  }
@@ -4275,9 +4834,9 @@
4275
4834
  var orig_render_item = self.settings.render.item;
4276
4835
 
4277
4836
  self.settings.render.item = (data, escape) => {
4278
- var rendered = getDom(orig_render_item.call(self, data, escape));
4837
+ var item = getDom(orig_render_item.call(self, data, escape));
4279
4838
  var close_button = getDom(html);
4280
- rendered.appendChild(close_button);
4839
+ item.appendChild(close_button);
4281
4840
  addEvent(close_button, 'mousedown', evt => {
4282
4841
  preventDefault(evt, true);
4283
4842
  });
@@ -4285,12 +4844,12 @@
4285
4844
  // propagating will trigger the dropdown to show for single mode
4286
4845
  preventDefault(evt, true);
4287
4846
  if (self.isLocked) return;
4288
- var value = rendered.dataset.value;
4289
- self.removeItem(value);
4847
+ if (!self.shouldDelete([item], evt)) return;
4848
+ self.removeItem(item);
4290
4849
  self.refreshOptions(false);
4291
4850
  self.inputState();
4292
4851
  });
4293
- return rendered;
4852
+ return item;
4294
4853
  };
4295
4854
  });
4296
4855
  }