tom-select-rails 2.2.2 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) 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 +614 -820
  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 +411 -685
  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 +436 -705
  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 +31 -27
  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 +11 -16
  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 +3 -2
  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 +47 -34
  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 +3 -13
  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 +249 -29
  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 +3 -11
  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 -24
  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 +4 -6
  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 +2 -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 +2 -2
  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 +3 -15
  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 +11 -15
  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 +2 -3
  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 +41 -50
  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 +614 -820
  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 +411 -685
  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 +436 -705
  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 +31 -26
  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 +11 -16
  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 +3 -2
  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 +47 -34
  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 +3 -13
  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 +249 -29
  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 +3 -11
  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 +15 -24
  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 +4 -6
  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 +2 -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 +2 -2
  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 +3 -15
  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 +11 -15
  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 +2 -3
  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 +41 -50
  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 +411 -685
  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 +87 -78
  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 +614 -820
  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 +195 -176
  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 +436 -705
  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 +87 -78
  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/contrib/microevent.d.ts +1 -1
  88. data/vendor/assets/javascripts/tom-select-rails/types/contrib/microplugin.d.ts +4 -4
  89. data/vendor/assets/javascripts/tom-select-rails/types/defaults.d.ts +1 -0
  90. data/vendor/assets/javascripts/tom-select-rails/types/plugins/checkbox_options/plugin.d.ts +3 -2
  91. data/vendor/assets/javascripts/tom-select-rails/types/plugins/checkbox_options/types.d.ts +14 -0
  92. data/vendor/assets/javascripts/tom-select-rails/types/plugins/clear_button/types.d.ts +1 -1
  93. data/vendor/assets/javascripts/tom-select-rails/types/plugins/dropdown_header/types.d.ts +1 -1
  94. data/vendor/assets/javascripts/tom-select-rails/types/plugins/remove_button/types.d.ts +1 -1
  95. data/vendor/assets/javascripts/tom-select-rails/types/plugins/restore_on_backspace/plugin.d.ts +1 -1
  96. data/vendor/assets/javascripts/tom-select-rails/types/tom-select.d.ts +10 -12
  97. data/vendor/assets/javascripts/tom-select-rails/types/types/core.d.ts +15 -14
  98. data/vendor/assets/javascripts/tom-select-rails/types/types/settings.d.ts +3 -2
  99. data/vendor/assets/javascripts/tom-select-rails/types/utils.d.ts +7 -0
  100. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css +224 -216
  101. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css.map +1 -1
  102. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css +1 -1
  103. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css.map +1 -1
  104. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css +245 -252
  105. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css.map +1 -1
  106. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css +1 -1
  107. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css.map +1 -1
  108. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css +213 -210
  109. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css.map +1 -1
  110. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css +223 -215
  111. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css.map +1 -1
  112. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css +1 -1
  113. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css.map +1 -1
  114. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css +1 -1
  115. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css.map +1 -1
  116. data/vendor/assets/stylesheets/tom-select-rails/scss/_dropdown.scss +7 -10
  117. data/vendor/assets/stylesheets/tom-select-rails/scss/_items.scss +2 -5
  118. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/checkbox_options.scss +8 -2
  119. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/clear_button.scss +16 -14
  120. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/drag_drop.scss +6 -12
  121. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/dropdown_header.scss +3 -2
  122. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/dropdown_input.scss +7 -11
  123. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/input_autogrow.scss +0 -3
  124. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/optgroup_columns.scss +7 -5
  125. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/remove_button.scss +20 -20
  126. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap4.scss +33 -39
  127. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap5.scss +54 -80
  128. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.default.scss +16 -14
  129. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.scss +52 -57
  130. metadata +8 -7
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tom Select v2.2.2
2
+ * Tom Select v2.3.1
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  */
5
5
 
@@ -22,13 +22,11 @@ function forEvents(events, callback) {
22
22
  callback(event);
23
23
  });
24
24
  }
25
-
26
25
  class MicroEvent {
27
26
  constructor() {
28
27
  this._events = void 0;
29
28
  this._events = {};
30
29
  }
31
-
32
30
  on(events, fct) {
33
31
  forEvents(events, event => {
34
32
  const event_array = this._events[event] || [];
@@ -36,28 +34,23 @@ class MicroEvent {
36
34
  this._events[event] = event_array;
37
35
  });
38
36
  }
39
-
40
37
  off(events, fct) {
41
38
  var n = arguments.length;
42
-
43
39
  if (n === 0) {
44
40
  this._events = {};
45
41
  return;
46
42
  }
47
-
48
43
  forEvents(events, event => {
49
44
  if (n === 1) {
50
45
  delete this._events[event];
51
46
  return;
52
47
  }
53
-
54
48
  const event_array = this._events[event];
55
49
  if (event_array === undefined) return;
56
50
  event_array.splice(event_array.indexOf(fct), 1);
57
51
  this._events[event] = event_array;
58
52
  });
59
53
  }
60
-
61
54
  trigger(events, ...args) {
62
55
  var self = this;
63
56
  forEvents(events, event => {
@@ -68,7 +61,6 @@ class MicroEvent {
68
61
  });
69
62
  });
70
63
  }
71
-
72
64
  }
73
65
 
74
66
  /**
@@ -86,6 +78,7 @@ class MicroEvent {
86
78
  *
87
79
  * @author Brian Reavis <brian@thirdroute.com>
88
80
  */
81
+
89
82
  function MicroPlugin(Interface) {
90
83
  Interface.plugins = {};
91
84
  return class extends Interface {
@@ -98,7 +91,6 @@ function MicroPlugin(Interface) {
98
91
  loaded: {}
99
92
  };
100
93
  }
101
-
102
94
  /**
103
95
  * Registers a plugin.
104
96
  *
@@ -110,6 +102,7 @@ function MicroPlugin(Interface) {
110
102
  'fn': fn
111
103
  };
112
104
  }
105
+
113
106
  /**
114
107
  * Initializes the listed plugins (with options).
115
108
  * Acceptable formats:
@@ -125,13 +118,10 @@ function MicroPlugin(Interface) {
125
118
  *
126
119
  * @param {array|object} plugins
127
120
  */
128
-
129
-
130
121
  initializePlugins(plugins) {
131
122
  var key, name;
132
123
  const self = this;
133
124
  const queue = [];
134
-
135
125
  if (Array.isArray(plugins)) {
136
126
  plugins.forEach(plugin => {
137
127
  if (typeof plugin === 'string') {
@@ -149,46 +139,37 @@ function MicroPlugin(Interface) {
149
139
  }
150
140
  }
151
141
  }
152
-
153
142
  while (name = queue.shift()) {
154
143
  self.require(name);
155
144
  }
156
145
  }
157
-
158
146
  loadPlugin(name) {
159
147
  var self = this;
160
148
  var plugins = self.plugins;
161
149
  var plugin = Interface.plugins[name];
162
-
163
150
  if (!Interface.plugins.hasOwnProperty(name)) {
164
151
  throw new Error('Unable to find "' + name + '" plugin');
165
152
  }
166
-
167
153
  plugins.requested[name] = true;
168
154
  plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]);
169
155
  plugins.names.push(name);
170
156
  }
157
+
171
158
  /**
172
159
  * Initializes a plugin.
173
160
  *
174
161
  */
175
-
176
-
177
162
  require(name) {
178
163
  var self = this;
179
164
  var plugins = self.plugins;
180
-
181
165
  if (!self.plugins.loaded.hasOwnProperty(name)) {
182
166
  if (plugins.requested[name]) {
183
167
  throw new Error('Plugin has circular dependency ("' + name + '")');
184
168
  }
185
-
186
169
  self.loadPlugin(name);
187
170
  }
188
-
189
171
  return plugins.loaded[name];
190
172
  }
191
-
192
173
  };
193
174
  }
194
175
 
@@ -1313,7 +1294,6 @@ class Sifter {
1313
1294
  * ```
1314
1295
  *
1315
1296
  */
1316
-
1317
1297
  const iterate = (object, callback) => {
1318
1298
  if (Array.isArray(object)) {
1319
1299
  object.forEach(callback);
@@ -1332,58 +1312,52 @@ const iterate = (object, callback) => {
1332
1312
  *
1333
1313
  * param query should be {}
1334
1314
  */
1335
-
1336
1315
  const getDom = query => {
1337
1316
  if (query.jquery) {
1338
1317
  return query[0];
1339
1318
  }
1340
-
1341
1319
  if (query instanceof HTMLElement) {
1342
1320
  return query;
1343
1321
  }
1344
-
1345
1322
  if (isHtmlString(query)) {
1346
1323
  var tpl = document.createElement('template');
1347
1324
  tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result
1348
-
1349
1325
  return tpl.content.firstChild;
1350
1326
  }
1351
-
1352
1327
  return document.querySelector(query);
1353
1328
  };
1354
1329
  const isHtmlString = arg => {
1355
1330
  if (typeof arg === 'string' && arg.indexOf('<') > -1) {
1356
1331
  return true;
1357
1332
  }
1358
-
1359
1333
  return false;
1360
1334
  };
1361
1335
  const escapeQuery = query => {
1362
1336
  return query.replace(/['"\\]/g, '\\$&');
1363
1337
  };
1338
+
1364
1339
  /**
1365
1340
  * Dispatch an event
1366
1341
  *
1367
1342
  */
1368
-
1369
1343
  const triggerEvent = (dom_el, event_name) => {
1370
1344
  var event = document.createEvent('HTMLEvents');
1371
1345
  event.initEvent(event_name, true, false);
1372
1346
  dom_el.dispatchEvent(event);
1373
1347
  };
1348
+
1374
1349
  /**
1375
1350
  * Apply CSS rules to a dom element
1376
1351
  *
1377
1352
  */
1378
-
1379
1353
  const applyCSS = (dom_el, css) => {
1380
1354
  Object.assign(dom_el.style, css);
1381
1355
  };
1356
+
1382
1357
  /**
1383
1358
  * Add css classes
1384
1359
  *
1385
1360
  */
1386
-
1387
1361
  const addClasses = (elmts, ...classes) => {
1388
1362
  var norm_classes = classesArray(classes);
1389
1363
  elmts = castAsArray(elmts);
@@ -1393,11 +1367,11 @@ const addClasses = (elmts, ...classes) => {
1393
1367
  });
1394
1368
  });
1395
1369
  };
1370
+
1396
1371
  /**
1397
1372
  * Remove css classes
1398
1373
  *
1399
1374
  */
1400
-
1401
1375
  const removeClasses = (elmts, ...classes) => {
1402
1376
  var norm_classes = classesArray(classes);
1403
1377
  elmts = castAsArray(elmts);
@@ -1407,55 +1381,52 @@ const removeClasses = (elmts, ...classes) => {
1407
1381
  });
1408
1382
  });
1409
1383
  };
1384
+
1410
1385
  /**
1411
1386
  * Return arguments
1412
1387
  *
1413
1388
  */
1414
-
1415
1389
  const classesArray = args => {
1416
1390
  var classes = [];
1417
1391
  iterate(args, _classes => {
1418
1392
  if (typeof _classes === 'string') {
1419
1393
  _classes = _classes.trim().split(/[\11\12\14\15\40]/);
1420
1394
  }
1421
-
1422
1395
  if (Array.isArray(_classes)) {
1423
1396
  classes = classes.concat(_classes);
1424
1397
  }
1425
1398
  });
1426
1399
  return classes.filter(Boolean);
1427
1400
  };
1401
+
1428
1402
  /**
1429
1403
  * Create an array from arg if it's not already an array
1430
1404
  *
1431
1405
  */
1432
-
1433
1406
  const castAsArray = arg => {
1434
1407
  if (!Array.isArray(arg)) {
1435
1408
  arg = [arg];
1436
1409
  }
1437
-
1438
1410
  return arg;
1439
1411
  };
1412
+
1440
1413
  /**
1441
1414
  * Get the closest node to the evt.target matching the selector
1442
1415
  * Stops at wrapper
1443
1416
  *
1444
1417
  */
1445
-
1446
1418
  const parentMatch = (target, selector, wrapper) => {
1447
1419
  if (wrapper && !wrapper.contains(target)) {
1448
1420
  return;
1449
1421
  }
1450
-
1451
1422
  while (target && target.matches) {
1452
1423
  if (target.matches(selector)) {
1453
1424
  return target;
1454
1425
  }
1455
-
1456
1426
  target = target.parentNode;
1457
1427
  }
1458
1428
  };
1429
+
1459
1430
  /**
1460
1431
  * Get the first or last item from an array
1461
1432
  *
@@ -1463,45 +1434,41 @@ const parentMatch = (target, selector, wrapper) => {
1463
1434
  * <= 0 - left (first)
1464
1435
  *
1465
1436
  */
1466
-
1467
1437
  const getTail = (list, direction = 0) => {
1468
1438
  if (direction > 0) {
1469
1439
  return list[list.length - 1];
1470
1440
  }
1471
-
1472
1441
  return list[0];
1473
1442
  };
1443
+
1474
1444
  /**
1475
1445
  * Return true if an object is empty
1476
1446
  *
1477
1447
  */
1478
-
1479
1448
  const isEmptyObject = obj => {
1480
1449
  return Object.keys(obj).length === 0;
1481
1450
  };
1451
+
1482
1452
  /**
1483
1453
  * Get the index of an element amongst sibling nodes of the same type
1484
1454
  *
1485
1455
  */
1486
-
1487
1456
  const nodeIndex = (el, amongst) => {
1488
1457
  if (!el) return -1;
1489
1458
  amongst = amongst || el.nodeName;
1490
1459
  var i = 0;
1491
-
1492
1460
  while (el = el.previousElementSibling) {
1493
1461
  if (el.matches(amongst)) {
1494
1462
  i++;
1495
1463
  }
1496
1464
  }
1497
-
1498
1465
  return i;
1499
1466
  };
1467
+
1500
1468
  /**
1501
1469
  * Set attributes of an element
1502
1470
  *
1503
1471
  */
1504
-
1505
1472
  const setAttr = (el, attrs) => {
1506
1473
  iterate(attrs, (val, attr) => {
1507
1474
  if (val == null) {
@@ -1511,10 +1478,10 @@ const setAttr = (el, attrs) => {
1511
1478
  }
1512
1479
  });
1513
1480
  };
1481
+
1514
1482
  /**
1515
1483
  * Replace a node
1516
1484
  */
1517
-
1518
1485
  const replaceNode = (existing, replacement) => {
1519
1486
  if (existing.parentNode) existing.parentNode.replaceChild(replacement, existing);
1520
1487
  };
@@ -1526,19 +1493,20 @@ const replaceNode = (existing, replacement) => {
1526
1493
  * - Modified by Marshal <beatgates@gmail.com> 2011-6-24 (added regex)
1527
1494
  * - Modified by Brian Reavis <brian@thirdroute.com> 2012-8-27 (cleanup)
1528
1495
  */
1496
+
1529
1497
  const highlight = (element, regex) => {
1530
- if (regex === null) return; // convet string to regex
1498
+ if (regex === null) return;
1531
1499
 
1500
+ // convet string to regex
1532
1501
  if (typeof regex === 'string') {
1533
1502
  if (!regex.length) return;
1534
1503
  regex = new RegExp(regex, 'i');
1535
- } // Wrap matching part of text node with highlighting <span>, e.g.
1536
- // Soccer -> <span class="highlight">Soc</span>cer for regex = /soc/i
1537
-
1504
+ }
1538
1505
 
1506
+ // Wrap matching part of text node with highlighting <span>, e.g.
1507
+ // Soccer -> <span class="highlight">Soc</span>cer for regex = /soc/i
1539
1508
  const highlightText = node => {
1540
1509
  var match = node.data.match(regex);
1541
-
1542
1510
  if (match && node.data.length > 0) {
1543
1511
  var spannode = document.createElement('span');
1544
1512
  spannode.className = 'highlight';
@@ -1549,12 +1517,11 @@ const highlight = (element, regex) => {
1549
1517
  replaceNode(middlebit, spannode);
1550
1518
  return 1;
1551
1519
  }
1552
-
1553
1520
  return 0;
1554
- }; // Recurse element node, looking for child text nodes to highlight, unless element
1555
- // is childless, <script>, <style>, or already highlighted: <span class="hightlight">
1556
-
1521
+ };
1557
1522
 
1523
+ // Recurse element node, looking for child text nodes to highlight, unless element
1524
+ // is childless, <script>, <style>, or already highlighted: <span class="hightlight">
1558
1525
  const highlightChildren = node => {
1559
1526
  if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && (node.className !== 'highlight' || node.tagName !== 'SPAN')) {
1560
1527
  Array.from(node.childNodes).forEach(element => {
@@ -1562,23 +1529,20 @@ const highlight = (element, regex) => {
1562
1529
  });
1563
1530
  }
1564
1531
  };
1565
-
1566
1532
  const highlightRecursive = node => {
1567
1533
  if (node.nodeType === 3) {
1568
1534
  return highlightText(node);
1569
1535
  }
1570
-
1571
1536
  highlightChildren(node);
1572
1537
  return 0;
1573
1538
  };
1574
-
1575
1539
  highlightRecursive(element);
1576
1540
  };
1541
+
1577
1542
  /**
1578
1543
  * removeHighlight fn copied from highlight v5 and
1579
1544
  * edited to remove with(), pass js strict mode, and use without jquery
1580
1545
  */
1581
-
1582
1546
  const removeHighlight = el => {
1583
1547
  var elements = el.querySelectorAll("span.highlight");
1584
1548
  Array.prototype.forEach.call(elements, function (el) {
@@ -1625,6 +1589,7 @@ var defaults = {
1625
1589
  preload: null,
1626
1590
  allowEmptyOption: false,
1627
1591
  //closeAfterSelect: false,
1592
+ refreshThrottle: 300,
1628
1593
  loadThrottle: 300,
1629
1594
  loadingClass: 'loading',
1630
1595
  dataAttr: null,
@@ -1654,7 +1619,6 @@ var defaults = {
1654
1619
  shouldLoad: function (query) {
1655
1620
  return query.length > 0;
1656
1621
  },
1657
-
1658
1622
  /*
1659
1623
  load : null, // function(query, callback) { ... }
1660
1624
  score : null, // function(search) { ... }
@@ -1674,6 +1638,7 @@ var defaults = {
1674
1638
  onType : null, // function(str) { ... }
1675
1639
  onDelete : null, // function(values) { ... }
1676
1640
  */
1641
+
1677
1642
  render: {
1678
1643
  /*
1679
1644
  item: null,
@@ -1707,29 +1672,38 @@ const get_hash = value => {
1707
1672
  if (typeof value === 'boolean') return value ? '1' : '0';
1708
1673
  return value + '';
1709
1674
  };
1675
+
1710
1676
  /**
1711
1677
  * Escapes a string for use within HTML.
1712
1678
  *
1713
1679
  */
1714
-
1715
1680
  const escape_html = str => {
1716
1681
  return (str + '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1717
1682
  };
1683
+
1684
+ /**
1685
+ * use setTimeout if timeout > 0
1686
+ */
1687
+ const timeout = (fn, timeout) => {
1688
+ if (timeout > 0) {
1689
+ return setTimeout(fn, timeout);
1690
+ }
1691
+ fn.call(null);
1692
+ return null;
1693
+ };
1694
+
1718
1695
  /**
1719
1696
  * Debounce the user provided load function
1720
1697
  *
1721
1698
  */
1722
-
1723
1699
  const loadDebounce = (fn, delay) => {
1724
1700
  var timeout;
1725
1701
  return function (value, callback) {
1726
1702
  var self = this;
1727
-
1728
1703
  if (timeout) {
1729
1704
  self.loading = Math.max(self.loading - 1, 0);
1730
1705
  clearTimeout(timeout);
1731
1706
  }
1732
-
1733
1707
  timeout = setTimeout(function () {
1734
1708
  timeout = null;
1735
1709
  self.loadedSearches[value] = true;
@@ -1737,124 +1711,120 @@ const loadDebounce = (fn, delay) => {
1737
1711
  }, delay);
1738
1712
  };
1739
1713
  };
1714
+
1740
1715
  /**
1741
1716
  * Debounce all fired events types listed in `types`
1742
1717
  * while executing the provided `fn`.
1743
1718
  *
1744
1719
  */
1745
-
1746
1720
  const debounce_events = (self, types, fn) => {
1747
1721
  var type;
1748
1722
  var trigger = self.trigger;
1749
- var event_args = {}; // override trigger method
1723
+ var event_args = {};
1750
1724
 
1725
+ // override trigger method
1751
1726
  self.trigger = function () {
1752
1727
  var type = arguments[0];
1753
-
1754
1728
  if (types.indexOf(type) !== -1) {
1755
1729
  event_args[type] = arguments;
1756
1730
  } else {
1757
1731
  return trigger.apply(self, arguments);
1758
1732
  }
1759
- }; // invoke provided function
1760
-
1733
+ };
1761
1734
 
1735
+ // invoke provided function
1762
1736
  fn.apply(self, []);
1763
- self.trigger = trigger; // trigger queued events
1737
+ self.trigger = trigger;
1764
1738
 
1739
+ // trigger queued events
1765
1740
  for (type of types) {
1766
1741
  if (type in event_args) {
1767
1742
  trigger.apply(self, event_args[type]);
1768
1743
  }
1769
1744
  }
1770
1745
  };
1746
+
1771
1747
  /**
1772
1748
  * Determines the current selection within a text input control.
1773
1749
  * Returns an object containing:
1774
1750
  * - start
1775
1751
  * - length
1776
1752
  *
1753
+ * Note: "selectionStart, selectionEnd ... apply only to inputs of types text, search, URL, tel and password"
1754
+ * - https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange
1777
1755
  */
1778
-
1779
1756
  const getSelection = input => {
1780
1757
  return {
1781
1758
  start: input.selectionStart || 0,
1782
1759
  length: (input.selectionEnd || 0) - (input.selectionStart || 0)
1783
1760
  };
1784
1761
  };
1762
+
1785
1763
  /**
1786
1764
  * Prevent default
1787
1765
  *
1788
1766
  */
1789
-
1790
1767
  const preventDefault = (evt, stop = false) => {
1791
1768
  if (evt) {
1792
1769
  evt.preventDefault();
1793
-
1794
1770
  if (stop) {
1795
1771
  evt.stopPropagation();
1796
1772
  }
1797
1773
  }
1798
1774
  };
1775
+
1799
1776
  /**
1800
1777
  * Add event helper
1801
1778
  *
1802
1779
  */
1803
-
1804
1780
  const addEvent = (target, type, callback, options) => {
1805
1781
  target.addEventListener(type, callback, options);
1806
1782
  };
1783
+
1807
1784
  /**
1808
1785
  * Return true if the requested key is down
1809
1786
  * Will return false if more than one control character is pressed ( when [ctrl+shift+a] != [ctrl+a] )
1810
1787
  * The current evt may not always set ( eg calling advanceSelection() )
1811
1788
  *
1812
1789
  */
1813
-
1814
1790
  const isKeyDown = (key_name, evt) => {
1815
1791
  if (!evt) {
1816
1792
  return false;
1817
1793
  }
1818
-
1819
1794
  if (!evt[key_name]) {
1820
1795
  return false;
1821
1796
  }
1822
-
1823
1797
  var count = (evt.altKey ? 1 : 0) + (evt.ctrlKey ? 1 : 0) + (evt.shiftKey ? 1 : 0) + (evt.metaKey ? 1 : 0);
1824
-
1825
1798
  if (count === 1) {
1826
1799
  return true;
1827
1800
  }
1828
-
1829
1801
  return false;
1830
1802
  };
1803
+
1831
1804
  /**
1832
1805
  * Get the id of an element
1833
1806
  * If the id attribute is not set, set the attribute with the given id
1834
1807
  *
1835
1808
  */
1836
-
1837
1809
  const getId = (el, id) => {
1838
1810
  const existing_id = el.getAttribute('id');
1839
-
1840
1811
  if (existing_id) {
1841
1812
  return existing_id;
1842
1813
  }
1843
-
1844
1814
  el.setAttribute('id', id);
1845
1815
  return id;
1846
1816
  };
1817
+
1847
1818
  /**
1848
1819
  * Returns a string with backslashes added before characters that need to be escaped.
1849
1820
  */
1850
-
1851
1821
  const addSlashes = str => {
1852
1822
  return str.replace(/[\\"']/g, '\\$&');
1853
1823
  };
1824
+
1854
1825
  /**
1855
1826
  *
1856
1827
  */
1857
-
1858
1828
  const append = (parent, node) => {
1859
1829
  if (node) parent.append(node);
1860
1830
  };
@@ -1870,15 +1840,12 @@ function getSettings(input, settings_user) {
1870
1840
  var field_optgroup_value = settings.optgroupValueField;
1871
1841
  var tag_name = input.tagName.toLowerCase();
1872
1842
  var placeholder = input.getAttribute('placeholder') || input.getAttribute('data-placeholder');
1873
-
1874
1843
  if (!placeholder && !settings.allowEmptyOption) {
1875
1844
  let option = input.querySelector('option[value=""]');
1876
-
1877
1845
  if (option) {
1878
1846
  placeholder = option.textContent;
1879
1847
  }
1880
1848
  }
1881
-
1882
1849
  var settings_element = {
1883
1850
  placeholder: placeholder,
1884
1851
  options: [],
@@ -1886,41 +1853,37 @@ function getSettings(input, settings_user) {
1886
1853
  items: [],
1887
1854
  maxItems: null
1888
1855
  };
1856
+
1889
1857
  /**
1890
1858
  * Initialize from a <select> element.
1891
1859
  *
1892
1860
  */
1893
-
1894
1861
  var init_select = () => {
1895
1862
  var tagName;
1896
1863
  var options = settings_element.options;
1897
1864
  var optionsMap = {};
1898
1865
  var group_count = 1;
1899
-
1866
+ let $order = 0;
1900
1867
  var readData = el => {
1901
1868
  var data = Object.assign({}, el.dataset); // get plain object from DOMStringMap
1902
-
1903
1869
  var json = attr_data && data[attr_data];
1904
-
1905
1870
  if (typeof json === 'string' && json.length) {
1906
1871
  data = Object.assign(data, JSON.parse(json));
1907
1872
  }
1908
-
1909
1873
  return data;
1910
1874
  };
1911
-
1912
1875
  var addOption = (option, group) => {
1913
1876
  var value = hash_key(option.value);
1914
1877
  if (value == null) return;
1915
- if (!value && !settings.allowEmptyOption) return; // if the option already exists, it's probably been
1878
+ if (!value && !settings.allowEmptyOption) return;
1879
+
1880
+ // if the option already exists, it's probably been
1916
1881
  // duplicated in another optgroup. in this case, push
1917
1882
  // the current group to the "optgroup" property on the
1918
1883
  // existing option so that it's rendered in both places.
1919
-
1920
1884
  if (optionsMap.hasOwnProperty(value)) {
1921
1885
  if (group) {
1922
1886
  var arr = optionsMap[value][field_optgroup];
1923
-
1924
1887
  if (!arr) {
1925
1888
  optionsMap[value][field_optgroup] = group;
1926
1889
  } else if (!Array.isArray(arr)) {
@@ -1936,32 +1899,30 @@ function getSettings(input, settings_user) {
1936
1899
  option_data[field_disabled] = option_data[field_disabled] || option.disabled;
1937
1900
  option_data[field_optgroup] = option_data[field_optgroup] || group;
1938
1901
  option_data.$option = option;
1902
+ option_data.$order = option_data.$order || ++$order;
1939
1903
  optionsMap[value] = option_data;
1940
1904
  options.push(option_data);
1941
1905
  }
1942
-
1943
1906
  if (option.selected) {
1944
1907
  settings_element.items.push(value);
1945
1908
  }
1946
1909
  };
1947
-
1948
1910
  var addGroup = optgroup => {
1949
1911
  var id, optgroup_data;
1950
1912
  optgroup_data = readData(optgroup);
1951
1913
  optgroup_data[field_optgroup_label] = optgroup_data[field_optgroup_label] || optgroup.getAttribute('label') || '';
1952
1914
  optgroup_data[field_optgroup_value] = optgroup_data[field_optgroup_value] || group_count++;
1953
1915
  optgroup_data[field_disabled] = optgroup_data[field_disabled] || optgroup.disabled;
1916
+ optgroup_data.$order = optgroup_data.$order || ++$order;
1954
1917
  settings_element.optgroups.push(optgroup_data);
1955
1918
  id = optgroup_data[field_optgroup_value];
1956
1919
  iterate(optgroup.children, option => {
1957
1920
  addOption(option, id);
1958
1921
  });
1959
1922
  };
1960
-
1961
1923
  settings_element.maxItems = input.hasAttribute('multiple') ? null : 1;
1962
1924
  iterate(input.children, child => {
1963
1925
  tagName = child.tagName.toLowerCase();
1964
-
1965
1926
  if (tagName === 'optgroup') {
1966
1927
  addGroup(child);
1967
1928
  } else if (tagName === 'option') {
@@ -1969,15 +1930,13 @@ function getSettings(input, settings_user) {
1969
1930
  }
1970
1931
  });
1971
1932
  };
1933
+
1972
1934
  /**
1973
1935
  * Initialize from a <input type="text"> element.
1974
1936
  *
1975
1937
  */
1976
-
1977
-
1978
1938
  var init_textbox = () => {
1979
1939
  const data_raw = input.getAttribute(attr_data);
1980
-
1981
1940
  if (!data_raw) {
1982
1941
  var value = input.value.trim() || '';
1983
1942
  if (!settings.allowEmptyOption && !value.length) return;
@@ -1996,19 +1955,16 @@ function getSettings(input, settings_user) {
1996
1955
  });
1997
1956
  }
1998
1957
  };
1999
-
2000
1958
  if (tag_name === 'select') {
2001
1959
  init_select();
2002
1960
  } else {
2003
1961
  init_textbox();
2004
1962
  }
2005
-
2006
1963
  return Object.assign({}, defaults, settings_element, settings_user);
2007
1964
  }
2008
1965
 
2009
1966
  var instance_i = 0;
2010
1967
  class TomSelect extends MicroPlugin(MicroEvent) {
2011
- // @deprecated 1.8
2012
1968
  constructor(input_arg, user_settings) {
2013
1969
  super();
2014
1970
  this.control_input = void 0;
@@ -2028,8 +1984,10 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2028
1984
  this.sifter = void 0;
2029
1985
  this.isOpen = false;
2030
1986
  this.isDisabled = false;
1987
+ this.isReadOnly = false;
2031
1988
  this.isRequired = void 0;
2032
1989
  this.isInvalid = false;
1990
+ // @deprecated 1.8
2033
1991
  this.isValid = true;
2034
1992
  this.isLocked = false;
2035
1993
  this.isFocused = false;
@@ -2049,19 +2007,20 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2049
2007
  this.options = {};
2050
2008
  this.userOptions = {};
2051
2009
  this.items = [];
2010
+ this.refreshTimeout = null;
2052
2011
  instance_i++;
2053
2012
  var dir;
2054
2013
  var input = getDom(input_arg);
2055
-
2056
2014
  if (input.tomselect) {
2057
2015
  throw new Error('Tom Select already initialized on this element');
2058
2016
  }
2017
+ input.tomselect = this;
2059
2018
 
2060
- input.tomselect = this; // detect rtl environment
2061
-
2019
+ // detect rtl environment
2062
2020
  var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);
2063
- dir = computedStyle.getPropertyValue('direction'); // setup default state
2021
+ dir = computedStyle.getPropertyValue('direction');
2064
2022
 
2023
+ // setup default state
2065
2024
  const settings = getSettings(input, user_settings);
2066
2025
  this.settings = settings;
2067
2026
  this.input = input;
@@ -2069,30 +2028,28 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2069
2028
  this.is_select_tag = input.tagName.toLowerCase() === 'select';
2070
2029
  this.rtl = /rtl/i.test(dir);
2071
2030
  this.inputId = getId(input, 'tomselect-' + instance_i);
2072
- this.isRequired = input.required; // search system
2031
+ this.isRequired = input.required;
2073
2032
 
2033
+ // search system
2074
2034
  this.sifter = new Sifter(this.options, {
2075
2035
  diacritics: settings.diacritics
2076
- }); // option-dependent defaults
2036
+ });
2077
2037
 
2038
+ // option-dependent defaults
2078
2039
  settings.mode = settings.mode || (settings.maxItems === 1 ? 'single' : 'multi');
2079
-
2080
2040
  if (typeof settings.hideSelected !== 'boolean') {
2081
2041
  settings.hideSelected = settings.mode === 'multi';
2082
2042
  }
2083
-
2084
2043
  if (typeof settings.hidePlaceholder !== 'boolean') {
2085
2044
  settings.hidePlaceholder = settings.mode !== 'multi';
2086
- } // set up createFilter callback
2087
-
2045
+ }
2088
2046
 
2047
+ // set up createFilter callback
2089
2048
  var filter = settings.createFilter;
2090
-
2091
2049
  if (typeof filter !== 'function') {
2092
2050
  if (typeof filter === 'string') {
2093
2051
  filter = new RegExp(filter);
2094
2052
  }
2095
-
2096
2053
  if (filter instanceof RegExp) {
2097
2054
  settings.createFilter = input => filter.test(input);
2098
2055
  } else {
@@ -2101,16 +2058,14 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2101
2058
  };
2102
2059
  }
2103
2060
  }
2104
-
2105
2061
  this.initializePlugins(settings.plugins);
2106
2062
  this.setupCallbacks();
2107
- this.setupTemplates(); // Create all elements
2063
+ this.setupTemplates();
2108
2064
 
2065
+ // Create all elements
2109
2066
  const wrapper = getDom('<div>');
2110
2067
  const control = getDom('<div>');
2111
-
2112
2068
  const dropdown = this._render('dropdown');
2113
-
2114
2069
  const dropdown_content = getDom(`<div role="listbox" tabindex="-1">`);
2115
2070
  const classes = this.input.getAttribute('class') || '';
2116
2071
  const inputMode = settings.mode;
@@ -2119,19 +2074,19 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2119
2074
  addClasses(control, settings.controlClass);
2120
2075
  append(wrapper, control);
2121
2076
  addClasses(dropdown, settings.dropdownClass, inputMode);
2122
-
2123
2077
  if (settings.copyClassesToDropdown) {
2124
2078
  addClasses(dropdown, classes);
2125
2079
  }
2126
-
2127
2080
  addClasses(dropdown_content, settings.dropdownContentClass);
2128
2081
  append(dropdown, dropdown_content);
2129
- getDom(settings.dropdownParent || wrapper).appendChild(dropdown); // default controlInput
2082
+ getDom(settings.dropdownParent || wrapper).appendChild(dropdown);
2130
2083
 
2084
+ // default controlInput
2131
2085
  if (isHtmlString(settings.controlInput)) {
2132
- control_input = getDom(settings.controlInput); // set attributes
2086
+ control_input = getDom(settings.controlInput);
2133
2087
 
2134
- var attrs = ['autocorrect', 'autocapitalize', 'autocomplete'];
2088
+ // set attributes
2089
+ var attrs = ['autocorrect', 'autocapitalize', 'autocomplete', 'spellcheck'];
2135
2090
  iterate$1(attrs, attr => {
2136
2091
  if (input.getAttribute(attr)) {
2137
2092
  setAttr(control_input, {
@@ -2141,7 +2096,9 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2141
2096
  });
2142
2097
  control_input.tabIndex = -1;
2143
2098
  control.appendChild(control_input);
2144
- this.focus_node = control_input; // dom element
2099
+ this.focus_node = control_input;
2100
+
2101
+ // dom element
2145
2102
  } else if (settings.controlInput) {
2146
2103
  control_input = getDom(settings.controlInput);
2147
2104
  this.focus_node = control_input;
@@ -2149,7 +2106,6 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2149
2106
  control_input = getDom('<input/>');
2150
2107
  this.focus_node = control;
2151
2108
  }
2152
-
2153
2109
  this.wrapper = wrapper;
2154
2110
  this.dropdown = dropdown;
2155
2111
  this.dropdown_content = dropdown_content;
@@ -2157,12 +2113,11 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2157
2113
  this.control_input = control_input;
2158
2114
  this.setup();
2159
2115
  }
2116
+
2160
2117
  /**
2161
2118
  * set up event bindings.
2162
2119
  *
2163
2120
  */
2164
-
2165
-
2166
2121
  setup() {
2167
2122
  const self = this;
2168
2123
  const settings = self.settings;
@@ -2190,7 +2145,6 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2190
2145
  const query = "label[for='" + escapeQuery(self.inputId) + "']";
2191
2146
  const label = document.querySelector(query);
2192
2147
  const label_click = self.focus.bind(self);
2193
-
2194
2148
  if (label) {
2195
2149
  addEvent(label, 'click', label_click);
2196
2150
  setAttr(label, {
@@ -2204,38 +2158,32 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2204
2158
  'aria-labelledby': label_id
2205
2159
  });
2206
2160
  }
2207
-
2208
2161
  wrapper.style.width = input.style.width;
2209
-
2210
2162
  if (self.plugins.names.length) {
2211
2163
  const classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');
2212
2164
  addClasses([wrapper, dropdown], classes_plugins);
2213
2165
  }
2214
-
2215
2166
  if ((settings.maxItems === null || settings.maxItems > 1) && self.is_select_tag) {
2216
2167
  setAttr(input, {
2217
2168
  multiple: 'multiple'
2218
2169
  });
2219
2170
  }
2220
-
2221
2171
  if (settings.placeholder) {
2222
2172
  setAttr(control_input, {
2223
2173
  placeholder: settings.placeholder
2224
2174
  });
2225
- } // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
2226
-
2175
+ }
2227
2176
 
2177
+ // if splitOn was not passed in, construct it from the delimiter to allow pasting universally
2228
2178
  if (!settings.splitOn && settings.delimiter) {
2229
2179
  settings.splitOn = new RegExp('\\s*' + escape_regex(settings.delimiter) + '+\\s*');
2230
- } // debounce user defined load() if loadThrottle > 0
2231
- // after initializePlugins() so plugins can create/modify user defined loaders
2232
-
2180
+ }
2233
2181
 
2182
+ // debounce user defined load() if loadThrottle > 0
2183
+ // after initializePlugins() so plugins can create/modify user defined loaders
2234
2184
  if (settings.load && settings.loadThrottle) {
2235
2185
  settings.load = loadDebounce(settings.load, settings.loadThrottle);
2236
2186
  }
2237
-
2238
- self.control_input.type = input.type;
2239
2187
  addEvent(dropdown, 'mousemove', () => {
2240
2188
  self.ignoreHover = false;
2241
2189
  });
@@ -2244,11 +2192,11 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2244
2192
  if (target_match) self.onOptionHover(e, target_match);
2245
2193
  }, {
2246
2194
  capture: true
2247
- }); // clicking on an option should select it
2195
+ });
2248
2196
 
2197
+ // clicking on an option should select it
2249
2198
  addEvent(dropdown, 'click', evt => {
2250
2199
  const option = parentMatch(evt.target, '[data-selectable]');
2251
-
2252
2200
  if (option) {
2253
2201
  self.onOptionSelect(evt, option);
2254
2202
  preventDefault(evt, true);
@@ -2256,73 +2204,69 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2256
2204
  });
2257
2205
  addEvent(control, 'click', evt => {
2258
2206
  var target_match = parentMatch(evt.target, '[data-ts-item]', control);
2259
-
2260
2207
  if (target_match && self.onItemSelect(evt, target_match)) {
2261
2208
  preventDefault(evt, true);
2262
2209
  return;
2263
- } // retain focus (see control_input mousedown)
2264
-
2210
+ }
2265
2211
 
2212
+ // retain focus (see control_input mousedown)
2266
2213
  if (control_input.value != '') {
2267
2214
  return;
2268
2215
  }
2269
-
2270
2216
  self.onClick();
2271
2217
  preventDefault(evt, true);
2272
- }); // keydown on focus_node for arrow_down/arrow_up
2218
+ });
2273
2219
 
2274
- addEvent(focus_node, 'keydown', e => self.onKeyDown(e)); // keypress and input/keyup
2220
+ // keydown on focus_node for arrow_down/arrow_up
2221
+ addEvent(focus_node, 'keydown', e => self.onKeyDown(e));
2275
2222
 
2223
+ // keypress and input/keyup
2276
2224
  addEvent(control_input, 'keypress', e => self.onKeyPress(e));
2277
2225
  addEvent(control_input, 'input', e => self.onInput(e));
2278
2226
  addEvent(focus_node, 'blur', e => self.onBlur(e));
2279
2227
  addEvent(focus_node, 'focus', e => self.onFocus(e));
2280
2228
  addEvent(control_input, 'paste', e => self.onPaste(e));
2281
-
2282
2229
  const doc_mousedown = evt => {
2283
2230
  // blur if target is outside of this instance
2284
2231
  // dropdown is not always inside wrapper
2285
2232
  const target = evt.composedPath()[0];
2286
-
2287
2233
  if (!wrapper.contains(target) && !dropdown.contains(target)) {
2288
2234
  if (self.isFocused) {
2289
2235
  self.blur();
2290
2236
  }
2291
-
2292
2237
  self.inputState();
2293
2238
  return;
2294
- } // retain focus by preventing native handling. if the
2239
+ }
2240
+
2241
+ // retain focus by preventing native handling. if the
2295
2242
  // event target is the input it should not be modified.
2296
2243
  // otherwise, text selection within the input won't work.
2297
2244
  // Fixes bug #212 which is no covered by tests
2298
-
2299
-
2300
2245
  if (target == control_input && self.isOpen) {
2301
- evt.stopPropagation(); // clicking anywhere in the control should not blur the control_input (which would close the dropdown)
2246
+ evt.stopPropagation();
2247
+
2248
+ // clicking anywhere in the control should not blur the control_input (which would close the dropdown)
2302
2249
  } else {
2303
2250
  preventDefault(evt, true);
2304
2251
  }
2305
2252
  };
2306
-
2307
2253
  const win_scroll = () => {
2308
2254
  if (self.isOpen) {
2309
2255
  self.positionDropdown();
2310
2256
  }
2311
2257
  };
2312
-
2313
2258
  addEvent(document, 'mousedown', doc_mousedown);
2314
2259
  addEvent(window, 'scroll', win_scroll, passive_event);
2315
2260
  addEvent(window, 'resize', win_scroll, passive_event);
2316
-
2317
2261
  this._destroy = () => {
2318
2262
  document.removeEventListener('mousedown', doc_mousedown);
2319
2263
  window.removeEventListener('scroll', win_scroll);
2320
2264
  window.removeEventListener('resize', win_scroll);
2321
2265
  if (label) label.removeEventListener('click', label_click);
2322
- }; // store original html and tab index so that they can be
2323
- // restored when the destroy() method is called.
2324
-
2266
+ };
2325
2267
 
2268
+ // store original html and tab index so that they can be
2269
+ // restored when the destroy() method is called.
2326
2270
  this.revertSettings = {
2327
2271
  innerHTML: input.innerHTML,
2328
2272
  tabIndex: input.tabIndex
@@ -2345,40 +2289,41 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2345
2289
  self.close(false);
2346
2290
  self.inputState();
2347
2291
  self.isSetup = true;
2348
-
2349
2292
  if (input.disabled) {
2350
2293
  self.disable();
2294
+ } else if (input.readOnly) {
2295
+ self.setReadOnly(true);
2351
2296
  } else {
2352
2297
  self.enable(); //sets tabIndex
2353
2298
  }
2354
2299
 
2355
2300
  self.on('change', this.onChange);
2356
2301
  addClasses(input, 'tomselected', 'ts-hidden-accessible');
2357
- self.trigger('initialize'); // preload options
2302
+ self.trigger('initialize');
2358
2303
 
2304
+ // preload options
2359
2305
  if (settings.preload === true) {
2360
2306
  self.preload();
2361
2307
  }
2362
2308
  }
2309
+
2363
2310
  /**
2364
2311
  * Register options and optgroups
2365
2312
  *
2366
2313
  */
2367
-
2368
-
2369
2314
  setupOptions(options = [], optgroups = []) {
2370
2315
  // build options table
2371
- this.addOptions(options); // build optgroup table
2316
+ this.addOptions(options);
2372
2317
 
2318
+ // build optgroup table
2373
2319
  iterate$1(optgroups, optgroup => {
2374
2320
  this.registerOptionGroup(optgroup);
2375
2321
  });
2376
2322
  }
2323
+
2377
2324
  /**
2378
2325
  * Sets up default rendering functions.
2379
2326
  */
2380
-
2381
-
2382
2327
  setupTemplates() {
2383
2328
  var self = this;
2384
2329
  var field_label = self.settings.labelField;
@@ -2415,12 +2360,11 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2415
2360
  };
2416
2361
  self.settings.render = Object.assign({}, templates, self.settings.render);
2417
2362
  }
2363
+
2418
2364
  /**
2419
2365
  * Maps fired events to callbacks provided
2420
2366
  * in the settings used when creating the control.
2421
2367
  */
2422
-
2423
-
2424
2368
  setupCallbacks() {
2425
2369
  var key, fn;
2426
2370
  var callbacks = {
@@ -2443,18 +2387,16 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2443
2387
  'focus': 'onFocus',
2444
2388
  'blur': 'onBlur'
2445
2389
  };
2446
-
2447
2390
  for (key in callbacks) {
2448
2391
  fn = this.settings[callbacks[key]];
2449
2392
  if (fn) this.on(key, fn);
2450
2393
  }
2451
2394
  }
2395
+
2452
2396
  /**
2453
2397
  * Sync the Tom Select instance with the original input or select
2454
2398
  *
2455
2399
  */
2456
-
2457
-
2458
2400
  sync(get_settings = true) {
2459
2401
  const self = this;
2460
2402
  const settings = get_settings ? getSettings(self.input, {
@@ -2465,78 +2407,68 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2465
2407
 
2466
2408
  self.lastQuery = null; // so updated options will be displayed in dropdown
2467
2409
  }
2410
+
2468
2411
  /**
2469
2412
  * Triggered when the main control element
2470
2413
  * has a click event.
2471
2414
  *
2472
2415
  */
2473
-
2474
-
2475
2416
  onClick() {
2476
2417
  var self = this;
2477
-
2478
2418
  if (self.activeItems.length > 0) {
2479
2419
  self.clearActiveItems();
2480
2420
  self.focus();
2481
2421
  return;
2482
2422
  }
2483
-
2484
2423
  if (self.isFocused && self.isOpen) {
2485
2424
  self.blur();
2486
2425
  } else {
2487
2426
  self.focus();
2488
2427
  }
2489
2428
  }
2429
+
2490
2430
  /**
2491
2431
  * @deprecated v1.7
2492
2432
  *
2493
2433
  */
2494
-
2495
-
2496
2434
  onMouseDown() {}
2435
+
2497
2436
  /**
2498
2437
  * Triggered when the value of the control has been changed.
2499
2438
  * This should propagate the event to the original DOM
2500
2439
  * input / select element.
2501
2440
  */
2502
-
2503
-
2504
2441
  onChange() {
2505
2442
  triggerEvent(this.input, 'input');
2506
2443
  triggerEvent(this.input, 'change');
2507
2444
  }
2445
+
2508
2446
  /**
2509
2447
  * Triggered on <input> paste.
2510
2448
  *
2511
2449
  */
2512
-
2513
-
2514
2450
  onPaste(e) {
2515
2451
  var self = this;
2516
-
2517
2452
  if (self.isInputHidden || self.isLocked) {
2518
2453
  preventDefault(e);
2519
2454
  return;
2520
- } // If a regex or string is included, this will split the pasted
2521
- // input and create Items for each separate value
2522
-
2455
+ }
2523
2456
 
2457
+ // If a regex or string is included, this will split the pasted
2458
+ // input and create Items for each separate value
2524
2459
  if (!self.settings.splitOn) {
2525
2460
  return;
2526
- } // Wait for pasted text to be recognized in value
2527
-
2461
+ }
2528
2462
 
2463
+ // Wait for pasted text to be recognized in value
2529
2464
  setTimeout(() => {
2530
2465
  var pastedText = self.inputValue();
2531
-
2532
2466
  if (!pastedText.match(self.settings.splitOn)) {
2533
2467
  return;
2534
2468
  }
2535
-
2536
2469
  var splitInput = pastedText.trim().split(self.settings.splitOn);
2537
2470
  iterate$1(splitInput, piece => {
2538
2471
  const hash = hash_key(piece);
2539
-
2540
2472
  if (hash) {
2541
2473
  if (this.options[piece]) {
2542
2474
  self.addItem(piece);
@@ -2547,46 +2479,38 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2547
2479
  });
2548
2480
  }, 0);
2549
2481
  }
2482
+
2550
2483
  /**
2551
2484
  * Triggered on <input> keypress.
2552
2485
  *
2553
2486
  */
2554
-
2555
-
2556
2487
  onKeyPress(e) {
2557
2488
  var self = this;
2558
-
2559
2489
  if (self.isLocked) {
2560
2490
  preventDefault(e);
2561
2491
  return;
2562
2492
  }
2563
-
2564
2493
  var character = String.fromCharCode(e.keyCode || e.which);
2565
-
2566
2494
  if (self.settings.create && self.settings.mode === 'multi' && character === self.settings.delimiter) {
2567
2495
  self.createItem();
2568
2496
  preventDefault(e);
2569
2497
  return;
2570
2498
  }
2571
2499
  }
2500
+
2572
2501
  /**
2573
2502
  * Triggered on <input> keydown.
2574
2503
  *
2575
2504
  */
2576
-
2577
-
2578
2505
  onKeyDown(e) {
2579
2506
  var self = this;
2580
2507
  self.ignoreHover = true;
2581
-
2582
2508
  if (self.isLocked) {
2583
2509
  if (e.keyCode !== KEY_TAB) {
2584
2510
  preventDefault(e);
2585
2511
  }
2586
-
2587
2512
  return;
2588
2513
  }
2589
-
2590
2514
  switch (e.keyCode) {
2591
2515
  // ctrl+A: select all
2592
2516
  case KEY_A:
@@ -2597,20 +2521,18 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2597
2521
  return;
2598
2522
  }
2599
2523
  }
2600
-
2601
2524
  break;
2602
- // esc: close dropdown
2603
2525
 
2526
+ // esc: close dropdown
2604
2527
  case KEY_ESC:
2605
2528
  if (self.isOpen) {
2606
2529
  preventDefault(e, true);
2607
2530
  self.close();
2608
2531
  }
2609
-
2610
2532
  self.clearActiveItems();
2611
2533
  return;
2612
- // down: open dropdown or move selection down
2613
2534
 
2535
+ // down: open dropdown or move selection down
2614
2536
  case KEY_DOWN:
2615
2537
  if (!self.isOpen && self.hasOptions) {
2616
2538
  self.open();
@@ -2618,178 +2540,174 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2618
2540
  let next = self.getAdjacent(self.activeOption, 1);
2619
2541
  if (next) self.setActiveOption(next);
2620
2542
  }
2621
-
2622
2543
  preventDefault(e);
2623
2544
  return;
2624
- // up: move selection up
2625
2545
 
2546
+ // up: move selection up
2626
2547
  case KEY_UP:
2627
2548
  if (self.activeOption) {
2628
2549
  let prev = self.getAdjacent(self.activeOption, -1);
2629
2550
  if (prev) self.setActiveOption(prev);
2630
2551
  }
2631
-
2632
2552
  preventDefault(e);
2633
2553
  return;
2634
- // return: select active option
2635
2554
 
2555
+ // return: select active option
2636
2556
  case KEY_RETURN:
2637
2557
  if (self.canSelect(self.activeOption)) {
2638
2558
  self.onOptionSelect(e, self.activeOption);
2639
- preventDefault(e); // if the option_create=null, the dropdown might be closed
2559
+ preventDefault(e);
2560
+
2561
+ // if the option_create=null, the dropdown might be closed
2640
2562
  } else if (self.settings.create && self.createItem()) {
2641
- preventDefault(e); // don't submit form when searching for a value
2563
+ preventDefault(e);
2564
+
2565
+ // don't submit form when searching for a value
2642
2566
  } else if (document.activeElement == self.control_input && self.isOpen) {
2643
2567
  preventDefault(e);
2644
2568
  }
2645
-
2646
2569
  return;
2647
- // left: modifiy item selection to the left
2648
2570
 
2571
+ // left: modifiy item selection to the left
2649
2572
  case KEY_LEFT:
2650
2573
  self.advanceSelection(-1, e);
2651
2574
  return;
2652
- // right: modifiy item selection to the right
2653
2575
 
2576
+ // right: modifiy item selection to the right
2654
2577
  case KEY_RIGHT:
2655
2578
  self.advanceSelection(1, e);
2656
2579
  return;
2657
- // tab: select active option and/or create item
2658
2580
 
2581
+ // tab: select active option and/or create item
2659
2582
  case KEY_TAB:
2660
2583
  if (self.settings.selectOnTab) {
2661
2584
  if (self.canSelect(self.activeOption)) {
2662
- self.onOptionSelect(e, self.activeOption); // prevent default [tab] behaviour of jump to the next field
2663
- // if select isFull, then the dropdown won't be open and [tab] will work normally
2585
+ self.onOptionSelect(e, self.activeOption);
2664
2586
 
2587
+ // prevent default [tab] behaviour of jump to the next field
2588
+ // if select isFull, then the dropdown won't be open and [tab] will work normally
2665
2589
  preventDefault(e);
2666
2590
  }
2667
-
2668
2591
  if (self.settings.create && self.createItem()) {
2669
2592
  preventDefault(e);
2670
2593
  }
2671
2594
  }
2672
-
2673
2595
  return;
2674
- // delete|backspace: delete items
2675
2596
 
2597
+ // delete|backspace: delete items
2676
2598
  case KEY_BACKSPACE:
2677
2599
  case KEY_DELETE:
2678
2600
  self.deleteSelection(e);
2679
2601
  return;
2680
- } // don't enter text in the control_input when active items are selected
2681
-
2602
+ }
2682
2603
 
2604
+ // don't enter text in the control_input when active items are selected
2683
2605
  if (self.isInputHidden && !isKeyDown(KEY_SHORTCUT, e)) {
2684
2606
  preventDefault(e);
2685
2607
  }
2686
2608
  }
2609
+
2687
2610
  /**
2688
2611
  * Triggered on <input> keyup.
2689
2612
  *
2690
2613
  */
2691
-
2692
-
2693
2614
  onInput(e) {
2694
- var self = this;
2695
-
2696
- if (self.isLocked) {
2615
+ if (this.isLocked) {
2697
2616
  return;
2698
2617
  }
2699
-
2700
- var value = self.inputValue();
2701
-
2702
- if (self.lastValue !== value) {
2703
- self.lastValue = value;
2704
-
2705
- if (self.settings.shouldLoad.call(self, value)) {
2706
- self.load(value);
2707
- }
2708
-
2709
- self.refreshOptions();
2710
- self.trigger('type', value);
2618
+ const value = this.inputValue();
2619
+ if (this.lastValue === value) return;
2620
+ this.lastValue = value;
2621
+ if (value == '') {
2622
+ this._onInput();
2623
+ return;
2624
+ }
2625
+ if (this.refreshTimeout) {
2626
+ clearTimeout(this.refreshTimeout);
2711
2627
  }
2628
+ this.refreshTimeout = timeout(() => {
2629
+ this.refreshTimeout = null;
2630
+ this._onInput();
2631
+ }, this.settings.refreshThrottle);
2632
+ }
2633
+ _onInput() {
2634
+ const value = this.lastValue;
2635
+ if (this.settings.shouldLoad.call(this, value)) {
2636
+ this.load(value);
2637
+ }
2638
+ this.refreshOptions();
2639
+ this.trigger('type', value);
2712
2640
  }
2641
+
2713
2642
  /**
2714
2643
  * Triggered when the user rolls over
2715
2644
  * an option in the autocomplete dropdown menu.
2716
2645
  *
2717
2646
  */
2718
-
2719
-
2720
2647
  onOptionHover(evt, option) {
2721
2648
  if (this.ignoreHover) return;
2722
2649
  this.setActiveOption(option, false);
2723
2650
  }
2651
+
2724
2652
  /**
2725
2653
  * Triggered on <input> focus.
2726
2654
  *
2727
2655
  */
2728
-
2729
-
2730
2656
  onFocus(e) {
2731
2657
  var self = this;
2732
2658
  var wasFocused = self.isFocused;
2733
-
2734
- if (self.isDisabled) {
2659
+ if (self.isDisabled || self.isReadOnly) {
2735
2660
  self.blur();
2736
2661
  preventDefault(e);
2737
2662
  return;
2738
2663
  }
2739
-
2740
2664
  if (self.ignoreFocus) return;
2741
2665
  self.isFocused = true;
2742
2666
  if (self.settings.preload === 'focus') self.preload();
2743
2667
  if (!wasFocused) self.trigger('focus');
2744
-
2745
2668
  if (!self.activeItems.length) {
2746
- self.showInput();
2669
+ self.inputState();
2747
2670
  self.refreshOptions(!!self.settings.openOnFocus);
2748
2671
  }
2749
-
2750
2672
  self.refreshState();
2751
2673
  }
2674
+
2752
2675
  /**
2753
2676
  * Triggered on <input> blur.
2754
2677
  *
2755
2678
  */
2756
-
2757
-
2758
2679
  onBlur(e) {
2759
2680
  if (document.hasFocus() === false) return;
2760
2681
  var self = this;
2761
2682
  if (!self.isFocused) return;
2762
2683
  self.isFocused = false;
2763
2684
  self.ignoreFocus = false;
2764
-
2765
2685
  var deactivate = () => {
2766
2686
  self.close();
2767
2687
  self.setActiveItem();
2768
2688
  self.setCaret(self.items.length);
2769
2689
  self.trigger('blur');
2770
2690
  };
2771
-
2772
2691
  if (self.settings.create && self.settings.createOnBlur) {
2773
2692
  self.createItem(null, deactivate);
2774
2693
  } else {
2775
2694
  deactivate();
2776
2695
  }
2777
2696
  }
2697
+
2778
2698
  /**
2779
2699
  * Triggered when the user clicks on an option
2780
2700
  * in the autocomplete dropdown menu.
2781
2701
  *
2782
2702
  */
2783
-
2784
-
2785
2703
  onOptionSelect(evt, option) {
2786
2704
  var value,
2787
- self = this; // should not be possible to trigger a option under a disabled optgroup
2705
+ self = this;
2788
2706
 
2707
+ // should not be possible to trigger a option under a disabled optgroup
2789
2708
  if (option.parentElement && option.parentElement.matches('[data-disabled]')) {
2790
2709
  return;
2791
2710
  }
2792
-
2793
2711
  if (option.classList.contains('create')) {
2794
2712
  self.createItem(null, () => {
2795
2713
  if (self.settings.closeAfterSelect) {
@@ -2798,52 +2716,45 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2798
2716
  });
2799
2717
  } else {
2800
2718
  value = option.dataset.value;
2801
-
2802
2719
  if (typeof value !== 'undefined') {
2803
2720
  self.lastQuery = null;
2804
2721
  self.addItem(value);
2805
-
2806
2722
  if (self.settings.closeAfterSelect) {
2807
2723
  self.close();
2808
2724
  }
2809
-
2810
2725
  if (!self.settings.hideSelected && evt.type && /click/.test(evt.type)) {
2811
2726
  self.setActiveOption(option);
2812
2727
  }
2813
2728
  }
2814
2729
  }
2815
2730
  }
2731
+
2816
2732
  /**
2817
2733
  * Return true if the given option can be selected
2818
2734
  *
2819
2735
  */
2820
-
2821
-
2822
2736
  canSelect(option) {
2823
2737
  if (this.isOpen && option && this.dropdown_content.contains(option)) {
2824
2738
  return true;
2825
2739
  }
2826
-
2827
2740
  return false;
2828
2741
  }
2742
+
2829
2743
  /**
2830
2744
  * Triggered when the user clicks on an item
2831
2745
  * that has been selected.
2832
2746
  *
2833
2747
  */
2834
-
2835
-
2836
2748
  onItemSelect(evt, item) {
2837
2749
  var self = this;
2838
-
2839
2750
  if (!self.isLocked && self.settings.mode === 'multi') {
2840
2751
  preventDefault(evt);
2841
2752
  self.setActiveItem(item, evt);
2842
2753
  return true;
2843
2754
  }
2844
-
2845
2755
  return false;
2846
2756
  }
2757
+
2847
2758
  /**
2848
2759
  * Determines whether or not to invoke
2849
2760
  * the user-provided option provider / loader
@@ -2860,19 +2771,16 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2860
2771
  * feedback when canLoad returns false
2861
2772
  *
2862
2773
  */
2863
-
2864
-
2865
2774
  canLoad(value) {
2866
2775
  if (!this.settings.load) return false;
2867
2776
  if (this.loadedSearches.hasOwnProperty(value)) return false;
2868
2777
  return true;
2869
2778
  }
2779
+
2870
2780
  /**
2871
2781
  * Invokes the user-provided option provider / loader.
2872
2782
  *
2873
2783
  */
2874
-
2875
-
2876
2784
  load(value) {
2877
2785
  const self = this;
2878
2786
  if (!self.canLoad(value)) return;
@@ -2881,50 +2789,44 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2881
2789
  const callback = self.loadCallback.bind(self);
2882
2790
  self.settings.load.call(self, value, callback);
2883
2791
  }
2792
+
2884
2793
  /**
2885
2794
  * Invoked by the user-provided option provider
2886
2795
  *
2887
2796
  */
2888
-
2889
-
2890
2797
  loadCallback(options, optgroups) {
2891
2798
  const self = this;
2892
2799
  self.loading = Math.max(self.loading - 1, 0);
2893
2800
  self.lastQuery = null;
2894
2801
  self.clearActiveOption(); // when new results load, focus should be on first option
2895
-
2896
2802
  self.setupOptions(options, optgroups);
2897
2803
  self.refreshOptions(self.isFocused && !self.isInputHidden);
2898
-
2899
2804
  if (!self.loading) {
2900
2805
  removeClasses(self.wrapper, self.settings.loadingClass);
2901
2806
  }
2902
-
2903
2807
  self.trigger('load', options, optgroups);
2904
2808
  }
2905
-
2906
2809
  preload() {
2907
2810
  var classList = this.wrapper.classList;
2908
2811
  if (classList.contains('preloaded')) return;
2909
2812
  classList.add('preloaded');
2910
2813
  this.load('');
2911
2814
  }
2815
+
2912
2816
  /**
2913
2817
  * Sets the input field of the control to the specified value.
2914
2818
  *
2915
2819
  */
2916
-
2917
-
2918
2820
  setTextboxValue(value = '') {
2919
2821
  var input = this.control_input;
2920
2822
  var changed = input.value !== value;
2921
-
2922
2823
  if (changed) {
2923
2824
  input.value = value;
2924
2825
  triggerEvent(input, 'update');
2925
2826
  this.lastValue = value;
2926
2827
  }
2927
2828
  }
2829
+
2928
2830
  /**
2929
2831
  * Returns the value of the control. If multiple items
2930
2832
  * can be selected (e.g. <select multiple>), this returns
@@ -2932,21 +2834,17 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2932
2834
  * returns a string.
2933
2835
  *
2934
2836
  */
2935
-
2936
-
2937
2837
  getValue() {
2938
2838
  if (this.is_select_tag && this.input.hasAttribute('multiple')) {
2939
2839
  return this.items;
2940
2840
  }
2941
-
2942
2841
  return this.items.join(this.settings.delimiter);
2943
2842
  }
2843
+
2944
2844
  /**
2945
2845
  * Resets the selected items to the given value.
2946
2846
  *
2947
2847
  */
2948
-
2949
-
2950
2848
  setValue(value, silent) {
2951
2849
  var events = silent ? [] : ['change'];
2952
2850
  debounce_events(this, events, () => {
@@ -2954,63 +2852,54 @@ class TomSelect extends MicroPlugin(MicroEvent) {
2954
2852
  this.addItems(value, silent);
2955
2853
  });
2956
2854
  }
2855
+
2957
2856
  /**
2958
2857
  * Resets the number of max items to the given value
2959
2858
  *
2960
2859
  */
2961
-
2962
-
2963
2860
  setMaxItems(value) {
2964
2861
  if (value === 0) value = null; //reset to unlimited items.
2965
-
2966
2862
  this.settings.maxItems = value;
2967
2863
  this.refreshState();
2968
2864
  }
2865
+
2969
2866
  /**
2970
2867
  * Sets the selected item.
2971
2868
  *
2972
2869
  */
2973
-
2974
-
2975
2870
  setActiveItem(item, e) {
2976
2871
  var self = this;
2977
2872
  var eventName;
2978
2873
  var i, begin, end, swap;
2979
2874
  var last;
2980
- if (self.settings.mode === 'single') return; // clear the active selection
2875
+ if (self.settings.mode === 'single') return;
2981
2876
 
2877
+ // clear the active selection
2982
2878
  if (!item) {
2983
2879
  self.clearActiveItems();
2984
-
2985
2880
  if (self.isFocused) {
2986
- self.showInput();
2881
+ self.inputState();
2987
2882
  }
2988
-
2989
2883
  return;
2990
- } // modify selection
2991
-
2884
+ }
2992
2885
 
2886
+ // modify selection
2993
2887
  eventName = e && e.type.toLowerCase();
2994
-
2995
2888
  if (eventName === 'click' && isKeyDown('shiftKey', e) && self.activeItems.length) {
2996
2889
  last = self.getLastActive();
2997
2890
  begin = Array.prototype.indexOf.call(self.control.children, last);
2998
2891
  end = Array.prototype.indexOf.call(self.control.children, item);
2999
-
3000
2892
  if (begin > end) {
3001
2893
  swap = begin;
3002
2894
  begin = end;
3003
2895
  end = swap;
3004
2896
  }
3005
-
3006
2897
  for (i = begin; i <= end; i++) {
3007
2898
  item = self.control.children[i];
3008
-
3009
2899
  if (self.activeItems.indexOf(item) === -1) {
3010
2900
  self.setActiveItemClass(item);
3011
2901
  }
3012
2902
  }
3013
-
3014
2903
  preventDefault(e);
3015
2904
  } else if (eventName === 'click' && isKeyDown(KEY_SHORTCUT, e) || eventName === 'keydown' && isKeyDown('shiftKey', e)) {
3016
2905
  if (item.classList.contains('active')) {
@@ -3021,65 +2910,58 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3021
2910
  } else {
3022
2911
  self.clearActiveItems();
3023
2912
  self.setActiveItemClass(item);
3024
- } // ensure control has focus
3025
-
3026
-
3027
- self.hideInput();
2913
+ }
3028
2914
 
2915
+ // ensure control has focus
2916
+ self.inputState();
3029
2917
  if (!self.isFocused) {
3030
2918
  self.focus();
3031
2919
  }
3032
2920
  }
2921
+
3033
2922
  /**
3034
2923
  * Set the active and last-active classes
3035
2924
  *
3036
2925
  */
3037
-
3038
-
3039
2926
  setActiveItemClass(item) {
3040
2927
  const self = this;
3041
2928
  const last_active = self.control.querySelector('.last-active');
3042
2929
  if (last_active) removeClasses(last_active, 'last-active');
3043
2930
  addClasses(item, 'active last-active');
3044
2931
  self.trigger('item_select', item);
3045
-
3046
2932
  if (self.activeItems.indexOf(item) == -1) {
3047
2933
  self.activeItems.push(item);
3048
2934
  }
3049
2935
  }
2936
+
3050
2937
  /**
3051
2938
  * Remove active item
3052
2939
  *
3053
2940
  */
3054
-
3055
-
3056
2941
  removeActiveItem(item) {
3057
2942
  var idx = this.activeItems.indexOf(item);
3058
2943
  this.activeItems.splice(idx, 1);
3059
2944
  removeClasses(item, 'active');
3060
2945
  }
2946
+
3061
2947
  /**
3062
2948
  * Clears all the active items
3063
2949
  *
3064
2950
  */
3065
-
3066
-
3067
2951
  clearActiveItems() {
3068
2952
  removeClasses(this.activeItems, 'active');
3069
2953
  this.activeItems = [];
3070
2954
  }
2955
+
3071
2956
  /**
3072
2957
  * Sets the selected item in the dropdown menu
3073
2958
  * of available options.
3074
2959
  *
3075
2960
  */
3076
-
3077
-
3078
2961
  setActiveOption(option, scroll = true) {
3079
2962
  if (option === this.activeOption) {
3080
2963
  return;
3081
2964
  }
3082
-
3083
2965
  this.clearActiveOption();
3084
2966
  if (!option) return;
3085
2967
  this.activeOption = option;
@@ -3092,12 +2974,11 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3092
2974
  addClasses(option, 'active');
3093
2975
  if (scroll) this.scrollToOption(option);
3094
2976
  }
2977
+
3095
2978
  /**
3096
2979
  * Sets the dropdown_content scrollTop to display the option
3097
2980
  *
3098
2981
  */
3099
-
3100
-
3101
2982
  scrollToOption(option, behavior) {
3102
2983
  if (!option) return;
3103
2984
  const content = this.dropdown_content;
@@ -3105,35 +2986,30 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3105
2986
  const scrollTop = content.scrollTop || 0;
3106
2987
  const height_item = option.offsetHeight;
3107
2988
  const y = option.getBoundingClientRect().top - content.getBoundingClientRect().top + scrollTop;
3108
-
3109
2989
  if (y + height_item > height_menu + scrollTop) {
3110
2990
  this.scroll(y - height_menu + height_item, behavior);
3111
2991
  } else if (y < scrollTop) {
3112
2992
  this.scroll(y, behavior);
3113
2993
  }
3114
2994
  }
2995
+
3115
2996
  /**
3116
2997
  * Scroll the dropdown to the given position
3117
2998
  *
3118
2999
  */
3119
-
3120
-
3121
3000
  scroll(scrollTop, behavior) {
3122
3001
  const content = this.dropdown_content;
3123
-
3124
3002
  if (behavior) {
3125
3003
  content.style.scrollBehavior = behavior;
3126
3004
  }
3127
-
3128
3005
  content.scrollTop = scrollTop;
3129
3006
  content.style.scrollBehavior = '';
3130
3007
  }
3008
+
3131
3009
  /**
3132
3010
  * Clears the active option
3133
3011
  *
3134
3012
  */
3135
-
3136
-
3137
3013
  clearActiveOption() {
3138
3014
  if (this.activeOption) {
3139
3015
  removeClasses(this.activeOption, 'active');
@@ -3141,42 +3017,38 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3141
3017
  'aria-selected': null
3142
3018
  });
3143
3019
  }
3144
-
3145
3020
  this.activeOption = null;
3146
3021
  setAttr(this.focus_node, {
3147
3022
  'aria-activedescendant': null
3148
3023
  });
3149
3024
  }
3025
+
3150
3026
  /**
3151
3027
  * Selects all items (CTRL + A).
3152
3028
  */
3153
-
3154
-
3155
3029
  selectAll() {
3156
3030
  const self = this;
3157
3031
  if (self.settings.mode === 'single') return;
3158
3032
  const activeItems = self.controlChildren();
3159
3033
  if (!activeItems.length) return;
3160
- self.hideInput();
3034
+ self.inputState();
3161
3035
  self.close();
3162
3036
  self.activeItems = activeItems;
3163
3037
  iterate$1(activeItems, item => {
3164
3038
  self.setActiveItemClass(item);
3165
3039
  });
3166
3040
  }
3041
+
3167
3042
  /**
3168
3043
  * Determines if the control_input should be in a hidden or visible state
3169
3044
  *
3170
3045
  */
3171
-
3172
-
3173
3046
  inputState() {
3174
3047
  var self = this;
3175
3048
  if (!self.control.contains(self.control_input)) return;
3176
3049
  setAttr(self.control_input, {
3177
3050
  placeholder: self.settings.placeholder
3178
3051
  });
3179
-
3180
3052
  if (self.activeItems.length > 0 || !self.isFocused && self.settings.hidePlaceholder && self.items.length > 0) {
3181
3053
  self.setTextboxValue();
3182
3054
  self.isInputHidden = true;
@@ -3186,70 +3058,45 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3186
3058
  placeholder: ''
3187
3059
  });
3188
3060
  }
3189
-
3190
3061
  self.isInputHidden = false;
3191
3062
  }
3192
-
3193
3063
  self.wrapper.classList.toggle('input-hidden', self.isInputHidden);
3194
3064
  }
3195
- /**
3196
- * Hides the input element out of view, while
3197
- * retaining its focus.
3198
- * @deprecated 1.3
3199
- */
3200
-
3201
-
3202
- hideInput() {
3203
- this.inputState();
3204
- }
3205
- /**
3206
- * Restores input visibility.
3207
- * @deprecated 1.3
3208
- */
3209
3065
 
3210
-
3211
- showInput() {
3212
- this.inputState();
3213
- }
3214
3066
  /**
3215
3067
  * Get the input value
3216
3068
  */
3217
-
3218
-
3219
3069
  inputValue() {
3220
3070
  return this.control_input.value.trim();
3221
3071
  }
3072
+
3222
3073
  /**
3223
3074
  * Gives the control focus.
3224
3075
  */
3225
-
3226
-
3227
3076
  focus() {
3228
3077
  var self = this;
3229
- if (self.isDisabled) return;
3078
+ if (self.isDisabled || self.isReadOnly) return;
3230
3079
  self.ignoreFocus = true;
3231
-
3232
3080
  if (self.control_input.offsetWidth) {
3233
3081
  self.control_input.focus();
3234
3082
  } else {
3235
3083
  self.focus_node.focus();
3236
3084
  }
3237
-
3238
3085
  setTimeout(() => {
3239
3086
  self.ignoreFocus = false;
3240
3087
  self.onFocus();
3241
3088
  }, 0);
3242
3089
  }
3090
+
3243
3091
  /**
3244
3092
  * Forces the control out of focus.
3245
3093
  *
3246
3094
  */
3247
-
3248
-
3249
3095
  blur() {
3250
3096
  this.focus_node.blur();
3251
3097
  this.onBlur();
3252
3098
  }
3099
+
3253
3100
  /**
3254
3101
  * Returns a function that scores an object
3255
3102
  * to show how good of a match it is to the
@@ -3257,11 +3104,10 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3257
3104
  *
3258
3105
  * @return {function}
3259
3106
  */
3260
-
3261
-
3262
3107
  getScoreFunction(query) {
3263
3108
  return this.sifter.getScoreFunction(query, this.getSearchOptions());
3264
3109
  }
3110
+
3265
3111
  /**
3266
3112
  * Returns search options for sifter (the system
3267
3113
  * for scoring and sorting results).
@@ -3269,18 +3115,14 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3269
3115
  * @see https://github.com/orchidjs/sifter.js
3270
3116
  * @return {object}
3271
3117
  */
3272
-
3273
-
3274
3118
  getSearchOptions() {
3275
3119
  var settings = this.settings;
3276
3120
  var sort = settings.sortField;
3277
-
3278
3121
  if (typeof settings.sortField === 'string') {
3279
3122
  sort = [{
3280
3123
  field: settings.sortField
3281
3124
  }];
3282
3125
  }
3283
-
3284
3126
  return {
3285
3127
  fields: settings.searchField,
3286
3128
  conjunction: settings.searchConjunction,
@@ -3288,27 +3130,26 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3288
3130
  nesting: settings.nesting
3289
3131
  };
3290
3132
  }
3133
+
3291
3134
  /**
3292
3135
  * Searches through available options and returns
3293
3136
  * a sorted array of matches.
3294
3137
  *
3295
3138
  */
3296
-
3297
-
3298
3139
  search(query) {
3299
3140
  var result, calculateScore;
3300
3141
  var self = this;
3301
- var options = this.getSearchOptions(); // validate user-provided result scoring function
3142
+ var options = this.getSearchOptions();
3302
3143
 
3144
+ // validate user-provided result scoring function
3303
3145
  if (self.settings.score) {
3304
3146
  calculateScore = self.settings.score.call(self, query);
3305
-
3306
3147
  if (typeof calculateScore !== 'function') {
3307
3148
  throw new Error('Tom Select "score" setting must be a function that returns a function');
3308
3149
  }
3309
- } // perform search
3310
-
3150
+ }
3311
3151
 
3152
+ // perform search
3312
3153
  if (query !== self.lastQuery) {
3313
3154
  self.lastQuery = query;
3314
3155
  result = self.sifter.search(query, Object.assign(options, {
@@ -3317,25 +3158,23 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3317
3158
  self.currentResults = result;
3318
3159
  } else {
3319
3160
  result = Object.assign({}, self.currentResults);
3320
- } // filter out selected items
3321
-
3161
+ }
3322
3162
 
3163
+ // filter out selected items
3323
3164
  if (self.settings.hideSelected) {
3324
3165
  result.items = result.items.filter(item => {
3325
3166
  let hashed = hash_key(item.id);
3326
3167
  return !(hashed && self.items.indexOf(hashed) !== -1);
3327
3168
  });
3328
3169
  }
3329
-
3330
3170
  return result;
3331
3171
  }
3172
+
3332
3173
  /**
3333
3174
  * Refreshes the list of available options shown
3334
3175
  * in the autocomplete dropdown menu.
3335
3176
  *
3336
3177
  */
3337
-
3338
-
3339
3178
  refreshOptions(triggerDropdown = true) {
3340
3179
  var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;
3341
3180
  var create;
@@ -3348,27 +3187,42 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3348
3187
  var active_option = null;
3349
3188
  var show_dropdown = self.settings.shouldOpen || false;
3350
3189
  var dropdown_content = self.dropdown_content;
3351
-
3352
3190
  if (same_query) {
3353
3191
  active_option = self.activeOption;
3354
-
3355
3192
  if (active_option) {
3356
3193
  active_group = active_option.closest('[data-group]');
3357
3194
  }
3358
- } // build markup
3359
-
3195
+ }
3360
3196
 
3197
+ // build markup
3361
3198
  n = results.items.length;
3362
-
3363
3199
  if (typeof self.settings.maxOptions === 'number') {
3364
3200
  n = Math.min(n, self.settings.maxOptions);
3365
3201
  }
3366
-
3367
3202
  if (n > 0) {
3368
3203
  show_dropdown = true;
3369
- } // render and group available options individually
3204
+ }
3370
3205
 
3206
+ // get fragment for group and the position of the group in group_order
3207
+ const getGroupFragment = (optgroup, order) => {
3208
+ let group_order_i = groups[optgroup];
3209
+ if (group_order_i !== undefined) {
3210
+ let order_group = groups_order[group_order_i];
3211
+ if (order_group !== undefined) {
3212
+ return [group_order_i, order_group.fragment];
3213
+ }
3214
+ }
3215
+ let group_fragment = document.createDocumentFragment();
3216
+ group_order_i = groups_order.length;
3217
+ groups_order.push({
3218
+ fragment: group_fragment,
3219
+ order,
3220
+ optgroup
3221
+ });
3222
+ return [group_order_i, group_fragment];
3223
+ };
3371
3224
 
3225
+ // render and group available options individually
3372
3226
  for (i = 0; i < n; i++) {
3373
3227
  // get option dom element
3374
3228
  let item = results.items[i];
@@ -3377,30 +3231,26 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3377
3231
  let option = self.options[opt_value];
3378
3232
  if (option === undefined) continue;
3379
3233
  let opt_hash = get_hash(opt_value);
3380
- let option_el = self.getOption(opt_hash, true); // toggle 'selected' class
3234
+ let option_el = self.getOption(opt_hash, true);
3381
3235
 
3236
+ // toggle 'selected' class
3382
3237
  if (!self.settings.hideSelected) {
3383
3238
  option_el.classList.toggle('selected', self.items.includes(opt_hash));
3384
3239
  }
3385
-
3386
3240
  optgroup = option[self.settings.optgroupField] || '';
3387
3241
  optgroups = Array.isArray(optgroup) ? optgroup : [optgroup];
3388
-
3389
3242
  for (j = 0, k = optgroups && optgroups.length; j < k; j++) {
3390
3243
  optgroup = optgroups[j];
3391
-
3392
- if (!self.optgroups.hasOwnProperty(optgroup)) {
3244
+ let order = option.$order;
3245
+ let self_optgroup = self.optgroups[optgroup];
3246
+ if (self_optgroup === undefined) {
3393
3247
  optgroup = '';
3248
+ } else {
3249
+ order = self_optgroup.$order;
3394
3250
  }
3251
+ const [group_order_i, group_fragment] = getGroupFragment(optgroup, order);
3395
3252
 
3396
- let group_fragment = groups[optgroup];
3397
-
3398
- if (group_fragment === undefined) {
3399
- group_fragment = document.createDocumentFragment();
3400
- groups_order.push(optgroup);
3401
- } // nodes can only have one parent, so if the option is in mutple groups, we need a clone
3402
-
3403
-
3253
+ // nodes can only have one parent, so if the option is in mutple groups, we need a clone
3404
3254
  if (j > 0) {
3405
3255
  option_el = option_el.cloneNode(true);
3406
3256
  setAttr(option_el, {
@@ -3408,38 +3258,36 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3408
3258
  'aria-selected': null
3409
3259
  });
3410
3260
  option_el.classList.add('ts-cloned');
3411
- removeClasses(option_el, 'active'); // make sure we keep the activeOption in the same group
3261
+ removeClasses(option_el, 'active');
3412
3262
 
3263
+ // make sure we keep the activeOption in the same group
3413
3264
  if (self.activeOption && self.activeOption.dataset.value == opt_value) {
3414
3265
  if (active_group && active_group.dataset.group === optgroup.toString()) {
3415
3266
  active_option = option_el;
3416
3267
  }
3417
3268
  }
3418
3269
  }
3419
-
3420
3270
  group_fragment.appendChild(option_el);
3421
- groups[optgroup] = group_fragment;
3271
+ if (optgroup != '') {
3272
+ groups[optgroup] = group_order_i;
3273
+ }
3422
3274
  }
3423
- } // sort optgroups
3424
-
3275
+ }
3425
3276
 
3277
+ // sort optgroups
3426
3278
  if (self.settings.lockOptgroupOrder) {
3427
3279
  groups_order.sort((a, b) => {
3428
- const grp_a = self.optgroups[a];
3429
- const grp_b = self.optgroups[b];
3430
- const a_order = grp_a && grp_a.$order || 0;
3431
- const b_order = grp_b && grp_b.$order || 0;
3432
- return a_order - b_order;
3280
+ return a.order - b.order;
3433
3281
  });
3434
- } // render optgroup headers & join groups
3435
-
3282
+ }
3436
3283
 
3284
+ // render optgroup headers & join groups
3437
3285
  html = document.createDocumentFragment();
3438
- iterate$1(groups_order, optgroup => {
3439
- let group_fragment = groups[optgroup];
3286
+ iterate$1(groups_order, group_order => {
3287
+ let group_fragment = group_order.fragment;
3288
+ let optgroup = group_order.optgroup;
3440
3289
  if (!group_fragment || !group_fragment.children.length) return;
3441
3290
  let group_heading = self.optgroups[optgroup];
3442
-
3443
3291
  if (group_heading !== undefined) {
3444
3292
  let group_options = document.createDocumentFragment();
3445
3293
  let header = self.render('optgroup_header', group_heading);
@@ -3455,93 +3303,87 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3455
3303
  }
3456
3304
  });
3457
3305
  dropdown_content.innerHTML = '';
3458
- append(dropdown_content, html); // highlight matching terms inline
3306
+ append(dropdown_content, html);
3459
3307
 
3308
+ // highlight matching terms inline
3460
3309
  if (self.settings.highlight) {
3461
3310
  removeHighlight(dropdown_content);
3462
-
3463
3311
  if (results.query.length && results.tokens.length) {
3464
3312
  iterate$1(results.tokens, tok => {
3465
3313
  highlight(dropdown_content, tok.regex);
3466
3314
  });
3467
3315
  }
3468
- } // helper method for adding templates to dropdown
3469
-
3316
+ }
3470
3317
 
3318
+ // helper method for adding templates to dropdown
3471
3319
  var add_template = template => {
3472
3320
  let content = self.render(template, {
3473
3321
  input: query
3474
3322
  });
3475
-
3476
3323
  if (content) {
3477
3324
  show_dropdown = true;
3478
3325
  dropdown_content.insertBefore(content, dropdown_content.firstChild);
3479
3326
  }
3480
-
3481
3327
  return content;
3482
- }; // add loading message
3483
-
3328
+ };
3484
3329
 
3330
+ // add loading message
3485
3331
  if (self.loading) {
3486
- add_template('loading'); // invalid query
3332
+ add_template('loading');
3333
+
3334
+ // invalid query
3487
3335
  } else if (!self.settings.shouldLoad.call(self, query)) {
3488
- add_template('not_loading'); // add no_results message
3336
+ add_template('not_loading');
3337
+
3338
+ // add no_results message
3489
3339
  } else if (results.items.length === 0) {
3490
3340
  add_template('no_results');
3491
- } // add create option
3492
-
3341
+ }
3493
3342
 
3343
+ // add create option
3494
3344
  has_create_option = self.canCreate(query);
3495
-
3496
3345
  if (has_create_option) {
3497
3346
  create = add_template('option_create');
3498
- } // activate
3499
-
3347
+ }
3500
3348
 
3349
+ // activate
3501
3350
  self.hasOptions = results.items.length > 0 || has_create_option;
3502
-
3503
3351
  if (show_dropdown) {
3504
3352
  if (results.items.length > 0) {
3505
3353
  if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {
3506
3354
  active_option = self.getOption(self.items[0]);
3507
3355
  }
3508
-
3509
3356
  if (!dropdown_content.contains(active_option)) {
3510
3357
  let active_index = 0;
3511
-
3512
3358
  if (create && !self.settings.addPrecedence) {
3513
3359
  active_index = 1;
3514
3360
  }
3515
-
3516
3361
  active_option = self.selectable()[active_index];
3517
3362
  }
3518
3363
  } else if (create) {
3519
3364
  active_option = create;
3520
3365
  }
3521
-
3522
3366
  if (triggerDropdown && !self.isOpen) {
3523
3367
  self.open();
3524
3368
  self.scrollToOption(active_option, 'auto');
3525
3369
  }
3526
-
3527
3370
  self.setActiveOption(active_option);
3528
3371
  } else {
3529
3372
  self.clearActiveOption();
3530
-
3531
3373
  if (triggerDropdown && self.isOpen) {
3532
3374
  self.close(false); // if create_option=null, we want the dropdown to close but not reset the textbox value
3533
3375
  }
3534
3376
  }
3535
3377
  }
3378
+
3536
3379
  /**
3537
3380
  * Return list of selectable options
3538
3381
  *
3539
3382
  */
3540
-
3541
-
3542
3383
  selectable() {
3543
3384
  return this.dropdown_content.querySelectorAll('[data-selectable]');
3544
3385
  }
3386
+
3545
3387
  /**
3546
3388
  * Adds an available option. If it already exists,
3547
3389
  * nothing will happen. Note: this does not refresh
@@ -3553,61 +3395,52 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3553
3395
  * this.addOption(data)
3554
3396
  *
3555
3397
  */
3556
-
3557
-
3558
3398
  addOption(data, user_created = false) {
3559
- const self = this; // @deprecated 1.7.7
3560
- // use addOptions( array, user_created ) for adding multiple options
3399
+ const self = this;
3561
3400
 
3401
+ // @deprecated 1.7.7
3402
+ // use addOptions( array, user_created ) for adding multiple options
3562
3403
  if (Array.isArray(data)) {
3563
3404
  self.addOptions(data, user_created);
3564
3405
  return false;
3565
3406
  }
3566
-
3567
3407
  const key = hash_key(data[self.settings.valueField]);
3568
-
3569
3408
  if (key === null || self.options.hasOwnProperty(key)) {
3570
3409
  return false;
3571
3410
  }
3572
-
3573
3411
  data.$order = data.$order || ++self.order;
3574
3412
  data.$id = self.inputId + '-opt-' + data.$order;
3575
3413
  self.options[key] = data;
3576
3414
  self.lastQuery = null;
3577
-
3578
3415
  if (user_created) {
3579
3416
  self.userOptions[key] = user_created;
3580
3417
  self.trigger('option_add', key, data);
3581
3418
  }
3582
-
3583
3419
  return key;
3584
3420
  }
3421
+
3585
3422
  /**
3586
3423
  * Add multiple options
3587
3424
  *
3588
3425
  */
3589
-
3590
-
3591
3426
  addOptions(data, user_created = false) {
3592
3427
  iterate$1(data, dat => {
3593
3428
  this.addOption(dat, user_created);
3594
3429
  });
3595
3430
  }
3431
+
3596
3432
  /**
3597
3433
  * @deprecated 1.7.7
3598
3434
  */
3599
-
3600
-
3601
3435
  registerOption(data) {
3602
3436
  return this.addOption(data);
3603
3437
  }
3438
+
3604
3439
  /**
3605
3440
  * Registers an option group to the pool of option groups.
3606
3441
  *
3607
3442
  * @return {boolean|string}
3608
3443
  */
3609
-
3610
-
3611
3444
  registerOptionGroup(data) {
3612
3445
  var key = hash_key(data[this.settings.optgroupValueField]);
3613
3446
  if (key === null) return false;
@@ -3615,27 +3448,24 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3615
3448
  this.optgroups[key] = data;
3616
3449
  return key;
3617
3450
  }
3451
+
3618
3452
  /**
3619
3453
  * Registers a new optgroup for options
3620
3454
  * to be bucketed into.
3621
3455
  *
3622
3456
  */
3623
-
3624
-
3625
3457
  addOptionGroup(id, data) {
3626
3458
  var hashed_id;
3627
3459
  data[this.settings.optgroupValueField] = id;
3628
-
3629
3460
  if (hashed_id = this.registerOptionGroup(data)) {
3630
3461
  this.trigger('optgroup_add', hashed_id, data);
3631
3462
  }
3632
3463
  }
3464
+
3633
3465
  /**
3634
3466
  * Removes an existing option group.
3635
3467
  *
3636
3468
  */
3637
-
3638
-
3639
3469
  removeOptionGroup(id) {
3640
3470
  if (this.optgroups.hasOwnProperty(id)) {
3641
3471
  delete this.optgroups[id];
@@ -3643,31 +3473,30 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3643
3473
  this.trigger('optgroup_remove', id);
3644
3474
  }
3645
3475
  }
3476
+
3646
3477
  /**
3647
3478
  * Clears all existing option groups.
3648
3479
  */
3649
-
3650
-
3651
3480
  clearOptionGroups() {
3652
3481
  this.optgroups = {};
3653
3482
  this.clearCache();
3654
3483
  this.trigger('optgroup_clear');
3655
3484
  }
3485
+
3656
3486
  /**
3657
3487
  * Updates an option available for selection. If
3658
3488
  * it is visible in the selected items or options
3659
3489
  * dropdown, it will be re-rendered automatically.
3660
3490
  *
3661
3491
  */
3662
-
3663
-
3664
3492
  updateOption(value, data) {
3665
3493
  const self = this;
3666
3494
  var item_new;
3667
3495
  var index_item;
3668
3496
  const value_old = hash_key(value);
3669
- const value_new = hash_key(data[self.settings.valueField]); // sanity checks
3497
+ const value_new = hash_key(data[self.settings.valueField]);
3670
3498
 
3499
+ // sanity checks
3671
3500
  if (value_old === null) return;
3672
3501
  const data_old = self.options[value_old];
3673
3502
  if (data_old == undefined) return;
@@ -3675,48 +3504,44 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3675
3504
  const option = self.getOption(value_old);
3676
3505
  const item = self.getItem(value_old);
3677
3506
  data.$order = data.$order || data_old.$order;
3678
- delete self.options[value_old]; // invalidate render cache
3679
- // don't remove existing node yet, we'll remove it after replacing it
3507
+ delete self.options[value_old];
3680
3508
 
3509
+ // invalidate render cache
3510
+ // don't remove existing node yet, we'll remove it after replacing it
3681
3511
  self.uncacheValue(value_new);
3682
- self.options[value_new] = data; // update the option if it's in the dropdown
3512
+ self.options[value_new] = data;
3683
3513
 
3514
+ // update the option if it's in the dropdown
3684
3515
  if (option) {
3685
3516
  if (self.dropdown_content.contains(option)) {
3686
3517
  const option_new = self._render('option', data);
3687
-
3688
3518
  replaceNode(option, option_new);
3689
-
3690
3519
  if (self.activeOption === option) {
3691
3520
  self.setActiveOption(option_new);
3692
3521
  }
3693
3522
  }
3694
-
3695
3523
  option.remove();
3696
- } // update the item if we have one
3697
-
3524
+ }
3698
3525
 
3526
+ // update the item if we have one
3699
3527
  if (item) {
3700
3528
  index_item = self.items.indexOf(value_old);
3701
-
3702
3529
  if (index_item !== -1) {
3703
3530
  self.items.splice(index_item, 1, value_new);
3704
3531
  }
3705
-
3706
3532
  item_new = self._render('item', data);
3707
3533
  if (item.classList.contains('active')) addClasses(item_new, 'active');
3708
3534
  replaceNode(item, item_new);
3709
- } // invalidate last query because we might have updated the sortField
3710
-
3535
+ }
3711
3536
 
3537
+ // invalidate last query because we might have updated the sortField
3712
3538
  self.lastQuery = null;
3713
3539
  }
3540
+
3714
3541
  /**
3715
3542
  * Removes a single option.
3716
3543
  *
3717
3544
  */
3718
-
3719
-
3720
3545
  removeOption(value, silent) {
3721
3546
  const self = this;
3722
3547
  value = get_hash(value);
@@ -3727,11 +3552,10 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3727
3552
  self.trigger('option_remove', value);
3728
3553
  self.removeItem(value, silent);
3729
3554
  }
3555
+
3730
3556
  /**
3731
3557
  * Clears all options.
3732
3558
  */
3733
-
3734
-
3735
3559
  clearOptions(filter) {
3736
3560
  const boundFilter = (filter || this.clearFilter).bind(this);
3737
3561
  this.loadedSearches = {};
@@ -3747,101 +3571,85 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3747
3571
  this.lastQuery = null;
3748
3572
  this.trigger('option_clear');
3749
3573
  }
3574
+
3750
3575
  /**
3751
3576
  * Used by clearOptions() to decide whether or not an option should be removed
3752
3577
  * Return true to keep an option, false to remove
3753
3578
  *
3754
3579
  */
3755
-
3756
-
3757
3580
  clearFilter(option, value) {
3758
3581
  if (this.items.indexOf(value) >= 0) {
3759
3582
  return true;
3760
3583
  }
3761
-
3762
3584
  return false;
3763
3585
  }
3586
+
3764
3587
  /**
3765
3588
  * Returns the dom element of the option
3766
3589
  * matching the given value.
3767
3590
  *
3768
3591
  */
3769
-
3770
-
3771
3592
  getOption(value, create = false) {
3772
3593
  const hashed = hash_key(value);
3773
3594
  if (hashed === null) return null;
3774
3595
  const option = this.options[hashed];
3775
-
3776
3596
  if (option != undefined) {
3777
3597
  if (option.$div) {
3778
3598
  return option.$div;
3779
3599
  }
3780
-
3781
3600
  if (create) {
3782
3601
  return this._render('option', option);
3783
3602
  }
3784
3603
  }
3785
-
3786
3604
  return null;
3787
3605
  }
3606
+
3788
3607
  /**
3789
3608
  * Returns the dom element of the next or previous dom element of the same type
3790
3609
  * Note: adjacent options may not be adjacent DOM elements (optgroups)
3791
3610
  *
3792
3611
  */
3793
-
3794
-
3795
3612
  getAdjacent(option, direction, type = 'option') {
3796
3613
  var self = this,
3797
- all;
3798
-
3614
+ all;
3799
3615
  if (!option) {
3800
3616
  return null;
3801
3617
  }
3802
-
3803
3618
  if (type == 'item') {
3804
3619
  all = self.controlChildren();
3805
3620
  } else {
3806
3621
  all = self.dropdown_content.querySelectorAll('[data-selectable]');
3807
3622
  }
3808
-
3809
3623
  for (let i = 0; i < all.length; i++) {
3810
3624
  if (all[i] != option) {
3811
3625
  continue;
3812
3626
  }
3813
-
3814
3627
  if (direction > 0) {
3815
3628
  return all[i + 1];
3816
3629
  }
3817
-
3818
3630
  return all[i - 1];
3819
3631
  }
3820
-
3821
3632
  return null;
3822
3633
  }
3634
+
3823
3635
  /**
3824
3636
  * Returns the dom element of the item
3825
3637
  * matching the given value.
3826
3638
  *
3827
3639
  */
3828
-
3829
-
3830
3640
  getItem(item) {
3831
3641
  if (typeof item == 'object') {
3832
3642
  return item;
3833
3643
  }
3834
-
3835
3644
  var value = hash_key(item);
3836
3645
  return value !== null ? this.control.querySelector(`[data-value="${addSlashes(value)}"]`) : null;
3837
3646
  }
3647
+
3838
3648
  /**
3839
3649
  * "Selects" multiple items at once. Adds them to the list
3840
3650
  * at the current caret position.
3841
3651
  *
3842
3652
  */
3843
-
3844
-
3845
3653
  addItems(values, silent) {
3846
3654
  var self = this;
3847
3655
  var items = Array.isArray(values) ? values : [values];
@@ -3852,13 +3660,12 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3852
3660
  self.addItem(item, silent);
3853
3661
  });
3854
3662
  }
3663
+
3855
3664
  /**
3856
3665
  * "Selects" an item. Adds it to the list
3857
3666
  * at the current caret position.
3858
3667
  *
3859
3668
  */
3860
-
3861
-
3862
3669
  addItem(value, silent) {
3863
3670
  var events = silent ? [] : ['change', 'dropdown_close'];
3864
3671
  debounce_events(this, events, () => {
@@ -3866,77 +3673,66 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3866
3673
  const self = this;
3867
3674
  const inputMode = self.settings.mode;
3868
3675
  const hashed = hash_key(value);
3869
-
3870
3676
  if (hashed && self.items.indexOf(hashed) !== -1) {
3871
3677
  if (inputMode === 'single') {
3872
3678
  self.close();
3873
3679
  }
3874
-
3875
3680
  if (inputMode === 'single' || !self.settings.duplicates) {
3876
3681
  return;
3877
3682
  }
3878
3683
  }
3879
-
3880
3684
  if (hashed === null || !self.options.hasOwnProperty(hashed)) return;
3881
3685
  if (inputMode === 'single') self.clear(silent);
3882
3686
  if (inputMode === 'multi' && self.isFull()) return;
3883
3687
  item = self._render('item', self.options[hashed]);
3884
-
3885
3688
  if (self.control.contains(item)) {
3886
3689
  // duplicates
3887
3690
  item = item.cloneNode(true);
3888
3691
  }
3889
-
3890
3692
  wasFull = self.isFull();
3891
3693
  self.items.splice(self.caretPos, 0, hashed);
3892
3694
  self.insertAtCaret(item);
3893
-
3894
3695
  if (self.isSetup) {
3895
3696
  // update menu / remove the option (if this is not one item being added as part of series)
3896
3697
  if (!self.isPending && self.settings.hideSelected) {
3897
3698
  let option = self.getOption(hashed);
3898
3699
  let next = self.getAdjacent(option, 1);
3899
-
3900
3700
  if (next) {
3901
3701
  self.setActiveOption(next);
3902
3702
  }
3903
- } // refreshOptions after setActiveOption(),
3904
- // otherwise setActiveOption() will be called by refreshOptions() with the wrong value
3905
-
3703
+ }
3906
3704
 
3705
+ // refreshOptions after setActiveOption(),
3706
+ // otherwise setActiveOption() will be called by refreshOptions() with the wrong value
3907
3707
  if (!self.isPending && !self.settings.closeAfterSelect) {
3908
3708
  self.refreshOptions(self.isFocused && inputMode !== 'single');
3909
- } // hide the menu if the maximum number of items have been selected or no options are left
3910
-
3709
+ }
3911
3710
 
3711
+ // hide the menu if the maximum number of items have been selected or no options are left
3912
3712
  if (self.settings.closeAfterSelect != false && self.isFull()) {
3913
3713
  self.close();
3914
3714
  } else if (!self.isPending) {
3915
3715
  self.positionDropdown();
3916
3716
  }
3917
-
3918
3717
  self.trigger('item_add', hashed, item);
3919
-
3920
3718
  if (!self.isPending) {
3921
3719
  self.updateOriginalInput({
3922
3720
  silent: silent
3923
3721
  });
3924
3722
  }
3925
3723
  }
3926
-
3927
3724
  if (!self.isPending || !wasFull && self.isFull()) {
3928
3725
  self.inputState();
3929
3726
  self.refreshState();
3930
3727
  }
3931
3728
  });
3932
3729
  }
3730
+
3933
3731
  /**
3934
3732
  * Removes the selected item matching
3935
3733
  * the provided value.
3936
3734
  *
3937
3735
  */
3938
-
3939
-
3940
3736
  removeItem(item = null, silent) {
3941
3737
  const self = this;
3942
3738
  item = self.getItem(item);
@@ -3945,24 +3741,19 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3945
3741
  const value = item.dataset.value;
3946
3742
  i = nodeIndex(item);
3947
3743
  item.remove();
3948
-
3949
3744
  if (item.classList.contains('active')) {
3950
3745
  idx = self.activeItems.indexOf(item);
3951
3746
  self.activeItems.splice(idx, 1);
3952
3747
  removeClasses(item, 'active');
3953
3748
  }
3954
-
3955
3749
  self.items.splice(i, 1);
3956
3750
  self.lastQuery = null;
3957
-
3958
3751
  if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
3959
3752
  self.removeOption(value, silent);
3960
3753
  }
3961
-
3962
3754
  if (i < self.caretPos) {
3963
3755
  self.setCaret(self.caretPos - 1);
3964
3756
  }
3965
-
3966
3757
  self.updateOriginalInput({
3967
3758
  silent: silent
3968
3759
  });
@@ -3970,6 +3761,7 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3970
3761
  self.positionDropdown();
3971
3762
  self.trigger('item_remove', value, item);
3972
3763
  }
3764
+
3973
3765
  /**
3974
3766
  * Invokes the `create` method provided in the
3975
3767
  * TomSelect options that should provide the data
@@ -3979,40 +3771,31 @@ class TomSelect extends MicroPlugin(MicroEvent) {
3979
3771
  * to the item list.
3980
3772
  *
3981
3773
  */
3982
-
3983
-
3984
3774
  createItem(input = null, callback = () => {}) {
3985
3775
  // triggerDropdown parameter @deprecated 2.1.1
3986
3776
  if (arguments.length === 3) {
3987
3777
  callback = arguments[2];
3988
3778
  }
3989
-
3990
3779
  if (typeof callback != 'function') {
3991
3780
  callback = () => {};
3992
3781
  }
3993
-
3994
3782
  var self = this;
3995
3783
  var caret = self.caretPos;
3996
3784
  var output;
3997
3785
  input = input || self.inputValue();
3998
-
3999
3786
  if (!self.canCreate(input)) {
4000
3787
  callback();
4001
3788
  return false;
4002
3789
  }
4003
-
4004
3790
  self.lock();
4005
3791
  var created = false;
4006
-
4007
3792
  var create = data => {
4008
3793
  self.unlock();
4009
3794
  if (!data || typeof data !== 'object') return callback();
4010
3795
  var value = hash_key(data[self.settings.valueField]);
4011
-
4012
3796
  if (typeof value !== 'string') {
4013
3797
  return callback();
4014
3798
  }
4015
-
4016
3799
  self.setTextboxValue();
4017
3800
  self.addOption(data, true);
4018
3801
  self.setCaret(caret);
@@ -4020,7 +3803,6 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4020
3803
  callback(data);
4021
3804
  created = true;
4022
3805
  };
4023
-
4024
3806
  if (typeof self.settings.create === 'function') {
4025
3807
  output = self.settings.create.call(this, input, create);
4026
3808
  } else {
@@ -4029,35 +3811,29 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4029
3811
  [self.settings.valueField]: input
4030
3812
  };
4031
3813
  }
4032
-
4033
3814
  if (!created) {
4034
3815
  create(output);
4035
3816
  }
4036
-
4037
3817
  return true;
4038
3818
  }
3819
+
4039
3820
  /**
4040
3821
  * Re-renders the selected item lists.
4041
3822
  */
4042
-
4043
-
4044
3823
  refreshItems() {
4045
3824
  var self = this;
4046
3825
  self.lastQuery = null;
4047
-
4048
3826
  if (self.isSetup) {
4049
3827
  self.addItems(self.items);
4050
3828
  }
4051
-
4052
3829
  self.updateOriginalInput();
4053
3830
  self.refreshState();
4054
3831
  }
3832
+
4055
3833
  /**
4056
3834
  * Updates all state-dependent attributes
4057
3835
  * and CSS classes.
4058
3836
  */
4059
-
4060
-
4061
3837
  refreshState() {
4062
3838
  const self = this;
4063
3839
  self.refreshValidityState();
@@ -4067,6 +3843,7 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4067
3843
  const wrap_classList = self.wrapper.classList;
4068
3844
  wrap_classList.toggle('focus', self.isFocused);
4069
3845
  wrap_classList.toggle('disabled', self.isDisabled);
3846
+ wrap_classList.toggle('readonly', self.isReadOnly);
4070
3847
  wrap_classList.toggle('required', self.isRequired);
4071
3848
  wrap_classList.toggle('invalid', !self.isValid);
4072
3849
  wrap_classList.toggle('locked', isLocked);
@@ -4076,6 +3853,7 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4076
3853
  wrap_classList.toggle('has-options', isEmptyObject(self.options));
4077
3854
  wrap_classList.toggle('has-items', self.items.length > 0);
4078
3855
  }
3856
+
4079
3857
  /**
4080
3858
  * Update the `required` attribute of both input and control input.
4081
3859
  *
@@ -4084,78 +3862,71 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4084
3862
  * needs to be temporarily deactivated on the input since the input is
4085
3863
  * hidden and can't show errors.
4086
3864
  */
4087
-
4088
-
4089
3865
  refreshValidityState() {
4090
3866
  var self = this;
4091
-
4092
3867
  if (!self.input.validity) {
4093
3868
  return;
4094
3869
  }
4095
-
4096
3870
  self.isValid = self.input.validity.valid;
4097
3871
  self.isInvalid = !self.isValid;
4098
3872
  }
3873
+
4099
3874
  /**
4100
3875
  * Determines whether or not more items can be added
4101
3876
  * to the control without exceeding the user-defined maximum.
4102
3877
  *
4103
3878
  * @returns {boolean}
4104
3879
  */
4105
-
4106
-
4107
3880
  isFull() {
4108
3881
  return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;
4109
3882
  }
3883
+
4110
3884
  /**
4111
3885
  * Refreshes the original <select> or <input>
4112
3886
  * element to reflect the current state.
4113
3887
  *
4114
3888
  */
4115
-
4116
-
4117
3889
  updateOriginalInput(opts = {}) {
4118
3890
  const self = this;
4119
3891
  var option, label;
4120
3892
  const empty_option = self.input.querySelector('option[value=""]');
4121
-
4122
3893
  if (self.is_select_tag) {
4123
3894
  const selected = [];
4124
3895
  const has_selected = self.input.querySelectorAll('option:checked').length;
4125
-
4126
3896
  function AddSelected(option_el, value, label) {
4127
3897
  if (!option_el) {
4128
3898
  option_el = getDom('<option value="' + escape_html(value) + '">' + escape_html(label) + '</option>');
4129
- } // don't move empty option from top of list
4130
- // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293
4131
-
3899
+ }
4132
3900
 
3901
+ // don't move empty option from top of list
3902
+ // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293
4133
3903
  if (option_el != empty_option) {
4134
3904
  self.input.append(option_el);
4135
3905
  }
3906
+ selected.push(option_el);
4136
3907
 
4137
- selected.push(option_el); // marking empty option as selected can break validation
3908
+ // marking empty option as selected can break validation
4138
3909
  // fixes https://github.com/orchidjs/tom-select/issues/303
4139
-
4140
3910
  if (option_el != empty_option || has_selected > 0) {
4141
3911
  option_el.selected = true;
4142
3912
  }
4143
-
4144
3913
  return option_el;
4145
- } // unselect all selected options
4146
-
3914
+ }
4147
3915
 
3916
+ // unselect all selected options
4148
3917
  self.input.querySelectorAll('option:checked').forEach(option_el => {
4149
3918
  option_el.selected = false;
4150
- }); // nothing selected?
3919
+ });
4151
3920
 
3921
+ // nothing selected?
4152
3922
  if (self.items.length == 0 && self.settings.mode == 'single') {
4153
- AddSelected(empty_option, "", ""); // order selected <option> tags for values in self.items
3923
+ AddSelected(empty_option, "", "");
3924
+
3925
+ // order selected <option> tags for values in self.items
4154
3926
  } else {
4155
3927
  self.items.forEach(value => {
4156
3928
  option = self.options[value];
4157
3929
  label = option[self.settings.labelField] || '';
4158
-
4159
3930
  if (selected.includes(option.$option)) {
4160
3931
  const reuse_opt = self.input.querySelector(`option[value="${addSlashes(value)}"]:not(:checked)`);
4161
3932
  AddSelected(reuse_opt, value, label);
@@ -4167,19 +3938,17 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4167
3938
  } else {
4168
3939
  self.input.value = self.getValue();
4169
3940
  }
4170
-
4171
3941
  if (self.isSetup) {
4172
3942
  if (!opts.silent) {
4173
3943
  self.trigger('change', self.getValue());
4174
3944
  }
4175
3945
  }
4176
3946
  }
3947
+
4177
3948
  /**
4178
3949
  * Shows the autocomplete dropdown containing
4179
3950
  * the available options.
4180
3951
  */
4181
-
4182
-
4183
3952
  open() {
4184
3953
  var self = this;
4185
3954
  if (self.isLocked || self.isOpen || self.settings.mode === 'multi' && self.isFull()) return;
@@ -4200,24 +3969,20 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4200
3969
  self.focus();
4201
3970
  self.trigger('dropdown_open', self.dropdown);
4202
3971
  }
3972
+
4203
3973
  /**
4204
3974
  * Closes the autocomplete dropdown menu.
4205
3975
  */
4206
-
4207
-
4208
3976
  close(setTextboxValue = true) {
4209
3977
  var self = this;
4210
3978
  var trigger = self.isOpen;
4211
-
4212
3979
  if (setTextboxValue) {
4213
3980
  // before blur() to prevent form onchange event
4214
3981
  self.setTextboxValue();
4215
-
4216
3982
  if (self.settings.mode === 'single' && self.items.length) {
4217
- self.hideInput();
3983
+ self.inputState();
4218
3984
  }
4219
3985
  }
4220
-
4221
3986
  self.isOpen = false;
4222
3987
  setAttr(self.focus_node, {
4223
3988
  'aria-expanded': 'false'
@@ -4225,26 +3990,22 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4225
3990
  applyCSS(self.dropdown, {
4226
3991
  display: 'none'
4227
3992
  });
4228
-
4229
3993
  if (self.settings.hideSelected) {
4230
3994
  self.clearActiveOption();
4231
3995
  }
4232
-
4233
3996
  self.refreshState();
4234
3997
  if (trigger) self.trigger('dropdown_close', self.dropdown);
4235
3998
  }
3999
+
4236
4000
  /**
4237
4001
  * Calculates and applies the appropriate
4238
4002
  * position of the dropdown if dropdownParent = 'body'.
4239
4003
  * Otherwise, position is determined by css
4240
4004
  */
4241
-
4242
-
4243
4005
  positionDropdown() {
4244
4006
  if (this.settings.dropdownParent !== 'body') {
4245
4007
  return;
4246
4008
  }
4247
-
4248
4009
  var context = this.control;
4249
4010
  var rect = context.getBoundingClientRect();
4250
4011
  var top = context.offsetHeight + rect.top + window.scrollY;
@@ -4255,13 +4016,12 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4255
4016
  left: left + 'px'
4256
4017
  });
4257
4018
  }
4019
+
4258
4020
  /**
4259
4021
  * Resets / clears all selected items
4260
4022
  * from the control.
4261
4023
  *
4262
4024
  */
4263
-
4264
-
4265
4025
  clear(silent) {
4266
4026
  var self = this;
4267
4027
  if (!self.items.length) return;
@@ -4269,17 +4029,16 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4269
4029
  iterate$1(items, item => {
4270
4030
  self.removeItem(item, true);
4271
4031
  });
4272
- self.showInput();
4032
+ self.inputState();
4273
4033
  if (!silent) self.updateOriginalInput();
4274
4034
  self.trigger('clear');
4275
4035
  }
4036
+
4276
4037
  /**
4277
4038
  * A helper method for inserting an element
4278
4039
  * at the current caret position.
4279
4040
  *
4280
4041
  */
4281
-
4282
-
4283
4042
  insertAtCaret(el) {
4284
4043
  const self = this;
4285
4044
  const caret = self.caretPos;
@@ -4287,77 +4046,69 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4287
4046
  target.insertBefore(el, target.children[caret] || null);
4288
4047
  self.setCaret(caret + 1);
4289
4048
  }
4049
+
4290
4050
  /**
4291
4051
  * Removes the current selected item(s).
4292
4052
  *
4293
4053
  */
4294
-
4295
-
4296
4054
  deleteSelection(e) {
4297
4055
  var direction, selection, caret, tail;
4298
4056
  var self = this;
4299
4057
  direction = e && e.keyCode === KEY_BACKSPACE ? -1 : 1;
4300
- selection = getSelection(self.control_input); // determine items that will be removed
4058
+ selection = getSelection(self.control_input);
4301
4059
 
4060
+ // determine items that will be removed
4302
4061
  const rm_items = [];
4303
-
4304
4062
  if (self.activeItems.length) {
4305
4063
  tail = getTail(self.activeItems, direction);
4306
4064
  caret = nodeIndex(tail);
4307
-
4308
4065
  if (direction > 0) {
4309
4066
  caret++;
4310
4067
  }
4311
-
4312
4068
  iterate$1(self.activeItems, item => rm_items.push(item));
4313
4069
  } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
4314
4070
  const items = self.controlChildren();
4315
4071
  let rm_item;
4316
-
4317
4072
  if (direction < 0 && selection.start === 0 && selection.length === 0) {
4318
4073
  rm_item = items[self.caretPos - 1];
4319
4074
  } else if (direction > 0 && selection.start === self.inputValue().length) {
4320
4075
  rm_item = items[self.caretPos];
4321
4076
  }
4322
-
4323
4077
  if (rm_item !== undefined) {
4324
4078
  rm_items.push(rm_item);
4325
4079
  }
4326
4080
  }
4327
-
4328
4081
  if (!self.shouldDelete(rm_items, e)) {
4329
4082
  return false;
4330
4083
  }
4084
+ preventDefault(e, true);
4331
4085
 
4332
- preventDefault(e, true); // perform removal
4333
-
4086
+ // perform removal
4334
4087
  if (typeof caret !== 'undefined') {
4335
4088
  self.setCaret(caret);
4336
4089
  }
4337
-
4338
4090
  while (rm_items.length) {
4339
4091
  self.removeItem(rm_items.pop());
4340
4092
  }
4341
-
4342
- self.showInput();
4093
+ self.inputState();
4343
4094
  self.positionDropdown();
4344
4095
  self.refreshOptions(false);
4345
4096
  return true;
4346
4097
  }
4098
+
4347
4099
  /**
4348
4100
  * Return true if the items should be deleted
4349
4101
  */
4350
-
4351
-
4352
4102
  shouldDelete(items, evt) {
4353
- const values = items.map(item => item.dataset.value); // allow the callback to abort
4103
+ const values = items.map(item => item.dataset.value);
4354
4104
 
4105
+ // allow the callback to abort
4355
4106
  if (!values.length || typeof this.settings.onDelete === 'function' && this.settings.onDelete(values, evt) === false) {
4356
4107
  return false;
4357
4108
  }
4358
-
4359
4109
  return true;
4360
4110
  }
4111
+
4361
4112
  /**
4362
4113
  * Selects the previous / next item (depending on the `direction` argument).
4363
4114
  *
@@ -4365,64 +4116,58 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4365
4116
  * < 0 - left
4366
4117
  *
4367
4118
  */
4368
-
4369
-
4370
4119
  advanceSelection(direction, e) {
4371
4120
  var last_active,
4372
- adjacent,
4373
- self = this;
4121
+ adjacent,
4122
+ self = this;
4374
4123
  if (self.rtl) direction *= -1;
4375
- if (self.inputValue().length) return; // add or remove to active items
4124
+ if (self.inputValue().length) return;
4376
4125
 
4126
+ // add or remove to active items
4377
4127
  if (isKeyDown(KEY_SHORTCUT, e) || isKeyDown('shiftKey', e)) {
4378
4128
  last_active = self.getLastActive(direction);
4379
-
4380
4129
  if (last_active) {
4381
4130
  if (!last_active.classList.contains('active')) {
4382
4131
  adjacent = last_active;
4383
4132
  } else {
4384
4133
  adjacent = self.getAdjacent(last_active, direction, 'item');
4385
- } // if no active item, get items adjacent to the control input
4134
+ }
4386
4135
 
4136
+ // if no active item, get items adjacent to the control input
4387
4137
  } else if (direction > 0) {
4388
4138
  adjacent = self.control_input.nextElementSibling;
4389
4139
  } else {
4390
4140
  adjacent = self.control_input.previousElementSibling;
4391
4141
  }
4392
-
4393
4142
  if (adjacent) {
4394
4143
  if (adjacent.classList.contains('active')) {
4395
4144
  self.removeActiveItem(last_active);
4396
4145
  }
4397
-
4398
4146
  self.setActiveItemClass(adjacent); // mark as last_active !! after removeActiveItem() on last_active
4399
- } // move caret to the left or right
4147
+ }
4400
4148
 
4149
+ // move caret to the left or right
4401
4150
  } else {
4402
4151
  self.moveCaret(direction);
4403
4152
  }
4404
4153
  }
4405
-
4406
4154
  moveCaret(direction) {}
4155
+
4407
4156
  /**
4408
4157
  * Get the last active item
4409
4158
  *
4410
4159
  */
4411
-
4412
-
4413
4160
  getLastActive(direction) {
4414
4161
  let last_active = this.control.querySelector('.last-active');
4415
-
4416
4162
  if (last_active) {
4417
4163
  return last_active;
4418
4164
  }
4419
-
4420
4165
  var result = this.control.querySelectorAll('.active');
4421
-
4422
4166
  if (result) {
4423
4167
  return getTail(result, direction);
4424
4168
  }
4425
4169
  }
4170
+
4426
4171
  /**
4427
4172
  * Moves the caret to the specified index.
4428
4173
  *
@@ -4431,75 +4176,76 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4431
4176
  * on mobile webkit devices
4432
4177
  *
4433
4178
  */
4434
-
4435
-
4436
4179
  setCaret(new_pos) {
4437
4180
  this.caretPos = this.items.length;
4438
4181
  }
4182
+
4439
4183
  /**
4440
4184
  * Return list of item dom elements
4441
4185
  *
4442
4186
  */
4443
-
4444
-
4445
4187
  controlChildren() {
4446
4188
  return Array.from(this.control.querySelectorAll('[data-ts-item]'));
4447
4189
  }
4190
+
4448
4191
  /**
4449
4192
  * Disables user input on the control. Used while
4450
4193
  * items are being asynchronously created.
4451
4194
  */
4452
-
4453
-
4454
4195
  lock() {
4455
- this.isLocked = true;
4456
- this.refreshState();
4196
+ this.setLocked(true);
4457
4197
  }
4198
+
4458
4199
  /**
4459
4200
  * Re-enables user input on the control.
4460
4201
  */
4461
-
4462
-
4463
4202
  unlock() {
4464
- this.isLocked = false;
4203
+ this.setLocked(false);
4204
+ }
4205
+
4206
+ /**
4207
+ * Disable or enable user input on the control
4208
+ */
4209
+ setLocked(lock = this.isReadOnly || this.isDisabled) {
4210
+ this.isLocked = lock;
4465
4211
  this.refreshState();
4466
4212
  }
4213
+
4467
4214
  /**
4468
4215
  * Disables user input on the control completely.
4469
4216
  * While disabled, it cannot receive focus.
4470
4217
  */
4471
-
4472
-
4473
4218
  disable() {
4474
- var self = this;
4475
- self.input.disabled = true;
4476
- self.control_input.disabled = true;
4477
- self.focus_node.tabIndex = -1;
4478
- self.isDisabled = true;
4219
+ this.setDisabled(true);
4479
4220
  this.close();
4480
- self.lock();
4481
4221
  }
4222
+
4482
4223
  /**
4483
4224
  * Enables the control so that it can respond
4484
4225
  * to focus and user input.
4485
4226
  */
4486
-
4487
-
4488
4227
  enable() {
4489
- var self = this;
4490
- self.input.disabled = false;
4491
- self.control_input.disabled = false;
4492
- self.focus_node.tabIndex = self.tabIndex;
4493
- self.isDisabled = false;
4494
- self.unlock();
4228
+ this.setDisabled(false);
4495
4229
  }
4230
+ setDisabled(disabled) {
4231
+ this.focus_node.tabIndex = disabled ? -1 : this.tabIndex;
4232
+ this.isDisabled = disabled;
4233
+ this.input.disabled = disabled;
4234
+ this.control_input.disabled = disabled;
4235
+ this.setLocked();
4236
+ }
4237
+ setReadOnly(isReadOnly) {
4238
+ this.isReadOnly = isReadOnly;
4239
+ this.input.readOnly = isReadOnly;
4240
+ this.control_input.readOnly = isReadOnly;
4241
+ this.setLocked();
4242
+ }
4243
+
4496
4244
  /**
4497
4245
  * Completely destroys the control and
4498
4246
  * unbinds all event listeners so that it can
4499
4247
  * be garbage collected.
4500
4248
  */
4501
-
4502
-
4503
4249
  destroy() {
4504
4250
  var self = this;
4505
4251
  var revertSettings = self.revertSettings;
@@ -4510,35 +4256,30 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4510
4256
  self.input.innerHTML = revertSettings.innerHTML;
4511
4257
  self.input.tabIndex = revertSettings.tabIndex;
4512
4258
  removeClasses(self.input, 'tomselected', 'ts-hidden-accessible');
4513
-
4514
4259
  self._destroy();
4515
-
4516
4260
  delete self.input.tomselect;
4517
4261
  }
4262
+
4518
4263
  /**
4519
4264
  * A helper method for rendering "item" and
4520
4265
  * "option" templates, given the data.
4521
4266
  *
4522
4267
  */
4523
-
4524
-
4525
4268
  render(templateName, data) {
4526
4269
  var id, html;
4527
4270
  const self = this;
4528
-
4529
4271
  if (typeof this.settings.render[templateName] !== 'function') {
4530
4272
  return null;
4531
- } // render markup
4532
-
4273
+ }
4533
4274
 
4275
+ // render markup
4534
4276
  html = self.settings.render[templateName].call(this, data, escape_html);
4535
-
4536
4277
  if (!html) {
4537
4278
  return null;
4538
4279
  }
4280
+ html = getDom(html);
4539
4281
 
4540
- html = getDom(html); // add mandatory attributes
4541
-
4282
+ // add mandatory attributes
4542
4283
  if (templateName === 'option' || templateName === 'option_create') {
4543
4284
  if (data[self.settings.disabledField]) {
4544
4285
  setAttr(html, {
@@ -4554,20 +4295,19 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4554
4295
  setAttr(html, {
4555
4296
  'data-group': id
4556
4297
  });
4557
-
4558
4298
  if (data.group[self.settings.disabledField]) {
4559
4299
  setAttr(html, {
4560
4300
  'data-disabled': ''
4561
4301
  });
4562
4302
  }
4563
4303
  }
4564
-
4565
4304
  if (templateName === 'option' || templateName === 'item') {
4566
4305
  const value = get_hash(data[self.settings.valueField]);
4567
4306
  setAttr(html, {
4568
4307
  'data-value': value
4569
- }); // make sure we have some classes if a template is overwritten
4308
+ });
4570
4309
 
4310
+ // make sure we have some classes if a template is overwritten
4571
4311
  if (templateName === 'item') {
4572
4312
  addClasses(html, self.settings.itemClass);
4573
4313
  setAttr(html, {
@@ -4578,38 +4318,34 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4578
4318
  setAttr(html, {
4579
4319
  role: 'option',
4580
4320
  id: data.$id
4581
- }); // update cache
4321
+ });
4582
4322
 
4323
+ // update cache
4583
4324
  data.$div = html;
4584
4325
  self.options[value] = data;
4585
4326
  }
4586
4327
  }
4587
-
4588
4328
  return html;
4589
4329
  }
4330
+
4590
4331
  /**
4591
4332
  * Type guarded rendering
4592
4333
  *
4593
4334
  */
4594
-
4595
-
4596
4335
  _render(templateName, data) {
4597
4336
  const html = this.render(templateName, data);
4598
-
4599
4337
  if (html == null) {
4600
4338
  throw 'HTMLElement expected';
4601
4339
  }
4602
-
4603
4340
  return html;
4604
4341
  }
4342
+
4605
4343
  /**
4606
4344
  * Clears the render cache for a template. If
4607
4345
  * no template is given, clears all render
4608
4346
  * caches.
4609
4347
  *
4610
4348
  */
4611
-
4612
-
4613
4349
  clearCache() {
4614
4350
  iterate$1(this.options, option => {
4615
4351
  if (option.$div) {
@@ -4618,26 +4354,25 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4618
4354
  }
4619
4355
  });
4620
4356
  }
4357
+
4621
4358
  /**
4622
4359
  * Removes a value from item and option caches
4623
4360
  *
4624
4361
  */
4625
-
4626
-
4627
4362
  uncacheValue(value) {
4628
4363
  const option_el = this.getOption(value);
4629
4364
  if (option_el) option_el.remove();
4630
4365
  }
4366
+
4631
4367
  /**
4632
4368
  * Determines whether or not to display the
4633
4369
  * create item prompt, given a user input.
4634
4370
  *
4635
4371
  */
4636
-
4637
-
4638
4372
  canCreate(input) {
4639
4373
  return this.settings.create && input.length > 0 && this.settings.createFilter.call(this, input);
4640
4374
  }
4375
+
4641
4376
  /**
4642
4377
  * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method
4643
4378
  *
@@ -4645,33 +4380,24 @@ class TomSelect extends MicroPlugin(MicroEvent) {
4645
4380
  *
4646
4381
  * });
4647
4382
  */
4648
-
4649
-
4650
4383
  hook(when, method, new_fn) {
4651
4384
  var self = this;
4652
4385
  var orig_method = self[method];
4653
-
4654
4386
  self[method] = function () {
4655
4387
  var result, result_new;
4656
-
4657
4388
  if (when === 'after') {
4658
4389
  result = orig_method.apply(self, arguments);
4659
4390
  }
4660
-
4661
4391
  result_new = new_fn.apply(self, arguments);
4662
-
4663
4392
  if (when === 'instead') {
4664
4393
  return result_new;
4665
4394
  }
4666
-
4667
4395
  if (when === 'before') {
4668
4396
  result = orig_method.apply(self, arguments);
4669
4397
  }
4670
-
4671
4398
  return result;
4672
4399
  };
4673
4400
  }
4674
-
4675
4401
  }
4676
4402
 
4677
4403
  export { TomSelect as default };