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