tsgrid-ui 2.7.1 → 2.10.0

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 (69) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/dist/base.d.ts +148 -0
  3. package/dist/base.es6.js +11 -0
  4. package/dist/base.es6.js.map +1 -0
  5. package/dist/chunks/chunk-3NYH6545.js +2423 -0
  6. package/dist/chunks/chunk-3NYH6545.js.map +1 -0
  7. package/dist/chunks/chunk-6MOFFUV2.js +2305 -0
  8. package/dist/chunks/chunk-6MOFFUV2.js.map +1 -0
  9. package/dist/chunks/chunk-6UCGFWIQ.js +865 -0
  10. package/dist/chunks/chunk-6UCGFWIQ.js.map +1 -0
  11. package/dist/chunks/chunk-DXZJHS4M.js +1283 -0
  12. package/dist/chunks/chunk-DXZJHS4M.js.map +1 -0
  13. package/dist/chunks/chunk-DZSFZLV6.js +1638 -0
  14. package/dist/chunks/chunk-DZSFZLV6.js.map +1 -0
  15. package/dist/chunks/chunk-EQK6JAHT.js +33 -0
  16. package/dist/chunks/chunk-EQK6JAHT.js.map +1 -0
  17. package/dist/chunks/chunk-FAIRNXQR.js +3020 -0
  18. package/dist/chunks/chunk-FAIRNXQR.js.map +1 -0
  19. package/dist/chunks/chunk-GZFWK4LZ.js +677 -0
  20. package/dist/chunks/chunk-GZFWK4LZ.js.map +1 -0
  21. package/dist/chunks/chunk-IYF3Q7GX.js +127 -0
  22. package/dist/chunks/chunk-IYF3Q7GX.js.map +1 -0
  23. package/dist/chunks/chunk-KLJ35UAH.js +1795 -0
  24. package/dist/chunks/chunk-KLJ35UAH.js.map +1 -0
  25. package/dist/chunks/chunk-LUSNRF73.js +1212 -0
  26. package/dist/chunks/chunk-LUSNRF73.js.map +1 -0
  27. package/dist/chunks/chunk-N3GASHTI.js +1127 -0
  28. package/dist/chunks/chunk-N3GASHTI.js.map +1 -0
  29. package/dist/field.d.ts +329 -0
  30. package/dist/field.es6.js +12 -0
  31. package/dist/field.es6.js.map +1 -0
  32. package/dist/form.d.ts +162 -0
  33. package/dist/form.es6.js +15 -0
  34. package/dist/form.es6.js.map +1 -0
  35. package/dist/layout.d.ts +108 -0
  36. package/dist/layout.es6.js +14 -0
  37. package/dist/layout.es6.js.map +1 -0
  38. package/dist/locale.d.ts +30 -0
  39. package/dist/locale.es6.js +7 -0
  40. package/dist/locale.es6.js.map +1 -0
  41. package/dist/popup.d.ts +97 -0
  42. package/dist/popup.es6.js +21 -0
  43. package/dist/popup.es6.js.map +1 -0
  44. package/dist/query-CKGg5Ugv.d.ts +81 -0
  45. package/dist/sidebar.d.ts +138 -0
  46. package/dist/sidebar.es6.js +12 -0
  47. package/dist/sidebar.es6.js.map +1 -0
  48. package/dist/tabs.d.ts +63 -0
  49. package/dist/tabs.es6.js +12 -0
  50. package/dist/tabs.es6.js.map +1 -0
  51. package/dist/toolbar.d.ts +97 -0
  52. package/dist/toolbar.es6.js +12 -0
  53. package/dist/toolbar.es6.js.map +1 -0
  54. package/dist/tooltip.d.ts +330 -0
  55. package/dist/tooltip.es6.js +21 -0
  56. package/dist/tooltip.es6.js.map +1 -0
  57. package/dist/tsgrid-ui.css +2 -2
  58. package/dist/tsgrid-ui.d.ts +16 -2004
  59. package/dist/tsgrid-ui.es6.js +7751 -23830
  60. package/dist/tsgrid-ui.es6.js.map +1 -1
  61. package/dist/tsgrid-ui.es6.min.js +37 -37
  62. package/dist/tsgrid-ui.js +150 -22
  63. package/dist/tsgrid-ui.min.css +2 -2
  64. package/dist/tsgrid-ui.min.js +39 -39
  65. package/dist/tsutils-message-CogFtVtO.d.ts +82 -0
  66. package/dist/utils.d.ts +418 -0
  67. package/dist/utils.es6.js +14 -0
  68. package/dist/utils.es6.js.map +1 -0
  69. package/package.json +25 -5
@@ -0,0 +1,1212 @@
1
+ import {
2
+ TsColor,
3
+ TsMenu,
4
+ TsTooltip
5
+ } from "./chunk-FAIRNXQR.js";
6
+ import {
7
+ TsUtils
8
+ } from "./chunk-3NYH6545.js";
9
+ import {
10
+ TsBase,
11
+ TsUi,
12
+ query
13
+ } from "./chunk-DXZJHS4M.js";
14
+
15
+ // src/tstoolbar.ts
16
+ var query2 = query;
17
+ var TsToolbar = class extends TsBase {
18
+ routeData;
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ items;
21
+ // any: toolbar items have dynamic shape
22
+ right;
23
+ tooltip;
24
+ item_template;
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ last;
27
+ // any: accumulates badge, pendingRefresh, etc.
28
+ // any: callback parameter — caller signature varies; TsToolbar item shape varies by `type` at runtime
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ _refresh;
31
+ _refreshDebounced;
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ constructor(options) {
34
+ super(options.name);
35
+ this.box = null;
36
+ this.name = "";
37
+ this.routeData = {};
38
+ this.items = [];
39
+ this.right = "";
40
+ this.tooltip = "top|left";
41
+ this["onClick"] = null;
42
+ this["onChange"] = null;
43
+ this["onMouseDown"] = null;
44
+ this["onMouseUp"] = null;
45
+ this["onMouseEnter"] = null;
46
+ this["onMouseLeave"] = null;
47
+ this["onRender"] = null;
48
+ this["onRefresh"] = null;
49
+ this["onResize"] = null;
50
+ this["onDestroy"] = null;
51
+ this["onLiveUpdate"] = null;
52
+ this.item_template = {
53
+ id: null,
54
+ // command to be sent to all event handlers
55
+ type: "button",
56
+ // button, check, radio, drop, menu, menu-radio, menu-check, break, html, label, input spacer
57
+ text: null,
58
+ html: "",
59
+ tooltip: null,
60
+ // TsToolbar.tooltip should be
61
+ count: null,
62
+ hidden: false,
63
+ disabled: false,
64
+ checked: false,
65
+ // used for radio buttons
66
+ icon: null,
67
+ route: null,
68
+ // if not null, it is route to go
69
+ arrow: null,
70
+ // arrow down for drop/menu types
71
+ style: null,
72
+ // extra css style for caption
73
+ group: null,
74
+ // used for radio buttons
75
+ items: null,
76
+ // for type menu* it is an array of items in the menu
77
+ selected: null,
78
+ // used for menu-check, menu-radio
79
+ color: null,
80
+ // color value - used in color pickers
81
+ backColor: null,
82
+ // background color value for color pickter
83
+ overlay: {
84
+ // additional options for overlay
85
+ anchorClass: ""
86
+ },
87
+ onClick: null,
88
+ onRefresh: null
89
+ };
90
+ this.last = {
91
+ badge: {},
92
+ pendingRefresh: {}
93
+ // what should be refreshed with a debounce
94
+ };
95
+ this._refresh = ({ effected, resize, refreshTooltip, hideTooltip }) => {
96
+ const options2 = this.last.pendingRefresh;
97
+ options2.ids ??= [];
98
+ options2.ids.push(...effected);
99
+ Object.assign(options2, { resize, refreshTooltip, hideTooltip });
100
+ this._refreshDebounced();
101
+ };
102
+ this._refreshDebounced = TsUtils.debounce(() => {
103
+ const options2 = this.last.pendingRefresh;
104
+ new Set(options2.ids).forEach((id) => {
105
+ this.refresh(id);
106
+ if (options2.hideTooltip) this.tooltipHide(id);
107
+ });
108
+ if (options2.resize) this.resize();
109
+ this.last.pendingRefresh = {};
110
+ }, 15);
111
+ const items = options.items;
112
+ delete options.items;
113
+ Object.assign(this, options);
114
+ if (Array.isArray(items)) this.add(items, true);
115
+ options.items = items;
116
+ if (typeof this.box == "string") this.box = query2(this.box).get(0);
117
+ if (this.box) this.render(this.box);
118
+ }
119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
+ add(items, skipRefresh) {
121
+ this.insert(null, items, skipRefresh);
122
+ }
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ insert(id, items, skipRefresh) {
125
+ if (!Array.isArray(items)) items = [items];
126
+ items.forEach((item, idx, arr) => {
127
+ if (typeof item === "string") {
128
+ item = arr[idx] = { id: item, text: item };
129
+ }
130
+ const valid = [
131
+ "button",
132
+ "check",
133
+ "radio",
134
+ "drop",
135
+ "menu",
136
+ "menu-radio",
137
+ "menu-check",
138
+ "color",
139
+ "text-color",
140
+ "html",
141
+ "label",
142
+ "input",
143
+ "group",
144
+ "break",
145
+ "spacer",
146
+ "new-line"
147
+ ];
148
+ if (!valid.includes(String(item.type))) {
149
+ console.log('ERROR: The parameter "type" should be one of the following:', valid, `, but ${item.type} is supplied.`, item);
150
+ return;
151
+ }
152
+ if (item.id == null && !["break", "spacer", "new-line"].includes(item.type)) {
153
+ console.log('ERROR: The parameter "id" is required but not supplied.', item);
154
+ return;
155
+ }
156
+ if (!TsUtils.checkUniqueId(item.id, this.items, "toolbar", this.name)) return;
157
+ const newItem = TsUtils.extend({}, this.item_template, item);
158
+ if (newItem.type == "group" && Array.isArray(newItem.items)) {
159
+ newItem.items.forEach((_it, ind) => {
160
+ newItem.items[ind] = TsUtils.extend({}, this.item_template, newItem.items[ind]);
161
+ });
162
+ }
163
+ if (newItem.type == "menu-check") {
164
+ if (!Array.isArray(newItem.selected)) newItem.selected = [];
165
+ if (Array.isArray(newItem.items)) {
166
+ newItem.items.forEach((it, idx2, arr2) => {
167
+ if (typeof it === "string") {
168
+ it = arr2[idx2] = { id: it, text: it };
169
+ }
170
+ if (it.checked && !newItem.selected.includes(it.id)) newItem.selected.push(it.id);
171
+ if (!it.checked && newItem.selected.includes(it.id)) it.checked = true;
172
+ if (it.checked == null) it.checked = false;
173
+ });
174
+ } else if (typeof newItem.items === "function") {
175
+ const materialized = newItem.items(newItem);
176
+ if (Array.isArray(materialized)) {
177
+ materialized.forEach((it) => {
178
+ if (it && it.checked && !newItem.selected.includes(it.id)) newItem.selected.push(it.id);
179
+ });
180
+ }
181
+ }
182
+ } else if (newItem.type == "menu-radio") {
183
+ if (Array.isArray(newItem.items)) {
184
+ newItem.items.forEach((it, idx2, arr2) => {
185
+ if (typeof it === "string") {
186
+ it = arr2[idx2] = { id: it, text: it };
187
+ }
188
+ if (it.checked && newItem.selected == null) newItem.selected = it.id;
189
+ else it.checked = false;
190
+ if (!it.checked && newItem.selected == it.id) it.checked = true;
191
+ if (it.checked == null) it.checked = false;
192
+ });
193
+ }
194
+ }
195
+ if (id == null) {
196
+ this.items.push(newItem);
197
+ } else {
198
+ const middle = this.get(id, true);
199
+ if (middle == null) {
200
+ console.warn(`TsToolbar: insert anchor id "${id}" not found; appending instead.`);
201
+ this.items.push(newItem);
202
+ } else {
203
+ this.items = this.items.slice(0, middle).concat([newItem], this.items.slice(middle));
204
+ }
205
+ }
206
+ newItem.line = newItem.line ?? 1;
207
+ if (skipRefresh !== true) this.refresh(newItem.id);
208
+ });
209
+ if (skipRefresh !== true) this.resize();
210
+ }
211
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213
+ remove(...args) {
214
+ let effected = 0;
215
+ args.forEach((item) => {
216
+ const it = this.get(item);
217
+ if (!it || String(item).indexOf(":") != -1) return;
218
+ effected++;
219
+ query2(this.box).find("#tb_" + this.name + "_item_" + TsUtils.escapeId(it.id)).remove();
220
+ const ind = this.get(it.id, true);
221
+ if (ind != null) {
222
+ const top = this.items[ind];
223
+ if (top.id === it.id) {
224
+ this.items.splice(ind, 1);
225
+ } else if (top.type === "group" && Array.isArray(top.items)) {
226
+ const subIdx = top.items.findIndex((s) => s && s.id === it.id);
227
+ if (subIdx !== -1) top.items.splice(subIdx, 1);
228
+ }
229
+ }
230
+ });
231
+ this.resize();
232
+ return effected;
233
+ }
234
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
+ set(id, newOptions) {
236
+ const item = this.get(id);
237
+ if (item == null) return false;
238
+ Object.assign(item, newOptions);
239
+ this.refresh(String(id).split(":")[0]);
240
+ return true;
241
+ }
242
+ // any: parameter typed any — runtime dispatch by call site; TsToolbar item shape varies by `type` at runtime
243
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
+ get(id, returnIndex, items) {
245
+ if (arguments.length === 0) {
246
+ const all = [];
247
+ for (let i1 = 0; i1 < this.items.length; i1++) {
248
+ const it = this.items[i1];
249
+ if (it.id != null) all.push(it.id);
250
+ if (it.type == "group") {
251
+ for (let i2 = 0; i2 < it.items.length; i2++) {
252
+ if (it.items[i2].id != null) all.push(it.items[i2].id);
253
+ }
254
+ }
255
+ }
256
+ return all;
257
+ }
258
+ const tmp = String(id).split(":");
259
+ if (items == null) items = this.items;
260
+ for (let i1 = 0; i1 < items.length; i1++) {
261
+ const it = items[i1];
262
+ if (["menu", "menu-radio", "menu-check"].includes(it.type) && tmp.length == 2 && it.id == tmp[0]) {
263
+ let subItems = it.items;
264
+ if (typeof subItems == "function") subItems = subItems(this);
265
+ for (let i = 0; i < subItems.length; i++) {
266
+ const item = subItems[i];
267
+ if (item.id == tmp[1] || item.id == null && item.text == tmp[1]) {
268
+ if (returnIndex == true) return i;
269
+ else return item;
270
+ }
271
+ if (Array.isArray(item.items)) {
272
+ for (let j = 0; j < item.items.length; j++) {
273
+ if (item.items[j].id == tmp[1] || item.items[j].id == null && item.items[j].text == tmp[1]) {
274
+ if (returnIndex == true) return i;
275
+ else return item.items[j];
276
+ }
277
+ }
278
+ }
279
+ }
280
+ } else if (it.id == tmp[0]) {
281
+ if (returnIndex == true) return i1;
282
+ else return it;
283
+ } else if (it.type == "group") {
284
+ const sub = this.get(id, returnIndex, it.items);
285
+ if (sub != null) {
286
+ if (returnIndex === true) return i1;
287
+ return sub;
288
+ }
289
+ }
290
+ }
291
+ return null;
292
+ }
293
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
294
+ setCount(id, count, className, style) {
295
+ const btn = query2(this.box).find(`#tb_${this.name}_item_${TsUtils.escapeId(id)} .tsg-tb-count > span`);
296
+ if (btn.length > 0) {
297
+ btn.removeClass(null).addClass(className ?? "").text(count);
298
+ btn.get(0).style.cssText = style ?? "";
299
+ this.last.badge[id] = {
300
+ className: className ?? "",
301
+ style: style ?? ""
302
+ };
303
+ const item = this.get(id);
304
+ item.count = count;
305
+ } else {
306
+ this.set(id, { count });
307
+ const after = query2(this.box).find(`#tb_${this.name}_item_${TsUtils.escapeId(id)} .tsg-tb-count > span`);
308
+ if (after.length === 0) return;
309
+ this.setCount(id, count, className, style);
310
+ }
311
+ }
312
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
313
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
314
+ show(...args) {
315
+ const effected = [];
316
+ args.forEach((item) => {
317
+ const it = this.get(item);
318
+ if (!it) return;
319
+ it.hidden = false;
320
+ effected.push(String(item).split(":")[0]);
321
+ if (it.type == "group") {
322
+ it.items.forEach((itm) => this.show(itm.id));
323
+ }
324
+ });
325
+ this._refresh({ effected, resize: true });
326
+ return effected;
327
+ }
328
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
329
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
330
+ hide(...args) {
331
+ const effected = [];
332
+ args.forEach((item) => {
333
+ const it = this.get(item);
334
+ if (!it) return;
335
+ it.hidden = true;
336
+ effected.push(String(item).split(":")[0]);
337
+ if (it.type == "group") {
338
+ it.items.forEach((itm) => this.hide(itm.id));
339
+ }
340
+ });
341
+ this._refresh({ effected, hideTooltip: true, resize: true });
342
+ return effected;
343
+ }
344
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
345
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
346
+ enable(...args) {
347
+ const effected = [];
348
+ args.forEach((item) => {
349
+ const it = this.get(item);
350
+ if (!it) return;
351
+ if (it.type == "group") {
352
+ it.items.forEach((itm) => this.enable(itm.id));
353
+ } else {
354
+ it.disabled = false;
355
+ effected.push(String(item).split(":")[0]);
356
+ }
357
+ });
358
+ this._refresh({ effected });
359
+ return effected;
360
+ }
361
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
362
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
363
+ disable(...args) {
364
+ const effected = [];
365
+ args.forEach((item) => {
366
+ const it = this.get(item);
367
+ if (!it) return;
368
+ if (it.type == "group") {
369
+ it.items.forEach((itm) => this.disable(itm.id));
370
+ } else {
371
+ it.disabled = true;
372
+ effected.push(String(item).split(":")[0]);
373
+ }
374
+ });
375
+ this._refresh({ effected, hideTooltip: true });
376
+ return effected;
377
+ }
378
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
379
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
380
+ check(...args) {
381
+ const effected = [];
382
+ args.forEach((item) => {
383
+ const it = this.get(item);
384
+ if (!it || String(item).indexOf(":") != -1) return;
385
+ if (it.type == "group") {
386
+ it.items.forEach((itm) => this.check(itm.id));
387
+ } else {
388
+ it.checked = true;
389
+ effected.push(String(item).split(":")[0]);
390
+ }
391
+ });
392
+ this._refresh({ effected });
393
+ return effected;
394
+ }
395
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
396
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
397
+ uncheck(...args) {
398
+ const effected = [];
399
+ args.forEach((item) => {
400
+ const it = this.get(item);
401
+ if (!it || String(item).indexOf(":") != -1) return;
402
+ if (["menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(it.type) && it.checked) {
403
+ TsTooltip.hide(this.name + "-drop");
404
+ }
405
+ if (it.type == "group") {
406
+ it.items.forEach((itm) => this.uncheck(itm.id));
407
+ } else {
408
+ it.checked = false;
409
+ effected.push(String(item).split(":")[0]);
410
+ }
411
+ });
412
+ this._refresh({ effected });
413
+ return effected;
414
+ }
415
+ /**
416
+ * Toggle the `checked` state of one or more items.
417
+ *
418
+ * State management only — does NOT fire events (no `onClick`, no `onChange`)
419
+ * and does NOT open drop / menu / color overlays. For full UI interaction
420
+ * including opening pickers, call `click(id)` instead.
421
+ *
422
+ * Per-item behaviour:
423
+ * - button / check / html / spacer / break: flips `it.checked`.
424
+ * - drop / menu / menu-radio / menu-check / color / text-color: if currently
425
+ * checked, closes the toolbar's `-drop` overlay via `TsTooltip.hide` before
426
+ * flipping. Same overlay-close path as `uncheck()`. Never opens overlays.
427
+ * - radio: emits `console.warn` and is skipped (would leave the group with
428
+ * no checked member). Use `check()` / `uncheck()` for radios.
429
+ * - group: recurses into `it.items` and toggles each child individually; the
430
+ * group container itself is never in the effected list.
431
+ * - sub-id with `:` notation: skipped (same guard as siblings).
432
+ * - missing id: silently skipped.
433
+ *
434
+ * @param args ids of items to toggle. Varargs, independent per id.
435
+ * @returns array of ids whose checked state actually flipped. Never `undefined`.
436
+ */
437
+ // any: array of heterogeneous runtime values; TsToolbar item shape varies by `type` at runtime
438
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
439
+ toggle(...args) {
440
+ const effected = [];
441
+ args.flat().forEach((item) => {
442
+ const it = this.get(item);
443
+ if (!it || String(item).indexOf(":") != -1) return;
444
+ if (it.type == "radio") {
445
+ console.warn(`TsToolbar.toggle: radio items are not supported, use check()/uncheck() instead. Item: ${item}`);
446
+ return;
447
+ }
448
+ if (it.type == "group") {
449
+ const childIds = it.items.map((itm) => itm.id);
450
+ const childEffected = this.toggle(...childIds);
451
+ effected.push(...childEffected);
452
+ return;
453
+ }
454
+ const newChecked = !it.checked;
455
+ if (["menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(it.type) && it.checked) {
456
+ TsTooltip.hide(this.name + "-drop");
457
+ }
458
+ it.checked = newChecked;
459
+ effected.push(String(item).split(":")[0]);
460
+ });
461
+ this._refresh({ effected });
462
+ return effected;
463
+ }
464
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
465
+ click(id, event) {
466
+ const tmp = String(id).split(":");
467
+ const it = this.get(tmp[0]);
468
+ let items = it && it.items ? TsUtils.normMenu.call(this, it.items, it) : [];
469
+ if (tmp.length > 1) {
470
+ const subItem = this.get(id);
471
+ if (subItem && !subItem.disabled) {
472
+ this.menuClick({ name: this.name, item: it, subItem, originalEvent: event });
473
+ }
474
+ return;
475
+ }
476
+ if (it && !it.disabled) {
477
+ const edata = this.trigger("click", {
478
+ target: id != null ? id : this.name,
479
+ item: it,
480
+ object: it,
481
+ originalEvent: event
482
+ });
483
+ if (edata.isCancelled === true) return;
484
+ items = it && it.items ? TsUtils.normMenu.call(this, it.items, it) : [];
485
+ const btn = "#tb_" + this.name + "_item_" + TsUtils.escapeId(it.id);
486
+ query2(this.box).find(btn).removeClass("down");
487
+ if (it.type == "radio") {
488
+ for (let i = 0; i < this.items.length; i++) {
489
+ const itt = this.items[i];
490
+ if (itt.type == "group") {
491
+ for (let i1 = 0; i1 < itt.items.length; i1++) {
492
+ const itt1 = itt.items[i1];
493
+ if (itt1 == null || itt1.id == it.id || itt1.type !== "radio") continue;
494
+ if (itt1.group == it.group && itt1.checked) {
495
+ itt1.checked = false;
496
+ this.refresh(itt1.id);
497
+ }
498
+ }
499
+ }
500
+ if (itt == null || itt.id == it.id || itt.type !== "radio") continue;
501
+ if (itt.group == it.group && itt.checked) {
502
+ itt.checked = false;
503
+ this.refresh(itt.id);
504
+ }
505
+ }
506
+ it.checked = true;
507
+ query2(this.box).find(btn).addClass("checked");
508
+ }
509
+ if (["menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(it.type)) {
510
+ this.tooltipHide(id);
511
+ if (it.checked) {
512
+ TsTooltip.hide(this.name + "-drop");
513
+ return;
514
+ } else {
515
+ const overlay = TsTooltip.get(this.name + "-drop");
516
+ if (overlay?.displayed) overlay.hide();
517
+ overlay?.listeners?.splice(0);
518
+ setTimeout(() => {
519
+ const hideDrop = (id2, _btn) => {
520
+ return () => {
521
+ this.set(id2, { checked: false });
522
+ };
523
+ };
524
+ const el = query2(this.box).find("#tb_" + this.name + "_item_" + TsUtils.escapeId(it.id));
525
+ if (!TsUtils.isPlainObject(it.overlay)) it.overlay = {};
526
+ if (it.type == "drop") {
527
+ ;
528
+ TsTooltip.show(TsUtils.extend({
529
+ html: it.html,
530
+ class: "tsg-white",
531
+ hideOn: ["doc-click"]
532
+ }, it.overlay, {
533
+ anchor: el[0],
534
+ name: this.name + "-drop",
535
+ data: { item: it, btn }
536
+ // any: cast-to-any for dynamic dispatch; TsToolbar item shape varies by `type` at runtime
537
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
538
+ })).hide(hideDrop(it.id, btn));
539
+ }
540
+ if (["menu", "menu-radio", "menu-check"].includes(it.type)) {
541
+ let menuType = "normal";
542
+ if (it.type == "menu-radio") {
543
+ menuType = "radio";
544
+ items?.forEach((item) => {
545
+ if (it.selected == item.id) item["checked"] = true;
546
+ else item["checked"] = false;
547
+ });
548
+ }
549
+ if (it.type == "menu-check") {
550
+ menuType = "check";
551
+ items?.forEach((item) => {
552
+ if (Array.isArray(it.selected) && it.selected.includes(item.id)) item["checked"] = true;
553
+ else item["checked"] = false;
554
+ });
555
+ }
556
+ ;
557
+ TsMenu.show(TsUtils.extend({
558
+ items,
559
+ selected: -1,
560
+ align: it.text ? "left" : "none"
561
+ // if there is no text, then no alignent
562
+ }, it.overlay, {
563
+ type: menuType,
564
+ name: this.name + "-drop",
565
+ anchor: el[0],
566
+ data: { item: it, btn }
567
+ // any: cast-to-any for dynamic dispatch; TsToolbar item shape varies by `type` at runtime
568
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
569
+ })).hide(hideDrop(it.id, btn)).remove((event2) => {
570
+ this.menuClick({
571
+ name: this.name,
572
+ remove: true,
573
+ item: it,
574
+ subItem: event2.detail.item,
575
+ originalEvent: event2
576
+ });
577
+ }).select((event2) => {
578
+ this.menuClick({
579
+ name: this.name,
580
+ item: it,
581
+ subItem: event2.detail.item,
582
+ originalEvent: event2
583
+ });
584
+ });
585
+ }
586
+ if (["color", "text-color"].includes(it.type)) {
587
+ ;
588
+ TsColor.show(TsUtils.extend({
589
+ color: it.color
590
+ }, it.overlay, {
591
+ anchor: el[0],
592
+ name: this.name + "-drop",
593
+ data: { item: it, btn }
594
+ // any: cast-to-any for dynamic dispatch; TsToolbar item shape varies by `type` at runtime
595
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
596
+ })).hide(hideDrop(it.id, btn)).liveUpdate((event2) => {
597
+ const edata2 = this.trigger("liveUpdate", { name: this.name, item: it, color: event2.detail.color });
598
+ edata2.finish();
599
+ }).select((event2) => {
600
+ if (event2.detail.color != null) {
601
+ this.colorClick({ name: this.name, item: it, color: event2.detail.color });
602
+ }
603
+ });
604
+ }
605
+ }, 0);
606
+ }
607
+ }
608
+ if (["check", "menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(it.type)) {
609
+ it.checked = !it.checked;
610
+ if (it.checked) {
611
+ query2(this.box).find(btn).addClass("checked");
612
+ } else {
613
+ query2(this.box).find(btn).removeClass("checked");
614
+ }
615
+ }
616
+ if (it.route) {
617
+ let route = String("/" + it.route).replace(/\/{2,}/g, "/");
618
+ const info = TsUtils.parseRoute(route);
619
+ if (info.keys.length > 0) {
620
+ for (let k = 0; k < info.keys.length; k++) {
621
+ const key = info.keys[k];
622
+ if (key == null) continue;
623
+ route = route.replace(new RegExp(":" + key.name, "g"), this.routeData[key.name]);
624
+ }
625
+ }
626
+ setTimeout(() => {
627
+ window.location.hash = route;
628
+ }, 1);
629
+ }
630
+ this.tooltipShow(id);
631
+ edata.finish();
632
+ }
633
+ }
634
+ // any: callback parameter — caller signature varies; TsToolbar item shape varies by `type` at runtime
635
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
636
+ scroll(direction, line, instant) {
637
+ return new Promise((resolve, _reject) => {
638
+ const scrollBox = query2(this.box).find(`.tsg-tb-line:nth-child(${line}) .tsg-scroll-wrapper`);
639
+ const scrollBoxEl = scrollBox.get(0);
640
+ const scrollLeft = scrollBoxEl.scrollLeft;
641
+ const right = scrollBox.find(".tsg-tb-right").get(0);
642
+ const width1 = scrollBox.parent().get(0).getBoundingClientRect().width;
643
+ const width2 = scrollLeft + right.offsetLeft + right.clientWidth;
644
+ switch (direction) {
645
+ case "left": {
646
+ let scrollPos = scrollLeft - width1 + 50;
647
+ if (scrollPos <= 0) scrollPos = 0;
648
+ scrollBoxEl.scrollTo({ top: 0, left: scrollPos, behavior: instant ? "auto" : "smooth" });
649
+ break;
650
+ }
651
+ case "right": {
652
+ let scrollPos = scrollLeft + width1 - 50;
653
+ if (scrollPos >= width2 - width1) scrollPos = width2 - width1;
654
+ scrollBoxEl.scrollTo({ top: 0, left: scrollPos, behavior: instant ? "auto" : "smooth" });
655
+ break;
656
+ }
657
+ }
658
+ setTimeout(() => {
659
+ this.resize();
660
+ resolve();
661
+ }, instant ? 0 : 600);
662
+ });
663
+ }
664
+ // any: callback parameter — caller signature varies; TsToolbar item shape varies by `type` at runtime
665
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
666
+ render(box) {
667
+ const time = Date.now();
668
+ if (typeof box == "string") box = query2(box).get(0);
669
+ const edata = this.trigger("render", { target: this.name, box: box ?? this.box });
670
+ if (edata.isCancelled === true) return;
671
+ if (box != null) {
672
+ this.unmount();
673
+ this.box = box;
674
+ }
675
+ if (!this.box) return;
676
+ if (!Array.isArray(this.right)) {
677
+ this.right = [this.right];
678
+ }
679
+ let html = "";
680
+ let line = 0;
681
+ for (let i = 0; i < this.items.length; i++) {
682
+ const it = this.items[i];
683
+ if (it == null) continue;
684
+ if (it.id == null) it.id = "item_" + i;
685
+ if (it.caption != null) {
686
+ console.log("NOTICE: toolbar item.caption property is deprecated, please use item.text. Item -> ", it);
687
+ }
688
+ if (it.hint != null) {
689
+ console.log("NOTICE: toolbar item.hint property is deprecated, please use item.tooltip. Item -> ", it);
690
+ }
691
+ if (i === 0 || it.type == "new-line") {
692
+ line++;
693
+ html += `
694
+ <div class="tsg-tb-line">
695
+ <div class="tsg-scroll-wrapper tsg-eaction" data-mousedown="resize">
696
+ <div class="tsg-tb-right">${this.right[line - 1] ?? ""}</div>
697
+ </div>
698
+ <div class="tsg-scroll-left tsg-eaction" data-click='["scroll", "left", "${line}"]'></div>
699
+ <div class="tsg-scroll-right tsg-eaction" data-click='["scroll", "right", "${line}"]'></div>
700
+ </div>
701
+ `;
702
+ }
703
+ it.line = line;
704
+ }
705
+ query2(this.box).attr("name", this.name).addClass("tsg-reset tsg-toolbar").html(html);
706
+ if (query2(this.box).length > 0) {
707
+ query2(this.box)[0].style.cssText += this["style"];
708
+ }
709
+ TsUtils.bindEvents(query2(this.box).find(".tsg-tb-line .tsg-eaction"), this);
710
+ this.last.observeResize = new ResizeObserver(() => {
711
+ this.resize();
712
+ });
713
+ this.last.observeResize.observe(this.box);
714
+ this.refresh();
715
+ this.resize();
716
+ edata.finish();
717
+ return Date.now() - time;
718
+ }
719
+ // any: callback parameter — caller signature varies; TsToolbar item shape varies by `type` at runtime
720
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
721
+ refresh(id) {
722
+ const time = Date.now();
723
+ const edata = this.trigger("refresh", { target: id != null ? id : this.name, item: this.get(id) });
724
+ if (edata.isCancelled === true) return;
725
+ let edata2;
726
+ if (id == null) {
727
+ for (let i = 0; i < this.items.length; i++) {
728
+ const it1 = this.items[i];
729
+ if (it1.id == null) it1.id = "item_" + i;
730
+ this.refresh(it1.id);
731
+ }
732
+ return;
733
+ }
734
+ const it = this.get(id);
735
+ if (it == null) return false;
736
+ if (typeof it.onRefresh == "function") {
737
+ edata2 = this.trigger("refresh", { target: id, item: it, object: it });
738
+ if (edata2.isCancelled === true) return;
739
+ }
740
+ const selector = `#tb_${this.name}_item_${TsUtils.escapeId(it.id)}`;
741
+ const btn = query2(this.box).find(selector);
742
+ const html = this.getItemHTML(it);
743
+ this.tooltipHide(id);
744
+ if (it.type == "spacer") {
745
+ query2(this.box).find(`.tsg-tb-line:nth-child(${it.line ?? 1})`).find(".tsg-tb-right").css("width", "auto");
746
+ }
747
+ if (btn.length === 0) {
748
+ const next = parseInt(this.get(id, true)) + 1;
749
+ let $next = query2(this.box).find(`#tb_${this.name}_item_${TsUtils.escapeId(this.items[next] ? this.items[next].id : "--")}`);
750
+ if ($next.length == 0) {
751
+ $next = query2(this.box).find(`.tsg-tb-line:nth-child(${it.line})`).find(".tsg-tb-right").before(html);
752
+ } else {
753
+ $next.after(html);
754
+ }
755
+ TsUtils.bindEvents(query2(this.box).find(`${selector}, ${selector} .tsg-eaction`), this);
756
+ } else {
757
+ query2(this.box).find(selector).replace(query.html(html));
758
+ const newBtn = query2(this.box).find(selector);
759
+ TsUtils.bindEvents(newBtn, this);
760
+ TsUtils.bindEvents(newBtn.find(".tsg-eaction"), this);
761
+ const overlays = TsTooltip.get(true);
762
+ if (overlays != null) Object.keys(overlays).forEach((key) => {
763
+ if (overlays[key]?.anchor == btn.get(0)) {
764
+ overlays[key].anchor = newBtn.get(0);
765
+ }
766
+ });
767
+ }
768
+ if (["menu", "menu-radio", "menu-check"].includes(it.type) && it.checked) {
769
+ const selected = Array.isArray(it.selected) ? it.selected : [it.selected];
770
+ const items = typeof it.items == "function" ? it.items(it) : [...it.items];
771
+ items.forEach((item) => {
772
+ if (selected.includes(item.id)) item.checked = true;
773
+ else item.checked = false;
774
+ });
775
+ TsMenu.update(this.name + "-drop", items);
776
+ }
777
+ if (typeof it.onRefresh == "function") {
778
+ edata2.finish();
779
+ }
780
+ edata.finish();
781
+ return Date.now() - time;
782
+ }
783
+ resize() {
784
+ const time = Date.now();
785
+ const edata = this.trigger("resize", { target: this.name });
786
+ if (edata.isCancelled === true) return;
787
+ query2(this.box).find(".tsg-tb-line").each((el) => {
788
+ const box = query2(el);
789
+ box.find(".tsg-scroll-left, .tsg-scroll-right").hide();
790
+ const scrollBox = box.find(".tsg-scroll-wrapper").get(0);
791
+ const $right = box.find(".tsg-tb-right");
792
+ const boxWidth = box.get(0).getBoundingClientRect().width;
793
+ const itemsWidth = $right.length > 0 ? $right[0].offsetLeft + $right[0].clientWidth : 0;
794
+ if (boxWidth < itemsWidth) {
795
+ if (scrollBox.scrollLeft > 0) {
796
+ box.find(".tsg-scroll-left").show();
797
+ }
798
+ if (boxWidth < itemsWidth - scrollBox.scrollLeft) {
799
+ box.find(".tsg-scroll-right").show();
800
+ }
801
+ }
802
+ });
803
+ edata.finish();
804
+ return Date.now() - time;
805
+ }
806
+ destroy() {
807
+ const edata = this.trigger("destroy", { target: this.name });
808
+ if (edata.isCancelled === true) return;
809
+ TsTooltip.hide(this.name + "-tooltip");
810
+ TsTooltip.hide(this.name + "-drop");
811
+ if (query2(this.box).find(".tsg-scroll-wrapper").length > 0) {
812
+ this.unmount();
813
+ }
814
+ delete TsUi[this.name];
815
+ edata.finish();
816
+ }
817
+ unmount() {
818
+ super.unmount();
819
+ this.last.observeResize?.disconnect();
820
+ }
821
+ // ========================================
822
+ // --- Internal Functions
823
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
824
+ getItemHTML(item) {
825
+ let html = "";
826
+ if (item.caption != null && item.text == null) item.text = item.caption;
827
+ if (item.text == null) item.text = "";
828
+ if (item.tooltip == null && item.hint != null) item.tooltip = item.hint;
829
+ if (item.tooltip == null) item.tooltip = "";
830
+ if (typeof item.get !== "function" && (Array.isArray(item.items) || typeof item.items == "function")) {
831
+ item.get = function get(id) {
832
+ let tmp = item.items;
833
+ if (typeof tmp == "function") tmp = item.items(item);
834
+ return tmp.find((it) => it.id == id ? true : false);
835
+ };
836
+ }
837
+ let icon = "";
838
+ let text = typeof item.text == "function" ? item.text.call(this, item) : item.text;
839
+ if (item.icon) {
840
+ icon = item.icon;
841
+ if (typeof item.icon == "function") {
842
+ icon = item.icon.call(this, item);
843
+ }
844
+ if (String(icon).slice(0, 1) !== "<") {
845
+ icon = `<span class="${icon}" ${item.icon_style ? `style="${item.icon_style}"` : ""}></span>`;
846
+ }
847
+ icon = `<div class="tsg-tb-icon">${icon}</div>`;
848
+ }
849
+ const classes = ["tsg-tb-button", "tsg-eaction"];
850
+ if (item.checked) classes.push("checked");
851
+ if (item.disabled) classes.push("disabled");
852
+ if (item.hidden) classes.push("hidden");
853
+ if (!icon) classes.push("no-icon");
854
+ switch (item.type) {
855
+ case "color":
856
+ case "text-color":
857
+ if (typeof item.color == "string") {
858
+ if (item.color.slice(0, 1) == "#") item.color = item.color.slice(1);
859
+ if ([3, 6, 8].includes(item.color.length)) item.color = "#" + item.color;
860
+ }
861
+ if (item.type == "color") {
862
+ text = `<span class="tsg-tb-color-box" style="background-color: ${item.color != null ? item.color : "#fff"}"></span>
863
+ ${item.text ? `<div style="margin-left: 17px;">${TsUtils.lang(item.text)}</div>` : ""}`;
864
+ }
865
+ if (item.type == "text-color") {
866
+ const color = item.color != null ? item.color : "#444";
867
+ let bcolor = item.backColor;
868
+ if (item.backColor === true) {
869
+ bcolor = "#fff";
870
+ if (TsUtils.colorContrastValue("#fff", color) < 2) {
871
+ bcolor = "#555";
872
+ }
873
+ }
874
+ text = `<span style="color: ${color}">${item.text ? TsUtils.lang(item.text) : item.backColor ? `<b style="background-color: ${bcolor ?? "transparent"}; padding: 2px 5px; border-radius: 3px;">Ab</b>` : "<b>Ab</b>"}</span>`;
875
+ }
876
+ // falls through
877
+ case "menu":
878
+ case "menu-check":
879
+ case "menu-radio":
880
+ case "button":
881
+ case "check":
882
+ case "radio":
883
+ case "label":
884
+ case "drop": {
885
+ const arrow = item.arrow === true || item.arrow !== false && ["menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(item.type);
886
+ html = `
887
+ <div id="tb_${this.name}_item_${item.id}" class="${classes.join(" ")} ${item.class ? item.class : ""}"
888
+ style="${item.hidden ? "display: none;" : ""} ${item.type == "label" ? (item.style ?? "") + ";" : ""}"
889
+ ${!item.disabled ? `data-click='["click","${item.id}", "event"]'
890
+ data-mouseenter='["mouseAction", "event", "this", "Enter", "${item.id}"]'
891
+ data-mouseleave='["mouseAction", "event", "this", "Leave", "${item.id}"]'
892
+ data-mousedown='["mouseAction", "event", "this", "Down", "${item.id}"]'
893
+ data-mouseup='["mouseAction", "event", "this", "Up", "${item.id}"]'` : ""}
894
+ >
895
+ ${icon}
896
+ ${text != "" && text != null || item.count != null || arrow ? `<div class="tsg-tb-text" style="${item.type != "label" ? item.style ?? "" : ""}; ${!text ? "padding-left: 0; margin-left: 23px;" : ""}">
897
+ ${TsUtils.lang(text)}
898
+ ${item.count != null ? TsUtils.stripSpaces(`
899
+ <span class="tsg-tb-count">
900
+ <span class="${this.last.badge[item.id] ? this.last.badge[item.id].className ?? "" : ""}"
901
+ style="${this.last.badge[item.id] ? this.last.badge[item.id].style ?? "" : ""}">${item.count}</span>
902
+ </span>`) : ""}
903
+ ${arrow ? `<span class="tsg-tb-down" ${!text && !item.count ? 'style="margin-left: -3px"' : ""}><span></span></span>` : ""}
904
+ </div>` : ""}
905
+ </div>
906
+ `;
907
+ break;
908
+ }
909
+ case "break": {
910
+ html = `<div id="tb_${this.name}_item_${item.id}" class="tsg-tb-break"
911
+ style="${item.hidden ? "display: none" : ""}; ${item.style ? item.style : ""}">
912
+ &#160;
913
+ </div>`;
914
+ break;
915
+ }
916
+ case "spacer": {
917
+ html = `<div id="tb_${this.name}_item_${item.id}" class="tsg-tb-spacer"
918
+ style="${item.hidden ? "display: none" : ""}; ${item.style ? item.style : ""}">
919
+ </div>`;
920
+ break;
921
+ }
922
+ case "html": {
923
+ html = `<div id="tb_${this.name}_item_${item.id}" class="tsg-tb-html ${classes.join(" ")}"
924
+ style="${item.hidden ? "display: none" : ""}; ${item.style ? item.style : ""}">
925
+ ${typeof item.html == "function" ? item.html.call(this, item) : item.html}
926
+ </div>`;
927
+ break;
928
+ }
929
+ case "input": {
930
+ const ph = item.placeholder;
931
+ let val = item.value;
932
+ if (item.spinner && typeof item.spinner == "object") {
933
+ item.input ??= {};
934
+ Object.assign(item.input, item.spinner, { spinner: true });
935
+ }
936
+ if (val != null && String(val).trim() !== "" && item.input?.spinner) {
937
+ const step = item.input?.step ?? 1;
938
+ const prec = item.input?.precision ?? String(step).split(".")[1]?.length ?? 0;
939
+ val = isNaN(val) ? val : Number(val).toFixed(prec);
940
+ }
941
+ html = `<div id="tb_${this.name}_item_${item.id}" class="tsg-tb-input tsg-eaction ${classes.join(" ")}"
942
+ style="${item.hidden ? "display: none" : ""}; ${item.style ? item.style : ""}"
943
+ >
944
+ <span class="tsg-input-label">${item.text ?? ""}</span>
945
+ ${item.input?.spinner ? `<span class="tsg-spinner-dec tsg-eaction" data-click='["spinner", "${item.id}", "dec", "event"]'> \u2013 </span>` : ""}
946
+ <input class="tsg-toolbar-input tsg-eaction ${item.input?.spinner ? "tsg-has-spinner" : ""}"
947
+ ${ph ? `placeholder="${ph}"` : ""} style="${item.input?.style ?? ""}"
948
+ value="${val ?? ""}${item.input?.suffix ?? ""}" ${item.input?.attrs ?? ""}
949
+ data-input='["change", "${item.id}", "this", true]'
950
+ data-change='["change", "${item.id}", "this"]'
951
+ data-keydown='["spinner", "${item.id}", "key", "event"]'
952
+ data-mouseenter='["mouseAction", "event", "this", "Enter", "${item.id}"]'
953
+ data-mouseleave='["mouseAction", "event", "this", "Leave", "${item.id}"]'
954
+ >
955
+ ${item.input?.spinner ? `<span class="tsg-spinner-inc tsg-eaction" data-click='["spinner", "${item.id}", "inc", "event"]'> + </span>` : ""}
956
+ </div>`;
957
+ break;
958
+ }
959
+ case "group": {
960
+ html = `<div id="tb_${this.name}_item_${item.id}" class="tsg-tb-group"
961
+ style="display: ${item.hidden ? "none" : "flex"}; ${item.style ? item.style : ""}">`;
962
+ if (Array.isArray(item.items)) {
963
+ item.items.forEach((it) => {
964
+ html += this.getItemHTML(it);
965
+ });
966
+ } else {
967
+ console.log("ERROR: toolbar group is empty");
968
+ }
969
+ html += "</div>";
970
+ }
971
+ }
972
+ return html;
973
+ }
974
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
975
+ spinner(id, action, event) {
976
+ const it = this.get(id);
977
+ let inc = 0;
978
+ const edata = this.trigger("keyDown", { id, item: it, originalEvent: event });
979
+ switch (action) {
980
+ case "inc": {
981
+ inc = it.input?.step ?? 1;
982
+ break;
983
+ }
984
+ case "dec": {
985
+ inc = -(it.input?.step ?? 1);
986
+ break;
987
+ }
988
+ case "key": {
989
+ if (it.input?.spinner || it.input?.step != null) {
990
+ let mult = 1;
991
+ if (event.shiftKey || event.metaKey) mult = 10;
992
+ if (event.altKey) mult = 0.1;
993
+ switch (event.key) {
994
+ case "ArrowUp": {
995
+ inc = (it.input?.step ?? 1) * mult;
996
+ event.preventDefault();
997
+ break;
998
+ }
999
+ case "ArrowDown": {
1000
+ inc = -(it.input?.step ?? 1) * mult;
1001
+ event.preventDefault();
1002
+ break;
1003
+ }
1004
+ }
1005
+ }
1006
+ break;
1007
+ }
1008
+ }
1009
+ if (inc !== 0) {
1010
+ this.change(id, parseFloat(it.value ?? 0) + inc);
1011
+ }
1012
+ edata.finish();
1013
+ }
1014
+ // any: callback parameter — caller signature varies; TsToolbar item shape varies by `type` at runtime
1015
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1016
+ change(id, value, dynamic) {
1017
+ const it = this.get(id);
1018
+ const input = query2(this.box).find("#tb_" + this.name + "_item_" + TsUtils.escapeId(id)).find("input.tsg-toolbar-input");
1019
+ if (value instanceof HTMLInputElement) {
1020
+ value = value.value;
1021
+ }
1022
+ if (value == null) value = input.val();
1023
+ if (it.input?.spinner || it.input?.min != null || it.input?.max != null || it.input?.step != null) {
1024
+ value = parseFloat(value);
1025
+ }
1026
+ if (it.input?.suffix != null) {
1027
+ const strValue = String(value);
1028
+ if (strValue.substr(-it.input.suffix.length) == it.input.suffix) {
1029
+ value = strValue.substr(0, strValue.length - it.input.suffix.length);
1030
+ }
1031
+ }
1032
+ if (it.input?.min != null && it.input.min > value) {
1033
+ value = it.input.min;
1034
+ }
1035
+ if (it.input?.max != null && it.input.max < value) {
1036
+ value = it.input.max;
1037
+ }
1038
+ if (it.input?.step != null) {
1039
+ if (isNaN(value)) value = it.input.min ?? 0;
1040
+ const step = it.input.step ?? 1;
1041
+ const prec = it.input.precision ?? String(step).split(".")[1]?.length ?? 0;
1042
+ value = Number(value).toFixed(prec);
1043
+ }
1044
+ const edata = this.trigger(dynamic ? "input" : "change", { target: id, id, value, item: it });
1045
+ if (edata.isCancelled) {
1046
+ return;
1047
+ }
1048
+ it.value = value;
1049
+ let suffix = "";
1050
+ if (it.input?.suffix != null && String(value).substr(-it.input.suffix.length) != it.input.suffix) {
1051
+ suffix = it.input.suffix;
1052
+ }
1053
+ if (!dynamic) input.val(value + suffix);
1054
+ edata.finish();
1055
+ }
1056
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1057
+ tooltipShow(id) {
1058
+ if (this.tooltip == null) return;
1059
+ const el = query2(this.box).find("#tb_" + this.name + "_item_" + TsUtils.escapeId(id)).get(0);
1060
+ const item = this.get(id);
1061
+ const overlay = typeof this.tooltip == "string" ? { position: this.tooltip } : this.tooltip;
1062
+ let txt = item.tooltip;
1063
+ if (typeof txt == "function") txt = txt.call(this, item);
1064
+ if (["menu", "menu-radio", "menu-check", "drop", "color", "text-color"].includes(item.type) && item.checked == true) {
1065
+ return;
1066
+ }
1067
+ TsTooltip.show({
1068
+ anchor: el,
1069
+ name: this.name + "-tooltip",
1070
+ html: txt,
1071
+ ...overlay
1072
+ });
1073
+ return;
1074
+ }
1075
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1076
+ tooltipHide(_id) {
1077
+ if (this.tooltip == null) return;
1078
+ TsTooltip.hide(this.name + "-tooltip");
1079
+ }
1080
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1081
+ menuClick(event) {
1082
+ if (event.item && !event.item.disabled) {
1083
+ const edata = this.trigger(event.remove !== true ? "click" : "remove", {
1084
+ target: event.item.id + ":" + event.subItem.id,
1085
+ item: event.item,
1086
+ subItem: event.subItem,
1087
+ originalEvent: event.originalEvent
1088
+ });
1089
+ if (edata.isCancelled === true) return;
1090
+ const it = event.subItem;
1091
+ const item = this.get(event.item.id);
1092
+ let items = item.items;
1093
+ if (typeof items == "function") items = item.items();
1094
+ if (item.type == "menu") {
1095
+ item.selected = it.id;
1096
+ }
1097
+ if (item.type == "menu-radio") {
1098
+ item.selected = it.id;
1099
+ if (Array.isArray(items)) {
1100
+ items.forEach((item2) => {
1101
+ if (item2.checked === true) delete item2.checked;
1102
+ if (Array.isArray(item2.items)) {
1103
+ item2.items.forEach((item3) => {
1104
+ if (item3.checked === true) delete item3.checked;
1105
+ });
1106
+ }
1107
+ });
1108
+ }
1109
+ it.checked = true;
1110
+ }
1111
+ if (item.type == "menu-check") {
1112
+ if (!Array.isArray(item.selected)) item.selected = [];
1113
+ if (it.group == null) {
1114
+ const ind = item.selected.indexOf(it.id);
1115
+ if (ind == -1) {
1116
+ item.selected.push(it.id);
1117
+ it.checked = true;
1118
+ } else {
1119
+ item.selected.splice(ind, 1);
1120
+ it.checked = false;
1121
+ }
1122
+ } else if (it.group === false) {
1123
+ } else {
1124
+ const unchecked = [];
1125
+ const ind = item.selected.indexOf(it.id);
1126
+ const checkNested = (items2) => {
1127
+ items2.forEach((sub) => {
1128
+ if (sub.group === it.group) {
1129
+ const ind2 = item.selected.indexOf(sub.id);
1130
+ if (ind2 != -1) {
1131
+ if (sub.id != it.id) unchecked.push(sub.id);
1132
+ item.selected.splice(ind2, 1);
1133
+ }
1134
+ }
1135
+ if (Array.isArray(sub.items)) checkNested(sub.items);
1136
+ });
1137
+ };
1138
+ checkNested(items);
1139
+ if (ind == -1) {
1140
+ item.selected.push(it.id);
1141
+ it.checked = true;
1142
+ }
1143
+ }
1144
+ }
1145
+ if (typeof it.route == "string") {
1146
+ let route = it.route !== "" ? String("/" + it.route).replace(/\/{2,}/g, "/") : "";
1147
+ const info = TsUtils.parseRoute(route);
1148
+ if (info.keys.length > 0) {
1149
+ for (let k = 0; k < info.keys.length; k++) {
1150
+ const key = info.keys[k];
1151
+ if (key == null || this.routeData[key.name] == null) continue;
1152
+ route = route.replace(new RegExp(":" + key.name, "g"), this.routeData[key.name]);
1153
+ }
1154
+ }
1155
+ setTimeout(() => {
1156
+ window.location.hash = route;
1157
+ }, 1);
1158
+ }
1159
+ this.refresh(event.item.id);
1160
+ edata.finish();
1161
+ }
1162
+ }
1163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1164
+ colorClick(event) {
1165
+ if (event.item && !event.item.disabled) {
1166
+ const edata = this.trigger("click", { target: event.item.id, item: event.item, color: event.color, final: true });
1167
+ if (edata.isCancelled === true) return;
1168
+ event.item.color = event.color;
1169
+ this.refresh(event.item.id);
1170
+ edata.finish();
1171
+ }
1172
+ }
1173
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1174
+ mouseAction(event, target, action, id) {
1175
+ const btn = this.get(id);
1176
+ const edata = this.trigger("mouse" + action, { target: id, item: btn, object: btn, originalEvent: event });
1177
+ if (edata.isCancelled === true || btn.disabled || btn.hidden) {
1178
+ edata.finish();
1179
+ return;
1180
+ }
1181
+ switch (action) {
1182
+ case "Enter":
1183
+ if (!["label", "input"].includes(btn.type)) {
1184
+ query2(target).addClass("over");
1185
+ }
1186
+ this.tooltipShow(id);
1187
+ break;
1188
+ case "Leave":
1189
+ if (!["label", "input"].includes(btn.type)) {
1190
+ query2(target).removeClass("over down");
1191
+ }
1192
+ this.tooltipHide(id);
1193
+ break;
1194
+ case "Down":
1195
+ if (!["label", "input"].includes(btn.type)) {
1196
+ query2(target).addClass("down");
1197
+ }
1198
+ break;
1199
+ case "Up":
1200
+ if (!["label", "input"].includes(btn.type)) {
1201
+ query2(target).removeClass("down");
1202
+ }
1203
+ break;
1204
+ }
1205
+ edata.finish();
1206
+ }
1207
+ };
1208
+
1209
+ export {
1210
+ TsToolbar
1211
+ };
1212
+ //# sourceMappingURL=chunk-LUSNRF73.js.map