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