tom-select-rails 2.2.2 → 2.3.1

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