tom-select-rails 2.2.2 → 2.3.1

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