tabulator-tables 5.1.7 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +3 -2
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/bower.json +1 -1
  4. package/dist/css/tabulator.css +64 -51
  5. package/dist/css/tabulator.css.map +1 -1
  6. package/dist/css/tabulator.min.css +1 -1
  7. package/dist/css/tabulator.min.css.map +1 -1
  8. package/dist/css/tabulator_bootstrap3.css +64 -51
  9. package/dist/css/tabulator_bootstrap3.css.map +1 -1
  10. package/dist/css/tabulator_bootstrap3.min.css +1 -1
  11. package/dist/css/tabulator_bootstrap3.min.css.map +1 -1
  12. package/dist/css/tabulator_bootstrap4.css +64 -51
  13. package/dist/css/tabulator_bootstrap4.css.map +1 -1
  14. package/dist/css/tabulator_bootstrap4.min.css +1 -1
  15. package/dist/css/tabulator_bootstrap4.min.css.map +1 -1
  16. package/dist/css/tabulator_bootstrap5.css +1580 -0
  17. package/dist/css/tabulator_bootstrap5.css.map +1 -0
  18. package/dist/css/tabulator_bootstrap5.min.css +2 -0
  19. package/dist/css/tabulator_bootstrap5.min.css.map +1 -0
  20. package/dist/css/tabulator_bulma.css +64 -51
  21. package/dist/css/tabulator_bulma.css.map +1 -1
  22. package/dist/css/tabulator_bulma.min.css +1 -1
  23. package/dist/css/tabulator_bulma.min.css.map +1 -1
  24. package/dist/css/tabulator_materialize.css +64 -51
  25. package/dist/css/tabulator_materialize.css.map +1 -1
  26. package/dist/css/tabulator_materialize.min.css +1 -1
  27. package/dist/css/tabulator_materialize.min.css.map +1 -1
  28. package/dist/css/tabulator_midnight.css +64 -51
  29. package/dist/css/tabulator_midnight.css.map +1 -1
  30. package/dist/css/tabulator_midnight.min.css +1 -1
  31. package/dist/css/tabulator_midnight.min.css.map +1 -1
  32. package/dist/css/tabulator_modern.css +64 -51
  33. package/dist/css/tabulator_modern.css.map +1 -1
  34. package/dist/css/tabulator_modern.min.css +1 -1
  35. package/dist/css/tabulator_modern.min.css.map +1 -1
  36. package/dist/css/tabulator_semanticui.css +64 -51
  37. package/dist/css/tabulator_semanticui.css.map +1 -1
  38. package/dist/css/tabulator_semanticui.min.css +1 -1
  39. package/dist/css/tabulator_semanticui.min.css.map +1 -1
  40. package/dist/css/tabulator_simple.css +64 -51
  41. package/dist/css/tabulator_simple.css.map +1 -1
  42. package/dist/css/tabulator_simple.min.css +1 -1
  43. package/dist/css/tabulator_simple.min.css.map +1 -1
  44. package/dist/css/tabulator_site.css +64 -51
  45. package/dist/css/tabulator_site.css.map +1 -1
  46. package/dist/css/tabulator_site.min.css +1 -1
  47. package/dist/css/tabulator_site.min.css.map +1 -1
  48. package/dist/js/tabulator.js +2543 -1658
  49. package/dist/js/tabulator.js.map +1 -1
  50. package/dist/js/tabulator.min.js +2 -2
  51. package/dist/js/tabulator.min.js.map +1 -1
  52. package/dist/js/tabulator_esm.js +2746 -2069
  53. package/dist/js/tabulator_esm.js.map +1 -1
  54. package/dist/js/tabulator_esm.min.js +2 -2
  55. package/dist/js/tabulator_esm.min.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/js/core/FooterManager.js +6 -13
  58. package/src/js/core/Module.js +44 -2
  59. package/src/js/core/Tabulator.js +341 -289
  60. package/src/js/core/cell/Cell.js +9 -38
  61. package/src/js/core/column/Column.js +8 -44
  62. package/src/js/core/column/defaults/options.js +0 -2
  63. package/src/js/core/defaults/options.js +5 -2
  64. package/src/js/core/modules/optional.js +2 -0
  65. package/src/js/core/row/Row.js +127 -118
  66. package/src/js/core/tools/Alert.js +63 -0
  67. package/src/js/core/tools/ComponentFunctionBinder.js +3 -3
  68. package/src/js/core/tools/DataLoader.js +12 -84
  69. package/src/js/core/tools/InteractionMonitor.js +1 -1
  70. package/src/js/core/tools/ModuleBinder.js +30 -23
  71. package/src/js/core/tools/Popup.js +251 -0
  72. package/src/js/modules/ColumnCalcs/ColumnCalcs.js +2 -2
  73. package/src/js/modules/Edit/Edit.js +6 -25
  74. package/src/js/modules/Edit/List.js +997 -0
  75. package/src/js/modules/Edit/defaults/editors/autocomplete.js +6 -446
  76. package/src/js/modules/Edit/defaults/editors/input.js +4 -0
  77. package/src/js/modules/Edit/defaults/editors/list.js +7 -0
  78. package/src/js/modules/Edit/defaults/editors/number.js +4 -0
  79. package/src/js/modules/Edit/defaults/editors/select.js +5 -584
  80. package/src/js/modules/Edit/defaults/editors/textarea.js +4 -0
  81. package/src/js/modules/Edit/defaults/editors/tickCross.js +17 -5
  82. package/src/js/modules/Edit/defaults/editors.js +2 -0
  83. package/src/js/modules/Filter/Filter.js +7 -4
  84. package/src/js/modules/Format/defaults/formatters/datetime.js +10 -4
  85. package/src/js/modules/Format/defaults/formatters/datetimediff.js +10 -3
  86. package/src/js/modules/Format/defaults/formatters/link.js +12 -1
  87. package/src/js/modules/Format/defaults/formatters/money.js +5 -3
  88. package/src/js/modules/Format/defaults/formatters/tickCross.js +2 -1
  89. package/src/js/modules/FrozenColumns/FrozenColumns.js +30 -8
  90. package/src/js/modules/HtmlTableImport/HtmlTableImport.js +5 -1
  91. package/src/js/modules/Menu/Menu.js +59 -157
  92. package/src/js/modules/Mutator/Mutator.js +20 -0
  93. package/src/js/modules/Page/Page.js +7 -3
  94. package/src/js/modules/Persistence/Persistence.js +1 -1
  95. package/src/js/modules/Popup/Popup.js +194 -0
  96. package/src/js/modules/ResizeColumns/ResizeColumns.js +138 -81
  97. package/src/js/modules/Sort/defaults/sorters/datetime.js +15 -2
  98. package/src/js/modules/Tooltip/Tooltip.js +132 -0
  99. package/src/js/modules/Validate/Validate.js +107 -71
  100. package/src/scss/tabulator.scss +354 -349
  101. package/src/scss/themes/bootstrap/functions5.scss +302 -0
  102. package/src/scss/themes/bootstrap/tabulator_bootstrap5.scss +546 -0
  103. package/src/scss/themes/bootstrap/variables5.scss +1641 -0
@@ -0,0 +1,997 @@
1
+ import maskInput from './inputMask.js';
2
+ import urlBuilder from '../Ajax/defaults/urlGenerator.js';
3
+
4
+ export default class Edit{
5
+ constructor(editor, cell, onRendered, success, cancel, editorParams){
6
+ this.edit = editor;
7
+ this.table = editor.table;
8
+ this.cell = cell;
9
+ this.params = this._initializeParams(editorParams);
10
+
11
+ this.data = [];
12
+ this.displayItems = [];
13
+ this.currentItems = [];
14
+ this.focusedItem = null;
15
+
16
+ this.input = this._createInputElement();
17
+ this.listEl = this._createListElement();
18
+
19
+ this.initialValues = null;
20
+
21
+ this.isFilter = !cell._getSelf;
22
+
23
+ this.filterTimeout = null;
24
+ this.filtered = false;
25
+ this.typing = false;
26
+
27
+ this.values = [];
28
+ this.popup = null;
29
+
30
+ this.listIteration = 0;
31
+
32
+ this.blurable = true;
33
+
34
+ this.actions = {
35
+ success:success,
36
+ cancel:cancel
37
+ }
38
+
39
+ this._deprecationCheck();
40
+ this._initializeValue();
41
+
42
+ onRendered(this._onRendered.bind(this));
43
+ }
44
+
45
+ _deprecationCheck(){
46
+ if(this.params.listItemFormatter){
47
+ console.warn("The listItemFormatter editor param has been deprecated, please see the latest editor documentation for updated options");
48
+ }
49
+
50
+ if(this.params.sortValuesList){
51
+ console.warn("The sortValuesList editor param has been deprecated, please see the latest editor documentation for updated options");
52
+ }
53
+
54
+ if(this.params.searchFunc){
55
+ console.warn("The searchFunc editor param has been deprecated, please see the latest editor documentation for updated options");
56
+ }
57
+
58
+ if(this.params.searchingPlaceholder){
59
+ console.warn("The searchingPlaceholder editor param has been deprecated, please see the latest editor documentation for updated options");
60
+ }
61
+ }
62
+
63
+ _initializeValue(){
64
+ var initialValue = this.cell.getValue();
65
+
66
+ if(typeof initialValue === "undefined" && typeof this.params.defaultValue !== "undefined"){
67
+ initialValue = this.params.defaultValue;
68
+ }
69
+
70
+ this.initialValues = this.params.multiselect ? initialValue : [initialValue];
71
+
72
+ if(this.isFilter){
73
+ this.input.value = this.initialValues.join(",");
74
+ this.headerFilterInitialListGen();
75
+ }
76
+ }
77
+
78
+ _onRendered(){
79
+ var cellEl = this.cell.getElement();
80
+
81
+ function clickStop(e){
82
+ e.stopPropagation();
83
+ }
84
+
85
+ this.input.style.height = "100%";
86
+ this.input.focus({preventScroll: true});
87
+
88
+
89
+ cellEl.addEventListener("click", clickStop);
90
+
91
+ setTimeout(() => {
92
+ cellEl.removeEventListener("click", clickStop);
93
+ }, 1000)
94
+ }
95
+
96
+ _createListElement(){
97
+ var listEl = document.createElement("div");
98
+ listEl.classList.add("tabulator-edit-list");
99
+
100
+ listEl.addEventListener("mousedown", this._preventBlur.bind(this));
101
+ listEl.addEventListener("keydown", this._inputKeyDown.bind(this))
102
+
103
+ return listEl;
104
+ }
105
+
106
+ _setListWidth(){
107
+ var element = this.isFilter ? this.input : this.cell.getElement();
108
+
109
+ this.listEl.style.minWidth = element.offsetWidth + "px";
110
+
111
+ if(this.params.maxWidth){
112
+ if(this.params.maxWidth === true){
113
+ this.listEl.style.maxWidth = element.offsetWidth + "px";
114
+ }else if(typeof this.params.maxWidth === "number"){
115
+ this.listEl.style.maxWidth = this.params.maxWidth + "px";
116
+ }else{
117
+ this.listEl.style.maxWidth = this.params.maxWidth;
118
+ }
119
+ }
120
+
121
+ }
122
+
123
+ _createInputElement(){
124
+ var attribs = this.params.elementAttributes;
125
+ var input = document.createElement("input");
126
+
127
+ input.setAttribute("type", this.params.clearable ? "search" : "text");
128
+
129
+ input.style.padding = "4px";
130
+ input.style.width = "100%";
131
+ input.style.boxSizing = "border-box";
132
+
133
+ if(!this.params.autocomplete){
134
+ input.style.cursor = "default";
135
+ input.style.caretColor = "transparent";
136
+ // input.readOnly = (this.edit.currentCell != false);
137
+ }
138
+
139
+ if(attribs && typeof attribs == "object"){
140
+ for (let key in attribs){
141
+ if(key.charAt(0) == "+"){
142
+ key = key.slice(1);
143
+ input.setAttribute(key, input.getAttribute(key) + attribs["+" + key]);
144
+ }else{
145
+ input.setAttribute(key, attribs[key]);
146
+ }
147
+ }
148
+ }
149
+
150
+ if(this.params.mask){
151
+ maskInput(input, this.params);
152
+ }
153
+
154
+ this._bindInputEvents(input);
155
+
156
+ return input;
157
+ }
158
+
159
+ _initializeParams(params){
160
+ var valueKeys = ["values", "valuesURL", "valuesLookup"],
161
+ valueCheck;
162
+
163
+ params = Object.assign({}, params);
164
+
165
+ params.verticalNavigation = params.verticalNavigation || "editor";
166
+ params.placeholderLoading = typeof params.placeholderLoading === "undefined" ? "Searching ..." : params.placeholderLoading;
167
+ params.placeholderEmpty = typeof params.placeholderEmpty === "undefined" ? "No Results Found" : params.placeholderEmpty;
168
+ params.filterDelay = typeof params.filterDelay === "undefined" ? 300 : params.filterDelay;
169
+
170
+ params.emptyValue = Object.keys(params).includes("emptyValue") ? params.emptyValue : "";
171
+
172
+ valueCheck = Object.keys(params).filter(key => valueKeys.includes(key)).length;
173
+
174
+ if(!valueCheck){
175
+ console.warn("list editor config error - either the values, valuesURL, or valuesLookup option must be set")
176
+ }else if(valueCheck > 1){
177
+ console.warn("list editor config error - only one of the values, valuesURL, or valuesLookup options can be set on the same editor")
178
+ }
179
+
180
+ if(params.autocomplete){
181
+ if(params.multiselect){
182
+ params.multiselect = false;
183
+ console.warn("list editor config error - multiselect option is not available when autocomplete is enabled")
184
+ }
185
+ }else{
186
+ if(params.freetext){
187
+ params.freetext = false;
188
+ console.warn("list editor config error - freetext option is only available when autocomplete is enabled");
189
+ }
190
+
191
+ if(params.filterFunc){
192
+ params.filterFunc = false;
193
+ console.warn("list editor config error - filterFunc option is only available when autocomplete is enabled");
194
+ }
195
+
196
+ if(params.filterRemote){
197
+ params.filterRemote = false;
198
+ console.warn("list editor config error - filterRemote option is only available when autocomplete is enabled");
199
+ }
200
+
201
+ if(params.mask){
202
+ params.mask = false;
203
+ console.warn("list editor config error - mask option is only available when autocomplete is enabled");
204
+ }
205
+
206
+ if(params.allowEmpty){
207
+ params.allowEmpty = false;
208
+ console.warn("list editor config error - allowEmpty option is only available when autocomplete is enabled");
209
+ }
210
+
211
+ if(params.listOnEmpty){
212
+ params.listOnEmpty = false;
213
+ console.warn("list editor config error - listOnEmpty option is only available when autocomplete is enabled");
214
+ }
215
+ }
216
+
217
+ if(params.filterRemote && !(typeof params.valuesLookup === "function" || typeof params.valuesURL)){
218
+ params.filterRemote = false;
219
+ console.warn("list editor config error - filterRemote option should only be used when values list is populated from a remote source");
220
+ }
221
+ return params;
222
+ }
223
+ //////////////////////////////////////
224
+ ////////// Event Handling ////////////
225
+ //////////////////////////////////////
226
+
227
+ _bindInputEvents(input){
228
+ input.addEventListener("focus", this._inputFocus.bind(this))
229
+ input.addEventListener("click", this._inputClick.bind(this))
230
+ input.addEventListener("blur", this._inputBlur.bind(this))
231
+ input.addEventListener("keydown", this._inputKeyDown.bind(this))
232
+ input.addEventListener("search", this._inputSearch.bind(this))
233
+
234
+ if(this.params.autocomplete){
235
+ input.addEventListener("keyup", this._inputKeyUp.bind(this))
236
+ }
237
+ }
238
+
239
+
240
+ _inputFocus(e){
241
+ this.rebuildOptionsList();
242
+ }
243
+
244
+ _filter(){
245
+ if(this.params.filterRemote){
246
+ clearTimeout(this.filterTimeout);
247
+
248
+ this.filterTimeout = setTimeout(() => {
249
+ this.rebuildOptionsList();
250
+ }, this.params.filterDelay);
251
+ }else{
252
+ this._filterList();
253
+ }
254
+ }
255
+
256
+ _inputClick(e){
257
+ e.stopPropagation();
258
+ }
259
+
260
+ _inputBlur(e){
261
+ if(this.blurable && this.popup){
262
+ this.popup.hide();
263
+ }
264
+ }
265
+
266
+ _inputSearch(){
267
+ this._clearChoices();
268
+ }
269
+
270
+ _inputKeyDown(e){
271
+ switch(e.keyCode){
272
+
273
+ case 38: //up arrow
274
+ this._keyUp(e);
275
+ break
276
+
277
+ case 40: //down arrow
278
+ this._keyDown(e);
279
+ break;
280
+
281
+ case 37: //left arrow
282
+ case 39: //right arrow
283
+ this._keySide(e);
284
+ break;
285
+
286
+ case 13: //enter
287
+ this._keyEnter();
288
+ break;
289
+
290
+ case 27: //escape
291
+ this._keyEsc();
292
+ break;
293
+
294
+ case 36: //home
295
+ case 35: //end
296
+ this._keyHomeEnd(e);
297
+ break;
298
+
299
+ case 9: //tab
300
+ break;
301
+
302
+ default:
303
+ this._keySelectLetter(e);
304
+ }
305
+ }
306
+
307
+ _inputKeyUp(e){
308
+ switch(e.keyCode){
309
+ case 38: //up arrow
310
+ case 37: //left arrow
311
+ case 39: //up arrow
312
+ case 40: //right arrow
313
+ case 13: //enter
314
+ case 27: //escape
315
+ break;
316
+
317
+ default:
318
+ this._keyAutoCompLetter(e);
319
+ }
320
+ }
321
+
322
+ _preventBlur(){
323
+ this.blurable = false;
324
+
325
+ setTimeout(function(){
326
+ this.blurable = true;
327
+ }, 10);
328
+ }
329
+
330
+ //////////////////////////////////////
331
+ //////// Keyboard Navigation /////////
332
+ //////////////////////////////////////
333
+
334
+ _keyUp(e){
335
+ var index = this.displayItems.indexOf(this.focusedItem);
336
+
337
+ if(this.params.verticalNavigation == "editor" || (this.params.verticalNavigation == "hybrid" && index)){
338
+ e.stopImmediatePropagation();
339
+ e.stopPropagation();
340
+ e.preventDefault();
341
+
342
+ if(index > 0){
343
+ this._focusItem(this.displayItems[index - 1]);
344
+ }
345
+ }
346
+ }
347
+
348
+ _keyDown(e){
349
+ var index = this.displayItems.indexOf(this.focusedItem);
350
+
351
+ if(this.params.verticalNavigation == "editor" || (this.params.verticalNavigation == "hybrid" && index < this.displayItems.length - 1)){
352
+ e.stopImmediatePropagation();
353
+ e.stopPropagation();
354
+ e.preventDefault();
355
+
356
+ if(index < this.displayItems.length - 1){
357
+ if(index == -1){
358
+ this._focusItem(this.displayItems[0]);
359
+ }else{
360
+ this._focusItem(this.displayItems[index + 1]);
361
+ }
362
+ }
363
+ }
364
+ }
365
+
366
+ _keySide(e){
367
+ e.stopImmediatePropagation();
368
+ e.stopPropagation();
369
+ e.preventDefault();
370
+ }
371
+
372
+ _keyEnter(e){
373
+ if(this.focusedItem){
374
+ this._chooseItem(this.focusedItem);
375
+ }else{
376
+ this._cancel();
377
+ }
378
+ }
379
+
380
+ _keyEsc(e){
381
+ this._cancel();
382
+ }
383
+
384
+ _keyHomeEnd(e){
385
+ if(this.params.autocomplete){
386
+ //prevent table navigation while using input element
387
+ e.stopImmediatePropagation();
388
+ }
389
+ }
390
+
391
+ _keySelectLetter(e){
392
+ if(!this.params.autocomplete){
393
+ // if(this.edit.currentCell === false){
394
+ e.preventDefault();
395
+ // }
396
+
397
+ if(e.keyCode >= 38 && e.keyCode <= 90){
398
+ this._scrollToValue(e.keyCode);
399
+ }
400
+ }
401
+ }
402
+
403
+ _keyAutoCompLetter(e){
404
+ this._filter();
405
+ this.typing = true;
406
+ }
407
+
408
+
409
+ _scrollToValue(char){
410
+ clearTimeout(this.filterTimeout);
411
+
412
+ var character = String.fromCharCode(char).toLowerCase();
413
+ this.filterTerm += character.toLowerCase();
414
+
415
+ var match = this.displayItems.find((item) => {
416
+ return typeof item.label !== "undefined" && item.label.toLowerCase().startsWith(this.filterTerm);
417
+ });
418
+
419
+ if(match){
420
+ this._focusItem(match);
421
+ }
422
+
423
+ this.filterTimeout = setTimeout(() => {
424
+ this.filterTerm = "";
425
+ }, 800)
426
+ }
427
+
428
+ _focusItem(item){
429
+ if(this.focusedItem && this.focusedItem.element){
430
+ this.focusedItem.element.classList.remove("focused");
431
+ }
432
+
433
+ this.focusedItem = item;
434
+
435
+ if(item && item.element){
436
+ item.element.classList.add("focused");
437
+ item.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'start'});
438
+ }
439
+ }
440
+
441
+
442
+ //////////////////////////////////////
443
+ /////// Data List Generation /////////
444
+ //////////////////////////////////////
445
+ headerFilterInitialListGen(){
446
+ this._generateOptions(true);
447
+ }
448
+
449
+ rebuildOptionsList(){
450
+ this._generateOptions()
451
+ .then(this._sortOptions.bind(this))
452
+ .then(this._buildList.bind(this))
453
+ .then(this._showList.bind(this))
454
+ .catch((e) => {
455
+ if(!Number.isInteger(e)){
456
+ console.error("List generation error", e);
457
+ }
458
+ })
459
+ }
460
+
461
+ _filterList(){
462
+ this._buildList(this._filterOptions());
463
+ this._showList();
464
+ }
465
+
466
+ _generateOptions(silent){
467
+ var values = [];
468
+ var itteration = ++ this.listIteration;
469
+
470
+ this.filtered = false;
471
+
472
+ if(this.params.values){
473
+ values = this.params.values;
474
+ }else if (this.params.valuesURL){
475
+ values = this._ajaxRequest(this.params.valuesURL, this.input.value);
476
+ }else{
477
+ if(typeof this.params.valuesLookup === "function"){
478
+ values = this.params.valuesLookup(cell, this.input.value);
479
+ }else if(this.params.valuesLookup){
480
+ values = this._uniqueColumnValues(this.params.valuesLookupField);
481
+ }
482
+ }
483
+
484
+ if(values instanceof Promise){
485
+ if(!silent){
486
+ this._addPlaceholder(this.params.placeholderLoading);
487
+ }
488
+
489
+ return values.then()
490
+ .then((responseValues) => {
491
+ if(this.listIteration === itteration){
492
+ return this._parseList(responseValues);
493
+ }else{
494
+ return Promise.reject(itteration);
495
+ }
496
+ });
497
+ }else{
498
+ return Promise.resolve(this._parseList(values))
499
+ }
500
+ }
501
+
502
+ _addPlaceholder(contents){
503
+ var placeholder = document.createElement("div");
504
+
505
+ if(typeof contents === "function"){
506
+ contents = contents(cell.getComponent(), this.listEl);
507
+ }
508
+
509
+ if(contents){
510
+ this._clearList();
511
+
512
+ if(contents instanceof HTMLElement){
513
+ placeholder = contents;
514
+ }else{
515
+ placeholder.classList.add("tabulator-edit-list-placeholder")
516
+ placeholder.innerHTML = contents;
517
+ }
518
+
519
+ this.listEl.appendChild(placeholder);
520
+
521
+ this._showList();
522
+ }
523
+ }
524
+
525
+ _ajaxRequest(url, term){
526
+ var params = this.params.filterRemote ? {term:term} : {};
527
+ url = urlBuilder(url, {}, params);
528
+
529
+ return fetch(url)
530
+ .then((response)=>{
531
+ if(response.ok) {
532
+ return response.json()
533
+ .catch((error)=>{
534
+ console.warn("List Ajax Load Error - Invalid JSON returned", error);
535
+ return Promise.reject(error);
536
+ });
537
+ }else{
538
+ console.error("List Ajax Load Error - Connection Error: " + response.status, response.statusText);
539
+ return Promise.reject(response);
540
+ }
541
+ })
542
+ .catch((error)=>{
543
+ console.error("List Ajax Load Error - Connection Error: ", error);
544
+ return Promise.reject(error);
545
+ });
546
+ }
547
+
548
+ _uniqueColumnValues(field){
549
+ var output = {},
550
+ data = this.table.getData(this.params.valuesLookup),
551
+ column;
552
+
553
+ if(field){
554
+ column = this.table.columnManager.getColumnByField(field);
555
+ }else{
556
+ column = this.cell.getColumn()._getSelf();
557
+ }
558
+
559
+ if(column){
560
+ data.forEach((row) => {
561
+ var val = column.getFieldValue(row);
562
+
563
+ if(val !== null && typeof val !== "undefined" && val !== ""){
564
+ output[val] = true;
565
+ }
566
+ });
567
+ }else{
568
+ console.warn("unable to find matching column to create select lookup list:", field);
569
+ output = [];
570
+ }
571
+
572
+ return Object.keys(output);
573
+ }
574
+
575
+
576
+ _parseList(inputValues){
577
+ var data = [];
578
+
579
+ if(!Array.isArray(inputValues)){
580
+ inputValues = Object.entries(inputValues).map(([key, value]) => {
581
+ return {
582
+ label:value,
583
+ value:key,
584
+ };
585
+ });
586
+ }
587
+
588
+ inputValues.forEach((value) => {
589
+ if(typeof value !== "object"){
590
+ value = {
591
+ label:value,
592
+ value:value,
593
+ };
594
+ }
595
+
596
+ this._parseListItem(value, data, 0);
597
+ });
598
+
599
+ this.data = data;
600
+
601
+ return data;
602
+ }
603
+
604
+ _parseListItem(option, data, level){
605
+ var item = {};
606
+
607
+ if(option.options){
608
+ item = this._parseListGroup(option, level + 1);
609
+ }else{
610
+ item = {
611
+ label:option.label,
612
+ value:option.value,
613
+ itemParams:option.itemParams,
614
+ elementAttributes: option.elementAttributes,
615
+ element:false,
616
+ selected:false,
617
+ visible:true,
618
+ level:level,
619
+ original:option,
620
+ };
621
+
622
+ if(this.initialValues && this.initialValues.indexOf(option.value) > -1){
623
+ this._chooseItem(item, true);
624
+ }
625
+ }
626
+
627
+ data.push(item);
628
+ }
629
+
630
+ _parseListGroup(option, level){
631
+ var item = {
632
+ label:option.label,
633
+ group:true,
634
+ itemParams:option.itemParams,
635
+ elementAttributes:option.elementAttributes,
636
+ element:false,
637
+ visible:true,
638
+ level:level,
639
+ options:[],
640
+ original:option,
641
+ };
642
+
643
+ option.options.forEach((child) => {
644
+ this._parseListItem(child, item.options, level);
645
+ });
646
+
647
+ return item;
648
+ }
649
+
650
+ _sortOptions(options){
651
+ var sorter;
652
+
653
+ if(this.params.sort){
654
+ sorter = typeof this.params.sort === "function" ? this.params.sort : this._defaultSortFunction.bind(this);
655
+
656
+ this._sortGroup(sorter, options);
657
+ }
658
+
659
+ return options;
660
+ }
661
+
662
+ _sortGroup(sorter, options){
663
+ options.sort((a,b) => {
664
+ return sorter(a.label, b.label, a.value, b.value, a.original, b.original);
665
+ });
666
+
667
+ options.forEach((option) => {
668
+ if(option.group){
669
+ this._sortGroup(sorter, option.options);
670
+ }
671
+ })
672
+ }
673
+
674
+ _defaultSortFunction(as, bs){
675
+ var a, b, a1, b1, i= 0, L, rx = /(\d+)|(\D+)/g, rd = /\d/;
676
+ var emptyAlign = 0;
677
+
678
+ if(this.params.sort === "desc"){
679
+ [as, bs] = [bs, as];
680
+ }
681
+
682
+ //handle empty values
683
+ if(!as && as!== 0){
684
+ emptyAlign = !bs && bs!== 0 ? 0 : -1;
685
+ }else if(!bs && bs!== 0){
686
+ emptyAlign = 1;
687
+ }else{
688
+ if(isFinite(as) && isFinite(bs)) return as - bs;
689
+ a = String(as).toLowerCase();
690
+ b = String(bs).toLowerCase();
691
+ if(a === b) return 0;
692
+ if(!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
693
+ a = a.match(rx);
694
+ b = b.match(rx);
695
+ L = a.length > b.length ? b.length : a.length;
696
+ while(i < L){
697
+ a1= a[i];
698
+ b1= b[i++];
699
+ if(a1 !== b1){
700
+ if(isFinite(a1) && isFinite(b1)){
701
+ if(a1.charAt(0) === "0") a1 = "." + a1;
702
+ if(b1.charAt(0) === "0") b1 = "." + b1;
703
+ return a1 - b1;
704
+ }
705
+ else return a1 > b1 ? 1 : -1;
706
+ }
707
+ }
708
+
709
+ return a.length > b.length;
710
+ }
711
+
712
+ return emptyAlign;
713
+ }
714
+
715
+ _filterOptions(){
716
+ var filterFunc = this.params.filterFunc || this._defaultFilterFunc;
717
+ var term = this.input.value;
718
+ var results = [];
719
+
720
+ if(term){
721
+ this.filtered = true;
722
+
723
+ this.data.forEach((item) => {
724
+ this._filterItem(filterFunc, term, item);
725
+ });
726
+ }else{
727
+ this.filtered = false;
728
+ }
729
+
730
+ return this.data;
731
+ }
732
+
733
+ _filterItem(func, term, item){
734
+ var matches = false;
735
+
736
+ if(!item.group){
737
+ item.visible = func(term, item.label, item.value, item.original);
738
+ }else{
739
+ item.options.forEach((option) => {
740
+ if(this._filterItem(func, term, option)){
741
+ matches = true;
742
+ }
743
+ });
744
+
745
+ item.visible = matches;
746
+ }
747
+
748
+ return item.visible;
749
+ }
750
+
751
+ _defaultFilterFunc(term, label, value, item){
752
+ var term = String(term).toLowerCase();
753
+
754
+ if(label !== null || typeof label !== "undefined"){
755
+ if(String(label).toLowerCase().indexOf(term) > -1 || String(value).toLowerCase(term).indexOf() > -1){
756
+ return true;
757
+ }
758
+ }
759
+
760
+ return false;
761
+ }
762
+
763
+ //////////////////////////////////////
764
+ /////////// Display List /////////////
765
+ //////////////////////////////////////
766
+
767
+ _clearList(){
768
+ while(this.listEl.firstChild) this.listEl.removeChild(this.listEl.firstChild);
769
+
770
+ this.displayItems = [];
771
+ }
772
+
773
+ _buildList(data){
774
+ this._clearList();
775
+
776
+ data.forEach((option) => {
777
+ this._buildItem(option);
778
+ });
779
+
780
+ if(!this.displayItems.length){
781
+ this._addPlaceholder(this.params.placeholderEmpty);
782
+ }
783
+ }
784
+
785
+ _buildItem(item){
786
+ var el = item.element,
787
+ contents;
788
+
789
+ if(!this.filtered || item.visible){
790
+
791
+ if(!el){
792
+ el = document.createElement("div");
793
+ el.tabIndex = 0;
794
+
795
+ contents = this.params.itemFormatter ? this.params.itemFormatter(item.label, item.value, item.original, el) : item.label;
796
+
797
+ if(contents instanceof HTMLElement){
798
+ el.appendChild(contents)
799
+ }else{
800
+ el.innerHTML = contents;
801
+ }
802
+
803
+ if(item.group){
804
+ el.classList.add("tabulator-edit-list-group");
805
+ }else{
806
+ el.classList.add("tabulator-edit-list-item");
807
+ }
808
+
809
+ el.classList.add("tabulator-edit-list-group-level-" + item.level);
810
+
811
+ if(item.elementAttributes && typeof item.elementAttributes == "object"){
812
+ for (let key in item.elementAttributes){
813
+ if(key.charAt(0) == "+"){
814
+ key = key.slice(1);
815
+ el.setAttribute(key, this.input.getAttribute(key) + item.elementAttributes["+" + key]);
816
+ }else{
817
+ el.setAttribute(key, item.elementAttributes[key]);
818
+ }
819
+ }
820
+ }
821
+
822
+ if(item.group){
823
+ el.addEventListener("click", this._groupClick.bind(this, item));
824
+ }else{
825
+ el.addEventListener("click", this._itemClick.bind(this, item));
826
+ }
827
+
828
+ el.addEventListener("mousedown", this._preventBlur.bind(this));
829
+
830
+ item.element = el;
831
+ }
832
+
833
+ this._styleItem(item);
834
+
835
+ this.listEl.appendChild(el);
836
+
837
+ if(item.group){
838
+ item.options.forEach((option) => {
839
+ this._buildItem(option);
840
+ });
841
+ }else{
842
+ this.displayItems.push(item);
843
+ }
844
+ }
845
+ }
846
+
847
+ _showList(){
848
+ var startVis = this.popup && this.popup.isVisible();
849
+
850
+ if(this.input.parentNode){
851
+ if(this.params.autocomplete && this.input.value === "" && !this.params.listOnEmpty){
852
+ if(this.popup){
853
+ this.popup.hide(true);
854
+ return;
855
+ }
856
+ }
857
+
858
+ this._setListWidth();
859
+
860
+ if(!this.popup){
861
+ this.popup = this.edit.popup(this.listEl);
862
+ }
863
+
864
+ this.popup.show(this.cell.getElement(), "bottom")
865
+
866
+ if(!startVis){
867
+ this.popup.hideOnBlur(this._resolveValue.bind(this, true));
868
+ }
869
+ }
870
+ }
871
+
872
+ _styleItem(item){
873
+ if(item && item.element){
874
+ if(item.selected){
875
+ item.element.classList.add("active");
876
+ }else{
877
+ item.element.classList.remove("active");
878
+ }
879
+ }
880
+ }
881
+
882
+ //////////////////////////////////////
883
+ ///////// User Interaction ///////////
884
+ //////////////////////////////////////
885
+
886
+ _itemClick(item, e){
887
+ e.stopPropagation();
888
+
889
+ this._chooseItem(item);
890
+ }
891
+
892
+ _groupClick(item, e){
893
+ e.stopPropagation();
894
+ }
895
+
896
+
897
+ //////////////////////////////////////
898
+ ////// Current Item Management ///////
899
+ //////////////////////////////////////
900
+
901
+ _cancel(){
902
+ this.popup.hide(true);
903
+ this.actions.cancel();
904
+ }
905
+
906
+ _clearChoices(){
907
+ this.typing = true;
908
+
909
+ this.currentItems.forEach((item) => {
910
+ item.selected = false;
911
+ this._styleItem(item);
912
+ });
913
+
914
+ this.currentItems = [];
915
+
916
+ this.focusedItem = null;
917
+ }
918
+
919
+ _chooseItem(item, silent){
920
+ var index;
921
+
922
+ this.typing = false;
923
+
924
+ if(this.params.multiselect){
925
+ index = this.currentItems.indexOf(item);
926
+
927
+ if(index > -1){
928
+ this.currentItems.splice(index, 1);
929
+ item.selected = false;
930
+ }else{
931
+ this.currentItems.push(item);
932
+ item.selected = true;
933
+ }
934
+
935
+ this.input.value = this.currentItems.map(item => item.label).join(",");
936
+
937
+ this._styleItem(item);
938
+
939
+ }else{
940
+ this.currentItems = [item];
941
+ item.selected = true;
942
+
943
+ this.input.value = item.label;
944
+
945
+ this._styleItem(item);
946
+
947
+ if(!silent){
948
+ this._resolveValue();
949
+ }
950
+ }
951
+
952
+ this._focusItem(item);
953
+ }
954
+
955
+ _resolveValue(blur){
956
+ var output, initialValue;
957
+
958
+ this.popup.hide(true);
959
+
960
+ if(this.params.multiselect){
961
+ output = this.currentItems.map(item => item.value);
962
+ }else{
963
+ if(blur && this.params.autocomplete && this.typing){
964
+ if(this.params.freetext || (this.params.allowEmpty && this.input.value === "")){
965
+ output = this.input.value;
966
+ }else{
967
+ this.actions.cancel();
968
+ return;
969
+ }
970
+ }else{
971
+ if(this.currentItems[0]){
972
+ output = this.currentItems[0].value;
973
+ }else{
974
+ initialValue = this.initialValues[0];
975
+
976
+ if(initialValue === null || typeof initialValue === "undefined" || initialValue === ""){
977
+ output = initialValue;
978
+ }else{
979
+ output = this.params.emptyValue;
980
+ }
981
+ }
982
+
983
+ }
984
+ }
985
+
986
+ if(output === ""){
987
+ output = this.params.emptyValue;
988
+ }
989
+
990
+ this.actions.success(output);
991
+
992
+ if(this.isFilter){
993
+ this.initialValues = output;
994
+ }
995
+ }
996
+
997
+ }