tom-select-rails 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tom-select-rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.complete.js +614 -820
  4. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.complete.js.map +1 -1
  5. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.js +411 -685
  6. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.js.map +1 -1
  7. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.popular.js +436 -705
  8. data/vendor/assets/javascripts/tom-select-rails/cjs/tom-select.popular.js.map +1 -1
  9. data/vendor/assets/javascripts/tom-select-rails/cjs/utils.js +31 -27
  10. data/vendor/assets/javascripts/tom-select-rails/cjs/utils.js.map +1 -1
  11. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/caret_position/plugin.js +11 -16
  12. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/caret_position/plugin.js.map +1 -1
  13. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/change_listener/plugin.js +3 -2
  14. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/change_listener/plugin.js.map +1 -1
  15. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/checkbox_options/plugin.js +47 -34
  16. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/checkbox_options/plugin.js.map +1 -1
  17. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/clear_button/plugin.js +3 -13
  18. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/clear_button/plugin.js.map +1 -1
  19. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/drag_drop/plugin.js +249 -29
  20. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/drag_drop/plugin.js.map +1 -1
  21. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_header/plugin.js +3 -11
  22. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_header/plugin.js.map +1 -1
  23. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_input/plugin.js +15 -24
  24. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/dropdown_input/plugin.js.map +1 -1
  25. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/input_autogrow/plugin.js +4 -6
  26. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/input_autogrow/plugin.js.map +1 -1
  27. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_active_items/plugin.js +2 -1
  28. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_active_items/plugin.js.map +1 -1
  29. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_backspace_delete/plugin.js +2 -2
  30. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/no_backspace_delete/plugin.js.map +1 -1
  31. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/optgroup_columns/plugin.js +3 -15
  32. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/optgroup_columns/plugin.js.map +1 -1
  33. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/remove_button/plugin.js +11 -15
  34. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/remove_button/plugin.js.map +1 -1
  35. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/restore_on_backspace/plugin.js +2 -3
  36. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/restore_on_backspace/plugin.js.map +1 -1
  37. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/virtual_scroll/plugin.js +41 -50
  38. data/vendor/assets/javascripts/tom-select-rails/esm/plugins/virtual_scroll/plugin.js.map +1 -1
  39. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.complete.js +614 -820
  40. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.complete.js.map +1 -1
  41. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.js +411 -685
  42. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.js.map +1 -1
  43. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.popular.js +436 -705
  44. data/vendor/assets/javascripts/tom-select-rails/esm/tom-select.popular.js.map +1 -1
  45. data/vendor/assets/javascripts/tom-select-rails/esm/utils.js +31 -26
  46. data/vendor/assets/javascripts/tom-select-rails/esm/utils.js.map +1 -1
  47. data/vendor/assets/javascripts/tom-select-rails/js/plugins/caret_position.js +11 -16
  48. data/vendor/assets/javascripts/tom-select-rails/js/plugins/caret_position.js.map +1 -1
  49. data/vendor/assets/javascripts/tom-select-rails/js/plugins/change_listener.js +3 -2
  50. data/vendor/assets/javascripts/tom-select-rails/js/plugins/change_listener.js.map +1 -1
  51. data/vendor/assets/javascripts/tom-select-rails/js/plugins/checkbox_options.js +47 -34
  52. data/vendor/assets/javascripts/tom-select-rails/js/plugins/checkbox_options.js.map +1 -1
  53. data/vendor/assets/javascripts/tom-select-rails/js/plugins/clear_button.js +3 -13
  54. data/vendor/assets/javascripts/tom-select-rails/js/plugins/clear_button.js.map +1 -1
  55. data/vendor/assets/javascripts/tom-select-rails/js/plugins/drag_drop.js +249 -29
  56. data/vendor/assets/javascripts/tom-select-rails/js/plugins/drag_drop.js.map +1 -1
  57. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_header.js +3 -11
  58. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_header.js.map +1 -1
  59. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_input.js +15 -24
  60. data/vendor/assets/javascripts/tom-select-rails/js/plugins/dropdown_input.js.map +1 -1
  61. data/vendor/assets/javascripts/tom-select-rails/js/plugins/input_autogrow.js +4 -6
  62. data/vendor/assets/javascripts/tom-select-rails/js/plugins/input_autogrow.js.map +1 -1
  63. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_active_items.js +2 -1
  64. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_active_items.js.map +1 -1
  65. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_backspace_delete.js +2 -2
  66. data/vendor/assets/javascripts/tom-select-rails/js/plugins/no_backspace_delete.js.map +1 -1
  67. data/vendor/assets/javascripts/tom-select-rails/js/plugins/optgroup_columns.js +3 -15
  68. data/vendor/assets/javascripts/tom-select-rails/js/plugins/optgroup_columns.js.map +1 -1
  69. data/vendor/assets/javascripts/tom-select-rails/js/plugins/remove_button.js +11 -15
  70. data/vendor/assets/javascripts/tom-select-rails/js/plugins/remove_button.js.map +1 -1
  71. data/vendor/assets/javascripts/tom-select-rails/js/plugins/restore_on_backspace.js +2 -3
  72. data/vendor/assets/javascripts/tom-select-rails/js/plugins/restore_on_backspace.js.map +1 -1
  73. data/vendor/assets/javascripts/tom-select-rails/js/plugins/virtual_scroll.js +41 -50
  74. data/vendor/assets/javascripts/tom-select-rails/js/plugins/virtual_scroll.js.map +1 -1
  75. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.js +411 -685
  76. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.js.map +1 -1
  77. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.min.js +87 -78
  78. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.base.min.js.map +1 -1
  79. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.js +614 -820
  80. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.js.map +1 -1
  81. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.min.js +195 -176
  82. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.complete.min.js.map +1 -1
  83. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.js +436 -705
  84. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.js.map +1 -1
  85. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.min.js +87 -78
  86. data/vendor/assets/javascripts/tom-select-rails/js/tom-select.popular.min.js.map +1 -1
  87. data/vendor/assets/javascripts/tom-select-rails/types/contrib/microevent.d.ts +1 -1
  88. data/vendor/assets/javascripts/tom-select-rails/types/contrib/microplugin.d.ts +4 -4
  89. data/vendor/assets/javascripts/tom-select-rails/types/defaults.d.ts +1 -0
  90. data/vendor/assets/javascripts/tom-select-rails/types/plugins/checkbox_options/plugin.d.ts +3 -2
  91. data/vendor/assets/javascripts/tom-select-rails/types/plugins/checkbox_options/types.d.ts +14 -0
  92. data/vendor/assets/javascripts/tom-select-rails/types/plugins/clear_button/types.d.ts +1 -1
  93. data/vendor/assets/javascripts/tom-select-rails/types/plugins/dropdown_header/types.d.ts +1 -1
  94. data/vendor/assets/javascripts/tom-select-rails/types/plugins/remove_button/types.d.ts +1 -1
  95. data/vendor/assets/javascripts/tom-select-rails/types/plugins/restore_on_backspace/plugin.d.ts +1 -1
  96. data/vendor/assets/javascripts/tom-select-rails/types/tom-select.d.ts +10 -12
  97. data/vendor/assets/javascripts/tom-select-rails/types/types/core.d.ts +15 -14
  98. data/vendor/assets/javascripts/tom-select-rails/types/types/settings.d.ts +3 -2
  99. data/vendor/assets/javascripts/tom-select-rails/types/utils.d.ts +7 -0
  100. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css +224 -216
  101. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.css.map +1 -1
  102. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css +1 -1
  103. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap4.min.css.map +1 -1
  104. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css +245 -252
  105. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.css.map +1 -1
  106. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css +1 -1
  107. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.bootstrap5.min.css.map +1 -1
  108. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css +213 -210
  109. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.css.map +1 -1
  110. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css +223 -215
  111. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.css.map +1 -1
  112. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css +1 -1
  113. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.default.min.css.map +1 -1
  114. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css +1 -1
  115. data/vendor/assets/stylesheets/tom-select-rails/css/tom-select.min.css.map +1 -1
  116. data/vendor/assets/stylesheets/tom-select-rails/scss/_dropdown.scss +7 -10
  117. data/vendor/assets/stylesheets/tom-select-rails/scss/_items.scss +2 -5
  118. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/checkbox_options.scss +8 -2
  119. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/clear_button.scss +16 -14
  120. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/drag_drop.scss +6 -12
  121. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/dropdown_header.scss +3 -2
  122. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/dropdown_input.scss +7 -11
  123. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/input_autogrow.scss +0 -3
  124. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/optgroup_columns.scss +7 -5
  125. data/vendor/assets/stylesheets/tom-select-rails/scss/plugins/remove_button.scss +20 -20
  126. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap4.scss +33 -39
  127. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.bootstrap5.scss +54 -80
  128. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.default.scss +16 -14
  129. data/vendor/assets/stylesheets/tom-select-rails/scss/tom-select.scss +52 -57
  130. metadata +8 -7
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tom Select v2.2.2
2
+ * Tom Select v2.3.1
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  */
5
5
 
@@ -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
  }