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