tabulator-tables 5.4.3 → 5.4.4

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