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