@drecchia/tom-select 2.5.2-virtual-scroll.0 → 2.5.2-virtual-scroll.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/dist/cjs/constants.js +16 -0
  2. package/dist/cjs/constants.js.map +1 -0
  3. package/dist/cjs/contrib/highlight.js +69 -0
  4. package/dist/cjs/contrib/highlight.js.map +1 -0
  5. package/dist/cjs/contrib/microevent.js +64 -0
  6. package/dist/cjs/contrib/microevent.js.map +1 -0
  7. package/dist/cjs/contrib/microplugin.js +112 -0
  8. package/dist/cjs/contrib/microplugin.js.map +1 -0
  9. package/dist/cjs/defaults.js +85 -0
  10. package/dist/cjs/defaults.js.map +1 -0
  11. package/dist/cjs/getSettings.js +146 -0
  12. package/dist/cjs/getSettings.js.map +1 -0
  13. package/dist/cjs/package.json +1 -0
  14. package/dist/cjs/plugins/caret_position/plugin.js +66 -0
  15. package/dist/cjs/plugins/caret_position/plugin.js.map +1 -0
  16. package/dist/cjs/plugins/change_listener/plugin.js +25 -0
  17. package/dist/cjs/plugins/change_listener/plugin.js.map +1 -0
  18. package/dist/cjs/plugins/checkbox_options/plugin.js +108 -0
  19. package/dist/cjs/plugins/checkbox_options/plugin.js.map +1 -0
  20. package/dist/cjs/plugins/checkbox_options/types.js +3 -0
  21. package/dist/cjs/plugins/checkbox_options/types.js.map +1 -0
  22. package/dist/cjs/plugins/clear_button/plugin.js +47 -0
  23. package/dist/cjs/plugins/clear_button/plugin.js.map +1 -0
  24. package/dist/cjs/plugins/clear_button/types.js +3 -0
  25. package/dist/cjs/plugins/clear_button/types.js.map +1 -0
  26. package/dist/cjs/plugins/drag_drop/plugin.js +117 -0
  27. package/dist/cjs/plugins/drag_drop/plugin.js.map +1 -0
  28. package/dist/cjs/plugins/dropdown_header/plugin.js +50 -0
  29. package/dist/cjs/plugins/dropdown_header/plugin.js.map +1 -0
  30. package/dist/cjs/plugins/dropdown_header/types.js +3 -0
  31. package/dist/cjs/plugins/dropdown_header/types.js.map +1 -0
  32. package/dist/cjs/plugins/dropdown_input/plugin.js +88 -0
  33. package/dist/cjs/plugins/dropdown_input/plugin.js.map +1 -0
  34. package/dist/cjs/plugins/input_autogrow/plugin.js +47 -0
  35. package/dist/cjs/plugins/input_autogrow/plugin.js.map +1 -0
  36. package/dist/cjs/plugins/local_virtual_scroll/plugin.js +293 -0
  37. package/dist/cjs/plugins/local_virtual_scroll/plugin.js.map +1 -0
  38. package/dist/cjs/plugins/local_virtual_scroll/types.js +3 -0
  39. package/dist/cjs/plugins/local_virtual_scroll/types.js.map +1 -0
  40. package/dist/cjs/plugins/no_active_items/plugin.js +22 -0
  41. package/dist/cjs/plugins/no_active_items/plugin.js.map +1 -0
  42. package/dist/cjs/plugins/no_backspace_delete/plugin.js +28 -0
  43. package/dist/cjs/plugins/no_backspace_delete/plugin.js.map +1 -0
  44. package/dist/cjs/plugins/optgroup_columns/plugin.js +51 -0
  45. package/dist/cjs/plugins/optgroup_columns/plugin.js.map +1 -0
  46. package/dist/cjs/plugins/remove_button/plugin.js +61 -0
  47. package/dist/cjs/plugins/remove_button/plugin.js.map +1 -0
  48. package/dist/cjs/plugins/remove_button/types.js +3 -0
  49. package/dist/cjs/plugins/remove_button/types.js.map +1 -0
  50. package/dist/cjs/plugins/restore_on_backspace/plugin.js +24 -0
  51. package/dist/cjs/plugins/restore_on_backspace/plugin.js.map +1 -0
  52. package/dist/cjs/plugins/virtual_scroll/plugin.js +170 -0
  53. package/dist/cjs/plugins/virtual_scroll/plugin.js.map +1 -0
  54. package/dist/cjs/tom-select.complete.js +35 -0
  55. package/dist/cjs/tom-select.complete.js.map +1 -0
  56. package/dist/cjs/tom-select.js +2303 -0
  57. package/dist/cjs/tom-select.js.map +1 -0
  58. package/dist/cjs/tom-select.popular.js +15 -0
  59. package/dist/cjs/tom-select.popular.js.map +1 -0
  60. package/dist/cjs/types/core.js +3 -0
  61. package/dist/cjs/types/core.js.map +1 -0
  62. package/dist/cjs/types/index.js +19 -0
  63. package/dist/cjs/types/index.js.map +1 -0
  64. package/dist/cjs/types/settings.js +3 -0
  65. package/dist/cjs/types/settings.js.map +1 -0
  66. package/dist/cjs/utils.js +212 -0
  67. package/dist/cjs/utils.js.map +1 -0
  68. package/dist/cjs/vanilla.js +190 -0
  69. package/dist/cjs/vanilla.js.map +1 -0
  70. package/dist/css/tom-select.bootstrap4.css +16 -4
  71. package/dist/css/tom-select.bootstrap4.css.map +1 -0
  72. package/dist/css/tom-select.bootstrap4.min.css +2 -0
  73. package/dist/css/tom-select.bootstrap4.min.css.map +1 -0
  74. package/dist/css/tom-select.bootstrap5.css +16 -4
  75. package/dist/css/tom-select.bootstrap5.css.map +1 -0
  76. package/dist/css/tom-select.bootstrap5.min.css +2 -0
  77. package/dist/css/tom-select.bootstrap5.min.css.map +1 -0
  78. package/dist/css/tom-select.css +12 -4
  79. package/dist/css/tom-select.css.map +1 -0
  80. package/dist/css/tom-select.default.css +11 -5
  81. package/dist/css/tom-select.default.css.map +1 -1
  82. package/dist/css/tom-select.default.min.css +2 -0
  83. package/dist/css/tom-select.default.min.css.map +1 -0
  84. package/dist/css/tom-select.min.css +2 -0
  85. package/dist/css/tom-select.min.css.map +1 -0
  86. package/dist/esm/constants.d.ts +12 -0
  87. package/dist/esm/constants.js +13 -0
  88. package/dist/esm/constants.js.map +1 -0
  89. package/dist/esm/contrib/highlight.d.ts +13 -0
  90. package/dist/esm/contrib/highlight.js +64 -0
  91. package/dist/esm/contrib/highlight.js.map +1 -0
  92. package/dist/esm/contrib/microevent.d.ts +20 -0
  93. package/dist/esm/contrib/microevent.js +61 -0
  94. package/dist/esm/contrib/microevent.js.map +1 -0
  95. package/dist/esm/contrib/microplugin.d.ts +71 -0
  96. package/dist/esm/contrib/microplugin.js +109 -0
  97. package/dist/esm/contrib/microplugin.js.map +1 -0
  98. package/dist/esm/defaults.d.ts +53 -0
  99. package/dist/esm/defaults.js +83 -0
  100. package/dist/esm/defaults.js.map +1 -0
  101. package/dist/esm/getSettings.d.ts +3 -0
  102. package/dist/esm/getSettings.js +143 -0
  103. package/dist/esm/getSettings.js.map +1 -0
  104. package/dist/esm/plugins/caret_position/plugin.d.ts +16 -0
  105. package/dist/esm/plugins/caret_position/plugin.js +1 -1
  106. package/dist/esm/plugins/change_listener/plugin.d.ts +16 -0
  107. package/dist/esm/plugins/change_listener/plugin.js +1 -1
  108. package/dist/esm/plugins/checkbox_options/plugin.d.ts +17 -0
  109. package/dist/esm/plugins/checkbox_options/plugin.js +1 -1
  110. package/dist/esm/plugins/checkbox_options/types.d.ts +14 -0
  111. package/dist/esm/plugins/checkbox_options/types.js +2 -0
  112. package/dist/esm/plugins/checkbox_options/types.js.map +1 -0
  113. package/dist/esm/plugins/clear_button/plugin.d.ts +17 -0
  114. package/dist/esm/plugins/clear_button/plugin.js +1 -1
  115. package/dist/esm/plugins/clear_button/types.d.ts +7 -0
  116. package/dist/esm/plugins/clear_button/types.js +2 -0
  117. package/dist/esm/plugins/clear_button/types.js.map +1 -0
  118. package/dist/esm/plugins/drag_drop/plugin.d.ts +16 -0
  119. package/dist/esm/plugins/drag_drop/plugin.js +1 -1
  120. package/dist/esm/plugins/dropdown_header/plugin.d.ts +17 -0
  121. package/dist/esm/plugins/dropdown_header/plugin.js +1 -1
  122. package/dist/esm/plugins/dropdown_header/types.d.ts +8 -0
  123. package/dist/esm/plugins/dropdown_header/types.js +2 -0
  124. package/dist/esm/plugins/dropdown_header/types.js.map +1 -0
  125. package/dist/esm/plugins/dropdown_input/plugin.d.ts +16 -0
  126. package/dist/esm/plugins/dropdown_input/plugin.js +1 -1
  127. package/dist/esm/plugins/input_autogrow/plugin.d.ts +15 -0
  128. package/dist/esm/plugins/input_autogrow/plugin.js +1 -1
  129. package/dist/esm/plugins/local_virtual_scroll/plugin.d.ts +19 -0
  130. package/dist/esm/plugins/local_virtual_scroll/plugin.js +92 -1
  131. package/dist/esm/plugins/local_virtual_scroll/plugin.js.map +1 -1
  132. package/dist/esm/plugins/local_virtual_scroll/types.d.ts +14 -0
  133. package/dist/esm/plugins/local_virtual_scroll/types.js +2 -0
  134. package/dist/esm/plugins/local_virtual_scroll/types.js.map +1 -0
  135. package/dist/esm/plugins/no_active_items/plugin.d.ts +15 -0
  136. package/dist/esm/plugins/no_active_items/plugin.js +1 -1
  137. package/dist/esm/plugins/no_backspace_delete/plugin.d.ts +15 -0
  138. package/dist/esm/plugins/no_backspace_delete/plugin.js +1 -1
  139. package/dist/esm/plugins/optgroup_columns/plugin.d.ts +16 -0
  140. package/dist/esm/plugins/optgroup_columns/plugin.js +1 -1
  141. package/dist/esm/plugins/remove_button/plugin.d.ts +17 -0
  142. package/dist/esm/plugins/remove_button/plugin.js +1 -1
  143. package/dist/esm/plugins/remove_button/types.d.ts +6 -0
  144. package/dist/esm/plugins/remove_button/types.js +2 -0
  145. package/dist/esm/plugins/remove_button/types.js.map +1 -0
  146. package/dist/esm/plugins/restore_on_backspace/plugin.d.ts +21 -0
  147. package/dist/esm/plugins/restore_on_backspace/plugin.js +1 -1
  148. package/dist/esm/plugins/virtual_scroll/plugin.d.ts +16 -0
  149. package/dist/esm/plugins/virtual_scroll/plugin.js +1 -1
  150. package/dist/esm/tom-select.complete.d.ts +2 -0
  151. package/dist/esm/tom-select.complete.js +33 -0
  152. package/dist/esm/tom-select.complete.js.map +1 -0
  153. package/dist/esm/tom-select.d.ts +594 -0
  154. package/dist/esm/tom-select.js +2300 -0
  155. package/dist/esm/tom-select.js.map +1 -0
  156. package/dist/esm/tom-select.popular.d.ts +2 -0
  157. package/dist/esm/tom-select.popular.js +13 -0
  158. package/dist/esm/tom-select.popular.js.map +1 -0
  159. package/dist/esm/types/core.d.ts +50 -0
  160. package/dist/esm/types/core.js +2 -0
  161. package/dist/esm/types/core.js.map +1 -0
  162. package/dist/esm/types/index.d.ts +2 -0
  163. package/dist/esm/types/index.js +3 -0
  164. package/dist/esm/types/index.js.map +1 -0
  165. package/dist/esm/types/settings.d.ts +81 -0
  166. package/dist/esm/types/settings.js +2 -0
  167. package/dist/esm/types/settings.js.map +1 -0
  168. package/dist/esm/utils.d.ts +95 -0
  169. package/dist/esm/utils.js +195 -0
  170. package/dist/esm/utils.js.map +1 -0
  171. package/dist/esm/vanilla.d.ts +76 -0
  172. package/dist/esm/vanilla.js +172 -0
  173. package/dist/esm/vanilla.js.map +1 -0
  174. package/dist/js/package.json +1 -0
  175. package/dist/js/plugins/caret_position.js +1 -1
  176. package/dist/js/plugins/change_listener.js +1 -1
  177. package/dist/js/plugins/checkbox_options.js +1 -1
  178. package/dist/js/plugins/clear_button.js +1 -1
  179. package/dist/js/plugins/drag_drop.js +1 -1
  180. package/dist/js/plugins/dropdown_header.js +1 -1
  181. package/dist/js/plugins/dropdown_input.js +1 -1
  182. package/dist/js/plugins/input_autogrow.js +1 -1
  183. package/dist/js/plugins/local_virtual_scroll.js +92 -1
  184. package/dist/js/plugins/local_virtual_scroll.js.map +1 -1
  185. package/dist/js/plugins/no_active_items.js +1 -1
  186. package/dist/js/plugins/no_backspace_delete.js +1 -1
  187. package/dist/js/plugins/optgroup_columns.js +1 -1
  188. package/dist/js/plugins/remove_button.js +1 -1
  189. package/dist/js/plugins/restore_on_backspace.js +1 -1
  190. package/dist/js/plugins/virtual_scroll.js +1 -1
  191. package/dist/js/tom-select.base.js +1 -1
  192. package/dist/js/tom-select.base.min.js +1 -1
  193. package/dist/js/tom-select.complete.js +19 -1
  194. package/dist/js/tom-select.complete.js.map +1 -1
  195. package/dist/js/tom-select.complete.min.js +51 -45
  196. package/dist/js/tom-select.complete.min.js.map +1 -1
  197. package/dist/js/tom-select.popular.js +1 -1
  198. package/dist/js/tom-select.popular.min.js +1 -1
  199. package/dist/scss/_dropdown.scss +99 -0
  200. package/dist/scss/_items.scss +114 -0
  201. package/dist/scss/plugins/checkbox_options.scss +11 -0
  202. package/dist/scss/plugins/clear_button.scss +33 -0
  203. package/dist/scss/plugins/drag_drop.scss +10 -0
  204. package/dist/scss/plugins/dropdown_header.scss +24 -0
  205. package/dist/scss/plugins/dropdown_input.scss +43 -0
  206. package/dist/scss/plugins/input_autogrow.scss +15 -0
  207. package/dist/scss/plugins/optgroup_columns.scss +25 -0
  208. package/dist/scss/plugins/remove_button.scss +70 -0
  209. package/dist/scss/tom-select.bootstrap4.scss +218 -0
  210. package/dist/scss/tom-select.bootstrap5.scss +270 -0
  211. package/dist/scss/tom-select.default.scss +89 -0
  212. package/dist/scss/tom-select.scss +179 -0
  213. package/package.json +2 -2
  214. package/src/plugins/local_virtual_scroll/plugin.ts +19 -0
  215. /package/dist/{types → cjs}/constants.d.ts +0 -0
  216. /package/dist/{types → cjs}/contrib/highlight.d.ts +0 -0
  217. /package/dist/{types → cjs}/contrib/microevent.d.ts +0 -0
  218. /package/dist/{types → cjs}/contrib/microplugin.d.ts +0 -0
  219. /package/dist/{types → cjs}/defaults.d.ts +0 -0
  220. /package/dist/{types → cjs}/getSettings.d.ts +0 -0
  221. /package/dist/{types → cjs}/plugins/caret_position/plugin.d.ts +0 -0
  222. /package/dist/{types → cjs}/plugins/change_listener/plugin.d.ts +0 -0
  223. /package/dist/{types → cjs}/plugins/checkbox_options/plugin.d.ts +0 -0
  224. /package/dist/{types → cjs}/plugins/checkbox_options/types.d.ts +0 -0
  225. /package/dist/{types → cjs}/plugins/clear_button/plugin.d.ts +0 -0
  226. /package/dist/{types → cjs}/plugins/clear_button/types.d.ts +0 -0
  227. /package/dist/{types → cjs}/plugins/drag_drop/plugin.d.ts +0 -0
  228. /package/dist/{types → cjs}/plugins/dropdown_header/plugin.d.ts +0 -0
  229. /package/dist/{types → cjs}/plugins/dropdown_header/types.d.ts +0 -0
  230. /package/dist/{types → cjs}/plugins/dropdown_input/plugin.d.ts +0 -0
  231. /package/dist/{types → cjs}/plugins/input_autogrow/plugin.d.ts +0 -0
  232. /package/dist/{types → cjs}/plugins/local_virtual_scroll/plugin.d.ts +0 -0
  233. /package/dist/{types → cjs}/plugins/local_virtual_scroll/types.d.ts +0 -0
  234. /package/dist/{types → cjs}/plugins/no_active_items/plugin.d.ts +0 -0
  235. /package/dist/{types → cjs}/plugins/no_backspace_delete/plugin.d.ts +0 -0
  236. /package/dist/{types → cjs}/plugins/optgroup_columns/plugin.d.ts +0 -0
  237. /package/dist/{types → cjs}/plugins/remove_button/plugin.d.ts +0 -0
  238. /package/dist/{types → cjs}/plugins/remove_button/types.d.ts +0 -0
  239. /package/dist/{types → cjs}/plugins/restore_on_backspace/plugin.d.ts +0 -0
  240. /package/dist/{types → cjs}/plugins/virtual_scroll/plugin.d.ts +0 -0
  241. /package/dist/{types → cjs}/tom-select.complete.d.ts +0 -0
  242. /package/dist/{types → cjs}/tom-select.d.ts +0 -0
  243. /package/dist/{types → cjs}/tom-select.popular.d.ts +0 -0
  244. /package/dist/{types → cjs}/types/core.d.ts +0 -0
  245. /package/dist/{types → cjs}/types/index.d.ts +0 -0
  246. /package/dist/{types → cjs}/types/settings.d.ts +0 -0
  247. /package/dist/{types → cjs}/utils.d.ts +0 -0
  248. /package/dist/{types → cjs}/vanilla.d.ts +0 -0
@@ -0,0 +1,2303 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const microevent_ts_1 = require("./contrib/microevent.js");
4
+ const microplugin_ts_1 = require("./contrib/microplugin.js");
5
+ const sifter_1 = require("@orchidjs/sifter");
6
+ const unicode_variants_1 = require("@orchidjs/unicode-variants");
7
+ const highlight_ts_1 = require("./contrib/highlight.js");
8
+ const constants = require("./constants.js");
9
+ const getSettings_ts_1 = require("./getSettings.js");
10
+ const utils_ts_1 = require("./utils.js");
11
+ const vanilla_ts_1 = require("./vanilla.js");
12
+ var instance_i = 0;
13
+ class TomSelect extends (0, microplugin_ts_1.default)(microevent_ts_1.default) {
14
+ constructor(input_arg, user_settings) {
15
+ super();
16
+ this.order = 0;
17
+ this.isOpen = false;
18
+ this.isDisabled = false;
19
+ this.isReadOnly = false;
20
+ this.isInvalid = false; // @deprecated 1.8
21
+ this.isValid = true;
22
+ this.isLocked = false;
23
+ this.isFocused = false;
24
+ this.isInputHidden = false;
25
+ this.isSetup = false;
26
+ this.ignoreFocus = false;
27
+ this.ignoreHover = false;
28
+ this.hasOptions = false;
29
+ this.lastValue = '';
30
+ this.caretPos = 0;
31
+ this.loading = 0;
32
+ this.loadedSearches = {};
33
+ this.activeOption = null;
34
+ this.activeItems = [];
35
+ this.optgroups = {};
36
+ this.options = {};
37
+ this.userOptions = {};
38
+ this.items = [];
39
+ this.refreshTimeout = null;
40
+ instance_i++;
41
+ var dir;
42
+ var input = (0, vanilla_ts_1.getDom)(input_arg);
43
+ if (input.tomselect) {
44
+ throw new Error('Tom Select already initialized on this element');
45
+ }
46
+ input.tomselect = this;
47
+ // detect rtl environment
48
+ var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);
49
+ dir = computedStyle.getPropertyValue('direction');
50
+ // setup default state
51
+ const settings = (0, getSettings_ts_1.default)(input, user_settings);
52
+ this.settings = settings;
53
+ this.input = input;
54
+ this.tabIndex = input.tabIndex || 0;
55
+ this.is_select_tag = input.tagName.toLowerCase() === 'select';
56
+ this.rtl = /rtl/i.test(dir);
57
+ this.inputId = (0, utils_ts_1.getId)(input, 'tomselect-' + instance_i);
58
+ this.isRequired = input.required;
59
+ // search system
60
+ this.sifter = new sifter_1.Sifter(this.options, { diacritics: settings.diacritics });
61
+ // option-dependent defaults
62
+ settings.mode = settings.mode || (settings.maxItems === 1 ? 'single' : 'multi');
63
+ if (typeof settings.hideSelected !== 'boolean') {
64
+ settings.hideSelected = settings.mode === 'multi';
65
+ }
66
+ if (typeof settings.hidePlaceholder !== 'boolean') {
67
+ settings.hidePlaceholder = settings.mode !== 'multi';
68
+ }
69
+ // set up createFilter callback
70
+ var filter = settings.createFilter;
71
+ if (typeof filter !== 'function') {
72
+ if (typeof filter === 'string') {
73
+ filter = new RegExp(filter);
74
+ }
75
+ if (filter instanceof RegExp) {
76
+ settings.createFilter = (input) => filter.test(input);
77
+ }
78
+ else {
79
+ settings.createFilter = (value) => {
80
+ return this.settings.duplicates || !this.options[value];
81
+ };
82
+ }
83
+ }
84
+ this.initializePlugins(settings.plugins);
85
+ this.setupCallbacks();
86
+ this.setupTemplates();
87
+ // Create all elements
88
+ const wrapper = (0, vanilla_ts_1.getDom)('<div>');
89
+ const control = (0, vanilla_ts_1.getDom)('<div>');
90
+ const dropdown = this._render('dropdown');
91
+ const dropdown_content = (0, vanilla_ts_1.getDom)(`<div role="listbox" tabindex="-1">`);
92
+ const classes = this.input.getAttribute('class') || '';
93
+ const inputMode = settings.mode;
94
+ var control_input;
95
+ (0, vanilla_ts_1.addClasses)(wrapper, settings.wrapperClass, classes, inputMode);
96
+ (0, vanilla_ts_1.addClasses)(control, settings.controlClass);
97
+ (0, utils_ts_1.append)(wrapper, control);
98
+ (0, vanilla_ts_1.addClasses)(dropdown, settings.dropdownClass, inputMode);
99
+ if (settings.copyClassesToDropdown) {
100
+ (0, vanilla_ts_1.addClasses)(dropdown, classes);
101
+ }
102
+ (0, vanilla_ts_1.addClasses)(dropdown_content, settings.dropdownContentClass);
103
+ (0, utils_ts_1.append)(dropdown, dropdown_content);
104
+ (0, vanilla_ts_1.getDom)(settings.dropdownParent || wrapper).appendChild(dropdown);
105
+ // default controlInput
106
+ if ((0, vanilla_ts_1.isHtmlString)(settings.controlInput)) {
107
+ control_input = (0, vanilla_ts_1.getDom)(settings.controlInput);
108
+ // set attributes
109
+ var attrs = ['autocorrect', 'autocapitalize', 'autocomplete', 'spellcheck', 'aria-label'];
110
+ (0, utils_ts_1.iterate)(attrs, (attr) => {
111
+ if (input.getAttribute(attr)) {
112
+ (0, vanilla_ts_1.setAttr)(control_input, { [attr]: input.getAttribute(attr) });
113
+ }
114
+ });
115
+ control_input.tabIndex = -1;
116
+ control.appendChild(control_input);
117
+ this.focus_node = control_input;
118
+ // dom element
119
+ }
120
+ else if (settings.controlInput) {
121
+ control_input = (0, vanilla_ts_1.getDom)(settings.controlInput);
122
+ this.focus_node = control_input;
123
+ }
124
+ else {
125
+ control_input = (0, vanilla_ts_1.getDom)('<input/>');
126
+ this.focus_node = control;
127
+ }
128
+ this.wrapper = wrapper;
129
+ this.dropdown = dropdown;
130
+ this.dropdown_content = dropdown_content;
131
+ this.control = control;
132
+ this.control_input = control_input;
133
+ this.setup();
134
+ }
135
+ /**
136
+ * set up event bindings.
137
+ *
138
+ */
139
+ setup() {
140
+ const self = this;
141
+ const settings = self.settings;
142
+ const control_input = self.control_input;
143
+ const dropdown = self.dropdown;
144
+ const dropdown_content = self.dropdown_content;
145
+ const wrapper = self.wrapper;
146
+ const control = self.control;
147
+ const input = self.input;
148
+ const focus_node = self.focus_node;
149
+ const passive_event = { passive: true };
150
+ const listboxId = self.inputId + '-ts-dropdown';
151
+ (0, vanilla_ts_1.setAttr)(dropdown_content, {
152
+ id: listboxId
153
+ });
154
+ (0, vanilla_ts_1.setAttr)(focus_node, {
155
+ role: 'combobox',
156
+ 'aria-haspopup': 'listbox',
157
+ 'aria-expanded': 'false',
158
+ 'aria-controls': listboxId
159
+ });
160
+ const control_id = (0, utils_ts_1.getId)(focus_node, self.inputId + '-ts-control');
161
+ const query = "label[for='" + (0, vanilla_ts_1.escapeQuery)(self.inputId) + "']";
162
+ const label = document.querySelector(query);
163
+ const label_click = self.focus.bind(self);
164
+ if (label) {
165
+ (0, utils_ts_1.addEvent)(label, 'click', label_click);
166
+ (0, vanilla_ts_1.setAttr)(label, { for: control_id });
167
+ const label_id = (0, utils_ts_1.getId)(label, self.inputId + '-ts-label');
168
+ (0, vanilla_ts_1.setAttr)(focus_node, { 'aria-labelledby': label_id });
169
+ (0, vanilla_ts_1.setAttr)(dropdown_content, { 'aria-labelledby': label_id });
170
+ }
171
+ wrapper.style.width = input.style.width;
172
+ wrapper.style.minWidth = input.style.minWidth;
173
+ wrapper.style.maxWidth = input.style.maxWidth;
174
+ if (self.plugins.names.length) {
175
+ const classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
176
+ (0, vanilla_ts_1.addClasses)([wrapper, dropdown], classes_plugins);
177
+ }
178
+ if ((settings.maxItems === null || settings.maxItems > 1) && self.is_select_tag) {
179
+ (0, vanilla_ts_1.setAttr)(input, { multiple: 'multiple' });
180
+ }
181
+ if (settings.placeholder) {
182
+ (0, vanilla_ts_1.setAttr)(control_input, { placeholder: settings.placeholder });
183
+ }
184
+ // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
185
+ if (!settings.splitOn && settings.delimiter) {
186
+ settings.splitOn = new RegExp('\\s*' + (0, unicode_variants_1.escape_regex)(settings.delimiter) + '+\\s*');
187
+ }
188
+ // debounce user defined load() if loadThrottle > 0
189
+ // after initializePlugins() so plugins can create/modify user defined loaders
190
+ if (settings.load && settings.loadThrottle) {
191
+ settings.load = (0, utils_ts_1.loadDebounce)(settings.load, settings.loadThrottle);
192
+ }
193
+ (0, utils_ts_1.addEvent)(dropdown, 'mousemove', () => {
194
+ self.ignoreHover = false;
195
+ });
196
+ (0, utils_ts_1.addEvent)(dropdown, 'mouseenter', (e) => {
197
+ var target_match = (0, vanilla_ts_1.parentMatch)(e.target, '[data-selectable]', dropdown);
198
+ if (target_match)
199
+ self.onOptionHover(e, target_match);
200
+ }, { capture: true });
201
+ // clicking on an option should select it
202
+ (0, utils_ts_1.addEvent)(dropdown, 'click', (evt) => {
203
+ const option = (0, vanilla_ts_1.parentMatch)(evt.target, '[data-selectable]');
204
+ if (option) {
205
+ self.onOptionSelect(evt, option);
206
+ (0, utils_ts_1.preventDefault)(evt, true);
207
+ }
208
+ });
209
+ (0, utils_ts_1.addEvent)(control, 'click', (evt) => {
210
+ var target_match = (0, vanilla_ts_1.parentMatch)(evt.target, '[data-ts-item]', control);
211
+ if (target_match && self.onItemSelect(evt, target_match)) {
212
+ (0, utils_ts_1.preventDefault)(evt, true);
213
+ return;
214
+ }
215
+ // retain focus (see control_input mousedown)
216
+ if (control_input.value != '') {
217
+ return;
218
+ }
219
+ self.onClick();
220
+ (0, utils_ts_1.preventDefault)(evt, true);
221
+ });
222
+ // keydown on focus_node for arrow_down/arrow_up
223
+ (0, utils_ts_1.addEvent)(focus_node, 'keydown', (e) => self.onKeyDown(e));
224
+ // keypress and input/keyup
225
+ (0, utils_ts_1.addEvent)(control_input, 'keypress', (e) => self.onKeyPress(e));
226
+ (0, utils_ts_1.addEvent)(control_input, 'input', (e) => self.onInput(e));
227
+ (0, utils_ts_1.addEvent)(focus_node, 'blur', (e) => self.onBlur(e));
228
+ (0, utils_ts_1.addEvent)(focus_node, 'focus', (e) => self.onFocus(e));
229
+ (0, utils_ts_1.addEvent)(control_input, 'paste', (e) => self.onPaste(e));
230
+ const doc_mousedown = (evt) => {
231
+ // blur if target is outside of this instance
232
+ // dropdown is not always inside wrapper
233
+ const target = evt.composedPath()[0];
234
+ if (!wrapper.contains(target) && !dropdown.contains(target)) {
235
+ if (self.isFocused) {
236
+ self.blur();
237
+ }
238
+ self.inputState();
239
+ return;
240
+ }
241
+ // retain focus by preventing native handling. if the
242
+ // event target is the input it should not be modified.
243
+ // otherwise, text selection within the input won't work.
244
+ // Fixes bug #212 which is no covered by tests
245
+ if (target == control_input && self.isOpen) {
246
+ evt.stopPropagation();
247
+ // clicking anywhere in the control should not blur the control_input (which would close the dropdown)
248
+ }
249
+ else {
250
+ (0, utils_ts_1.preventDefault)(evt, true);
251
+ }
252
+ };
253
+ const win_scroll = () => {
254
+ if (self.isOpen) {
255
+ self.positionDropdown();
256
+ }
257
+ };
258
+ const input_invalid = () => {
259
+ if (self.isValid) {
260
+ self.isValid = false;
261
+ self.isInvalid = true;
262
+ self.refreshState();
263
+ }
264
+ };
265
+ (0, utils_ts_1.addEvent)(input, 'invalid', input_invalid);
266
+ (0, utils_ts_1.addEvent)(document, 'mousedown', doc_mousedown);
267
+ (0, utils_ts_1.addEvent)(window, 'scroll', win_scroll, passive_event);
268
+ (0, utils_ts_1.addEvent)(window, 'resize', win_scroll, passive_event);
269
+ this._destroy = () => {
270
+ input.removeEventListener('invalid', input_invalid);
271
+ document.removeEventListener('mousedown', doc_mousedown);
272
+ window.removeEventListener('scroll', win_scroll);
273
+ window.removeEventListener('resize', win_scroll);
274
+ if (label)
275
+ label.removeEventListener('click', label_click);
276
+ };
277
+ // store original html and tab index so that they can be
278
+ // restored when the destroy() method is called.
279
+ this.revertSettings = {
280
+ innerHTML: input.innerHTML,
281
+ tabIndex: input.tabIndex
282
+ };
283
+ input.tabIndex = -1;
284
+ input.insertAdjacentElement('afterend', self.wrapper);
285
+ self.sync(false);
286
+ settings.items = [];
287
+ delete settings.optgroups;
288
+ delete settings.options;
289
+ self.refreshItems();
290
+ self.close(false);
291
+ self.inputState();
292
+ self.isSetup = true;
293
+ if (input.disabled) {
294
+ self.disable();
295
+ }
296
+ else if (input.readOnly) {
297
+ self.setReadOnly(true);
298
+ }
299
+ else {
300
+ self.enable(); //sets tabIndex
301
+ }
302
+ self.on('change', this.onChange);
303
+ (0, vanilla_ts_1.addClasses)(input, 'tomselected', 'ts-hidden-accessible');
304
+ self.trigger('initialize');
305
+ // preload options
306
+ if (settings.preload === true) {
307
+ self.preload();
308
+ }
309
+ }
310
+ /**
311
+ * Register options and optgroups
312
+ *
313
+ */
314
+ setupOptions(options = [], optgroups = []) {
315
+ // build options table
316
+ this.addOptions(options);
317
+ // build optgroup table
318
+ (0, utils_ts_1.iterate)(optgroups, (optgroup) => {
319
+ this.registerOptionGroup(optgroup);
320
+ });
321
+ }
322
+ /**
323
+ * Sets up default rendering functions.
324
+ */
325
+ setupTemplates() {
326
+ var self = this;
327
+ var field_label = self.settings.labelField;
328
+ var field_optgroup = self.settings.optgroupLabelField;
329
+ var templates = {
330
+ 'optgroup': (data) => {
331
+ let optgroup = document.createElement('div');
332
+ optgroup.className = 'optgroup';
333
+ optgroup.appendChild(data.options);
334
+ return optgroup;
335
+ },
336
+ 'optgroup_header': (data, escape) => {
337
+ return '<div class="optgroup-header">' + escape(data[field_optgroup]) + '</div>';
338
+ },
339
+ 'option': (data, escape) => {
340
+ return '<div>' + escape(data[field_label]) + '</div>';
341
+ },
342
+ 'item': (data, escape) => {
343
+ return '<div>' + escape(data[field_label]) + '</div>';
344
+ },
345
+ 'option_create': (data, escape) => {
346
+ return '<div class="create">Add <strong>' + escape(data.input) + '</strong>&hellip;</div>';
347
+ },
348
+ 'no_results': () => {
349
+ return '<div class="no-results">No results found</div>';
350
+ },
351
+ 'loading': () => {
352
+ return '<div class="spinner"></div>';
353
+ },
354
+ 'not_loading': () => { },
355
+ 'dropdown': () => {
356
+ return '<div></div>';
357
+ }
358
+ };
359
+ self.settings.render = Object.assign({}, templates, self.settings.render);
360
+ }
361
+ /**
362
+ * Maps fired events to callbacks provided
363
+ * in the settings used when creating the control.
364
+ */
365
+ setupCallbacks() {
366
+ var key, fn;
367
+ var callbacks = {
368
+ 'initialize': 'onInitialize',
369
+ 'change': 'onChange',
370
+ 'item_add': 'onItemAdd',
371
+ 'item_remove': 'onItemRemove',
372
+ 'item_select': 'onItemSelect',
373
+ 'clear': 'onClear',
374
+ 'option_add': 'onOptionAdd',
375
+ 'option_remove': 'onOptionRemove',
376
+ 'option_clear': 'onOptionClear',
377
+ 'optgroup_add': 'onOptionGroupAdd',
378
+ 'optgroup_remove': 'onOptionGroupRemove',
379
+ 'optgroup_clear': 'onOptionGroupClear',
380
+ 'dropdown_open': 'onDropdownOpen',
381
+ 'dropdown_close': 'onDropdownClose',
382
+ 'type': 'onType',
383
+ 'load': 'onLoad',
384
+ 'focus': 'onFocus',
385
+ 'blur': 'onBlur'
386
+ };
387
+ for (key in callbacks) {
388
+ fn = this.settings[callbacks[key]];
389
+ if (fn)
390
+ this.on(key, fn);
391
+ }
392
+ }
393
+ /**
394
+ * Sync the Tom Select instance with the original input or select
395
+ *
396
+ */
397
+ sync(get_settings = true) {
398
+ const self = this;
399
+ const settings = get_settings ? (0, getSettings_ts_1.default)(self.input, { delimiter: self.settings.delimiter, allowEmptyOption: self.settings.allowEmptyOption }) : self.settings;
400
+ self.setupOptions(settings.options, settings.optgroups);
401
+ self.setValue(settings.items || [], true); // silent prevents recursion
402
+ self.lastQuery = null; // so updated options will be displayed in dropdown
403
+ }
404
+ /**
405
+ * Triggered when the main control element
406
+ * has a click event.
407
+ *
408
+ */
409
+ onClick() {
410
+ var self = this;
411
+ if (self.activeItems.length > 0) {
412
+ self.clearActiveItems();
413
+ self.focus();
414
+ return;
415
+ }
416
+ if (self.isFocused && self.isOpen) {
417
+ self.blur();
418
+ }
419
+ else {
420
+ self.focus();
421
+ }
422
+ }
423
+ /**
424
+ * @deprecated v1.7
425
+ *
426
+ */
427
+ onMouseDown() { }
428
+ /**
429
+ * Triggered when the value of the control has been changed.
430
+ * This should propagate the event to the original DOM
431
+ * input / select element.
432
+ */
433
+ onChange() {
434
+ (0, vanilla_ts_1.triggerEvent)(this.input, 'input');
435
+ (0, vanilla_ts_1.triggerEvent)(this.input, 'change');
436
+ }
437
+ /**
438
+ * Triggered on <input> paste.
439
+ *
440
+ */
441
+ onPaste(e) {
442
+ var self = this;
443
+ if (self.isInputHidden || self.isLocked) {
444
+ (0, utils_ts_1.preventDefault)(e);
445
+ return;
446
+ }
447
+ // If a regex or string is included, this will split the pasted
448
+ // input and create Items for each separate value
449
+ if (!self.settings.splitOn) {
450
+ return;
451
+ }
452
+ // Wait for pasted text to be recognized in value
453
+ setTimeout(() => {
454
+ var pastedText = self.inputValue();
455
+ if (!pastedText.match(self.settings.splitOn)) {
456
+ return;
457
+ }
458
+ var splitInput = pastedText.trim().split(self.settings.splitOn);
459
+ (0, utils_ts_1.iterate)(splitInput, (piece) => {
460
+ const hash = (0, utils_ts_1.hash_key)(piece);
461
+ if (hash) {
462
+ if (this.options[piece]) {
463
+ self.addItem(piece);
464
+ }
465
+ else {
466
+ self.createItem(piece);
467
+ }
468
+ }
469
+ });
470
+ }, 0);
471
+ }
472
+ /**
473
+ * Triggered on <input> keypress.
474
+ *
475
+ */
476
+ onKeyPress(e) {
477
+ var self = this;
478
+ if (self.isLocked) {
479
+ (0, utils_ts_1.preventDefault)(e);
480
+ return;
481
+ }
482
+ var character = String.fromCharCode(e.keyCode || e.which);
483
+ if (self.settings.create && self.settings.mode === 'multi' && character === self.settings.delimiter) {
484
+ self.createItem();
485
+ (0, utils_ts_1.preventDefault)(e);
486
+ return;
487
+ }
488
+ }
489
+ /**
490
+ * Triggered on <input> keydown.
491
+ *
492
+ */
493
+ onKeyDown(e) {
494
+ var self = this;
495
+ self.ignoreHover = true;
496
+ if (self.isLocked) {
497
+ if (e.keyCode !== constants.KEY_TAB) {
498
+ (0, utils_ts_1.preventDefault)(e);
499
+ }
500
+ return;
501
+ }
502
+ switch (e.keyCode) {
503
+ // ctrl+A: select all
504
+ case constants.KEY_A:
505
+ if ((0, utils_ts_1.isKeyDown)(constants.KEY_SHORTCUT, e)) {
506
+ if (self.control_input.value == '') {
507
+ (0, utils_ts_1.preventDefault)(e);
508
+ self.selectAll();
509
+ return;
510
+ }
511
+ }
512
+ break;
513
+ // esc: close dropdown
514
+ case constants.KEY_ESC:
515
+ if (self.isOpen) {
516
+ (0, utils_ts_1.preventDefault)(e, true);
517
+ self.close();
518
+ }
519
+ self.clearActiveItems();
520
+ return;
521
+ // down: open dropdown or move selection down
522
+ case constants.KEY_DOWN:
523
+ if (!self.isOpen && self.hasOptions) {
524
+ self.open();
525
+ }
526
+ else if (self.activeOption) {
527
+ let next = self.getAdjacent(self.activeOption, 1);
528
+ if (next)
529
+ self.setActiveOption(next);
530
+ }
531
+ (0, utils_ts_1.preventDefault)(e);
532
+ return;
533
+ // up: move selection up
534
+ case constants.KEY_UP:
535
+ if (self.activeOption) {
536
+ let prev = self.getAdjacent(self.activeOption, -1);
537
+ if (prev)
538
+ self.setActiveOption(prev);
539
+ }
540
+ (0, utils_ts_1.preventDefault)(e);
541
+ return;
542
+ // return: select active option
543
+ case constants.KEY_RETURN:
544
+ if (self.canSelect(self.activeOption)) {
545
+ self.onOptionSelect(e, self.activeOption);
546
+ (0, utils_ts_1.preventDefault)(e);
547
+ // if the option_create=null, the dropdown might be closed
548
+ }
549
+ else if (self.settings.create && self.createItem()) {
550
+ (0, utils_ts_1.preventDefault)(e);
551
+ // don't submit form when searching for a value
552
+ }
553
+ else if (document.activeElement == self.control_input && self.isOpen) {
554
+ (0, utils_ts_1.preventDefault)(e);
555
+ }
556
+ return;
557
+ // left: modifiy item selection to the left
558
+ case constants.KEY_LEFT:
559
+ self.advanceSelection(-1, e);
560
+ return;
561
+ // right: modifiy item selection to the right
562
+ case constants.KEY_RIGHT:
563
+ self.advanceSelection(1, e);
564
+ return;
565
+ // tab: select active option and/or create item
566
+ case constants.KEY_TAB:
567
+ if (self.settings.selectOnTab) {
568
+ if (self.canSelect(self.activeOption)) {
569
+ self.onOptionSelect(e, self.activeOption);
570
+ // prevent default [tab] behaviour of jump to the next field
571
+ // if select isFull, then the dropdown won't be open and [tab] will work normally
572
+ (0, utils_ts_1.preventDefault)(e);
573
+ }
574
+ else if (self.settings.create && self.createItem()) {
575
+ (0, utils_ts_1.preventDefault)(e);
576
+ }
577
+ }
578
+ return;
579
+ // delete|backspace: delete items
580
+ case constants.KEY_BACKSPACE:
581
+ case constants.KEY_DELETE:
582
+ self.deleteSelection(e);
583
+ return;
584
+ }
585
+ // don't enter text in the control_input when active items are selected
586
+ if (self.isInputHidden && !(0, utils_ts_1.isKeyDown)(constants.KEY_SHORTCUT, e)) {
587
+ (0, utils_ts_1.preventDefault)(e);
588
+ }
589
+ }
590
+ /**
591
+ * Triggered on <input> keyup.
592
+ *
593
+ */
594
+ onInput(e) {
595
+ if (this.isLocked) {
596
+ return;
597
+ }
598
+ const value = this.inputValue();
599
+ if (this.lastValue === value)
600
+ return;
601
+ this.lastValue = value;
602
+ if (value == '') {
603
+ this._onInput();
604
+ return;
605
+ }
606
+ if (this.refreshTimeout) {
607
+ window.clearTimeout(this.refreshTimeout);
608
+ }
609
+ this.refreshTimeout = (0, utils_ts_1.timeout)(() => {
610
+ this.refreshTimeout = null;
611
+ this._onInput();
612
+ }, this.settings.refreshThrottle);
613
+ }
614
+ _onInput() {
615
+ const value = this.lastValue;
616
+ if (this.settings.shouldLoad.call(this, value)) {
617
+ this.load(value);
618
+ }
619
+ this.refreshOptions();
620
+ this.trigger('type', value);
621
+ }
622
+ /**
623
+ * Triggered when the user rolls over
624
+ * an option in the autocomplete dropdown menu.
625
+ *
626
+ */
627
+ onOptionHover(evt, option) {
628
+ if (this.ignoreHover)
629
+ return;
630
+ this.setActiveOption(option, false);
631
+ }
632
+ /**
633
+ * Triggered on <input> focus.
634
+ *
635
+ */
636
+ onFocus(e) {
637
+ var self = this;
638
+ var wasFocused = self.isFocused;
639
+ if (self.isDisabled || self.isReadOnly) {
640
+ self.blur();
641
+ (0, utils_ts_1.preventDefault)(e);
642
+ return;
643
+ }
644
+ if (self.ignoreFocus)
645
+ return;
646
+ self.isFocused = true;
647
+ if (self.settings.preload === 'focus')
648
+ self.preload();
649
+ if (!wasFocused)
650
+ self.trigger('focus');
651
+ if (!self.activeItems.length) {
652
+ self.inputState();
653
+ self.refreshOptions(!!self.settings.openOnFocus);
654
+ }
655
+ self.refreshState();
656
+ }
657
+ /**
658
+ * Triggered on <input> blur.
659
+ *
660
+ */
661
+ onBlur(e) {
662
+ if (document.hasFocus() === false)
663
+ return;
664
+ var self = this;
665
+ if (!self.isFocused)
666
+ return;
667
+ self.isFocused = false;
668
+ self.ignoreFocus = false;
669
+ var deactivate = () => {
670
+ self.close();
671
+ self.setActiveItem();
672
+ self.setCaret(self.items.length);
673
+ self.trigger('blur');
674
+ };
675
+ if (self.settings.create && self.settings.createOnBlur) {
676
+ self.createItem(null, deactivate);
677
+ }
678
+ else {
679
+ deactivate();
680
+ }
681
+ }
682
+ /**
683
+ * Triggered when the user clicks on an option
684
+ * in the autocomplete dropdown menu.
685
+ *
686
+ */
687
+ onOptionSelect(evt, option) {
688
+ var value, self = this;
689
+ // should not be possible to trigger a option under a disabled optgroup
690
+ if (option.parentElement && option.parentElement.matches('[data-disabled]')) {
691
+ return;
692
+ }
693
+ if (option.classList.contains('create')) {
694
+ self.createItem(null, () => {
695
+ if (self.settings.closeAfterSelect) {
696
+ self.close();
697
+ }
698
+ else if (self.settings.clearAfterSelect) {
699
+ self.setTextboxValue();
700
+ }
701
+ });
702
+ }
703
+ else {
704
+ value = option.dataset.value;
705
+ if (typeof value !== 'undefined') {
706
+ self.lastQuery = null;
707
+ self.addItem(value);
708
+ if (self.settings.closeAfterSelect) {
709
+ self.close();
710
+ }
711
+ else if (self.settings.clearAfterSelect) {
712
+ self.setTextboxValue();
713
+ }
714
+ if (!self.settings.hideSelected && evt.type && /click/.test(evt.type)) {
715
+ self.setActiveOption(option);
716
+ }
717
+ }
718
+ }
719
+ }
720
+ /**
721
+ * Return true if the given option can be selected
722
+ *
723
+ */
724
+ canSelect(option) {
725
+ if (this.isOpen && option && this.dropdown_content.contains(option)) {
726
+ return true;
727
+ }
728
+ return false;
729
+ }
730
+ /**
731
+ * Triggered when the user clicks on an item
732
+ * that has been selected.
733
+ *
734
+ */
735
+ onItemSelect(evt, item) {
736
+ var self = this;
737
+ if (!self.isLocked && self.settings.mode === 'multi') {
738
+ (0, utils_ts_1.preventDefault)(evt);
739
+ self.setActiveItem(item, evt);
740
+ return true;
741
+ }
742
+ return false;
743
+ }
744
+ /**
745
+ * Determines whether or not to invoke
746
+ * the user-provided option provider / loader
747
+ *
748
+ * Note, there is a subtle difference between
749
+ * this.canLoad() and this.settings.shouldLoad();
750
+ *
751
+ * - settings.shouldLoad() is a user-input validator.
752
+ * When false is returned, the not_loading template
753
+ * will be added to the dropdown
754
+ *
755
+ * - canLoad() is lower level validator that checks
756
+ * the Tom Select instance. There is no inherent user
757
+ * feedback when canLoad returns false
758
+ *
759
+ */
760
+ canLoad(value) {
761
+ if (!this.settings.load)
762
+ return false;
763
+ if (this.loadedSearches.hasOwnProperty(value))
764
+ return false;
765
+ return true;
766
+ }
767
+ /**
768
+ * Invokes the user-provided option provider / loader.
769
+ *
770
+ */
771
+ load(value) {
772
+ const self = this;
773
+ if (!self.canLoad(value))
774
+ return;
775
+ (0, vanilla_ts_1.addClasses)(self.wrapper, self.settings.loadingClass);
776
+ self.loading++;
777
+ const callback = self.loadCallback.bind(self);
778
+ self.settings.load.call(self, value, callback);
779
+ }
780
+ /**
781
+ * Invoked by the user-provided option provider
782
+ *
783
+ */
784
+ loadCallback(options, optgroups) {
785
+ const self = this;
786
+ self.loading = Math.max(self.loading - 1, 0);
787
+ self.lastQuery = null;
788
+ self.clearActiveOption(); // when new results load, focus should be on first option
789
+ self.setupOptions(options, optgroups);
790
+ self.refreshOptions(self.isFocused && !self.isInputHidden);
791
+ if (!self.loading) {
792
+ (0, vanilla_ts_1.removeClasses)(self.wrapper, self.settings.loadingClass);
793
+ }
794
+ self.trigger('load', options, optgroups);
795
+ }
796
+ preload() {
797
+ var classList = this.wrapper.classList;
798
+ if (classList.contains('preloaded'))
799
+ return;
800
+ classList.add('preloaded');
801
+ this.load('');
802
+ }
803
+ /**
804
+ * Sets the input field of the control to the specified value.
805
+ *
806
+ */
807
+ setTextboxValue(value = '') {
808
+ var input = this.control_input;
809
+ var changed = input.value !== value;
810
+ if (changed) {
811
+ input.value = value;
812
+ (0, vanilla_ts_1.triggerEvent)(input, 'update');
813
+ this.lastValue = value;
814
+ }
815
+ }
816
+ /**
817
+ * Returns the value of the control. If multiple items
818
+ * can be selected (e.g. <select multiple>), this returns
819
+ * an array. If only one item can be selected, this
820
+ * returns a string.
821
+ *
822
+ */
823
+ getValue() {
824
+ if (this.is_select_tag && this.input.hasAttribute('multiple')) {
825
+ return this.items;
826
+ }
827
+ return this.items.join(this.settings.delimiter);
828
+ }
829
+ /**
830
+ * Resets the selected items to the given value.
831
+ *
832
+ */
833
+ setValue(value, silent) {
834
+ var events = silent ? [] : ['change'];
835
+ (0, utils_ts_1.debounce_events)(this, events, () => {
836
+ this.clear(silent);
837
+ this.addItems(value, silent);
838
+ });
839
+ }
840
+ /**
841
+ * Resets the number of max items to the given value
842
+ *
843
+ */
844
+ setMaxItems(value) {
845
+ if (value === 0)
846
+ value = null; //reset to unlimited items.
847
+ this.settings.maxItems = value;
848
+ this.refreshState();
849
+ }
850
+ /**
851
+ * Sets the selected item.
852
+ *
853
+ */
854
+ setActiveItem(item, e) {
855
+ var self = this;
856
+ var eventName;
857
+ var i, begin, end, swap;
858
+ var last;
859
+ if (self.settings.mode === 'single')
860
+ return;
861
+ // clear the active selection
862
+ if (!item) {
863
+ self.clearActiveItems();
864
+ if (self.isFocused) {
865
+ self.inputState();
866
+ }
867
+ return;
868
+ }
869
+ // modify selection
870
+ eventName = e && e.type.toLowerCase();
871
+ if (eventName === 'click' && (0, utils_ts_1.isKeyDown)('shiftKey', e) && self.activeItems.length) {
872
+ last = self.getLastActive();
873
+ begin = Array.prototype.indexOf.call(self.control.children, last);
874
+ end = Array.prototype.indexOf.call(self.control.children, item);
875
+ if (begin > end) {
876
+ swap = begin;
877
+ begin = end;
878
+ end = swap;
879
+ }
880
+ for (i = begin; i <= end; i++) {
881
+ item = self.control.children[i];
882
+ if (self.activeItems.indexOf(item) === -1) {
883
+ self.setActiveItemClass(item);
884
+ }
885
+ }
886
+ (0, utils_ts_1.preventDefault)(e);
887
+ }
888
+ else if ((eventName === 'click' && (0, utils_ts_1.isKeyDown)(constants.KEY_SHORTCUT, e)) || (eventName === 'keydown' && (0, utils_ts_1.isKeyDown)('shiftKey', e))) {
889
+ if (item.classList.contains('active')) {
890
+ self.removeActiveItem(item);
891
+ }
892
+ else {
893
+ self.setActiveItemClass(item);
894
+ }
895
+ }
896
+ else {
897
+ self.clearActiveItems();
898
+ self.setActiveItemClass(item);
899
+ }
900
+ // ensure control has focus
901
+ self.inputState();
902
+ if (!self.isFocused) {
903
+ self.focus();
904
+ }
905
+ }
906
+ /**
907
+ * Set the active and last-active classes
908
+ *
909
+ */
910
+ setActiveItemClass(item) {
911
+ const self = this;
912
+ const last_active = self.control.querySelector('.last-active');
913
+ if (last_active)
914
+ (0, vanilla_ts_1.removeClasses)(last_active, 'last-active');
915
+ (0, vanilla_ts_1.addClasses)(item, 'active last-active');
916
+ self.trigger('item_select', item);
917
+ if (self.activeItems.indexOf(item) == -1) {
918
+ self.activeItems.push(item);
919
+ }
920
+ }
921
+ /**
922
+ * Remove active item
923
+ *
924
+ */
925
+ removeActiveItem(item) {
926
+ var idx = this.activeItems.indexOf(item);
927
+ this.activeItems.splice(idx, 1);
928
+ (0, vanilla_ts_1.removeClasses)(item, 'active');
929
+ }
930
+ /**
931
+ * Clears all the active items
932
+ *
933
+ */
934
+ clearActiveItems() {
935
+ (0, vanilla_ts_1.removeClasses)(this.activeItems, 'active');
936
+ this.activeItems = [];
937
+ }
938
+ /**
939
+ * Sets the selected item in the dropdown menu
940
+ * of available options.
941
+ *
942
+ */
943
+ setActiveOption(option, scroll = true) {
944
+ if (option === this.activeOption) {
945
+ return;
946
+ }
947
+ this.clearActiveOption();
948
+ if (!option)
949
+ return;
950
+ this.activeOption = option;
951
+ (0, vanilla_ts_1.setAttr)(this.focus_node, { 'aria-activedescendant': option.getAttribute('id') });
952
+ (0, vanilla_ts_1.setAttr)(option, { 'aria-selected': 'true' });
953
+ (0, vanilla_ts_1.addClasses)(option, 'active');
954
+ if (scroll)
955
+ this.scrollToOption(option);
956
+ }
957
+ /**
958
+ * Sets the dropdown_content scrollTop to display the option
959
+ *
960
+ */
961
+ scrollToOption(option, behavior) {
962
+ if (!option)
963
+ return;
964
+ const content = this.dropdown_content;
965
+ const height_menu = content.clientHeight;
966
+ const scrollTop = content.scrollTop || 0;
967
+ const height_item = option.offsetHeight;
968
+ const y = option.getBoundingClientRect().top - content.getBoundingClientRect().top + scrollTop;
969
+ if (y + height_item > height_menu + scrollTop) {
970
+ this.scroll(y - height_menu + height_item, behavior);
971
+ }
972
+ else if (y < scrollTop) {
973
+ this.scroll(y, behavior);
974
+ }
975
+ }
976
+ /**
977
+ * Scroll the dropdown to the given position
978
+ *
979
+ */
980
+ scroll(scrollTop, behavior) {
981
+ const content = this.dropdown_content;
982
+ if (behavior) {
983
+ content.style.scrollBehavior = behavior;
984
+ }
985
+ content.scrollTop = scrollTop;
986
+ content.style.scrollBehavior = '';
987
+ }
988
+ /**
989
+ * Clears the active option
990
+ *
991
+ */
992
+ clearActiveOption() {
993
+ if (this.activeOption) {
994
+ (0, vanilla_ts_1.removeClasses)(this.activeOption, 'active');
995
+ (0, vanilla_ts_1.setAttr)(this.activeOption, { 'aria-selected': null });
996
+ }
997
+ this.activeOption = null;
998
+ (0, vanilla_ts_1.setAttr)(this.focus_node, { 'aria-activedescendant': null });
999
+ }
1000
+ /**
1001
+ * Selects all items (CTRL + A).
1002
+ */
1003
+ selectAll() {
1004
+ const self = this;
1005
+ if (self.settings.mode === 'single')
1006
+ return;
1007
+ const activeItems = self.controlChildren();
1008
+ if (!activeItems.length)
1009
+ return;
1010
+ self.inputState();
1011
+ self.close();
1012
+ self.activeItems = activeItems;
1013
+ (0, utils_ts_1.iterate)(activeItems, (item) => {
1014
+ self.setActiveItemClass(item);
1015
+ });
1016
+ }
1017
+ /**
1018
+ * Determines if the control_input should be in a hidden or visible state
1019
+ *
1020
+ */
1021
+ inputState() {
1022
+ var self = this;
1023
+ if (!self.control.contains(self.control_input))
1024
+ return;
1025
+ (0, vanilla_ts_1.setAttr)(self.control_input, { placeholder: self.settings.placeholder });
1026
+ if (self.activeItems.length > 0 || (!self.isFocused && self.settings.hidePlaceholder && self.items.length > 0)) {
1027
+ self.setTextboxValue();
1028
+ self.isInputHidden = true;
1029
+ }
1030
+ else {
1031
+ if (self.settings.hidePlaceholder && self.items.length > 0) {
1032
+ (0, vanilla_ts_1.setAttr)(self.control_input, { placeholder: '' });
1033
+ }
1034
+ self.isInputHidden = false;
1035
+ }
1036
+ self.wrapper.classList.toggle('input-hidden', self.isInputHidden);
1037
+ }
1038
+ /**
1039
+ * Get the input value
1040
+ */
1041
+ inputValue() {
1042
+ return this.control_input.value.trim();
1043
+ }
1044
+ /**
1045
+ * Gives the control focus.
1046
+ */
1047
+ focus() {
1048
+ var self = this;
1049
+ if (self.isDisabled || self.isReadOnly)
1050
+ return;
1051
+ self.ignoreFocus = true;
1052
+ if (self.control_input.offsetWidth) {
1053
+ self.control_input.focus();
1054
+ }
1055
+ else {
1056
+ self.focus_node.focus();
1057
+ }
1058
+ setTimeout(() => {
1059
+ self.ignoreFocus = false;
1060
+ self.onFocus();
1061
+ }, 0);
1062
+ }
1063
+ /**
1064
+ * Forces the control out of focus.
1065
+ *
1066
+ */
1067
+ blur() {
1068
+ this.focus_node.blur();
1069
+ this.onBlur();
1070
+ }
1071
+ /**
1072
+ * Returns a function that scores an object
1073
+ * to show how good of a match it is to the
1074
+ * provided query.
1075
+ *
1076
+ * @return {function}
1077
+ */
1078
+ getScoreFunction(query) {
1079
+ return this.sifter.getScoreFunction(query, this.getSearchOptions());
1080
+ }
1081
+ /**
1082
+ * Returns search options for sifter (the system
1083
+ * for scoring and sorting results).
1084
+ *
1085
+ * @see https://github.com/orchidjs/sifter.js
1086
+ * @return {object}
1087
+ */
1088
+ getSearchOptions() {
1089
+ var settings = this.settings;
1090
+ var sort = settings.sortField;
1091
+ if (typeof settings.sortField === 'string') {
1092
+ sort = [{ field: settings.sortField }];
1093
+ }
1094
+ return {
1095
+ fields: settings.searchField,
1096
+ conjunction: settings.searchConjunction,
1097
+ sort: sort,
1098
+ nesting: settings.nesting
1099
+ };
1100
+ }
1101
+ /**
1102
+ * Searches through available options and returns
1103
+ * a sorted array of matches.
1104
+ *
1105
+ */
1106
+ search(query) {
1107
+ var result, calculateScore;
1108
+ var self = this;
1109
+ var options = this.getSearchOptions();
1110
+ // validate user-provided result scoring function
1111
+ if (self.settings.score) {
1112
+ calculateScore = self.settings.score.call(self, query);
1113
+ if (typeof calculateScore !== 'function') {
1114
+ throw new Error('Tom Select "score" setting must be a function that returns a function');
1115
+ }
1116
+ }
1117
+ // perform search
1118
+ if (query !== self.lastQuery) {
1119
+ self.lastQuery = query;
1120
+ // temp fix for https://github.com/orchidjs/tom-select/issues/987
1121
+ // UI crashed when more than 30 same chars in a row, prevent search and return empt result
1122
+ if (/(.)\1{15,}/.test(query)) {
1123
+ query = '';
1124
+ }
1125
+ result = self.sifter.search(query, Object.assign(options, { score: calculateScore }));
1126
+ self.currentResults = result;
1127
+ }
1128
+ else {
1129
+ result = Object.assign({}, self.currentResults);
1130
+ }
1131
+ // filter out selected items
1132
+ if (self.settings.hideSelected) {
1133
+ result.items = result.items.filter((item) => {
1134
+ let hashed = (0, utils_ts_1.hash_key)(item.id);
1135
+ return !(hashed !== null && self.items.indexOf(hashed) !== -1);
1136
+ });
1137
+ }
1138
+ return result;
1139
+ }
1140
+ /**
1141
+ * Refreshes the list of available options shown
1142
+ * in the autocomplete dropdown menu.
1143
+ *
1144
+ */
1145
+ refreshOptions(triggerDropdown = true) {
1146
+ var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;
1147
+ var create;
1148
+ const groups = {};
1149
+ const groups_order = [];
1150
+ var self = this;
1151
+ var query = self.inputValue();
1152
+ const same_query = query === self.lastQuery || (query == '' && self.lastQuery == null);
1153
+ var results = self.search(query);
1154
+ var active_option = null;
1155
+ var show_dropdown = self.settings.shouldOpen || false;
1156
+ var dropdown_content = self.dropdown_content;
1157
+ if (same_query) {
1158
+ active_option = self.activeOption;
1159
+ if (active_option) {
1160
+ active_group = active_option.closest('[data-group]');
1161
+ }
1162
+ }
1163
+ // build markup
1164
+ n = results.items.length;
1165
+ if (typeof self.settings.maxOptions === 'number') {
1166
+ n = Math.min(n, self.settings.maxOptions);
1167
+ }
1168
+ if (n > 0) {
1169
+ show_dropdown = true;
1170
+ }
1171
+ // get fragment for group and the position of the group in group_order
1172
+ const getGroupFragment = (optgroup, order) => {
1173
+ let group_order_i = groups[optgroup];
1174
+ if (group_order_i !== undefined) {
1175
+ let order_group = groups_order[group_order_i];
1176
+ if (order_group !== undefined) {
1177
+ return [group_order_i, order_group.fragment];
1178
+ }
1179
+ }
1180
+ let group_fragment = document.createDocumentFragment();
1181
+ group_order_i = groups_order.length;
1182
+ groups_order.push({ fragment: group_fragment, order, optgroup });
1183
+ return [group_order_i, group_fragment];
1184
+ };
1185
+ // render and group available options individually
1186
+ for (i = 0; i < n; i++) {
1187
+ // get option dom element
1188
+ let item = results.items[i];
1189
+ if (!item)
1190
+ continue;
1191
+ let opt_value = item.id;
1192
+ let option = self.options[opt_value];
1193
+ if (option === undefined)
1194
+ continue;
1195
+ let opt_hash = (0, utils_ts_1.get_hash)(opt_value);
1196
+ let option_el = self.getOption(opt_hash, true);
1197
+ // toggle 'selected' class
1198
+ if (!self.settings.hideSelected) {
1199
+ option_el.classList.toggle('selected', self.items.includes(opt_hash));
1200
+ }
1201
+ optgroup = option[self.settings.optgroupField] || '';
1202
+ optgroups = Array.isArray(optgroup) ? optgroup : [optgroup];
1203
+ for (j = 0, k = optgroups && optgroups.length; j < k; j++) {
1204
+ optgroup = optgroups[j];
1205
+ let order = option.$order;
1206
+ let self_optgroup = self.optgroups[optgroup];
1207
+ if (self_optgroup === undefined && typeof self.settings.optionGroupRegister === 'function') {
1208
+ var regGroup;
1209
+ if (regGroup = self.settings.optionGroupRegister.apply(self, [optgroup])) {
1210
+ self.registerOptionGroup(regGroup);
1211
+ }
1212
+ }
1213
+ self_optgroup = self.optgroups[optgroup];
1214
+ if (self_optgroup === undefined) {
1215
+ optgroup = '';
1216
+ }
1217
+ else {
1218
+ order = self_optgroup.$order;
1219
+ }
1220
+ const [group_order_i, group_fragment] = getGroupFragment(optgroup, order);
1221
+ // nodes can only have one parent, so if the option is in mutple groups, we need a clone
1222
+ if (j > 0) {
1223
+ option_el = option_el.cloneNode(true);
1224
+ (0, vanilla_ts_1.setAttr)(option_el, { id: option.$id + '-clone-' + j, 'aria-selected': null });
1225
+ option_el.classList.add('ts-cloned');
1226
+ (0, vanilla_ts_1.removeClasses)(option_el, 'active');
1227
+ // make sure we keep the activeOption in the same group
1228
+ if (self.activeOption && self.activeOption.dataset.value == opt_value) {
1229
+ if (active_group && active_group.dataset.group === optgroup.toString()) {
1230
+ active_option = option_el;
1231
+ }
1232
+ }
1233
+ }
1234
+ group_fragment.appendChild(option_el);
1235
+ if (optgroup != '') {
1236
+ groups[optgroup] = group_order_i;
1237
+ }
1238
+ }
1239
+ }
1240
+ // sort optgroups
1241
+ if (self.settings.lockOptgroupOrder) {
1242
+ groups_order.sort((a, b) => {
1243
+ return a.order - b.order;
1244
+ });
1245
+ }
1246
+ // render optgroup headers & join groups
1247
+ html = document.createDocumentFragment();
1248
+ (0, utils_ts_1.iterate)(groups_order, (group_order) => {
1249
+ let group_fragment = group_order.fragment;
1250
+ let optgroup = group_order.optgroup;
1251
+ if (!group_fragment || !group_fragment.children.length)
1252
+ return;
1253
+ let group_heading = self.optgroups[optgroup];
1254
+ if (group_heading !== undefined) {
1255
+ let group_options = document.createDocumentFragment();
1256
+ let header = self.render('optgroup_header', group_heading);
1257
+ (0, utils_ts_1.append)(group_options, header);
1258
+ (0, utils_ts_1.append)(group_options, group_fragment);
1259
+ let group_html = self.render('optgroup', { group: group_heading, options: group_options });
1260
+ (0, utils_ts_1.append)(html, group_html);
1261
+ }
1262
+ else {
1263
+ (0, utils_ts_1.append)(html, group_fragment);
1264
+ }
1265
+ });
1266
+ dropdown_content.innerHTML = '';
1267
+ (0, utils_ts_1.append)(dropdown_content, html);
1268
+ // highlight matching terms inline
1269
+ if (self.settings.highlight) {
1270
+ (0, highlight_ts_1.removeHighlight)(dropdown_content);
1271
+ if (results.query.length && results.tokens.length) {
1272
+ (0, utils_ts_1.iterate)(results.tokens, (tok) => {
1273
+ (0, highlight_ts_1.highlight)(dropdown_content, tok.regex);
1274
+ });
1275
+ }
1276
+ }
1277
+ // helper method for adding templates to dropdown
1278
+ var add_template = (template) => {
1279
+ let content = self.render(template, { input: query });
1280
+ if (content) {
1281
+ show_dropdown = true;
1282
+ dropdown_content.insertBefore(content, dropdown_content.firstChild);
1283
+ }
1284
+ return content;
1285
+ };
1286
+ // add loading message
1287
+ if (self.loading) {
1288
+ add_template('loading');
1289
+ // invalid query
1290
+ }
1291
+ else if (!self.settings.shouldLoad.call(self, query)) {
1292
+ add_template('not_loading');
1293
+ // add no_results message
1294
+ }
1295
+ else if (results.items.length === 0) {
1296
+ add_template('no_results');
1297
+ }
1298
+ // add create option
1299
+ has_create_option = self.canCreate(query);
1300
+ if (has_create_option) {
1301
+ create = add_template('option_create');
1302
+ }
1303
+ // activate
1304
+ self.hasOptions = results.items.length > 0 || has_create_option;
1305
+ if (show_dropdown) {
1306
+ if (results.items.length > 0) {
1307
+ if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {
1308
+ active_option = self.getOption(self.items[0]);
1309
+ }
1310
+ if (!dropdown_content.contains(active_option)) {
1311
+ let active_index = 0;
1312
+ if (create && !self.settings.addPrecedence) {
1313
+ active_index = 1;
1314
+ }
1315
+ active_option = self.selectable()[active_index];
1316
+ }
1317
+ }
1318
+ else if (create) {
1319
+ active_option = create;
1320
+ }
1321
+ if (triggerDropdown && !self.isOpen) {
1322
+ self.open();
1323
+ self.scrollToOption(active_option, 'auto');
1324
+ }
1325
+ self.setActiveOption(active_option);
1326
+ }
1327
+ else {
1328
+ self.clearActiveOption();
1329
+ if (triggerDropdown && self.isOpen) {
1330
+ self.close(false); // if create_option=null, we want the dropdown to close but not reset the textbox value
1331
+ }
1332
+ }
1333
+ }
1334
+ /**
1335
+ * Return list of selectable options
1336
+ *
1337
+ */
1338
+ selectable() {
1339
+ return this.dropdown_content.querySelectorAll('[data-selectable]');
1340
+ }
1341
+ /**
1342
+ * Adds an available option. If it already exists,
1343
+ * nothing will happen. Note: this does not refresh
1344
+ * the options list dropdown (use `refreshOptions`
1345
+ * for that).
1346
+ *
1347
+ * Usage:
1348
+ *
1349
+ * this.addOption(data)
1350
+ *
1351
+ */
1352
+ addOption(data, user_created = false) {
1353
+ const self = this;
1354
+ // @deprecated 1.7.7
1355
+ // use addOptions( array, user_created ) for adding multiple options
1356
+ if (Array.isArray(data)) {
1357
+ self.addOptions(data, user_created);
1358
+ return false;
1359
+ }
1360
+ const key = (0, utils_ts_1.hash_key)(data[self.settings.valueField]);
1361
+ if (key === null || self.options.hasOwnProperty(key)) {
1362
+ return false;
1363
+ }
1364
+ data.$order = data.$order || ++self.order;
1365
+ data.$id = self.inputId + '-opt-' + data.$order;
1366
+ self.options[key] = data;
1367
+ self.lastQuery = null;
1368
+ if (user_created) {
1369
+ self.userOptions[key] = user_created;
1370
+ self.trigger('option_add', key, data);
1371
+ }
1372
+ return key;
1373
+ }
1374
+ /**
1375
+ * Add multiple options
1376
+ *
1377
+ */
1378
+ addOptions(data, user_created = false) {
1379
+ (0, utils_ts_1.iterate)(data, (dat) => {
1380
+ this.addOption(dat, user_created);
1381
+ });
1382
+ }
1383
+ /**
1384
+ * @deprecated 1.7.7
1385
+ */
1386
+ registerOption(data) {
1387
+ return this.addOption(data);
1388
+ }
1389
+ /**
1390
+ * Registers an option group to the pool of option groups.
1391
+ *
1392
+ * @return {boolean|string}
1393
+ */
1394
+ registerOptionGroup(data) {
1395
+ var key = (0, utils_ts_1.hash_key)(data[this.settings.optgroupValueField]);
1396
+ if (key === null)
1397
+ return false;
1398
+ data.$order = data.$order || ++this.order;
1399
+ this.optgroups[key] = data;
1400
+ return key;
1401
+ }
1402
+ /**
1403
+ * Registers a new optgroup for options
1404
+ * to be bucketed into.
1405
+ *
1406
+ */
1407
+ addOptionGroup(id, data) {
1408
+ var hashed_id;
1409
+ data[this.settings.optgroupValueField] = id;
1410
+ if (hashed_id = this.registerOptionGroup(data)) {
1411
+ this.trigger('optgroup_add', hashed_id, data);
1412
+ }
1413
+ }
1414
+ /**
1415
+ * Removes an existing option group.
1416
+ *
1417
+ */
1418
+ removeOptionGroup(id) {
1419
+ if (this.optgroups.hasOwnProperty(id)) {
1420
+ delete this.optgroups[id];
1421
+ this.clearCache();
1422
+ this.trigger('optgroup_remove', id);
1423
+ }
1424
+ }
1425
+ /**
1426
+ * Clears all existing option groups.
1427
+ */
1428
+ clearOptionGroups() {
1429
+ this.optgroups = {};
1430
+ this.clearCache();
1431
+ this.trigger('optgroup_clear');
1432
+ }
1433
+ /**
1434
+ * Updates an option available for selection. If
1435
+ * it is visible in the selected items or options
1436
+ * dropdown, it will be re-rendered automatically.
1437
+ *
1438
+ */
1439
+ updateOption(value, data) {
1440
+ const self = this;
1441
+ var item_new;
1442
+ var index_item;
1443
+ const value_old = (0, utils_ts_1.hash_key)(value);
1444
+ const value_new = (0, utils_ts_1.hash_key)(data[self.settings.valueField]);
1445
+ // sanity checks
1446
+ if (value_old === null)
1447
+ return;
1448
+ const data_old = self.options[value_old];
1449
+ if (data_old == undefined)
1450
+ return;
1451
+ if (typeof value_new !== 'string')
1452
+ throw new Error('Value must be set in option data');
1453
+ const option = self.getOption(value_old);
1454
+ const item = self.getItem(value_old);
1455
+ data.$order = data.$order || data_old.$order;
1456
+ delete self.options[value_old];
1457
+ // invalidate render cache
1458
+ // don't remove existing node yet, we'll remove it after replacing it
1459
+ self.uncacheValue(value_new);
1460
+ self.options[value_new] = data;
1461
+ // update the option if it's in the dropdown
1462
+ if (option) {
1463
+ if (self.dropdown_content.contains(option)) {
1464
+ const option_new = self._render('option', data);
1465
+ (0, vanilla_ts_1.replaceNode)(option, option_new);
1466
+ if (self.activeOption === option) {
1467
+ self.setActiveOption(option_new);
1468
+ }
1469
+ }
1470
+ option.remove();
1471
+ }
1472
+ // update the item if we have one
1473
+ if (item) {
1474
+ index_item = self.items.indexOf(value_old);
1475
+ if (index_item !== -1) {
1476
+ self.items.splice(index_item, 1, value_new);
1477
+ }
1478
+ item_new = self._render('item', data);
1479
+ if (item.classList.contains('active'))
1480
+ (0, vanilla_ts_1.addClasses)(item_new, 'active');
1481
+ (0, vanilla_ts_1.replaceNode)(item, item_new);
1482
+ }
1483
+ // invalidate last query because we might have updated the sortField
1484
+ self.lastQuery = null;
1485
+ }
1486
+ /**
1487
+ * Removes a single option.
1488
+ *
1489
+ */
1490
+ removeOption(value, silent) {
1491
+ const self = this;
1492
+ value = (0, utils_ts_1.get_hash)(value);
1493
+ self.uncacheValue(value);
1494
+ delete self.userOptions[value];
1495
+ delete self.options[value];
1496
+ self.lastQuery = null;
1497
+ self.trigger('option_remove', value);
1498
+ self.removeItem(value, silent);
1499
+ }
1500
+ /**
1501
+ * Clears all options.
1502
+ */
1503
+ clearOptions(filter) {
1504
+ const boundFilter = (filter || this.clearFilter).bind(this);
1505
+ this.loadedSearches = {};
1506
+ this.userOptions = {};
1507
+ this.clearCache();
1508
+ const selected = {};
1509
+ (0, utils_ts_1.iterate)(this.options, (option, key) => {
1510
+ if (boundFilter(option, key)) {
1511
+ selected[key] = option;
1512
+ }
1513
+ });
1514
+ this.options = this.sifter.items = selected;
1515
+ this.lastQuery = null;
1516
+ this.trigger('option_clear');
1517
+ }
1518
+ /**
1519
+ * Used by clearOptions() to decide whether or not an option should be removed
1520
+ * Return true to keep an option, false to remove
1521
+ *
1522
+ */
1523
+ clearFilter(option, value) {
1524
+ if (this.items.indexOf(value) >= 0) {
1525
+ return true;
1526
+ }
1527
+ return false;
1528
+ }
1529
+ /**
1530
+ * Returns the dom element of the option
1531
+ * matching the given value.
1532
+ *
1533
+ */
1534
+ getOption(value, create = false) {
1535
+ const hashed = (0, utils_ts_1.hash_key)(value);
1536
+ if (hashed === null)
1537
+ return null;
1538
+ const option = this.options[hashed];
1539
+ if (option != undefined) {
1540
+ if (option.$div) {
1541
+ return option.$div;
1542
+ }
1543
+ if (create) {
1544
+ return this._render('option', option);
1545
+ }
1546
+ }
1547
+ return null;
1548
+ }
1549
+ /**
1550
+ * Returns the dom element of the next or previous dom element of the same type
1551
+ * Note: adjacent options may not be adjacent DOM elements (optgroups)
1552
+ *
1553
+ */
1554
+ getAdjacent(option, direction, type = 'option') {
1555
+ var self = this, all;
1556
+ if (!option) {
1557
+ return null;
1558
+ }
1559
+ if (type == 'item') {
1560
+ all = self.controlChildren();
1561
+ }
1562
+ else {
1563
+ all = self.dropdown_content.querySelectorAll('[data-selectable]');
1564
+ }
1565
+ for (let i = 0; i < all.length; i++) {
1566
+ if (all[i] != option) {
1567
+ continue;
1568
+ }
1569
+ if (direction > 0) {
1570
+ return all[i + 1];
1571
+ }
1572
+ return all[i - 1];
1573
+ }
1574
+ return null;
1575
+ }
1576
+ /**
1577
+ * Returns the dom element of the item
1578
+ * matching the given value.
1579
+ *
1580
+ */
1581
+ getItem(item) {
1582
+ if (typeof item == 'object') {
1583
+ return item;
1584
+ }
1585
+ var value = (0, utils_ts_1.hash_key)(item);
1586
+ return value !== null
1587
+ ? this.control.querySelector(`[data-value="${(0, utils_ts_1.addSlashes)(value)}"]`)
1588
+ : null;
1589
+ }
1590
+ /**
1591
+ * "Selects" multiple items at once. Adds them to the list
1592
+ * at the current caret position.
1593
+ *
1594
+ */
1595
+ addItems(values, silent) {
1596
+ var self = this;
1597
+ var items = Array.isArray(values) ? values : [values];
1598
+ items = items.filter(x => self.items.indexOf(x) === -1);
1599
+ const last_item = items[items.length - 1];
1600
+ items.forEach(item => {
1601
+ self.isPending = (item !== last_item);
1602
+ self.addItem(item, silent);
1603
+ });
1604
+ }
1605
+ /**
1606
+ * "Selects" an item. Adds it to the list
1607
+ * at the current caret position.
1608
+ *
1609
+ */
1610
+ addItem(value, silent) {
1611
+ var events = silent ? [] : ['change', 'dropdown_close'];
1612
+ (0, utils_ts_1.debounce_events)(this, events, () => {
1613
+ var item, wasFull;
1614
+ const self = this;
1615
+ const inputMode = self.settings.mode;
1616
+ const hashed = (0, utils_ts_1.hash_key)(value);
1617
+ if (hashed && self.items.indexOf(hashed) !== -1) {
1618
+ if (inputMode === 'single') {
1619
+ self.close();
1620
+ }
1621
+ if (inputMode === 'single' || !self.settings.duplicates) {
1622
+ return;
1623
+ }
1624
+ }
1625
+ if (hashed === null || !self.options.hasOwnProperty(hashed))
1626
+ return;
1627
+ if (inputMode === 'single')
1628
+ self.clear(silent);
1629
+ if (inputMode === 'multi' && self.isFull())
1630
+ return;
1631
+ item = self._render('item', self.options[hashed]);
1632
+ if (self.control.contains(item)) { // duplicates
1633
+ item = item.cloneNode(true);
1634
+ }
1635
+ wasFull = self.isFull();
1636
+ self.items.splice(self.caretPos, 0, hashed);
1637
+ self.insertAtCaret(item);
1638
+ if (self.isSetup) {
1639
+ // update menu / remove the option (if this is not one item being added as part of series)
1640
+ if (!self.isPending && self.settings.hideSelected) {
1641
+ let option = self.getOption(hashed);
1642
+ let next = self.getAdjacent(option, 1);
1643
+ if (next) {
1644
+ self.setActiveOption(next);
1645
+ }
1646
+ }
1647
+ //remove input value when enabled
1648
+ if (self.settings.clearAfterSelect) {
1649
+ self.setTextboxValue();
1650
+ }
1651
+ // refreshOptions after setActiveOption(),
1652
+ // otherwise setActiveOption() will be called by refreshOptions() with the wrong value
1653
+ if (!self.isPending && !self.settings.closeAfterSelect) {
1654
+ self.refreshOptions(self.isFocused && inputMode !== 'single');
1655
+ }
1656
+ // hide the menu if the maximum number of items have been selected or no options are left
1657
+ if (self.settings.closeAfterSelect != false && self.isFull()) {
1658
+ self.close();
1659
+ }
1660
+ else if (!self.isPending) {
1661
+ self.positionDropdown();
1662
+ }
1663
+ self.trigger('item_add', hashed, item);
1664
+ if (!self.isPending) {
1665
+ self.updateOriginalInput({ silent: silent });
1666
+ }
1667
+ }
1668
+ if (!self.isPending || (!wasFull && self.isFull())) {
1669
+ self.inputState();
1670
+ self.refreshState();
1671
+ }
1672
+ });
1673
+ }
1674
+ /**
1675
+ * Removes the selected item matching
1676
+ * the provided value.
1677
+ *
1678
+ */
1679
+ removeItem(item = null, silent) {
1680
+ const self = this;
1681
+ item = self.getItem(item);
1682
+ if (!item)
1683
+ return;
1684
+ var i, idx;
1685
+ const value = item.dataset.value;
1686
+ i = (0, vanilla_ts_1.nodeIndex)(item);
1687
+ item.remove();
1688
+ if (item.classList.contains('active')) {
1689
+ idx = self.activeItems.indexOf(item);
1690
+ self.activeItems.splice(idx, 1);
1691
+ (0, vanilla_ts_1.removeClasses)(item, 'active');
1692
+ }
1693
+ self.items.splice(i, 1);
1694
+ self.lastQuery = null;
1695
+ if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
1696
+ self.removeOption(value, silent);
1697
+ }
1698
+ if (i < self.caretPos) {
1699
+ self.setCaret(self.caretPos - 1);
1700
+ }
1701
+ self.updateOriginalInput({ silent: silent });
1702
+ self.refreshState();
1703
+ self.positionDropdown();
1704
+ self.trigger('item_remove', value, item);
1705
+ }
1706
+ /**
1707
+ * Invokes the `create` method provided in the
1708
+ * TomSelect options that should provide the data
1709
+ * for the new item, given the user input.
1710
+ *
1711
+ * Once this completes, it will be added
1712
+ * to the item list.
1713
+ *
1714
+ */
1715
+ createItem(input = null, callback = () => { }) {
1716
+ // triggerDropdown parameter @deprecated 2.1.1
1717
+ if (arguments.length === 3) {
1718
+ callback = arguments[2];
1719
+ }
1720
+ if (typeof callback != 'function') {
1721
+ callback = () => { };
1722
+ }
1723
+ var self = this;
1724
+ var caret = self.caretPos;
1725
+ var output;
1726
+ input = input || self.inputValue();
1727
+ if (!self.canCreate(input)) {
1728
+ const hash = (0, utils_ts_1.hash_key)(input);
1729
+ if (hash) {
1730
+ if (this.options[input]) {
1731
+ self.addItem(input);
1732
+ }
1733
+ }
1734
+ callback();
1735
+ return false;
1736
+ }
1737
+ self.lock();
1738
+ var created = false;
1739
+ var create = (data) => {
1740
+ self.unlock();
1741
+ if (!data || typeof data !== 'object')
1742
+ return callback();
1743
+ var value = (0, utils_ts_1.hash_key)(data[self.settings.valueField]);
1744
+ if (typeof value !== 'string') {
1745
+ return callback();
1746
+ }
1747
+ self.setTextboxValue();
1748
+ self.addOption(data, true);
1749
+ self.setCaret(caret);
1750
+ self.addItem(value);
1751
+ callback(data);
1752
+ created = true;
1753
+ };
1754
+ if (typeof self.settings.create === 'function') {
1755
+ output = self.settings.create.call(this, input, create);
1756
+ }
1757
+ else {
1758
+ output = {
1759
+ [self.settings.labelField]: input,
1760
+ [self.settings.valueField]: input,
1761
+ };
1762
+ }
1763
+ if (!created) {
1764
+ create(output);
1765
+ }
1766
+ return true;
1767
+ }
1768
+ /**
1769
+ * Re-renders the selected item lists.
1770
+ */
1771
+ refreshItems() {
1772
+ var self = this;
1773
+ self.lastQuery = null;
1774
+ if (self.isSetup) {
1775
+ self.addItems(self.items);
1776
+ }
1777
+ self.updateOriginalInput();
1778
+ self.refreshState();
1779
+ }
1780
+ /**
1781
+ * Updates all state-dependent attributes
1782
+ * and CSS classes.
1783
+ */
1784
+ refreshState() {
1785
+ const self = this;
1786
+ self.refreshValidityState();
1787
+ const isFull = self.isFull();
1788
+ const isLocked = self.isLocked;
1789
+ self.wrapper.classList.toggle('rtl', self.rtl);
1790
+ const wrap_classList = self.wrapper.classList;
1791
+ wrap_classList.toggle('focus', self.isFocused);
1792
+ wrap_classList.toggle('disabled', self.isDisabled);
1793
+ wrap_classList.toggle('readonly', self.isReadOnly);
1794
+ wrap_classList.toggle('required', self.isRequired);
1795
+ wrap_classList.toggle('invalid', !self.isValid);
1796
+ wrap_classList.toggle('locked', isLocked);
1797
+ wrap_classList.toggle('full', isFull);
1798
+ wrap_classList.toggle('input-active', self.isFocused && !self.isInputHidden);
1799
+ wrap_classList.toggle('dropdown-active', self.isOpen);
1800
+ wrap_classList.toggle('has-options', (0, vanilla_ts_1.isEmptyObject)(self.options));
1801
+ wrap_classList.toggle('has-items', self.items.length > 0);
1802
+ }
1803
+ /**
1804
+ * Update the `required` attribute of both input and control input.
1805
+ *
1806
+ * The `required` property needs to be activated on the control input
1807
+ * for the error to be displayed at the right place. `required` also
1808
+ * needs to be temporarily deactivated on the input since the input is
1809
+ * hidden and can't show errors.
1810
+ */
1811
+ refreshValidityState() {
1812
+ var self = this;
1813
+ if (!self.input.validity) {
1814
+ return;
1815
+ }
1816
+ self.isValid = self.input.validity.valid;
1817
+ self.isInvalid = !self.isValid;
1818
+ }
1819
+ /**
1820
+ * Determines whether or not more items can be added
1821
+ * to the control without exceeding the user-defined maximum.
1822
+ *
1823
+ * @returns {boolean}
1824
+ */
1825
+ isFull() {
1826
+ return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
1827
+ }
1828
+ /**
1829
+ * Refreshes the original <select> or <input>
1830
+ * element to reflect the current state.
1831
+ *
1832
+ */
1833
+ updateOriginalInput(opts = {}) {
1834
+ const self = this;
1835
+ var option, label;
1836
+ const empty_option = self.input.querySelector('option[value=""]');
1837
+ if (self.is_select_tag) {
1838
+ const selected = [];
1839
+ const has_selected = self.input.querySelectorAll('option:checked').length;
1840
+ function AddSelected(option_el, value, label) {
1841
+ if (!option_el) {
1842
+ option_el = (0, vanilla_ts_1.getDom)('<option value="' + (0, utils_ts_1.escape_html)(value) + '">' + (0, utils_ts_1.escape_html)(label) + '</option>');
1843
+ }
1844
+ // don't move empty option from top of list
1845
+ // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293
1846
+ if (option_el != empty_option) {
1847
+ self.input.append(option_el);
1848
+ }
1849
+ selected.push(option_el);
1850
+ // marking empty option as selected can break validation
1851
+ // fixes https://github.com/orchidjs/tom-select/issues/303
1852
+ if (option_el != empty_option || has_selected > 0) {
1853
+ option_el.selected = true;
1854
+ }
1855
+ return option_el;
1856
+ }
1857
+ // unselect all selected options
1858
+ self.input.querySelectorAll('option:checked').forEach((option_el) => {
1859
+ option_el.selected = false;
1860
+ });
1861
+ // nothing selected?
1862
+ if (self.items.length == 0 && self.settings.mode == 'single') {
1863
+ AddSelected(empty_option, "", "");
1864
+ // order selected <option> tags for values in self.items
1865
+ }
1866
+ else {
1867
+ self.items.forEach((value) => {
1868
+ option = self.options[value];
1869
+ label = option[self.settings.labelField] || '';
1870
+ if (selected.includes(option.$option)) {
1871
+ const reuse_opt = self.input.querySelector(`option[value="${(0, utils_ts_1.addSlashes)(value)}"]:not(:checked)`);
1872
+ AddSelected(reuse_opt, value, label);
1873
+ }
1874
+ else {
1875
+ option.$option = AddSelected(option.$option, value, label);
1876
+ }
1877
+ });
1878
+ }
1879
+ }
1880
+ else {
1881
+ self.input.value = self.getValue();
1882
+ }
1883
+ if (self.isSetup) {
1884
+ if (!opts.silent) {
1885
+ self.trigger('change', self.getValue());
1886
+ }
1887
+ }
1888
+ }
1889
+ /**
1890
+ * Shows the autocomplete dropdown containing
1891
+ * the available options.
1892
+ */
1893
+ open() {
1894
+ var self = this;
1895
+ if (self.isLocked || self.isOpen || (self.settings.mode === 'multi' && self.isFull()))
1896
+ return;
1897
+ self.isOpen = true;
1898
+ (0, vanilla_ts_1.setAttr)(self.focus_node, { 'aria-expanded': 'true' });
1899
+ self.refreshState();
1900
+ (0, vanilla_ts_1.applyCSS)(self.dropdown, { visibility: 'hidden', display: 'block' });
1901
+ self.positionDropdown();
1902
+ (0, vanilla_ts_1.applyCSS)(self.dropdown, { visibility: 'visible', display: 'block' });
1903
+ self.focus();
1904
+ self.trigger('dropdown_open', self.dropdown);
1905
+ }
1906
+ /**
1907
+ * Closes the autocomplete dropdown menu.
1908
+ */
1909
+ close(setTextboxValue = true) {
1910
+ var self = this;
1911
+ var trigger = self.isOpen;
1912
+ if (setTextboxValue) {
1913
+ // before blur() to prevent form onchange event
1914
+ self.setTextboxValue();
1915
+ if (self.settings.mode === 'single' && self.items.length) {
1916
+ self.inputState();
1917
+ }
1918
+ }
1919
+ self.isOpen = false;
1920
+ (0, vanilla_ts_1.setAttr)(self.focus_node, { 'aria-expanded': 'false' });
1921
+ (0, vanilla_ts_1.applyCSS)(self.dropdown, { display: 'none' });
1922
+ if (self.settings.hideSelected) {
1923
+ self.clearActiveOption();
1924
+ }
1925
+ self.refreshState();
1926
+ if (trigger)
1927
+ self.trigger('dropdown_close', self.dropdown);
1928
+ }
1929
+ /**
1930
+ * Calculates and applies the appropriate
1931
+ * position of the dropdown if dropdownParent = 'body'.
1932
+ * Otherwise, position is determined by css
1933
+ */
1934
+ positionDropdown() {
1935
+ if (this.settings.dropdownParent !== 'body') {
1936
+ return;
1937
+ }
1938
+ var context = this.control;
1939
+ var rect = context.getBoundingClientRect();
1940
+ var top = context.offsetHeight + rect.top + window.scrollY;
1941
+ var left = rect.left + window.scrollX;
1942
+ (0, vanilla_ts_1.applyCSS)(this.dropdown, {
1943
+ width: rect.width + 'px',
1944
+ top: top + 'px',
1945
+ left: left + 'px'
1946
+ });
1947
+ }
1948
+ /**
1949
+ * Resets / clears all selected items
1950
+ * from the control.
1951
+ *
1952
+ */
1953
+ clear(silent) {
1954
+ var self = this;
1955
+ if (!self.items.length)
1956
+ return;
1957
+ var items = self.controlChildren();
1958
+ (0, utils_ts_1.iterate)(items, (item) => {
1959
+ self.removeItem(item, true);
1960
+ });
1961
+ self.inputState();
1962
+ if (!silent)
1963
+ self.updateOriginalInput();
1964
+ self.trigger('clear');
1965
+ }
1966
+ /**
1967
+ * A helper method for inserting an element
1968
+ * at the current caret position.
1969
+ *
1970
+ */
1971
+ insertAtCaret(el) {
1972
+ const self = this;
1973
+ const caret = self.caretPos;
1974
+ const target = self.control;
1975
+ target.insertBefore(el, target.children[caret] || null);
1976
+ self.setCaret(caret + 1);
1977
+ }
1978
+ /**
1979
+ * Removes the current selected item(s).
1980
+ *
1981
+ */
1982
+ deleteSelection(e) {
1983
+ var direction, selection, caret, tail;
1984
+ var self = this;
1985
+ direction = (e && e.keyCode === constants.KEY_BACKSPACE) ? -1 : 1;
1986
+ selection = (0, utils_ts_1.getSelection)(self.control_input);
1987
+ // determine items that will be removed
1988
+ const rm_items = [];
1989
+ if (self.activeItems.length) {
1990
+ tail = (0, vanilla_ts_1.getTail)(self.activeItems, direction);
1991
+ caret = (0, vanilla_ts_1.nodeIndex)(tail);
1992
+ if (direction > 0) {
1993
+ caret++;
1994
+ }
1995
+ (0, utils_ts_1.iterate)(self.activeItems, (item) => rm_items.push(item));
1996
+ }
1997
+ else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
1998
+ const items = self.controlChildren();
1999
+ let rm_item;
2000
+ if (direction < 0 && selection.start === 0 && selection.length === 0) {
2001
+ rm_item = items[self.caretPos - 1];
2002
+ }
2003
+ else if (direction > 0 && selection.start === self.inputValue().length) {
2004
+ rm_item = items[self.caretPos];
2005
+ }
2006
+ if (rm_item !== undefined) {
2007
+ rm_items.push(rm_item);
2008
+ }
2009
+ }
2010
+ if (!self.shouldDelete(rm_items, e)) {
2011
+ return false;
2012
+ }
2013
+ (0, utils_ts_1.preventDefault)(e, true);
2014
+ // perform removal
2015
+ if (typeof caret !== 'undefined') {
2016
+ self.setCaret(caret);
2017
+ }
2018
+ while (rm_items.length) {
2019
+ self.removeItem(rm_items.pop());
2020
+ }
2021
+ self.inputState();
2022
+ self.positionDropdown();
2023
+ self.refreshOptions(false);
2024
+ return true;
2025
+ }
2026
+ /**
2027
+ * Return true if the items should be deleted
2028
+ */
2029
+ shouldDelete(items, evt) {
2030
+ const values = items.map(item => item.dataset.value);
2031
+ // allow the callback to abort
2032
+ if (!values.length || (typeof this.settings.onDelete === 'function' && this.settings.onDelete.call(this, values, evt) === false)) {
2033
+ return false;
2034
+ }
2035
+ return true;
2036
+ }
2037
+ /**
2038
+ * Selects the previous / next item (depending on the `direction` argument).
2039
+ *
2040
+ * > 0 - right
2041
+ * < 0 - left
2042
+ *
2043
+ */
2044
+ advanceSelection(direction, e) {
2045
+ var last_active, adjacent, self = this;
2046
+ if (self.rtl)
2047
+ direction *= -1;
2048
+ if (self.inputValue().length)
2049
+ return;
2050
+ // add or remove to active items
2051
+ if ((0, utils_ts_1.isKeyDown)(constants.KEY_SHORTCUT, e) || (0, utils_ts_1.isKeyDown)('shiftKey', e)) {
2052
+ last_active = self.getLastActive(direction);
2053
+ if (last_active) {
2054
+ if (!last_active.classList.contains('active')) {
2055
+ adjacent = last_active;
2056
+ }
2057
+ else {
2058
+ adjacent = self.getAdjacent(last_active, direction, 'item');
2059
+ }
2060
+ // if no active item, get items adjacent to the control input
2061
+ }
2062
+ else if (direction > 0) {
2063
+ adjacent = self.control_input.nextElementSibling;
2064
+ }
2065
+ else {
2066
+ adjacent = self.control_input.previousElementSibling;
2067
+ }
2068
+ if (adjacent) {
2069
+ if (adjacent.classList.contains('active')) {
2070
+ self.removeActiveItem(last_active);
2071
+ }
2072
+ self.setActiveItemClass(adjacent); // mark as last_active !! after removeActiveItem() on last_active
2073
+ }
2074
+ // move caret to the left or right
2075
+ }
2076
+ else {
2077
+ self.moveCaret(direction);
2078
+ }
2079
+ }
2080
+ moveCaret(direction) { }
2081
+ /**
2082
+ * Get the last active item
2083
+ *
2084
+ */
2085
+ getLastActive(direction) {
2086
+ let last_active = this.control.querySelector('.last-active');
2087
+ if (last_active) {
2088
+ return last_active;
2089
+ }
2090
+ var result = this.control.querySelectorAll('.active');
2091
+ if (result) {
2092
+ return (0, vanilla_ts_1.getTail)(result, direction);
2093
+ }
2094
+ }
2095
+ /**
2096
+ * Moves the caret to the specified index.
2097
+ *
2098
+ * The input must be moved by leaving it in place and moving the
2099
+ * siblings, due to the fact that focus cannot be restored once lost
2100
+ * on mobile webkit devices
2101
+ *
2102
+ */
2103
+ setCaret(new_pos) {
2104
+ this.caretPos = this.items.length;
2105
+ }
2106
+ /**
2107
+ * Return list of item dom elements
2108
+ *
2109
+ */
2110
+ controlChildren() {
2111
+ return Array.from(this.control.querySelectorAll('[data-ts-item]'));
2112
+ }
2113
+ /**
2114
+ * Disables user input on the control. Used while
2115
+ * items are being asynchronously created.
2116
+ */
2117
+ lock() {
2118
+ this.setLocked(true);
2119
+ }
2120
+ /**
2121
+ * Re-enables user input on the control.
2122
+ */
2123
+ unlock() {
2124
+ this.setLocked(false);
2125
+ }
2126
+ /**
2127
+ * Disable or enable user input on the control
2128
+ */
2129
+ setLocked(lock = this.isReadOnly || this.isDisabled) {
2130
+ this.isLocked = lock;
2131
+ this.refreshState();
2132
+ }
2133
+ /**
2134
+ * Disables user input on the control completely.
2135
+ * While disabled, it cannot receive focus.
2136
+ */
2137
+ disable() {
2138
+ this.setDisabled(true);
2139
+ this.close();
2140
+ }
2141
+ /**
2142
+ * Enables the control so that it can respond
2143
+ * to focus and user input.
2144
+ */
2145
+ enable() {
2146
+ this.setDisabled(false);
2147
+ }
2148
+ setDisabled(disabled) {
2149
+ this.focus_node.tabIndex = disabled ? -1 : this.tabIndex;
2150
+ this.isDisabled = disabled;
2151
+ this.input.disabled = disabled;
2152
+ this.control_input.disabled = disabled;
2153
+ this.setLocked();
2154
+ }
2155
+ setReadOnly(isReadOnly) {
2156
+ this.isReadOnly = isReadOnly;
2157
+ this.input.readOnly = isReadOnly;
2158
+ this.control_input.readOnly = isReadOnly;
2159
+ this.setLocked();
2160
+ }
2161
+ /**
2162
+ * Completely destroys the control and
2163
+ * unbinds all event listeners so that it can
2164
+ * be garbage collected.
2165
+ */
2166
+ destroy() {
2167
+ var self = this;
2168
+ var revertSettings = self.revertSettings;
2169
+ self.trigger('destroy');
2170
+ self.off();
2171
+ self.wrapper.remove();
2172
+ self.dropdown.remove();
2173
+ self.input.innerHTML = revertSettings.innerHTML;
2174
+ self.input.tabIndex = revertSettings.tabIndex;
2175
+ (0, vanilla_ts_1.removeClasses)(self.input, 'tomselected', 'ts-hidden-accessible');
2176
+ self._destroy();
2177
+ delete self.input.tomselect;
2178
+ }
2179
+ /**
2180
+ * A helper method for rendering "item" and
2181
+ * "option" templates, given the data.
2182
+ *
2183
+ */
2184
+ render(templateName, data) {
2185
+ var id, html;
2186
+ const self = this;
2187
+ if (typeof this.settings.render[templateName] !== 'function') {
2188
+ return null;
2189
+ }
2190
+ // render markup
2191
+ html = self.settings.render[templateName].call(this, data, utils_ts_1.escape_html);
2192
+ if (!html) {
2193
+ return null;
2194
+ }
2195
+ html = (0, vanilla_ts_1.getDom)(html);
2196
+ // add mandatory attributes
2197
+ if (templateName === 'option' || templateName === 'option_create') {
2198
+ if (data[self.settings.disabledField]) {
2199
+ (0, vanilla_ts_1.setAttr)(html, { 'aria-disabled': 'true' });
2200
+ }
2201
+ else {
2202
+ (0, vanilla_ts_1.setAttr)(html, { 'data-selectable': '' });
2203
+ }
2204
+ }
2205
+ else if (templateName === 'optgroup') {
2206
+ id = data.group[self.settings.optgroupValueField];
2207
+ (0, vanilla_ts_1.setAttr)(html, { 'data-group': id });
2208
+ if (data.group[self.settings.disabledField]) {
2209
+ (0, vanilla_ts_1.setAttr)(html, { 'data-disabled': '' });
2210
+ }
2211
+ }
2212
+ if (templateName === 'option' || templateName === 'item') {
2213
+ const value = (0, utils_ts_1.get_hash)(data[self.settings.valueField]);
2214
+ (0, vanilla_ts_1.setAttr)(html, { 'data-value': value });
2215
+ // make sure we have some classes if a template is overwritten
2216
+ if (templateName === 'item') {
2217
+ (0, vanilla_ts_1.addClasses)(html, self.settings.itemClass);
2218
+ (0, vanilla_ts_1.setAttr)(html, { 'data-ts-item': '' });
2219
+ }
2220
+ else {
2221
+ (0, vanilla_ts_1.addClasses)(html, self.settings.optionClass);
2222
+ (0, vanilla_ts_1.setAttr)(html, {
2223
+ role: 'option',
2224
+ id: data.$id
2225
+ });
2226
+ // update cache
2227
+ data.$div = html;
2228
+ self.options[value] = data;
2229
+ }
2230
+ }
2231
+ return html;
2232
+ }
2233
+ /**
2234
+ * Type guarded rendering
2235
+ *
2236
+ */
2237
+ _render(templateName, data) {
2238
+ const html = this.render(templateName, data);
2239
+ if (html == null) {
2240
+ throw 'HTMLElement expected';
2241
+ }
2242
+ return html;
2243
+ }
2244
+ /**
2245
+ * Clears the render cache for a template. If
2246
+ * no template is given, clears all render
2247
+ * caches.
2248
+ *
2249
+ */
2250
+ clearCache() {
2251
+ (0, utils_ts_1.iterate)(this.options, (option) => {
2252
+ if (option.$div) {
2253
+ option.$div.remove();
2254
+ delete option.$div;
2255
+ }
2256
+ });
2257
+ }
2258
+ /**
2259
+ * Removes a value from item and option caches
2260
+ *
2261
+ */
2262
+ uncacheValue(value) {
2263
+ const option_el = this.getOption(value);
2264
+ if (option_el)
2265
+ option_el.remove();
2266
+ }
2267
+ /**
2268
+ * Determines whether or not to display the
2269
+ * create item prompt, given a user input.
2270
+ *
2271
+ */
2272
+ canCreate(input) {
2273
+ return this.settings.create && (input.length > 0) && this.settings.createFilter.call(this, input);
2274
+ }
2275
+ /**
2276
+ * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method
2277
+ *
2278
+ * this.hook('instead','onKeyDown',function( arg1, arg2 ...){
2279
+ *
2280
+ * });
2281
+ */
2282
+ hook(when, method, new_fn) {
2283
+ var self = this;
2284
+ var orig_method = self[method];
2285
+ self[method] = function () {
2286
+ var result, result_new;
2287
+ if (when === 'after') {
2288
+ result = orig_method.apply(self, arguments);
2289
+ }
2290
+ result_new = new_fn.apply(self, arguments);
2291
+ if (when === 'instead') {
2292
+ return result_new;
2293
+ }
2294
+ if (when === 'before') {
2295
+ result = orig_method.apply(self, arguments);
2296
+ }
2297
+ return result;
2298
+ };
2299
+ }
2300
+ }
2301
+ exports.default = TomSelect;
2302
+ ;
2303
+ //# sourceMappingURL=tom-select.js.map