tsgrid-ui 2.7.0 → 2.9.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.
- package/CHANGELOG.md +229 -0
- package/dist/base.d.ts +148 -0
- package/dist/base.es6.js +11 -0
- package/dist/base.es6.js.map +1 -0
- package/dist/chunks/chunk-26XP2XU3.js +1795 -0
- package/dist/chunks/chunk-26XP2XU3.js.map +1 -0
- package/dist/chunks/chunk-3NYH6545.js +2423 -0
- package/dist/chunks/chunk-3NYH6545.js.map +1 -0
- package/dist/chunks/chunk-BIB3X2TW.js +1638 -0
- package/dist/chunks/chunk-BIB3X2TW.js.map +1 -0
- package/dist/chunks/chunk-DXZJHS4M.js +1283 -0
- package/dist/chunks/chunk-DXZJHS4M.js.map +1 -0
- package/dist/chunks/chunk-EVZMMVXO.js +1212 -0
- package/dist/chunks/chunk-EVZMMVXO.js.map +1 -0
- package/dist/chunks/chunk-GJD5NFWQ.js +2305 -0
- package/dist/chunks/chunk-GJD5NFWQ.js.map +1 -0
- package/dist/chunks/chunk-IYF3Q7GX.js +127 -0
- package/dist/chunks/chunk-IYF3Q7GX.js.map +1 -0
- package/dist/chunks/chunk-OFASTA2A.js +2980 -0
- package/dist/chunks/chunk-OFASTA2A.js.map +1 -0
- package/dist/chunks/chunk-OMLGN735.js +677 -0
- package/dist/chunks/chunk-OMLGN735.js.map +1 -0
- package/dist/chunks/chunk-WKSLGUB3.js +1127 -0
- package/dist/chunks/chunk-WKSLGUB3.js.map +1 -0
- package/dist/chunks/chunk-YBY52G2U.js +849 -0
- package/dist/chunks/chunk-YBY52G2U.js.map +1 -0
- package/dist/field.d.ts +329 -0
- package/dist/field.es6.js +11 -0
- package/dist/field.es6.js.map +1 -0
- package/dist/form.d.ts +162 -0
- package/dist/form.es6.js +14 -0
- package/dist/form.es6.js.map +1 -0
- package/dist/layout.d.ts +108 -0
- package/dist/layout.es6.js +13 -0
- package/dist/layout.es6.js.map +1 -0
- package/dist/locale.d.ts +30 -0
- package/dist/locale.es6.js +7 -0
- package/dist/locale.es6.js.map +1 -0
- package/dist/metafile-esm.json +1 -0
- package/dist/popup.d.ts +92 -0
- package/dist/popup.es6.js +18 -0
- package/dist/popup.es6.js.map +1 -0
- package/dist/query-CKGg5Ugv.d.ts +81 -0
- package/dist/sidebar.d.ts +138 -0
- package/dist/sidebar.es6.js +11 -0
- package/dist/sidebar.es6.js.map +1 -0
- package/dist/tabs.d.ts +63 -0
- package/dist/tabs.es6.js +11 -0
- package/dist/tabs.es6.js.map +1 -0
- package/dist/toolbar.d.ts +97 -0
- package/dist/toolbar.es6.js +11 -0
- package/dist/toolbar.es6.js.map +1 -0
- package/dist/tooltip.d.ts +322 -0
- package/dist/tooltip.es6.js +18 -0
- package/dist/tooltip.es6.js.map +1 -0
- package/dist/tsgrid-ui.css +2 -2
- package/dist/tsgrid-ui.d.ts +16 -2004
- package/dist/tsgrid-ui.es6.js +7750 -23831
- package/dist/tsgrid-ui.es6.js.map +1 -1
- package/dist/tsgrid-ui.es6.min.js +28 -28
- package/dist/tsgrid-ui.js +103 -25
- package/dist/tsgrid-ui.min.css +2 -2
- package/dist/tsgrid-ui.min.js +24 -24
- package/dist/tsutils-message-CogFtVtO.d.ts +82 -0
- package/dist/utils.d.ts +418 -0
- package/dist/utils.es6.js +14 -0
- package/dist/utils.es6.js.map +1 -0
- package/package.json +26 -5
|
@@ -0,0 +1,2980 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TsUtils
|
|
3
|
+
} from "./chunk-3NYH6545.js";
|
|
4
|
+
import {
|
|
5
|
+
TsBase,
|
|
6
|
+
query
|
|
7
|
+
} from "./chunk-DXZJHS4M.js";
|
|
8
|
+
|
|
9
|
+
// src/tstooltip.ts
|
|
10
|
+
var query2 = query;
|
|
11
|
+
var Tooltip = class _Tooltip {
|
|
12
|
+
// no need to extend TsBase, as each individual tooltip extends it
|
|
13
|
+
static active = {};
|
|
14
|
+
defaults;
|
|
15
|
+
// any: setColor is assigned dynamically inside ColorTooltip.initControls closure
|
|
16
|
+
setColor;
|
|
17
|
+
// optional hook — overridden in subclasses; declared as method stub to allow subclass override
|
|
18
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
initControls(_overlay) {
|
|
21
|
+
}
|
|
22
|
+
constructor() {
|
|
23
|
+
this.defaults = {
|
|
24
|
+
name: null,
|
|
25
|
+
// name for the overlay, otherwise input id is used
|
|
26
|
+
html: "",
|
|
27
|
+
// text or html
|
|
28
|
+
style: "",
|
|
29
|
+
// additional style for the overlay
|
|
30
|
+
class: "",
|
|
31
|
+
// add class for tsg-tooltip-body
|
|
32
|
+
position: "top|bottom",
|
|
33
|
+
// can be left, right, top, bottom
|
|
34
|
+
draggable: false,
|
|
35
|
+
// if true, then tooltip can be move with mouse
|
|
36
|
+
align: "",
|
|
37
|
+
// can be: both, both:XX left, right, both, top, bottom
|
|
38
|
+
anchor: null,
|
|
39
|
+
// element it is attached to, if anchor is body, then it is context menu
|
|
40
|
+
contextMenu: false,
|
|
41
|
+
// if true, then it is context menu
|
|
42
|
+
anchorClass: "",
|
|
43
|
+
// add class for anchor when tooltip is shown
|
|
44
|
+
anchorStyle: "",
|
|
45
|
+
// add style for anchor when tooltip is shown
|
|
46
|
+
autoShow: false,
|
|
47
|
+
// if autoShow true, then tooltip will show on mouseEnter and hide on mouseLeave
|
|
48
|
+
autoShowOn: null,
|
|
49
|
+
// when options.autoShow = true, mouse event to show on
|
|
50
|
+
autoHideOn: null,
|
|
51
|
+
// when options.autoShow = true, mouse event to hide on
|
|
52
|
+
arrowSize: 8,
|
|
53
|
+
// size of the carret
|
|
54
|
+
screenMargin: 2,
|
|
55
|
+
// min margin from screen to tooltip
|
|
56
|
+
autoResize: true,
|
|
57
|
+
// auto resize based on content size and available size
|
|
58
|
+
margin: 1,
|
|
59
|
+
// distance from the anchor
|
|
60
|
+
offsetX: 0,
|
|
61
|
+
// delta for left coordinate
|
|
62
|
+
offsetY: 0,
|
|
63
|
+
// delta for top coordinate
|
|
64
|
+
maxWidth: null,
|
|
65
|
+
// max width
|
|
66
|
+
maxHeight: null,
|
|
67
|
+
// max height
|
|
68
|
+
hideOn: null,
|
|
69
|
+
// events when to hide tooltip, ['doc-click', 'tooltip-click', 'focus-change', 'select', 'item-remove', ... or any standard event on the anchor],
|
|
70
|
+
onThen: null,
|
|
71
|
+
// called when displayed
|
|
72
|
+
onShow: null,
|
|
73
|
+
// callBack when shown
|
|
74
|
+
onHide: null,
|
|
75
|
+
// callBack when hidden
|
|
76
|
+
onUpdate: null,
|
|
77
|
+
// callback when tooltip gets updated
|
|
78
|
+
onMove: null
|
|
79
|
+
// callback when tooltip is moved
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
static observeRemove = new MutationObserver((_mutations) => {
|
|
83
|
+
let cnt = 0;
|
|
84
|
+
Object.keys(_Tooltip.active).forEach((name) => {
|
|
85
|
+
const overlay = _Tooltip.active[name];
|
|
86
|
+
if (overlay?.displayed) {
|
|
87
|
+
if (!overlay.anchor || !overlay.anchor.isConnected) {
|
|
88
|
+
overlay.hide();
|
|
89
|
+
} else {
|
|
90
|
+
cnt++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
if (cnt === 0) {
|
|
95
|
+
_Tooltip.observeRemove.disconnect();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
+
trigger(event, data) {
|
|
100
|
+
if (arguments.length == 2) {
|
|
101
|
+
const type = event;
|
|
102
|
+
event = data;
|
|
103
|
+
data.type = type;
|
|
104
|
+
}
|
|
105
|
+
if (event.overlay) {
|
|
106
|
+
return event.overlay.trigger(event);
|
|
107
|
+
} else {
|
|
108
|
+
console.log("ERROR: cannot find overlay where to trigger events");
|
|
109
|
+
return { finish: () => {
|
|
110
|
+
} };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
get(name) {
|
|
114
|
+
if (arguments.length == 0) {
|
|
115
|
+
return Object.keys(_Tooltip.active);
|
|
116
|
+
} else if (name === true) {
|
|
117
|
+
return _Tooltip.active;
|
|
118
|
+
} else {
|
|
119
|
+
return _Tooltip.active[(name ?? "").replace(/[\s\.#]/g, "_")];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
attach(anchorArg, textArg) {
|
|
123
|
+
let anchor = anchorArg;
|
|
124
|
+
let text = textArg;
|
|
125
|
+
let options;
|
|
126
|
+
let overlay;
|
|
127
|
+
const self = this;
|
|
128
|
+
if (arguments.length == 0) {
|
|
129
|
+
return;
|
|
130
|
+
} else if (arguments.length == 1 && anchor instanceof Object) {
|
|
131
|
+
options = anchor;
|
|
132
|
+
anchor = options.anchor;
|
|
133
|
+
} else if (arguments.length === 2 && typeof text === "string") {
|
|
134
|
+
options = { anchor, html: text };
|
|
135
|
+
text = options.html;
|
|
136
|
+
} else if (arguments.length === 2 && text != null && typeof text === "object") {
|
|
137
|
+
options = text;
|
|
138
|
+
text = options.html;
|
|
139
|
+
}
|
|
140
|
+
options = TsUtils.extend({}, this.defaults, options || {});
|
|
141
|
+
if (!text && options.text) text = options.text;
|
|
142
|
+
if (!text && options.html) text = options.html;
|
|
143
|
+
delete options.anchor;
|
|
144
|
+
let name = options.name ? options.name : anchor?.id;
|
|
145
|
+
if (anchor == document || anchor == null) {
|
|
146
|
+
anchor = document.body;
|
|
147
|
+
}
|
|
148
|
+
if (options.contextMenu) {
|
|
149
|
+
anchor = document.body;
|
|
150
|
+
name = name ?? "context-menu";
|
|
151
|
+
}
|
|
152
|
+
if (!name) {
|
|
153
|
+
name = "noname-" + Object.keys(_Tooltip.active).length;
|
|
154
|
+
console.log("NOTICE: name property is not defined for tooltip, could lead to too many instances");
|
|
155
|
+
}
|
|
156
|
+
name = name.replace(/[\s\.#]/g, "_");
|
|
157
|
+
if (_Tooltip.active[name]) {
|
|
158
|
+
overlay = _Tooltip.active[name];
|
|
159
|
+
overlay.prevOptions = overlay.options;
|
|
160
|
+
overlay.options = options;
|
|
161
|
+
overlay.anchor = anchor;
|
|
162
|
+
if (overlay.prevOptions.html != overlay.options.html || overlay.prevOptions.class != overlay.options.class || overlay.prevOptions.style != overlay.options.style) {
|
|
163
|
+
overlay.needsUpdate = true;
|
|
164
|
+
}
|
|
165
|
+
options = overlay.options;
|
|
166
|
+
Object.keys(overlay).forEach((key) => {
|
|
167
|
+
const val = overlay[key];
|
|
168
|
+
if (key.startsWith("on") && typeof val == "function") {
|
|
169
|
+
delete overlay[key];
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
overlay = new TsBase();
|
|
174
|
+
Object.assign(overlay, {
|
|
175
|
+
id: "w2overlay-" + name,
|
|
176
|
+
name,
|
|
177
|
+
options,
|
|
178
|
+
anchor,
|
|
179
|
+
self,
|
|
180
|
+
displayed: false,
|
|
181
|
+
tmp: {
|
|
182
|
+
observeTooltipResize: new ResizeObserver(() => {
|
|
183
|
+
this.resize(overlay.name);
|
|
184
|
+
}),
|
|
185
|
+
observeAnchorResize: new ResizeObserver(() => {
|
|
186
|
+
this.resize(overlay.name);
|
|
187
|
+
}),
|
|
188
|
+
observeAnchorMove: new MutationObserver((mutations) => {
|
|
189
|
+
const target = mutations[0].target;
|
|
190
|
+
const currRect = target.getBoundingClientRect();
|
|
191
|
+
const lastRect = target._lastBoundingRect;
|
|
192
|
+
if (!target._lastBoundingRect) {
|
|
193
|
+
target._lastBoundingRect = currRect;
|
|
194
|
+
} else if (currRect.left !== lastRect.left || currRect.top !== lastRect.top) {
|
|
195
|
+
this.resize(overlay.name);
|
|
196
|
+
target._lastBoundingRect = currRect;
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
},
|
|
200
|
+
hide() {
|
|
201
|
+
self.hide(name);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
_Tooltip.active[name] = overlay;
|
|
205
|
+
}
|
|
206
|
+
Object.keys(overlay.options).forEach((key) => {
|
|
207
|
+
const val = overlay.options[key];
|
|
208
|
+
if (key.startsWith("on") && typeof val == "function") {
|
|
209
|
+
overlay[key] = val;
|
|
210
|
+
delete overlay.options[key];
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
if (options.autoShow === true) {
|
|
214
|
+
options.autoShowOn = options.autoShowOn ?? "mouseenter";
|
|
215
|
+
options.autoHideOn = options.autoHideOn ?? "mouseleave";
|
|
216
|
+
options.autoShow = false;
|
|
217
|
+
options._keep = true;
|
|
218
|
+
}
|
|
219
|
+
if (options.autoShowOn) {
|
|
220
|
+
const scope = "autoShow-" + overlay.name;
|
|
221
|
+
query2(anchor).off(`.${scope}`).on(`${options.autoShowOn}.${scope}`, (event) => {
|
|
222
|
+
self.show(overlay.name);
|
|
223
|
+
event.stopPropagation();
|
|
224
|
+
});
|
|
225
|
+
delete options.autoShowOn;
|
|
226
|
+
options._keep = true;
|
|
227
|
+
}
|
|
228
|
+
if (options.autoHideOn) {
|
|
229
|
+
const scope = "autoHide-" + overlay.name;
|
|
230
|
+
query2(anchor).off(`.${scope}`).on(`${options.autoHideOn}.${scope}`, (event) => {
|
|
231
|
+
self.hide(overlay.name);
|
|
232
|
+
event.stopPropagation();
|
|
233
|
+
});
|
|
234
|
+
delete options.autoHideOn;
|
|
235
|
+
options._keep = true;
|
|
236
|
+
}
|
|
237
|
+
overlay.off(".attach");
|
|
238
|
+
const ret = {
|
|
239
|
+
overlay,
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
241
|
+
then: (callback) => {
|
|
242
|
+
overlay.on("show:after.attach", (event) => {
|
|
243
|
+
callback(event);
|
|
244
|
+
});
|
|
245
|
+
return ret;
|
|
246
|
+
},
|
|
247
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
|
+
show: (callback) => {
|
|
249
|
+
overlay.on("show.attach", (event) => {
|
|
250
|
+
callback(event);
|
|
251
|
+
});
|
|
252
|
+
return ret;
|
|
253
|
+
},
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
255
|
+
hide: (callback) => {
|
|
256
|
+
overlay.on("hide.attach", (event) => {
|
|
257
|
+
callback(event);
|
|
258
|
+
});
|
|
259
|
+
return ret;
|
|
260
|
+
},
|
|
261
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
262
|
+
update: (callback) => {
|
|
263
|
+
overlay.on("update.attach", (event) => {
|
|
264
|
+
callback(event);
|
|
265
|
+
});
|
|
266
|
+
return ret;
|
|
267
|
+
},
|
|
268
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
269
|
+
move: (callback) => {
|
|
270
|
+
overlay.on("move.attach", (event) => {
|
|
271
|
+
callback(event);
|
|
272
|
+
});
|
|
273
|
+
return ret;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
return ret;
|
|
277
|
+
}
|
|
278
|
+
update(name, html) {
|
|
279
|
+
const overlay = _Tooltip.active[name];
|
|
280
|
+
if (overlay) {
|
|
281
|
+
overlay.needsUpdate = true;
|
|
282
|
+
overlay.options.html = html;
|
|
283
|
+
this.show(name);
|
|
284
|
+
} else {
|
|
285
|
+
console.log(`Tooltip "${name}" is not displayed. Cannot update it.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
show(name, extraOptions) {
|
|
289
|
+
if (name instanceof HTMLElement || name instanceof Object) {
|
|
290
|
+
let options2 = name;
|
|
291
|
+
if (name instanceof HTMLElement) {
|
|
292
|
+
options2 = extraOptions || {};
|
|
293
|
+
options2.anchor = name;
|
|
294
|
+
}
|
|
295
|
+
const ret = this.attach(options2);
|
|
296
|
+
ret.overlay.tmp.hidden = false;
|
|
297
|
+
query2(ret.overlay.anchor).off(".autoShow-" + ret.overlay.name).off(".autoHide-" + ret.overlay.name);
|
|
298
|
+
setTimeout(() => {
|
|
299
|
+
if (!ret.overlay.tmp.hidden) {
|
|
300
|
+
this.show(ret.overlay.name);
|
|
301
|
+
if (this.initControls) {
|
|
302
|
+
this.initControls(ret.overlay);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}, 1);
|
|
306
|
+
return ret;
|
|
307
|
+
}
|
|
308
|
+
let edata;
|
|
309
|
+
const self = this;
|
|
310
|
+
const overlay = _Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
311
|
+
if (!overlay) return;
|
|
312
|
+
const options = overlay.options;
|
|
313
|
+
if (!overlay || overlay.displayed && !overlay.needsUpdate) {
|
|
314
|
+
this.resize(overlay?.name);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const position = options.position.split("|");
|
|
318
|
+
const isVertical = ["top", "bottom"].includes(position[0]);
|
|
319
|
+
let overlayStyles = options.align == "both" && isVertical ? "" : "white-space: nowrap;";
|
|
320
|
+
if (options.maxWidth == null && /^<div[^>]*style=["'][^"']*max-width[^"']*["'][^>]*>/i.test(options.html?.trim?.() ?? "")) {
|
|
321
|
+
options.maxWidth = TsUtils.getStrWidth(options.html, "", true);
|
|
322
|
+
}
|
|
323
|
+
if (options.maxWidth && TsUtils.getStrWidth(options.html, "", true) >= options.maxWidth) {
|
|
324
|
+
overlayStyles = "width: " + options.maxWidth + "px; white-space: inherit; overflow: auto;";
|
|
325
|
+
}
|
|
326
|
+
overlayStyles += " max-height: " + (options.maxHeight ? options.maxHeight : window.innerHeight - 4) + "px;";
|
|
327
|
+
if (options.html === "" || options.html == null) {
|
|
328
|
+
self.hide(name);
|
|
329
|
+
return;
|
|
330
|
+
} else if (overlay.box) {
|
|
331
|
+
edata = this.trigger("update", { target: name, overlay });
|
|
332
|
+
if (edata.isCancelled === true) {
|
|
333
|
+
if (overlay.prevOptions) {
|
|
334
|
+
overlay.options = overlay.prevOptions;
|
|
335
|
+
delete overlay.prevOptions;
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
query2(overlay.box).find(".tsg-overlay-body").attr("style", (options.style || "") + "; " + overlayStyles).removeClass(null).addClass("tsg-overlay-body " + options.class + (options.draggable ? " tsg-draggable" : "")).html(options.html);
|
|
340
|
+
this.resize(overlay.name);
|
|
341
|
+
} else {
|
|
342
|
+
edata = this.trigger("show", { target: name, overlay });
|
|
343
|
+
if (edata.isCancelled === true) return;
|
|
344
|
+
query2("body").append(
|
|
345
|
+
// pointer-events will be re-enabled leter
|
|
346
|
+
`<div id="${overlay.id}" name="${name}" style="display: none; pointer-events: none" class="tsg-overlay"
|
|
347
|
+
data-click="stop" data-focusin="stop">
|
|
348
|
+
<style></style>
|
|
349
|
+
<div class="tsg-overlay-body tsg-eaction ${options.class} ${options.draggable ? "tsg-draggable" : ""}"
|
|
350
|
+
style="${options.style || ""}; ${overlayStyles}" ${options.draggable ? 'data-mousedown="startDrag|event"' : ""}>
|
|
351
|
+
${options.html}
|
|
352
|
+
</div>
|
|
353
|
+
</div>`
|
|
354
|
+
);
|
|
355
|
+
overlay.box = query2("#" + TsUtils.escapeId(overlay.id))[0];
|
|
356
|
+
overlay.displayed = true;
|
|
357
|
+
const names = query2(overlay.anchor).data("tooltipName") ?? [];
|
|
358
|
+
names.push(name);
|
|
359
|
+
query2(overlay.anchor).data("tooltipName", names);
|
|
360
|
+
TsUtils.bindEvents(overlay.box, {});
|
|
361
|
+
overlay.tmp.originalCSS = "";
|
|
362
|
+
if (query2(overlay.anchor).length > 0) {
|
|
363
|
+
overlay.tmp.originalCSS = query2(overlay.anchor)[0].style.cssText;
|
|
364
|
+
}
|
|
365
|
+
this.resize(overlay.name);
|
|
366
|
+
}
|
|
367
|
+
if (options.anchorStyle) {
|
|
368
|
+
overlay.anchor.style.cssText += ";" + options.anchorStyle;
|
|
369
|
+
}
|
|
370
|
+
if (options.anchorClass) {
|
|
371
|
+
if (!(options.anchorClass == "tsg-focus" && overlay.anchor == document.body)) {
|
|
372
|
+
query2(overlay.anchor).addClass(options.anchorClass);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (typeof options.hideOn == "string") options.hideOn = [options.hideOn];
|
|
376
|
+
if (!Array.isArray(options.hideOn)) options.hideOn = [];
|
|
377
|
+
Object.assign(overlay.tmp, {
|
|
378
|
+
scrollLeft: document.body.scrollLeft,
|
|
379
|
+
scrollTop: document.body.scrollTop
|
|
380
|
+
});
|
|
381
|
+
addHideEvents();
|
|
382
|
+
addWatchEvents(document.body);
|
|
383
|
+
query2(overlay.box).show();
|
|
384
|
+
overlay.tmp.observeTooltipResize.observe(overlay.box);
|
|
385
|
+
overlay.tmp.observeAnchorResize.observe(overlay.anchor);
|
|
386
|
+
overlay.tmp.observeAnchorMove.observe(overlay.anchor, { attributes: true });
|
|
387
|
+
_Tooltip.observeRemove.observe(document.body, { subtree: true, childList: true });
|
|
388
|
+
query2(overlay.box).css("opacity", 1).find(".tsg-overlay-body").html(options.html);
|
|
389
|
+
setTimeout(() => {
|
|
390
|
+
query2(overlay.box).css({ "pointer-events": "auto" }).data("ready", "yes");
|
|
391
|
+
}, 100);
|
|
392
|
+
TsUtils.bindEvents(query2(overlay.box).find(".tsg-eaction"), this);
|
|
393
|
+
delete overlay.needsUpdate;
|
|
394
|
+
overlay.box.overlay = overlay;
|
|
395
|
+
query2(overlay.box).off("mousedown.tsg-bringfront").on("mousedown.tsg-bringfront", () => {
|
|
396
|
+
self.bringOverlayToFront(overlay);
|
|
397
|
+
});
|
|
398
|
+
if (edata) edata.finish();
|
|
399
|
+
return { overlay };
|
|
400
|
+
function addWatchEvents(el) {
|
|
401
|
+
const scope = "tooltip-" + overlay.name;
|
|
402
|
+
let queryEl = el;
|
|
403
|
+
if (el.tagName == "BODY") {
|
|
404
|
+
queryEl = el.ownerDocument;
|
|
405
|
+
}
|
|
406
|
+
query2(queryEl).off(`.${scope}`).on(`scroll.${scope}`, (_event) => {
|
|
407
|
+
Object.assign(overlay.tmp, {
|
|
408
|
+
scrollLeft: el.scrollLeft,
|
|
409
|
+
scrollTop: el.scrollTop
|
|
410
|
+
});
|
|
411
|
+
self.resize(overlay.name);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
function addHideEvents() {
|
|
415
|
+
const hide = (_event) => {
|
|
416
|
+
self.hide(overlay.name);
|
|
417
|
+
};
|
|
418
|
+
const $anchor = query2(overlay.anchor);
|
|
419
|
+
const scope = "tooltip-" + overlay.name;
|
|
420
|
+
query2("html").off(`.${scope}`);
|
|
421
|
+
if (options.hideOn.includes("doc-click")) {
|
|
422
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
423
|
+
$anchor.off(`.${scope}-doc`).on(`click.${scope}-doc`, (event) => {
|
|
424
|
+
event.stopPropagation();
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
query2("html").on(`click.${scope}`, hide);
|
|
428
|
+
}
|
|
429
|
+
if (options.hideOn.includes("tooltip-click")) {
|
|
430
|
+
query2(overlay.box).off(`click.${scope}`).on(`click.${scope}`, hide);
|
|
431
|
+
}
|
|
432
|
+
if (options.hideOn.includes("focus-change") || options.hideOn.includes("blur")) {
|
|
433
|
+
query2("html").on(`focusin.${scope}`, (_e) => {
|
|
434
|
+
if (document.activeElement != overlay.anchor) {
|
|
435
|
+
self.hide(overlay.name);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
440
|
+
$anchor.off(`.${scope}`);
|
|
441
|
+
options.hideOn.forEach((event) => {
|
|
442
|
+
if (["doc-click", "focus-change", "blur"].indexOf(event) == -1) {
|
|
443
|
+
$anchor.on(`${event}.${scope}`, { once: true }, hide);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
hide(name) {
|
|
450
|
+
let overlay;
|
|
451
|
+
if (arguments.length == 0) {
|
|
452
|
+
Object.keys(_Tooltip.active).forEach((name2) => {
|
|
453
|
+
this.hide(name2);
|
|
454
|
+
});
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (name instanceof HTMLElement) {
|
|
458
|
+
const names2 = query2(name).data("tooltipName") ?? [];
|
|
459
|
+
names2.forEach((name2) => {
|
|
460
|
+
this.hide(name2);
|
|
461
|
+
});
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (typeof name == "string") {
|
|
465
|
+
name = name.replace(/[\s\.#]/g, "_");
|
|
466
|
+
overlay = _Tooltip.active[name];
|
|
467
|
+
}
|
|
468
|
+
if (overlay?.tmp) overlay.tmp.hidden = true;
|
|
469
|
+
if (!overlay || !overlay.box) return;
|
|
470
|
+
const edata = this.trigger("hide", { target: name, overlay });
|
|
471
|
+
if (edata.isCancelled === true) return;
|
|
472
|
+
if (!overlay.options._keep) delete _Tooltip.active[name];
|
|
473
|
+
const scope = "tooltip-" + overlay.name;
|
|
474
|
+
overlay.tmp.observeTooltipResize?.disconnect();
|
|
475
|
+
overlay.tmp.observeAnchorResize?.disconnect();
|
|
476
|
+
overlay.tmp.observeAnchorMove?.disconnect();
|
|
477
|
+
let cnt = 0;
|
|
478
|
+
Object.keys(_Tooltip.active).forEach((key) => {
|
|
479
|
+
const overlay2 = _Tooltip.active[key];
|
|
480
|
+
if (overlay2?.displayed) {
|
|
481
|
+
cnt++;
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
if (cnt == 0) {
|
|
485
|
+
_Tooltip.observeRemove.disconnect();
|
|
486
|
+
}
|
|
487
|
+
query2("html").off(`.${scope}`);
|
|
488
|
+
query2(document).off(`.${scope}`);
|
|
489
|
+
overlay.box?.remove();
|
|
490
|
+
overlay.box = null;
|
|
491
|
+
overlay.displayed = false;
|
|
492
|
+
const names = query2(overlay.anchor).data("tooltipName") ?? [];
|
|
493
|
+
const ind = names.indexOf(overlay.name);
|
|
494
|
+
if (ind != -1) names.splice(names.indexOf(overlay.name), 1);
|
|
495
|
+
if (names.length == 0) {
|
|
496
|
+
query2(overlay.anchor).removeData("tooltipName");
|
|
497
|
+
} else {
|
|
498
|
+
query2(overlay.anchor).data("tooltipName", names);
|
|
499
|
+
}
|
|
500
|
+
if (overlay.options.anchorStyle) {
|
|
501
|
+
overlay.anchor.style.cssText = overlay.tmp.originalCSS;
|
|
502
|
+
}
|
|
503
|
+
query2(overlay.anchor).off(`.${scope}`).removeClass(overlay.options.anchorClass);
|
|
504
|
+
if (overlay.options.url) {
|
|
505
|
+
overlay.options.items.splice(0);
|
|
506
|
+
overlay.tmp.remote.hasMore = true;
|
|
507
|
+
overlay.tmp.remote.search = null;
|
|
508
|
+
}
|
|
509
|
+
edata.finish();
|
|
510
|
+
}
|
|
511
|
+
resize(name) {
|
|
512
|
+
const state = { moved: false, resize: false };
|
|
513
|
+
if (arguments.length == 0) {
|
|
514
|
+
Object.keys(_Tooltip.active).forEach((key) => {
|
|
515
|
+
const overlay2 = _Tooltip.active[key];
|
|
516
|
+
if (overlay2.displayed) this.resize(overlay2.name);
|
|
517
|
+
});
|
|
518
|
+
return { multiple: true };
|
|
519
|
+
}
|
|
520
|
+
const overlay = _Tooltip.active[(name ?? "").replace(/[\s\.#]/g, "_")];
|
|
521
|
+
const pos = this.getPosition(overlay.name);
|
|
522
|
+
const newPos = pos.left + "x" + pos.top;
|
|
523
|
+
const newSize = pos.width + "x" + pos.height;
|
|
524
|
+
let edata1, edata2;
|
|
525
|
+
if (overlay.tmp.lastPos != newPos) {
|
|
526
|
+
edata1 = this.trigger("move", { target: name, overlay, pos });
|
|
527
|
+
state.moved = true;
|
|
528
|
+
}
|
|
529
|
+
if (overlay.tmp.lastSize != newSize) {
|
|
530
|
+
edata2 = this.trigger("resize", { target: name, overlay, pos });
|
|
531
|
+
state.moved = true;
|
|
532
|
+
}
|
|
533
|
+
const qBox = query2(overlay.box).css({
|
|
534
|
+
left: pos.left + "px",
|
|
535
|
+
top: pos.top + "px"
|
|
536
|
+
});
|
|
537
|
+
qBox.then((q) => {
|
|
538
|
+
if (pos.width != null) {
|
|
539
|
+
q.css("width", pos.width + "px").find(".tsg-overlay-body").css("width", "100%");
|
|
540
|
+
}
|
|
541
|
+
if (pos.height != null) {
|
|
542
|
+
q.css("height", pos.height + "px").find(".tsg-overlay-body").css("height", "100%");
|
|
543
|
+
}
|
|
544
|
+
return q;
|
|
545
|
+
}).find(".tsg-overlay-body").removeClass("tsg-arrow-right tsg-arrow-left tsg-arrow-top tsg-arrow-bottom").addClass(pos.arrow.class).closest(".tsg-overlay").find("style:first-child").text(pos.arrow.style);
|
|
546
|
+
if (overlay.tmp.lastPos != newPos && edata1) {
|
|
547
|
+
overlay.tmp.lastPos = newPos;
|
|
548
|
+
edata1.finish();
|
|
549
|
+
}
|
|
550
|
+
if (overlay.tmp.lastSize != newSize && edata2) {
|
|
551
|
+
overlay.tmp.lastSize = newSize;
|
|
552
|
+
edata2.finish();
|
|
553
|
+
}
|
|
554
|
+
return state;
|
|
555
|
+
}
|
|
556
|
+
getPosition(name) {
|
|
557
|
+
const overlay = _Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
558
|
+
if (!overlay || !overlay.box) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const options = overlay.options;
|
|
562
|
+
if (overlay.tmp.resizedY || overlay.tmp.resizedX) {
|
|
563
|
+
query2(overlay.box).css({ width: "", height: "", scroll: "auto" });
|
|
564
|
+
}
|
|
565
|
+
const scrollSize = TsUtils.scrollBarSize();
|
|
566
|
+
const hasScrollBarX = !(document.body.scrollWidth == document.body.clientWidth);
|
|
567
|
+
const hasScrollBarY = !(document.body.scrollHeight == document.body.clientHeight);
|
|
568
|
+
const max = {
|
|
569
|
+
width: window.innerWidth - (hasScrollBarY ? scrollSize : 0),
|
|
570
|
+
height: window.innerHeight - (hasScrollBarX ? scrollSize : 0)
|
|
571
|
+
};
|
|
572
|
+
const position = options.position == "auto" ? "top|bottom|right|left".split("|") : Array.isArray(options.position) ? options.position : options.position.split("|");
|
|
573
|
+
const isVertical = ["top", "bottom"].includes(position[0]);
|
|
574
|
+
const content = overlay.box.getBoundingClientRect();
|
|
575
|
+
let anchor = overlay.anchor?.getBoundingClientRect?.();
|
|
576
|
+
const min_width = TsUtils.getStrWidth(options.html, "", true);
|
|
577
|
+
if (content.width < min_width) content.width = min_width;
|
|
578
|
+
if (overlay.anchor == document.body) {
|
|
579
|
+
let evt = options.originalEvent;
|
|
580
|
+
while (evt?.originalEvent) {
|
|
581
|
+
evt = evt.originalEvent;
|
|
582
|
+
}
|
|
583
|
+
const { x, y, width: width2, height: height2 } = evt ?? { x: options.x, y: options.y, width: 0, height: 10 };
|
|
584
|
+
anchor = {
|
|
585
|
+
left: x - (options.contextMenu ? 4 : 0),
|
|
586
|
+
top: y - (options.contextMenu ? 4 : 0),
|
|
587
|
+
width: width2 ?? 0,
|
|
588
|
+
height: height2 ?? 10,
|
|
589
|
+
arrow: options.contextMenu ? "none" : null
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
let arrowSize = options.arrowSize;
|
|
593
|
+
if (anchor.arrow == "none") arrowSize = 0;
|
|
594
|
+
if (isNaN(arrowSize)) arrowSize = this.defaults.arrowSize;
|
|
595
|
+
const available = {
|
|
596
|
+
// tipsize adjustment should be here, not in max.width/max.height
|
|
597
|
+
top: anchor.top - arrowSize,
|
|
598
|
+
bottom: max.height - arrowSize - (anchor.top + anchor.height) - (hasScrollBarX ? scrollSize : 0) - 2,
|
|
599
|
+
left: anchor.left,
|
|
600
|
+
right: max.width - (anchor.left + anchor.width) + (hasScrollBarY ? scrollSize : 0)
|
|
601
|
+
};
|
|
602
|
+
if (content.width < 22) content.width = 22;
|
|
603
|
+
if (content.height < 14) content.height = 14;
|
|
604
|
+
let left, top, width, height;
|
|
605
|
+
let found = "";
|
|
606
|
+
const arrow = {
|
|
607
|
+
offset: 0,
|
|
608
|
+
class: "",
|
|
609
|
+
style: `#${overlay.id} { --tip-size: ${arrowSize}px; }`
|
|
610
|
+
};
|
|
611
|
+
const adjust = { left: 0, top: 0 };
|
|
612
|
+
const bestFit = { posX: "", x: 0, posY: "", y: 0 };
|
|
613
|
+
position.forEach((pos) => {
|
|
614
|
+
const avail = available[pos] ?? 0;
|
|
615
|
+
if (["top", "bottom"].includes(pos)) {
|
|
616
|
+
if (!found && content.height + arrowSize / 1.893 < avail) {
|
|
617
|
+
found = pos;
|
|
618
|
+
}
|
|
619
|
+
if (avail > bestFit.y) {
|
|
620
|
+
Object.assign(bestFit, { posY: pos, y: avail });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (["left", "right"].includes(pos)) {
|
|
624
|
+
if (!found && content.width + arrowSize / 1.893 < avail) {
|
|
625
|
+
found = pos;
|
|
626
|
+
}
|
|
627
|
+
if (avail > bestFit.x) {
|
|
628
|
+
Object.assign(bestFit, { posX: pos, x: avail });
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
if (!found) {
|
|
633
|
+
if (isVertical) {
|
|
634
|
+
found = bestFit.posY;
|
|
635
|
+
} else {
|
|
636
|
+
found = bestFit.posX;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (options.autoResize) {
|
|
640
|
+
if (["top", "bottom"].includes(found)) {
|
|
641
|
+
const availFound = available[found] ?? 0;
|
|
642
|
+
if (content.height > availFound) {
|
|
643
|
+
height = availFound;
|
|
644
|
+
overlay.tmp.resizedY = true;
|
|
645
|
+
} else {
|
|
646
|
+
overlay.tmp.resizedY = false;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (["left", "right"].includes(found)) {
|
|
650
|
+
const availFound = available[found] ?? 0;
|
|
651
|
+
if (content.width > availFound) {
|
|
652
|
+
width = availFound;
|
|
653
|
+
overlay.tmp.resizedX = true;
|
|
654
|
+
} else {
|
|
655
|
+
overlay.tmp.resizedX = false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
usePosition(found);
|
|
660
|
+
if (isVertical) anchorAlignment();
|
|
661
|
+
top = (top ?? 0) + parseFloat(String(options.offsetY * (found == "top" ? -1 : 1)));
|
|
662
|
+
left = (left ?? 0) + parseFloat(String(options.offsetX * (found == "left" ? -1 : 1)));
|
|
663
|
+
screenAdjust();
|
|
664
|
+
const extraTop = found == "top" ? -options.margin : found == "bottom" ? options.margin : 0;
|
|
665
|
+
const extraLeft = found == "left" ? -options.margin : found == "right" ? options.margin : 0;
|
|
666
|
+
top = Math.floor(((top ?? 0) + parseFloat(extraTop)) * 100) / 100;
|
|
667
|
+
left = Math.floor(((left ?? 0) + parseFloat(extraLeft)) * 100) / 100;
|
|
668
|
+
const retPos = { left: left ?? 0, top: top ?? 0, arrow, adjust, pos: found };
|
|
669
|
+
if (width != null) retPos.width = width;
|
|
670
|
+
if (height != null) retPos.height = height;
|
|
671
|
+
return retPos;
|
|
672
|
+
function usePosition(pos) {
|
|
673
|
+
arrow.class = anchor.arrow ? anchor.arrow : `tsg-arrow-${pos}`;
|
|
674
|
+
switch (pos) {
|
|
675
|
+
case "top": {
|
|
676
|
+
left = anchor.left + (anchor.width - (width ?? content.width)) / 2;
|
|
677
|
+
top = anchor.top - (height ?? content.height) - arrowSize / 1.5 + 1;
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
case "bottom": {
|
|
681
|
+
left = anchor.left + (anchor.width - (width ?? content.width)) / 2;
|
|
682
|
+
top = anchor.top + anchor.height + arrowSize / 1.25 + 1;
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
case "left": {
|
|
686
|
+
left = anchor.left - (width ?? content.width) - arrowSize / 1.2 - 1;
|
|
687
|
+
top = anchor.top + (anchor.height - (height ?? content.height)) / 2;
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
case "right": {
|
|
691
|
+
left = anchor.left + anchor.width + arrowSize / 1.2 + 1;
|
|
692
|
+
top = anchor.top + (anchor.height - (height ?? content.height)) / 2;
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
function anchorAlignment() {
|
|
698
|
+
if (options.align == "left") {
|
|
699
|
+
adjust.left = anchor.left - (left ?? 0);
|
|
700
|
+
left = anchor.left;
|
|
701
|
+
}
|
|
702
|
+
if (options.align == "right") {
|
|
703
|
+
adjust.left = anchor.left + anchor.width - (width ?? content.width) - (left ?? 0);
|
|
704
|
+
left = anchor.left + anchor.width - (width ?? content.width);
|
|
705
|
+
}
|
|
706
|
+
if (["top", "bottom"].includes(found) && options.align.startsWith("both")) {
|
|
707
|
+
const minWidth = options.align.split(":")[1] ?? 50;
|
|
708
|
+
if (anchor.width >= minWidth) {
|
|
709
|
+
left = anchor.left;
|
|
710
|
+
width = anchor.width;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (options.align == "top") {
|
|
714
|
+
adjust.top = anchor.top - (top ?? 0);
|
|
715
|
+
top = anchor.top;
|
|
716
|
+
}
|
|
717
|
+
if (options.align == "bottom") {
|
|
718
|
+
adjust.top = anchor.top + anchor.height - (height ?? content.height) - (top ?? 0);
|
|
719
|
+
top = anchor.top + anchor.height - (height ?? content.height);
|
|
720
|
+
}
|
|
721
|
+
if (["left", "right"].includes(found) && options.align.startsWith("both")) {
|
|
722
|
+
const minHeight = options.align.split(":")[1] ?? 50;
|
|
723
|
+
if (anchor.height >= minHeight) {
|
|
724
|
+
top = anchor.top;
|
|
725
|
+
height = anchor.height;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
function screenAdjust() {
|
|
730
|
+
let adjustArrow;
|
|
731
|
+
if (["left", "right"].includes(options.align) && anchor.width < (width ?? content.width) || ["top", "bottom"].includes(options.align) && anchor.height < (height ?? content.height)) {
|
|
732
|
+
adjustArrow = true;
|
|
733
|
+
}
|
|
734
|
+
const minLeft = found == "right" ? arrowSize : options.screenMargin;
|
|
735
|
+
const minTop = found == "bottom" ? arrowSize : options.screenMargin;
|
|
736
|
+
const maxLeft = max.width - (width ?? content.width) - (found == "left" ? arrowSize : options.screenMargin);
|
|
737
|
+
const maxTop = max.height - (height ?? content.height) - (found == "top" ? arrowSize : options.screenMargin) + 3;
|
|
738
|
+
if (["top", "bottom"].includes(found) || options.autoResize) {
|
|
739
|
+
if ((left ?? 0) < minLeft) {
|
|
740
|
+
adjustArrow = true;
|
|
741
|
+
adjust.left -= left ?? 0;
|
|
742
|
+
left = minLeft;
|
|
743
|
+
}
|
|
744
|
+
if ((left ?? 0) > maxLeft) {
|
|
745
|
+
adjustArrow = true;
|
|
746
|
+
adjust.left -= (left ?? 0) - maxLeft;
|
|
747
|
+
left = (left ?? 0) + maxLeft - (left ?? 0);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (["left", "right"].includes(found) || options.autoResize) {
|
|
751
|
+
if ((top ?? 0) < minTop) {
|
|
752
|
+
adjustArrow = true;
|
|
753
|
+
adjust.top -= top ?? 0;
|
|
754
|
+
top = minTop;
|
|
755
|
+
}
|
|
756
|
+
if ((top ?? 0) > maxTop) {
|
|
757
|
+
adjustArrow = true;
|
|
758
|
+
adjust.top -= (top ?? 0) - maxTop;
|
|
759
|
+
top = (top ?? 0) + maxTop - (top ?? 0);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (adjustArrow) {
|
|
763
|
+
const aType = isVertical ? "left" : "top";
|
|
764
|
+
const sType = isVertical ? "width" : "height";
|
|
765
|
+
arrow.offset = -adjust[aType];
|
|
766
|
+
const maxOffset = content[sType] / 2 - arrowSize;
|
|
767
|
+
if (Math.abs(arrow.offset) > maxOffset + arrowSize) {
|
|
768
|
+
arrow.class = "";
|
|
769
|
+
}
|
|
770
|
+
if (Math.abs(arrow.offset) > maxOffset) {
|
|
771
|
+
arrow.offset = arrow.offset < 0 ? -maxOffset : maxOffset;
|
|
772
|
+
}
|
|
773
|
+
arrow.style = TsUtils.stripSpaces(`#${overlay.id} .tsg-overlay-body:after,
|
|
774
|
+
#${overlay.id} .tsg-overlay-body:before {
|
|
775
|
+
--tip-size: ${arrowSize}px;
|
|
776
|
+
margin-${aType}: ${arrow.offset}px;
|
|
777
|
+
}`);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Move overlay node to the end of its parent (typically body) so it stacks above other .tsg-overlay siblings
|
|
783
|
+
* without relying on z-index. No-op if it is already the last element child.
|
|
784
|
+
*/
|
|
785
|
+
bringOverlayToFront(overlay) {
|
|
786
|
+
if (!overlay || !overlay.box || !overlay.box.parentNode || !overlay.box.nextElementSibling) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
overlay.box.parentNode.appendChild(overlay.box);
|
|
790
|
+
}
|
|
791
|
+
startDrag(event) {
|
|
792
|
+
if (event.preventDefault) {
|
|
793
|
+
event.preventDefault();
|
|
794
|
+
}
|
|
795
|
+
const el = query2(event.target).closest(".tsg-overlay");
|
|
796
|
+
const overlay = el[0]?.overlay;
|
|
797
|
+
if (overlay) {
|
|
798
|
+
this.bringOverlayToFront(overlay);
|
|
799
|
+
}
|
|
800
|
+
const initial = {
|
|
801
|
+
el,
|
|
802
|
+
x: parseFloat(el.css("left")),
|
|
803
|
+
// any: css(string) returns string when reading a property
|
|
804
|
+
y: parseFloat(el.css("top")),
|
|
805
|
+
pageX: event.pageX,
|
|
806
|
+
pageY: event.pageY,
|
|
807
|
+
moved: false,
|
|
808
|
+
_removed: false
|
|
809
|
+
};
|
|
810
|
+
query2(document).off(".tsg-drag").on("selectstart.tsg-drag, dragstart.tsg-drag", (e) => e.preventDefault()).find("body").addClass("tsg-overlay-dragging");
|
|
811
|
+
query2("html").off(".TsColor").on("mousemove.TsColor", mouseMove).on("mouseup.TsColor", mouseUp);
|
|
812
|
+
function mouseUp(_event) {
|
|
813
|
+
query2("html").off(".TsColor");
|
|
814
|
+
query2(document).off("selectstart.tsg-drag");
|
|
815
|
+
query2(document).off("dragstart.tsg-drag");
|
|
816
|
+
query2(document.body).removeClass("tsg-overlay-dragging");
|
|
817
|
+
if (initial["moved"]) {
|
|
818
|
+
const ov = initial.el[0] && initial.el[0].overlay;
|
|
819
|
+
if (ov) {
|
|
820
|
+
if (!ov.tmp) ov.tmp = {};
|
|
821
|
+
ov.tmp["moved"] = true;
|
|
822
|
+
clearTimeout(ov.tmp["_movedClearTimer"]);
|
|
823
|
+
ov.tmp["_movedClearTimer"] = setTimeout(() => {
|
|
824
|
+
if (ov.tmp) {
|
|
825
|
+
delete ov.tmp["moved"];
|
|
826
|
+
delete ov.tmp["_movedClearTimer"];
|
|
827
|
+
}
|
|
828
|
+
}, 400);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function mouseMove(event2) {
|
|
833
|
+
const divX = event2.pageX - initial.pageX;
|
|
834
|
+
const divY = event2.pageY - initial.pageY;
|
|
835
|
+
if (Math.abs(divX) > 3 || Math.abs(divY) > 3) {
|
|
836
|
+
initial.moved = true;
|
|
837
|
+
}
|
|
838
|
+
initial.el.css({
|
|
839
|
+
left: initial.x + divX + "px",
|
|
840
|
+
top: initial.y + divY + "px"
|
|
841
|
+
});
|
|
842
|
+
if (!initial._removed) {
|
|
843
|
+
initial._removed = true;
|
|
844
|
+
initial.el.find(":scope > .tsg-overlay-body").removeClass("tsg-arrow-right tsg-arrow-left tsg-arrow-top tsg-arrow-bottom");
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
var ColorTooltip = class _ColorTooltip extends Tooltip {
|
|
850
|
+
static custom_colors = [];
|
|
851
|
+
palette;
|
|
852
|
+
// any: index tracks keyboard position in the palette grid; tuple [row, col]
|
|
853
|
+
index;
|
|
854
|
+
constructor() {
|
|
855
|
+
super();
|
|
856
|
+
this.palette = [
|
|
857
|
+
["000000", "333333", "555555", "777777", "888888", "999999", "AAAAAA", "CCCCCC", "DDDDDD", "EEEEEE", "F7F7F7", "FFFFFF"],
|
|
858
|
+
["FF011B", "FF9838", "FFC300", "FFFD59", "86FF14", "14FF7A", "2EFFFC", "2693FF", "006CE7", "9B24F4", "FF21F5", "FF0099"],
|
|
859
|
+
["FFEAEA", "FCEFE1", "FCF4DC", "FFFECF", "EBFFD9", "D9FFE9", "E0FFFF", "E8F4FF", "ECF4FC", "EAE6F4", "FFF5FE", "FCF0F7"],
|
|
860
|
+
["F4CCCC", "FCE5CD", "FFF1C2", "FFFDA1", "D5FCB1", "B5F7D0", "BFFFFF", "D6ECFF", "CFE2F3", "D9D1E9", "FFE3FD", "FFD9F0"],
|
|
861
|
+
["EA9899", "F9CB9C", "FFE48C", "F7F56F", "B9F77E", "84F0B1", "83F7F7", "B5DAFF", "9FC5E8", "B4A7D6", "FAB9F6", "FFADDE"],
|
|
862
|
+
["E06666", "F6B26B", "DEB737", "E0DE51", "8FDB48", "52D189", "4EDEDB", "76ACE3", "6FA8DC", "8E7CC3", "E07EDA", "F26DBD"],
|
|
863
|
+
["CC0814", "E69138", "AB8816", "B5B20E", "6BAB30", "27A85F", "1BA8A6", "3C81C7", "3D85C6", "674EA7", "A14F9D", "BF4990"],
|
|
864
|
+
["99050C", "B45F17", "80650E", "737103", "395E14", "10783D", "13615E", "094785", "0A5394", "351C75", "780172", "782C5A"]
|
|
865
|
+
];
|
|
866
|
+
this.defaults = TsUtils.extend({}, this.defaults, {
|
|
867
|
+
advanced: false,
|
|
868
|
+
transparent: true,
|
|
869
|
+
position: "top|bottom",
|
|
870
|
+
class: "tsg-white",
|
|
871
|
+
color: "",
|
|
872
|
+
updateInput: true,
|
|
873
|
+
arrowSize: 12,
|
|
874
|
+
autoResize: false,
|
|
875
|
+
anchorClass: "tsg-focus",
|
|
876
|
+
autoShowOn: "focus",
|
|
877
|
+
hideOn: ["doc-click", "focus-change"],
|
|
878
|
+
onSelect: null,
|
|
879
|
+
onLiveUpdate: null
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
883
|
+
attach(anchor, text) {
|
|
884
|
+
let options;
|
|
885
|
+
if (arguments.length == 1 && anchor instanceof Object) {
|
|
886
|
+
options = anchor;
|
|
887
|
+
anchor = options.anchor;
|
|
888
|
+
} else if (arguments.length === 2 && text != null && typeof text === "object") {
|
|
889
|
+
options = text;
|
|
890
|
+
options.anchor = anchor;
|
|
891
|
+
}
|
|
892
|
+
const prevHideOn = options.hideOn;
|
|
893
|
+
options = TsUtils.extend({}, this.defaults, options || {});
|
|
894
|
+
if (prevHideOn) {
|
|
895
|
+
options.hideOn = prevHideOn;
|
|
896
|
+
}
|
|
897
|
+
options.style += "; padding: 0;";
|
|
898
|
+
if (options.transparent && this.palette[0][1] == "333333") {
|
|
899
|
+
this.palette[0].splice(1, 1);
|
|
900
|
+
this.palette[0].push("TRANSPARENT");
|
|
901
|
+
}
|
|
902
|
+
if (!options.transparent && this.palette[0][1] != "333333") {
|
|
903
|
+
this.palette[0].splice(1, 0, "333333");
|
|
904
|
+
this.palette[0].pop();
|
|
905
|
+
}
|
|
906
|
+
if (options.color) options.color = String(options.color).toUpperCase();
|
|
907
|
+
if (typeof options.color === "string" && options.color.substr(0, 1) === "#") options.color = options.color.substr(1);
|
|
908
|
+
this.index = [-1, -1];
|
|
909
|
+
const ret = super.attach(options);
|
|
910
|
+
const overlay = ret.overlay;
|
|
911
|
+
overlay.options.html = this.getColorHTML(overlay.name, options);
|
|
912
|
+
overlay.on("show.attach", (event) => {
|
|
913
|
+
const overlay2 = event.detail.overlay;
|
|
914
|
+
const anchor2 = overlay2.anchor;
|
|
915
|
+
const options2 = overlay2.options;
|
|
916
|
+
if (["INPUT", "TEXTAREA"].includes(anchor2.tagName) && !options2.color && anchor2.value) {
|
|
917
|
+
overlay2.tmp["initColor"] = anchor2.value;
|
|
918
|
+
}
|
|
919
|
+
delete overlay2.newColor;
|
|
920
|
+
});
|
|
921
|
+
overlay.on("show:after.attach", (_event) => {
|
|
922
|
+
if (ret.overlay?.box) {
|
|
923
|
+
const actions = query2(ret.overlay.box).find(".tsg-eaction");
|
|
924
|
+
TsUtils.bindEvents(actions, this);
|
|
925
|
+
this.initControls(ret.overlay);
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
overlay.on("update:after.attach", (_event) => {
|
|
929
|
+
if (ret.overlay?.box) {
|
|
930
|
+
const actions = query2(ret.overlay.box).find(".tsg-eaction");
|
|
931
|
+
TsUtils.bindEvents(actions, this);
|
|
932
|
+
this.initControls(ret.overlay);
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
overlay.on("hide.attach", (event) => {
|
|
936
|
+
const overlay2 = event.detail.overlay;
|
|
937
|
+
const anchor2 = overlay2.anchor;
|
|
938
|
+
const color = overlay2.newColor ?? overlay2.options.color ?? "";
|
|
939
|
+
if (color !== "") {
|
|
940
|
+
if (["INPUT", "TEXTAREA"].includes(anchor2.tagName) && anchor2.value != color && overlay2.options.updateInput) {
|
|
941
|
+
anchor2.value = color;
|
|
942
|
+
}
|
|
943
|
+
const edata = this.trigger("select", { color, target: overlay2.name, overlay: overlay2 });
|
|
944
|
+
if (edata.isCancelled === true) return;
|
|
945
|
+
edata.finish();
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
ret.liveUpdate = (callback) => {
|
|
949
|
+
overlay.on("liveUpdate.attach", (event) => {
|
|
950
|
+
callback(event);
|
|
951
|
+
});
|
|
952
|
+
return ret;
|
|
953
|
+
};
|
|
954
|
+
ret.select = (callback) => {
|
|
955
|
+
overlay.on("select.attach", (event) => {
|
|
956
|
+
callback(event);
|
|
957
|
+
});
|
|
958
|
+
return ret;
|
|
959
|
+
};
|
|
960
|
+
return ret;
|
|
961
|
+
}
|
|
962
|
+
// regular panel handler, adds selection class
|
|
963
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
964
|
+
select(color, name) {
|
|
965
|
+
let target;
|
|
966
|
+
this.index = [-1, -1];
|
|
967
|
+
if (typeof name != "string") {
|
|
968
|
+
target = name.target;
|
|
969
|
+
this.index = (query2(target).attr("index") ?? "").split(":").map(Number);
|
|
970
|
+
name = query2(target).closest(".tsg-overlay").attr("name");
|
|
971
|
+
}
|
|
972
|
+
const overlay = this.get(name);
|
|
973
|
+
const edata = this.trigger("liveUpdate", { color, target: name, overlay, param: name });
|
|
974
|
+
if (edata.isCancelled === true) return;
|
|
975
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName) && overlay.options.updateInput) {
|
|
976
|
+
query2(overlay.anchor).val(color);
|
|
977
|
+
}
|
|
978
|
+
overlay.newColor = color;
|
|
979
|
+
query2(overlay.box).find(".tsg-color.tsg-selected").removeClass("tsg-selected");
|
|
980
|
+
if (target) {
|
|
981
|
+
query2(target).addClass("tsg-selected");
|
|
982
|
+
}
|
|
983
|
+
edata.finish();
|
|
984
|
+
}
|
|
985
|
+
// used for keyboard navigation, if any
|
|
986
|
+
nextColor(direction) {
|
|
987
|
+
const pal = this.palette;
|
|
988
|
+
switch (direction) {
|
|
989
|
+
case "up":
|
|
990
|
+
this.index[0]--;
|
|
991
|
+
break;
|
|
992
|
+
case "down":
|
|
993
|
+
this.index[0]++;
|
|
994
|
+
break;
|
|
995
|
+
case "right":
|
|
996
|
+
this.index[1]++;
|
|
997
|
+
break;
|
|
998
|
+
case "left":
|
|
999
|
+
this.index[1]--;
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
if (this.index[0] < 0) this.index[0] = 0;
|
|
1003
|
+
if (this.index[0] > pal.length - 2) this.index[0] = pal.length - 2;
|
|
1004
|
+
if (this.index[1] < 0) this.index[1] = 0;
|
|
1005
|
+
if (this.index[1] > (pal[0]?.length ?? 0) - 1) this.index[1] = (pal[0]?.length ?? 1) - 1;
|
|
1006
|
+
return pal[this.index[0]]?.[this.index[1]];
|
|
1007
|
+
}
|
|
1008
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1009
|
+
tabClick(index, name) {
|
|
1010
|
+
if (typeof name != "string") {
|
|
1011
|
+
name = query2(name.target).closest(".tsg-overlay").attr("name");
|
|
1012
|
+
}
|
|
1013
|
+
const overlay = this.get(name);
|
|
1014
|
+
const tab = query2(overlay.box).find(`.tsg-color-tab:nth-child(${index})`);
|
|
1015
|
+
query2(overlay.box).find(".tsg-color-tab").removeClass("tsg-selected");
|
|
1016
|
+
query2(tab).addClass("tsg-selected");
|
|
1017
|
+
query2(overlay.box).find(".tsg-tab-content").hide().closest(".tsg-colors").find(".tab-" + index).show();
|
|
1018
|
+
}
|
|
1019
|
+
// generate HTML with color pallent and controls
|
|
1020
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1021
|
+
getColorHTML(name, options) {
|
|
1022
|
+
let html = `
|
|
1023
|
+
<div class="tsg-colors-header tsg-eaction" data-mousedown="startDrag|event">
|
|
1024
|
+
Colors
|
|
1025
|
+
</div>
|
|
1026
|
+
<div class="tsg-colors">
|
|
1027
|
+
<div class="tsg-tab-content tab-1">`;
|
|
1028
|
+
for (let i = 0; i < this.palette.length; i++) {
|
|
1029
|
+
html += '<div class="tsg-color-row">';
|
|
1030
|
+
for (let j = 0; j < (this.palette[i]?.length ?? 0); j++) {
|
|
1031
|
+
const color = this.palette[i][j];
|
|
1032
|
+
let border = "";
|
|
1033
|
+
if (color === "FFFFFF") border = "; border: 1px solid #efefef";
|
|
1034
|
+
html += `
|
|
1035
|
+
<div class="tsg-color tsg-eaction ${color === "TRANSPARENT" ? "tsg-no-color" : ""} ${options.color == color ? "tsg-selected" : ""}"
|
|
1036
|
+
style="background-color: #${color + border};" name="${color}" index="${i}:${j}"
|
|
1037
|
+
data-mousedown="select|'${color}'|event" data-mouseup="hide|${name}">
|
|
1038
|
+
</div>`;
|
|
1039
|
+
}
|
|
1040
|
+
html += "</div>";
|
|
1041
|
+
if (i < 2) html += '<div style="height: 8px"></div>';
|
|
1042
|
+
}
|
|
1043
|
+
html += `
|
|
1044
|
+
<div style="height: 8px"></div>
|
|
1045
|
+
<div class="tsg-colors-custom">
|
|
1046
|
+
${this.getCustomColorsHTML(name)}
|
|
1047
|
+
</div>`;
|
|
1048
|
+
html += "</div>";
|
|
1049
|
+
html += `
|
|
1050
|
+
<div class="tsg-tab-content tab-2" style="display: none">
|
|
1051
|
+
<div class="color-info">
|
|
1052
|
+
<div class="color-preview-bg"><div class="color-preview"></div><div class="color-original"></div></div>
|
|
1053
|
+
<div class="color-part">
|
|
1054
|
+
<span>H</span> <input class="tsg-input" name="h" maxlength="3" max="360" tabindex="101">
|
|
1055
|
+
<span>R</span> <input class="tsg-input" name="r" maxlength="3" max="255" tabindex="104">
|
|
1056
|
+
</div>
|
|
1057
|
+
<div class="color-part">
|
|
1058
|
+
<span>S</span> <input class="tsg-input" name="s" maxlength="3" max="100" tabindex="102">
|
|
1059
|
+
<span>G</span> <input class="tsg-input" name="g" maxlength="3" max="255" tabindex="105">
|
|
1060
|
+
</div>
|
|
1061
|
+
<div class="color-part">
|
|
1062
|
+
<span>V</span> <input class="tsg-input" name="v" maxlength="3" max="100" tabindex="103">
|
|
1063
|
+
<span>B</span> <input class="tsg-input" name="b" maxlength="3" max="255" tabindex="106">
|
|
1064
|
+
</div>
|
|
1065
|
+
<div class="color-part opacity">
|
|
1066
|
+
<span>${TsUtils.lang("Opacity")}</span>
|
|
1067
|
+
<input class="tsg-input" name="a" maxlength="5" max="1" tabindex="107">
|
|
1068
|
+
</div>
|
|
1069
|
+
</div>
|
|
1070
|
+
<div class="palette" name="palette">
|
|
1071
|
+
<div class="palette-bg"></div>
|
|
1072
|
+
<div class="value1 move-x move-y"></div>
|
|
1073
|
+
</div>
|
|
1074
|
+
<div class="rainbow" name="rainbow">
|
|
1075
|
+
<div class="value2 move-x"></div>
|
|
1076
|
+
</div>
|
|
1077
|
+
<div class="alpha" name="alpha">
|
|
1078
|
+
<div class="alpha-bg"></div>
|
|
1079
|
+
<div class="value2 move-x"></div>
|
|
1080
|
+
</div>
|
|
1081
|
+
<div class="final" name="final">
|
|
1082
|
+
<span style="text-align: right"> Hex </span>
|
|
1083
|
+
<input class="tsg-input final" name="hex" tabindex="107" style="width: 70px" readonly>
|
|
1084
|
+
<div class="tsg-color tsg-color-picker tsg-eaction" data-click="pickAndUse|${name}">
|
|
1085
|
+
<span class="tsg-icon tsg-icon-eye-dropper"></span>
|
|
1086
|
+
</div>
|
|
1087
|
+
</div>
|
|
1088
|
+
</div>`;
|
|
1089
|
+
html += `
|
|
1090
|
+
<div class="tsg-color-tabs">
|
|
1091
|
+
<div class="tsg-color-tab tsg-selected tsg-eaction" data-click="tabClick|1|event|this"><span class="tsg-icon tsg-icon-colors"></span></div>
|
|
1092
|
+
<div class="tsg-color-tab tsg-eaction" data-click="tabClick|2|event|this"><span class="tsg-icon tsg-icon-settings"></span></div>
|
|
1093
|
+
<div style="padding: 5px; width: 100%; text-align: right;">
|
|
1094
|
+
${typeof options.html == "string" ? options.html : ""}
|
|
1095
|
+
</div>
|
|
1096
|
+
</div>`;
|
|
1097
|
+
return html;
|
|
1098
|
+
}
|
|
1099
|
+
getCustomColorsHTML(name) {
|
|
1100
|
+
const options = this.get(name)?.options;
|
|
1101
|
+
let html = '<div class="tsg-color-row" style="min-height: 21px">';
|
|
1102
|
+
_ColorTooltip.custom_colors.forEach((color, i) => {
|
|
1103
|
+
let border = "";
|
|
1104
|
+
if (color === "FFFFFF") border = "; border: 1px solid #efefef";
|
|
1105
|
+
html += `
|
|
1106
|
+
<div class="tsg-color tsg-eaction ${color === "TRANSPARENT" ? "tsg-no-color" : ""} ${options.color == color ? "tsg-selected" : ""}"
|
|
1107
|
+
style="background-color: #${color + border};" name="${color}" index="c:${i}"
|
|
1108
|
+
data-mousedown="select|'${color}'|event" data-mouseup="hide|${name}">
|
|
1109
|
+
</div>`;
|
|
1110
|
+
});
|
|
1111
|
+
html += `
|
|
1112
|
+
<div class="tsg-color tsg-color-picker tsg-eaction" data-click="pickAndSelect|${name}|event">
|
|
1113
|
+
<span class="tsg-icon tsg-icon-eye-dropper"></span>
|
|
1114
|
+
</div>
|
|
1115
|
+
</div>`;
|
|
1116
|
+
return html;
|
|
1117
|
+
}
|
|
1118
|
+
// bind advanced tab controls
|
|
1119
|
+
initControls(overlay) {
|
|
1120
|
+
let initial;
|
|
1121
|
+
const self = this;
|
|
1122
|
+
const options = overlay.options;
|
|
1123
|
+
const color = options.color || overlay.tmp["initColor"];
|
|
1124
|
+
let rgb = TsUtils.parseColor(color);
|
|
1125
|
+
if (rgb == null) {
|
|
1126
|
+
rgb = { r: 140, g: 150, b: 160, a: 1 };
|
|
1127
|
+
}
|
|
1128
|
+
let hsv = TsUtils.rgb2hsv(rgb);
|
|
1129
|
+
if (options.advanced === true) {
|
|
1130
|
+
this.tabClick(2, overlay.name);
|
|
1131
|
+
}
|
|
1132
|
+
setColor(hsv, true, color ?? "");
|
|
1133
|
+
query2(overlay.box).off(".TsColor").on("contextmenu.TsColor", (event) => {
|
|
1134
|
+
event.preventDefault();
|
|
1135
|
+
}).find("input").off(".TsColor").on("change.TsColor", (event) => {
|
|
1136
|
+
const el = query2(event.target);
|
|
1137
|
+
let val = parseFloat(el.val());
|
|
1138
|
+
const max = parseFloat(el.attr("max"));
|
|
1139
|
+
if (isNaN(val)) {
|
|
1140
|
+
val = 0;
|
|
1141
|
+
el.val(0);
|
|
1142
|
+
}
|
|
1143
|
+
if (max > 1) val = parseInt(String(val));
|
|
1144
|
+
if (max > 0 && val > max) {
|
|
1145
|
+
el.val(max);
|
|
1146
|
+
val = max;
|
|
1147
|
+
}
|
|
1148
|
+
if (val < 0) {
|
|
1149
|
+
el.val(0);
|
|
1150
|
+
val = 0;
|
|
1151
|
+
}
|
|
1152
|
+
const name = el.attr("name");
|
|
1153
|
+
const color2 = {};
|
|
1154
|
+
if (["r", "g", "b", "a"].indexOf(name) !== -1) {
|
|
1155
|
+
rgb[name] = val;
|
|
1156
|
+
hsv = TsUtils.rgb2hsv(rgb);
|
|
1157
|
+
} else if (["h", "s", "v"].indexOf(name) !== -1) {
|
|
1158
|
+
color2[name] = val;
|
|
1159
|
+
}
|
|
1160
|
+
setColor(color2, true);
|
|
1161
|
+
});
|
|
1162
|
+
query2(overlay.box).find(".color-original").off(".TsColor").on("click.TsColor", (event) => {
|
|
1163
|
+
const tmp = TsUtils.parseColor(query2(event.target).css("background-color"));
|
|
1164
|
+
if (tmp != null) {
|
|
1165
|
+
rgb = tmp;
|
|
1166
|
+
hsv = TsUtils.rgb2hsv(rgb);
|
|
1167
|
+
setColor(hsv, true);
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
const mDown = `${!TsUtils.isMobile ? "mousedown" : "touchstart"}.TsColor`;
|
|
1171
|
+
const mUp = `${!TsUtils.isMobile ? "mouseup" : "touchend"}.TsColor`;
|
|
1172
|
+
const mMove = `${!TsUtils.isMobile ? "mousemove" : "touchmove"}.TsColor`;
|
|
1173
|
+
query2(overlay.box).find(".palette, .rainbow, .alpha").off(".TsColor").on(`${mDown}.TsColor`, mouseDown);
|
|
1174
|
+
this.setColor = setColor;
|
|
1175
|
+
return;
|
|
1176
|
+
function setColor(color2, fullUpdate, initial2) {
|
|
1177
|
+
if (color2.h != null) hsv.h = color2.h;
|
|
1178
|
+
if (color2.s != null) hsv.s = color2.s;
|
|
1179
|
+
if (color2.v != null) hsv.v = color2.v;
|
|
1180
|
+
if (color2.a != null) {
|
|
1181
|
+
rgb.a = color2.a;
|
|
1182
|
+
hsv.a = color2.a;
|
|
1183
|
+
}
|
|
1184
|
+
rgb = TsUtils.hsv2rgb(hsv);
|
|
1185
|
+
const rgba = "rgba(" + rgb.r + "," + rgb.g + "," + rgb.b + "," + rgb.a + ")";
|
|
1186
|
+
const cl = [
|
|
1187
|
+
Number(rgb.r).toString(16).toUpperCase(),
|
|
1188
|
+
Number(rgb.g).toString(16).toUpperCase(),
|
|
1189
|
+
Number(rgb.b).toString(16).toUpperCase(),
|
|
1190
|
+
Math.round(Number(rgb.a) * 255).toString(16).toUpperCase()
|
|
1191
|
+
];
|
|
1192
|
+
cl.forEach((item, ind) => {
|
|
1193
|
+
if (item.length === 1) cl[ind] = "0" + item;
|
|
1194
|
+
});
|
|
1195
|
+
let newColor = cl[0] + cl[1] + cl[2] + cl[3];
|
|
1196
|
+
if (rgb.a === 1) {
|
|
1197
|
+
newColor = cl[0] + cl[1] + cl[2];
|
|
1198
|
+
}
|
|
1199
|
+
query2(overlay.box).find(".color-preview").css("background-color", "#" + newColor);
|
|
1200
|
+
query2(overlay.box).find("input").each((el) => {
|
|
1201
|
+
if (el.name) {
|
|
1202
|
+
if (rgb[el.name] != null) el.value = String(rgb[el.name]);
|
|
1203
|
+
if (hsv[el.name] != null) el.value = String(hsv[el.name]);
|
|
1204
|
+
if (el.name === "a") el.value = String(rgb.a);
|
|
1205
|
+
if (el.name == "hex") el.value = newColor;
|
|
1206
|
+
if (el.name == "rgb") el.value = rgba;
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1209
|
+
if (initial2 != null) {
|
|
1210
|
+
const color3 = overlay.tmp["initColor"] || newColor;
|
|
1211
|
+
query2(overlay.box).find(".color-original").css("background-color", "#" + color3);
|
|
1212
|
+
query2(overlay.box).find(".tsg-color.tsg-selected").removeClass("tsg-selected");
|
|
1213
|
+
query2(overlay.box).find(`.tsg-colors [name="${color3}"], .tsg-colors [name="${initial2}"]`).addClass("tsg-selected");
|
|
1214
|
+
if (newColor.length == 8) {
|
|
1215
|
+
self.tabClick(2, overlay.name);
|
|
1216
|
+
}
|
|
1217
|
+
} else {
|
|
1218
|
+
self.select(newColor, overlay.name);
|
|
1219
|
+
}
|
|
1220
|
+
if (fullUpdate) {
|
|
1221
|
+
updateSliders();
|
|
1222
|
+
refreshPalette();
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function updateSliders() {
|
|
1226
|
+
const el1 = query2(overlay.box).find(".palette .value1");
|
|
1227
|
+
const el2 = query2(overlay.box).find(".rainbow .value2");
|
|
1228
|
+
const el3 = query2(overlay.box).find(".alpha .value2");
|
|
1229
|
+
if (!el1[0] || !el2[0] || !el3[0]) return;
|
|
1230
|
+
const offset1 = el1[0].clientWidth / 2;
|
|
1231
|
+
const offset2 = el2[0].clientWidth / 2;
|
|
1232
|
+
el1.css({
|
|
1233
|
+
"left": hsv.s * 150 / 100 - offset1 + "px",
|
|
1234
|
+
"top": (100 - hsv.v) * 125 / 100 - offset1 + "px"
|
|
1235
|
+
});
|
|
1236
|
+
el2.css("left", hsv.h / (360 / 150) - offset2 + "px");
|
|
1237
|
+
el3.css("left", rgb.a * 150 - offset2 + "px");
|
|
1238
|
+
}
|
|
1239
|
+
function refreshPalette() {
|
|
1240
|
+
const cl = TsUtils.hsv2rgb(hsv.h, 100, 100);
|
|
1241
|
+
const rgb2 = `${cl.r},${cl.g},${cl.b}`;
|
|
1242
|
+
query2(overlay.box).find(".palette").css("background-image", `linear-gradient(90deg, rgba(${rgb2},0) 0%, rgba(${rgb2},1) 100%)`);
|
|
1243
|
+
}
|
|
1244
|
+
function mouseDown(event) {
|
|
1245
|
+
const el = query2(this).find(".value1, .value2");
|
|
1246
|
+
const offset = el.prop("clientWidth") / 2;
|
|
1247
|
+
if (el.hasClass("move-x")) el.css({ left: event.offsetX - offset + "px" });
|
|
1248
|
+
if (el.hasClass("move-y")) el.css({ top: event.offsetY - offset + "px" });
|
|
1249
|
+
initial = {
|
|
1250
|
+
el,
|
|
1251
|
+
x: event.pageX,
|
|
1252
|
+
y: event.pageY,
|
|
1253
|
+
width: el.prop("parentNode").clientWidth,
|
|
1254
|
+
height: el.prop("parentNode").clientHeight,
|
|
1255
|
+
left: parseInt(el.css("left")),
|
|
1256
|
+
top: parseInt(el.css("top"))
|
|
1257
|
+
};
|
|
1258
|
+
mouseMove(event);
|
|
1259
|
+
query2("html").off(".TsColor").on(mMove, mouseMove).on(mUp, mouseUp);
|
|
1260
|
+
}
|
|
1261
|
+
function mouseUp(_event) {
|
|
1262
|
+
query2("html").off(".TsColor");
|
|
1263
|
+
}
|
|
1264
|
+
function mouseMove(event) {
|
|
1265
|
+
const el = initial.el;
|
|
1266
|
+
const divX = event.pageX - initial.x;
|
|
1267
|
+
const divY = event.pageY - initial.y;
|
|
1268
|
+
let newX = initial.left + divX;
|
|
1269
|
+
let newY = initial.top + divY;
|
|
1270
|
+
const offset = el.prop("clientWidth") / 2;
|
|
1271
|
+
if (newX < -offset) newX = -offset;
|
|
1272
|
+
if (newY < -offset) newY = -offset;
|
|
1273
|
+
if (newX > initial.width - offset) newX = initial.width - offset;
|
|
1274
|
+
if (newY > initial.height - offset) newY = initial.height - offset;
|
|
1275
|
+
if (el.hasClass("move-x")) el.css({ left: newX + "px" });
|
|
1276
|
+
if (el.hasClass("move-y")) el.css({ top: newY + "px" });
|
|
1277
|
+
const name = query2(el.get(0).parentNode).attr("name");
|
|
1278
|
+
const x = parseInt(el.css("left")) + offset;
|
|
1279
|
+
const y = parseInt(el.css("top")) + offset;
|
|
1280
|
+
if (name === "palette") {
|
|
1281
|
+
setColor({
|
|
1282
|
+
s: Math.round(x / initial.width * 100),
|
|
1283
|
+
v: Math.round(100 - y / initial.height * 100)
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
if (name === "rainbow") {
|
|
1287
|
+
const h = Math.round(360 / 150 * x);
|
|
1288
|
+
setColor({ h });
|
|
1289
|
+
refreshPalette();
|
|
1290
|
+
}
|
|
1291
|
+
if (name === "alpha") {
|
|
1292
|
+
setColor({ a: parseFloat(Number(x / 150).toFixed(2)) });
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1297
|
+
addCustomColor(color, _name) {
|
|
1298
|
+
if (typeof color == "string" && color.substr(0, 1) == "#" && [7, 9].includes(color.length)) {
|
|
1299
|
+
color = color.substr(1).toUpperCase();
|
|
1300
|
+
const custom = _ColorTooltip.custom_colors;
|
|
1301
|
+
if (custom.includes(color)) {
|
|
1302
|
+
custom.splice(custom.indexOf(color), 1);
|
|
1303
|
+
}
|
|
1304
|
+
if (custom.length >= 5) {
|
|
1305
|
+
custom.pop();
|
|
1306
|
+
}
|
|
1307
|
+
custom.unshift(color);
|
|
1308
|
+
}
|
|
1309
|
+
return color;
|
|
1310
|
+
}
|
|
1311
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1312
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1313
|
+
async pickAndSelect(name, event) {
|
|
1314
|
+
const color = await this.pickColor();
|
|
1315
|
+
if (typeof color == "string" && color.substr(0, 1) == "#" && [7, 9].includes(color.length)) {
|
|
1316
|
+
this.addCustomColor(color, name);
|
|
1317
|
+
const cnt = query2(event.target).closest(".tsg-colors-custom");
|
|
1318
|
+
cnt.html(this.getCustomColorsHTML(name));
|
|
1319
|
+
TsUtils.bindEvents(cnt.find(".tsg-eaction"), this);
|
|
1320
|
+
this.select(color.substr(1), name);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
async pickAndUse(_name) {
|
|
1324
|
+
const color = await this.pickColor();
|
|
1325
|
+
if (typeof color == "string" && color.substr(0, 1) == "#" && [7, 9].includes(color.length)) {
|
|
1326
|
+
const hsv = TsUtils.rgb2hsv(TsUtils.parseColor(color));
|
|
1327
|
+
this.setColor(hsv, true);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
async pickColor() {
|
|
1331
|
+
const win = window;
|
|
1332
|
+
if (!win.EyeDropper) {
|
|
1333
|
+
console.error("EyeDropper API is not supported in this browser.");
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
const eyeDropper = new win.EyeDropper();
|
|
1337
|
+
try {
|
|
1338
|
+
const result = await eyeDropper.open();
|
|
1339
|
+
return result.sRGBHex;
|
|
1340
|
+
} catch (err) {
|
|
1341
|
+
console.error("Error picking color:", err);
|
|
1342
|
+
}
|
|
1343
|
+
return "";
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
var MenuTooltip = class extends Tooltip {
|
|
1347
|
+
constructor() {
|
|
1348
|
+
super();
|
|
1349
|
+
this.defaults = TsUtils.extend({}, this.defaults, {
|
|
1350
|
+
type: "normal",
|
|
1351
|
+
// can be normal, radio, check
|
|
1352
|
+
items: [],
|
|
1353
|
+
selected: null,
|
|
1354
|
+
// current selected
|
|
1355
|
+
render: null,
|
|
1356
|
+
spinner: false,
|
|
1357
|
+
msgNoItems: TsUtils.lang("No items found"),
|
|
1358
|
+
topHTML: "",
|
|
1359
|
+
menuStyle: "",
|
|
1360
|
+
search: false,
|
|
1361
|
+
// search input inside tooltip
|
|
1362
|
+
filter: false,
|
|
1363
|
+
// will apply filter, if anchor is INPUT or TEXTAREA
|
|
1364
|
+
match: "contains",
|
|
1365
|
+
// is, begins, ends, contains, regexp
|
|
1366
|
+
markSearch: false,
|
|
1367
|
+
prefilter: false,
|
|
1368
|
+
altRows: false,
|
|
1369
|
+
arrowSize: 10,
|
|
1370
|
+
align: "left",
|
|
1371
|
+
position: "bottom|top",
|
|
1372
|
+
class: "tsg-white",
|
|
1373
|
+
anchorClass: "tsg-focus",
|
|
1374
|
+
autoShowOn: "focus",
|
|
1375
|
+
hideOn: ["doc-click", "focus-change", "select"],
|
|
1376
|
+
// also can 'item-remove'
|
|
1377
|
+
onSelect: null,
|
|
1378
|
+
onSubMenu: null,
|
|
1379
|
+
onRemove: null,
|
|
1380
|
+
onTooltip: null,
|
|
1381
|
+
onMouseEnter: null,
|
|
1382
|
+
onMouseLeave: null
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1386
|
+
attach(anchor, text) {
|
|
1387
|
+
let options;
|
|
1388
|
+
if (arguments.length == 1 && anchor instanceof Object) {
|
|
1389
|
+
options = anchor;
|
|
1390
|
+
anchor = options.anchor;
|
|
1391
|
+
} else if (arguments.length === 2 && text != null && typeof text === "object") {
|
|
1392
|
+
options = text;
|
|
1393
|
+
options.anchor = anchor;
|
|
1394
|
+
}
|
|
1395
|
+
const prevHideOn = options.hideOn;
|
|
1396
|
+
options = TsUtils.extend({}, this.defaults, options || {});
|
|
1397
|
+
if (prevHideOn) {
|
|
1398
|
+
options.hideOn = prevHideOn;
|
|
1399
|
+
}
|
|
1400
|
+
options.style += "; padding: 0;";
|
|
1401
|
+
if (options.items == null) {
|
|
1402
|
+
options.items = [];
|
|
1403
|
+
}
|
|
1404
|
+
if (options.cacheMax <= 0) {
|
|
1405
|
+
console.log(`The option "cacheMax" is ${options.cacheMax} but should be more than 0`);
|
|
1406
|
+
}
|
|
1407
|
+
options.items = TsUtils.normMenu(options.items, options);
|
|
1408
|
+
options.html = this.getMenuHTML(options);
|
|
1409
|
+
const ret = super.attach(options);
|
|
1410
|
+
const overlay = ret.overlay;
|
|
1411
|
+
overlay.on("show:after.attach, update:after.attach", (_event) => {
|
|
1412
|
+
if (ret.overlay?.box) {
|
|
1413
|
+
let search = "";
|
|
1414
|
+
overlay.selected = overlay.options.selected;
|
|
1415
|
+
const index = overlay.anchor.dataset?.selectedIndex;
|
|
1416
|
+
if (overlay.options.selected !== false && overlay.options.selected !== -1 || index != null) {
|
|
1417
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
1418
|
+
search = overlay.anchor.value;
|
|
1419
|
+
overlay.selected = null;
|
|
1420
|
+
if (index != null) {
|
|
1421
|
+
overlay.selected = index;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
const actions = query2(ret.overlay.box).find(".tsg-eaction");
|
|
1426
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
1427
|
+
overlay.tmp._new_search = false;
|
|
1428
|
+
query2(overlay.anchor).on("input.search-trigger", () => {
|
|
1429
|
+
overlay.tmp._new_search = true;
|
|
1430
|
+
query2(overlay.anchor).off("input.search-trigger");
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
TsUtils.bindEvents(actions, this);
|
|
1434
|
+
this.applyFilter(overlay.name, null, search, void 0).then((data) => {
|
|
1435
|
+
if (!Tooltip.active[overlay.name]?.displayed) {
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
this.getActiveChain(overlay.name, options.items);
|
|
1439
|
+
overlay.tmp.searchCount = data.count;
|
|
1440
|
+
overlay.tmp.search = data.search;
|
|
1441
|
+
if (options.prefilter || search !== "") {
|
|
1442
|
+
if (data.count === 0 || !this.getActiveChain(overlay.name, options.items).includes(overlay.selected)) {
|
|
1443
|
+
overlay.selected = null;
|
|
1444
|
+
}
|
|
1445
|
+
this.refreshSearch(overlay.name);
|
|
1446
|
+
}
|
|
1447
|
+
this.initControls(ret.overlay);
|
|
1448
|
+
this.refreshIndex(overlay.name, true);
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
overlay.next = () => {
|
|
1453
|
+
const chain = this.getActiveChain(overlay.name);
|
|
1454
|
+
if (overlay.selected == null || String(overlay.selected).length == 0) {
|
|
1455
|
+
overlay.selected = chain[0];
|
|
1456
|
+
} else {
|
|
1457
|
+
const ind = chain.indexOf(String(overlay.selected));
|
|
1458
|
+
if (ind == -1) {
|
|
1459
|
+
overlay.selected = chain[0];
|
|
1460
|
+
}
|
|
1461
|
+
if (ind < chain.length - 1) {
|
|
1462
|
+
overlay.selected = chain[ind + 1];
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
this.refreshIndex(overlay.name);
|
|
1466
|
+
this.showTooltip(overlay.name);
|
|
1467
|
+
};
|
|
1468
|
+
overlay.prev = () => {
|
|
1469
|
+
const chain = this.getActiveChain(overlay.name);
|
|
1470
|
+
if (overlay.selected == null || String(overlay.selected).length == 0) {
|
|
1471
|
+
overlay.selected = chain[chain.length - 1];
|
|
1472
|
+
} else {
|
|
1473
|
+
const ind = chain.indexOf(String(overlay.selected));
|
|
1474
|
+
if (ind == -1) {
|
|
1475
|
+
overlay.selected = chain[chain.length - 1];
|
|
1476
|
+
}
|
|
1477
|
+
if (ind > 0) {
|
|
1478
|
+
overlay.selected = chain[ind - 1];
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
this.refreshIndex(overlay.name);
|
|
1482
|
+
this.showTooltip(overlay.name);
|
|
1483
|
+
};
|
|
1484
|
+
overlay.click = () => {
|
|
1485
|
+
query2(overlay.box).find(".tsg-selected").each((el) => {
|
|
1486
|
+
el.click();
|
|
1487
|
+
});
|
|
1488
|
+
};
|
|
1489
|
+
overlay.on("hide:after.attach", (_event) => {
|
|
1490
|
+
TsTooltip.hide(overlay.name + "-tooltip");
|
|
1491
|
+
});
|
|
1492
|
+
ret.select = (callback) => {
|
|
1493
|
+
overlay.on("select.attach", (event) => {
|
|
1494
|
+
callback(event);
|
|
1495
|
+
});
|
|
1496
|
+
return ret;
|
|
1497
|
+
};
|
|
1498
|
+
ret.remove = (callback) => {
|
|
1499
|
+
overlay.on("remove.attach", (event) => {
|
|
1500
|
+
callback(event);
|
|
1501
|
+
});
|
|
1502
|
+
return ret;
|
|
1503
|
+
};
|
|
1504
|
+
ret.subMenu = (callback) => {
|
|
1505
|
+
overlay.on("subMenu.attach", (event) => {
|
|
1506
|
+
callback(event);
|
|
1507
|
+
});
|
|
1508
|
+
return ret;
|
|
1509
|
+
};
|
|
1510
|
+
return ret;
|
|
1511
|
+
}
|
|
1512
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1513
|
+
update(name, items) {
|
|
1514
|
+
const overlay = Tooltip.active[name];
|
|
1515
|
+
if (overlay) {
|
|
1516
|
+
const options = overlay.options;
|
|
1517
|
+
if (options.items != items) {
|
|
1518
|
+
options.items = items;
|
|
1519
|
+
}
|
|
1520
|
+
const menuHTML = this.getMenuHTML(options);
|
|
1521
|
+
if (options.html != menuHTML) {
|
|
1522
|
+
options.html = menuHTML;
|
|
1523
|
+
overlay.needsUpdate = true;
|
|
1524
|
+
this.show(name);
|
|
1525
|
+
}
|
|
1526
|
+
} else {
|
|
1527
|
+
console.log(`Tooltip "${name}" is not displayed. Cannot update it.`);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1531
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1532
|
+
initControls(overlay) {
|
|
1533
|
+
let mdown = "mousedown";
|
|
1534
|
+
let mclick = "click";
|
|
1535
|
+
if (TsUtils.isMobile) {
|
|
1536
|
+
mdown = "touchstart";
|
|
1537
|
+
mclick = "touchend";
|
|
1538
|
+
}
|
|
1539
|
+
query2(overlay.box).find(".tsg-menu:not(.tsg-sub-menu)").off(".TsMenu").on("contextmenu.TsMenu", (event) => {
|
|
1540
|
+
event.preventDefault();
|
|
1541
|
+
}).on(`${mdown}.TsMenu`, { delegate: ".tsg-menu-item" }, (event) => {
|
|
1542
|
+
const dt = event.delegate.dataset;
|
|
1543
|
+
const parents = query2(event.delegate).closest(".tsg-menu").data("parents");
|
|
1544
|
+
this.menuDown(overlay, event, dt.index, parents);
|
|
1545
|
+
if (TsUtils.isMobile) {
|
|
1546
|
+
event.preventDefault();
|
|
1547
|
+
}
|
|
1548
|
+
}).on(`${mclick}.TsMenu`, { delegate: ".tsg-menu-item" }, (event) => {
|
|
1549
|
+
const dt = event.delegate.dataset;
|
|
1550
|
+
const parents = query2(event.delegate).closest(".tsg-menu").data("parents");
|
|
1551
|
+
this.menuClick(overlay, event, parseInt(dt["index"] ?? "0"), parents);
|
|
1552
|
+
}).find(".tsg-menu-item").off(".TsMenu").on("mouseEnter.TsMenu", (event) => {
|
|
1553
|
+
const dt = event.target.dataset;
|
|
1554
|
+
const item = overlay.options.items[dt["index"] ?? ""];
|
|
1555
|
+
const edata = this.trigger("mouseEnter", { overlay, item, originalEvent: event });
|
|
1556
|
+
if (edata.isCancelled) {
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
const tooltip = item?.tooltip;
|
|
1560
|
+
if (tooltip && dt["hassubmenu"] != "yes") {
|
|
1561
|
+
this.showTooltip(overlay.name, { tooltip, anchor: event.target });
|
|
1562
|
+
}
|
|
1563
|
+
const _menu = query2(event.target).closest(".tsg-menu").get(0);
|
|
1564
|
+
if (_menu._evt && _menu._evt.target != event.target) {
|
|
1565
|
+
this.closeSubMenu(_menu._evt);
|
|
1566
|
+
}
|
|
1567
|
+
if (dt["hassubmenu"] == "yes") {
|
|
1568
|
+
const _evt = {
|
|
1569
|
+
index: parseInt(dt["index"] ?? "0"),
|
|
1570
|
+
parents: _menu.dataset.parents !== "" ? _menu.dataset.parents.split("-").map((ind) => parseInt(ind)) : [],
|
|
1571
|
+
target: event.target,
|
|
1572
|
+
originalEvent: event,
|
|
1573
|
+
overlay
|
|
1574
|
+
};
|
|
1575
|
+
_menu._evt = _evt;
|
|
1576
|
+
this.openSubMenu(_evt);
|
|
1577
|
+
}
|
|
1578
|
+
edata.finish();
|
|
1579
|
+
}).on("mouseLeave.TsMenu", (event) => {
|
|
1580
|
+
const dt = event.target.dataset;
|
|
1581
|
+
const item = overlay.options.items[dt["index"] ?? ""];
|
|
1582
|
+
const edata = this.trigger("mouseLeave", { overlay, item, originalEvent: event });
|
|
1583
|
+
if (edata.isCancelled) {
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
TsTooltip.hide(overlay.name + "-tooltip");
|
|
1587
|
+
edata.finish();
|
|
1588
|
+
}).find(".menu-help").off(".TsMenu").on("mouseEnter.TsMenu", (event) => {
|
|
1589
|
+
const target = event.target;
|
|
1590
|
+
const dt = target.parentNode?.parentNode;
|
|
1591
|
+
const tooltip = overlay.options.items[dt.dataset?.index]?.help;
|
|
1592
|
+
if (tooltip) {
|
|
1593
|
+
TsTooltip.show({
|
|
1594
|
+
name: overlay.name + "-help-tp",
|
|
1595
|
+
anchor: event.target,
|
|
1596
|
+
html: tooltip,
|
|
1597
|
+
position: "right|left",
|
|
1598
|
+
hideOn: ["doc-click"]
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
}).on("mouseLeave.TsMenu", (_event) => {
|
|
1602
|
+
TsTooltip.hide(overlay.name + "-help-tp");
|
|
1603
|
+
});
|
|
1604
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
1605
|
+
query2(overlay.anchor).off(".TsMenu").on("input.TsMenu", (_event) => {
|
|
1606
|
+
}).on("keyup.TsMenu", (event) => {
|
|
1607
|
+
event._searchType = "filter";
|
|
1608
|
+
this.keyUp(overlay, event);
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
if (overlay.options.search) {
|
|
1612
|
+
query2(overlay.box).find("#menu-search").off(".TsMenu").on("keyup.TsMenu", (event) => {
|
|
1613
|
+
event._searchType = "search";
|
|
1614
|
+
this.keyUp(overlay, event);
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1619
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1620
|
+
getCurrent(name, id) {
|
|
1621
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
1622
|
+
const options = overlay.options;
|
|
1623
|
+
const selected = String(id ? id : overlay.selected || "").split("-");
|
|
1624
|
+
if (selected?.[0] === "") {
|
|
1625
|
+
selected.shift();
|
|
1626
|
+
}
|
|
1627
|
+
const last = selected.length - 1;
|
|
1628
|
+
let index = selected[last];
|
|
1629
|
+
const parents = selected.slice(0, selected.length - 1).join("-");
|
|
1630
|
+
index = TsUtils.isInt(index) ? parseInt(index) : 0;
|
|
1631
|
+
let items = options.items;
|
|
1632
|
+
selected.forEach((id2, ind) => {
|
|
1633
|
+
if (ind < selected.length - 1) {
|
|
1634
|
+
items = items[id2].items;
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
return { last, index, items, item: items?.[index], parents };
|
|
1638
|
+
}
|
|
1639
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1640
|
+
getMenuHTML(options) {
|
|
1641
|
+
if (options.spinner) {
|
|
1642
|
+
return `
|
|
1643
|
+
<div class="tsg-menu">
|
|
1644
|
+
<div class="tsg-no-items">
|
|
1645
|
+
<div class="tsg-spinner"></div>
|
|
1646
|
+
${TsUtils.lang("Loading...")}
|
|
1647
|
+
</div>
|
|
1648
|
+
</div>`;
|
|
1649
|
+
}
|
|
1650
|
+
const parents = options.parents ?? [];
|
|
1651
|
+
let items = options.items;
|
|
1652
|
+
if (!Array.isArray(items)) items = [];
|
|
1653
|
+
let count = 0;
|
|
1654
|
+
let icon = null;
|
|
1655
|
+
let topHTML = "";
|
|
1656
|
+
if (options.search) {
|
|
1657
|
+
topHTML += `
|
|
1658
|
+
<div class="tsg-menu-search">
|
|
1659
|
+
<span class="tsg-icon tsg-icon-search"></span>
|
|
1660
|
+
<input id="menu-search" class="tsg-input" type="text"/>
|
|
1661
|
+
</div>`;
|
|
1662
|
+
items.forEach((item) => item.hidden = false);
|
|
1663
|
+
}
|
|
1664
|
+
if (options.topHTML) {
|
|
1665
|
+
topHTML += `<div class="tsg-menu-top">${options.topHTML}</div>`;
|
|
1666
|
+
}
|
|
1667
|
+
let menu_html = `
|
|
1668
|
+
${topHTML}
|
|
1669
|
+
<div class="tsg-menu" style="${options.menuStyle}" data-parents="${parents.join("-")}">
|
|
1670
|
+
`;
|
|
1671
|
+
items.forEach((mitem, f) => {
|
|
1672
|
+
icon = mitem.icon;
|
|
1673
|
+
const index = (parents.length > 0 ? parents.join("-") + "-" : "") + f;
|
|
1674
|
+
if (icon == null) icon = null;
|
|
1675
|
+
if (["radio", "check"].includes(options.type) && !Array.isArray(mitem.items) && mitem.group !== false) {
|
|
1676
|
+
if (mitem.checked === true) icon = "tsg-icon-check";
|
|
1677
|
+
else icon = "tsg-icon-empty";
|
|
1678
|
+
}
|
|
1679
|
+
if (mitem.hidden !== true) {
|
|
1680
|
+
let txt = mitem.text;
|
|
1681
|
+
let icon_dsp = "";
|
|
1682
|
+
if (typeof options.render === "function") txt = options.render(mitem, options);
|
|
1683
|
+
if (typeof txt == "function") txt = txt(mitem, options);
|
|
1684
|
+
if (icon) {
|
|
1685
|
+
const first = String(icon).trim().slice(0, 1);
|
|
1686
|
+
if (first == "#") {
|
|
1687
|
+
icon = `<span class="tsg-icon tsg-icon-empty" style="background-color: ${icon}"></span>`;
|
|
1688
|
+
} else if (first !== "<") {
|
|
1689
|
+
icon = `<span class="tsg-icon ${icon}"></span>`;
|
|
1690
|
+
}
|
|
1691
|
+
icon_dsp = `<div class="menu-icon">${icon}</div>`;
|
|
1692
|
+
}
|
|
1693
|
+
if (mitem.removable == null && mitem.remove != null) {
|
|
1694
|
+
mitem.removable = mitem.remove;
|
|
1695
|
+
}
|
|
1696
|
+
if (mitem.type !== "break" && txt != null && txt !== "" && String(txt).substr(0, 2) != "--") {
|
|
1697
|
+
const classes = ["tsg-menu-item"];
|
|
1698
|
+
if (options.altRows == true) {
|
|
1699
|
+
classes.push(count % 2 === 0 ? "tsg-even" : "tsg-odd");
|
|
1700
|
+
}
|
|
1701
|
+
let colspan = 1;
|
|
1702
|
+
if (icon_dsp === "") colspan++;
|
|
1703
|
+
if (mitem.count == null && mitem.hotkey == null && mitem.removable !== true && mitem.items == null) colspan++;
|
|
1704
|
+
if (mitem.tooltip == null && mitem.hint != null) mitem.tooltip = mitem.hint;
|
|
1705
|
+
let count_dsp = "";
|
|
1706
|
+
if (mitem.removable === true) {
|
|
1707
|
+
count_dsp = '<span class="menu-remove">x</span>';
|
|
1708
|
+
} else if (mitem.items != null) {
|
|
1709
|
+
classes.push("has-sub-menu");
|
|
1710
|
+
count_dsp = '<span style="background-color: transparent; border: transparent; box-shadow: none;"></span>';
|
|
1711
|
+
} else {
|
|
1712
|
+
if (mitem.count != null) count_dsp += "<span>" + mitem.count + "</span>";
|
|
1713
|
+
if (mitem.hotkey != null) count_dsp += '<span class="menu-hotkey">' + mitem.hotkey + "</span>";
|
|
1714
|
+
if (mitem.help != null) count_dsp += '<span class="menu-help">?</span>';
|
|
1715
|
+
}
|
|
1716
|
+
if (mitem.disabled === true) classes.push("tsg-disabled");
|
|
1717
|
+
if (mitem._noSearchInside === true) classes.push("tsg-no-search-inside");
|
|
1718
|
+
menu_html += `
|
|
1719
|
+
<div index="${index}" class="${classes.join(" ")}" style="${mitem.style ? mitem.style : ""}"
|
|
1720
|
+
data-index="${f}" data-hasSubmenu="${mitem.items != null ? "yes" : ""}">
|
|
1721
|
+
<div style="width: ${parseInt(mitem.indent ?? 0)}px"></div>
|
|
1722
|
+
${icon_dsp}
|
|
1723
|
+
<div class="menu-text" colspan="${colspan}">${TsUtils.lang(txt)}</div>
|
|
1724
|
+
<div class="menu-extra">${mitem.extra ?? ""}${count_dsp}</div>
|
|
1725
|
+
</div>`;
|
|
1726
|
+
count++;
|
|
1727
|
+
} else {
|
|
1728
|
+
const divText = (txt ?? "").replace(/^-+/g, "");
|
|
1729
|
+
menu_html += `
|
|
1730
|
+
<div index="${index}" class="tsg-menu-divider ${divText != "" ? "has-text" : ""}">
|
|
1731
|
+
<div class="line"></div>
|
|
1732
|
+
${divText ? `<div class="text">${divText}</div>` : ""}
|
|
1733
|
+
</div>`;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
items[f] = mitem;
|
|
1737
|
+
});
|
|
1738
|
+
if (count === 0 && options.msgNoItems) {
|
|
1739
|
+
const overlay = Tooltip.active[options.name.replace(/[\s\.#]/g, "_")];
|
|
1740
|
+
const remote = overlay?.tmp["remote"];
|
|
1741
|
+
let msg = options.msgNoItems;
|
|
1742
|
+
if (options.url) {
|
|
1743
|
+
if (count == 0 && remote?.hasMore === false) {
|
|
1744
|
+
msg = options.msgNoItems;
|
|
1745
|
+
} else {
|
|
1746
|
+
msg = options.msgSearch;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
menu_html += `
|
|
1750
|
+
<div class="tsg-no-items">
|
|
1751
|
+
${TsUtils.lang(msg)}
|
|
1752
|
+
</div>`;
|
|
1753
|
+
}
|
|
1754
|
+
menu_html += "</div>";
|
|
1755
|
+
return menu_html;
|
|
1756
|
+
}
|
|
1757
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1758
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1759
|
+
openSubMenu(event) {
|
|
1760
|
+
const anchor = query2(event.originalEvent.target).get(0);
|
|
1761
|
+
const { overlay } = event;
|
|
1762
|
+
const { items } = overlay.options;
|
|
1763
|
+
const mitem = items[event.index];
|
|
1764
|
+
let _items = [];
|
|
1765
|
+
if (typeof mitem.items == "function") {
|
|
1766
|
+
_items = mitem.items(mitem);
|
|
1767
|
+
} else if (Array.isArray(mitem.items)) {
|
|
1768
|
+
_items = mitem.items;
|
|
1769
|
+
}
|
|
1770
|
+
const prev = TsMenu.get(overlay.name + "-submenu");
|
|
1771
|
+
if (prev) {
|
|
1772
|
+
prev.hide();
|
|
1773
|
+
}
|
|
1774
|
+
query2(event.target).addClass("expanded");
|
|
1775
|
+
TsMenu.show({
|
|
1776
|
+
name: overlay.name + "-submenu",
|
|
1777
|
+
anchor,
|
|
1778
|
+
items: _items,
|
|
1779
|
+
class: overlay.options.class + " " + mitem.overlay?.class,
|
|
1780
|
+
offsetX: -7,
|
|
1781
|
+
arrowSize: 0,
|
|
1782
|
+
parentOverlay: overlay,
|
|
1783
|
+
parents: [...event.parents, event.index],
|
|
1784
|
+
position: "right|left",
|
|
1785
|
+
hideOn: ["doc-click", "select"]
|
|
1786
|
+
// any: cast-to-any for dynamic dispatch; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1787
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1788
|
+
}).hide((_evt) => {
|
|
1789
|
+
query2(event.target).removeClass("expanded");
|
|
1790
|
+
});
|
|
1791
|
+
setTimeout(() => {
|
|
1792
|
+
query2("#w2overlay-" + overlay.name + "-submenu").on("mouseenter", (event2) => {
|
|
1793
|
+
event2.target._keepSubOpen = true;
|
|
1794
|
+
}).on("mouseleave", (event2) => {
|
|
1795
|
+
event2.target._keepSubOpen = false;
|
|
1796
|
+
});
|
|
1797
|
+
}, 10);
|
|
1798
|
+
}
|
|
1799
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1800
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1801
|
+
closeSubMenu(event) {
|
|
1802
|
+
const { overlay } = event;
|
|
1803
|
+
if (event.target._keepSubOpen !== true) {
|
|
1804
|
+
const prev = TsMenu.get(overlay.name + "-submenu");
|
|
1805
|
+
if (prev) {
|
|
1806
|
+
prev.hide();
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
// Refreshed only selected item highligh, used in keyboard navigation
|
|
1811
|
+
refreshIndex(name, instant) {
|
|
1812
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
1813
|
+
if (!overlay) return;
|
|
1814
|
+
if (!overlay.displayed) {
|
|
1815
|
+
this.show(overlay.name);
|
|
1816
|
+
}
|
|
1817
|
+
const view = query2(overlay.box).find(".tsg-overlay-body").get(0);
|
|
1818
|
+
const search = query2(overlay.box).find(".tsg-menu-search, .tsg-menu-top").get(0);
|
|
1819
|
+
query2(overlay.box).find(".tsg-menu-item.tsg-selected").removeClass("tsg-selected");
|
|
1820
|
+
const el = query2(overlay.box).find(`.tsg-menu-item[index="${overlay.selected}"]`).addClass("tsg-selected").get(0);
|
|
1821
|
+
if (el) {
|
|
1822
|
+
if (el.offsetTop + el.clientHeight > view.clientHeight + view.scrollTop) {
|
|
1823
|
+
el.scrollIntoView({
|
|
1824
|
+
behavior: instant ? "instant" : "smooth",
|
|
1825
|
+
block: instant ? "center" : "start",
|
|
1826
|
+
inline: instant ? "center" : "start"
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
if (el.offsetTop < view.scrollTop + (search ? search.clientHeight : 0)) {
|
|
1830
|
+
el.scrollIntoView({
|
|
1831
|
+
behavior: instant ? "instant" : "smooth",
|
|
1832
|
+
block: instant ? "center" : "end",
|
|
1833
|
+
inline: instant ? "center" : "end"
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
TsTooltip.hide(overlay.name + "-tooltip");
|
|
1838
|
+
}
|
|
1839
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1840
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1841
|
+
showTooltip(name, options) {
|
|
1842
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
1843
|
+
if (!overlay || !overlay.displayed) return;
|
|
1844
|
+
const anchor = options?.anchor ?? query2(overlay.box).find(`.tsg-menu-item[index="${overlay.selected}"]`).get(0);
|
|
1845
|
+
const tooltip = options?.tooltip ?? (overlay.selected != null ? overlay.options.items?.[overlay.selected]?.tooltip : void 0);
|
|
1846
|
+
if (tooltip) {
|
|
1847
|
+
const html = tooltip.html ?? tooltip;
|
|
1848
|
+
TsTooltip.show(Object.assign({
|
|
1849
|
+
name: overlay.name + "-tooltip",
|
|
1850
|
+
anchor,
|
|
1851
|
+
html,
|
|
1852
|
+
position: "right|left",
|
|
1853
|
+
hideOn: ["doc-click"],
|
|
1854
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1855
|
+
onShow(event) {
|
|
1856
|
+
overlay.self.trigger("tooltip", { overlay, action: "show", originalEvent: event });
|
|
1857
|
+
},
|
|
1858
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1859
|
+
onHide(event) {
|
|
1860
|
+
overlay.self.trigger("tooltip", { overlay, action: "hide", originalEvent: event });
|
|
1861
|
+
}
|
|
1862
|
+
}, typeof tooltip == "object" && tooltip != null ? tooltip : {}));
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
// show/hide searched items
|
|
1866
|
+
refreshSearch(name) {
|
|
1867
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
1868
|
+
if (!overlay) return;
|
|
1869
|
+
if (!overlay.displayed) {
|
|
1870
|
+
this.show(overlay.name);
|
|
1871
|
+
}
|
|
1872
|
+
TsTooltip.hide(overlay.name + "-tooltip");
|
|
1873
|
+
query2(overlay.box).find(".tsg-no-items").hide();
|
|
1874
|
+
query2(overlay.box).find(".tsg-menu-item, .tsg-menu-divider").each((el) => {
|
|
1875
|
+
const cur = this.getCurrent(name, el.getAttribute("index"));
|
|
1876
|
+
if (cur.item?.hidden) {
|
|
1877
|
+
query2(el).hide();
|
|
1878
|
+
} else {
|
|
1879
|
+
const search = overlay.tmp?.["search"];
|
|
1880
|
+
if (overlay.options.markSearch) {
|
|
1881
|
+
TsUtils.marker(el, search, { onlyFirst: overlay.options.match == "begins" });
|
|
1882
|
+
}
|
|
1883
|
+
query2(el).show();
|
|
1884
|
+
}
|
|
1885
|
+
});
|
|
1886
|
+
query2(overlay.box).find(".tsg-sub-menu").each((sub) => {
|
|
1887
|
+
const hasItems = query2(sub).find(".tsg-menu-item").get().some((el) => {
|
|
1888
|
+
return el.style.display != "none" ? true : false;
|
|
1889
|
+
});
|
|
1890
|
+
const parent = this.getCurrent(name, sub.dataset?.parent);
|
|
1891
|
+
if (parent.item.expanded) {
|
|
1892
|
+
if (!hasItems) {
|
|
1893
|
+
query2(sub).parent().hide();
|
|
1894
|
+
} else {
|
|
1895
|
+
query2(sub).parent().show();
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1899
|
+
if (overlay.tmp["searchCount"] == 0 || (overlay.options?.items?.length ?? 0) == 0) {
|
|
1900
|
+
if (query2(overlay.box).find(".tsg-no-items").length == 0) {
|
|
1901
|
+
query2(overlay.box).find(".tsg-menu:not(.tsg-sub-menu)").append(`
|
|
1902
|
+
<div class="tsg-no-items">
|
|
1903
|
+
${TsUtils.lang(overlay.options.msgNoItems)}
|
|
1904
|
+
</div>`);
|
|
1905
|
+
}
|
|
1906
|
+
query2(overlay.box).find(".tsg-no-items").show();
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* Loops through the items and markes item.hidden = true for those that need to be hidden, and item.hidden = false
|
|
1911
|
+
* for those that are visible. Return a promise (since items can be on the server) with the number of visible items.
|
|
1912
|
+
*/
|
|
1913
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
1914
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1915
|
+
applyFilter(name, items, search, debounce) {
|
|
1916
|
+
let count = 0;
|
|
1917
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
1918
|
+
const options = overlay.options;
|
|
1919
|
+
let resolve, reject;
|
|
1920
|
+
const prom = new Promise((res, rej) => {
|
|
1921
|
+
resolve = res;
|
|
1922
|
+
reject = rej;
|
|
1923
|
+
});
|
|
1924
|
+
if (overlay.tmp["_skip_filter"] === true) {
|
|
1925
|
+
return prom;
|
|
1926
|
+
}
|
|
1927
|
+
if (search == null) {
|
|
1928
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
1929
|
+
search = overlay.anchor.value;
|
|
1930
|
+
} else {
|
|
1931
|
+
search = "";
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
if (overlay.tmp["_new_search"] === false) {
|
|
1935
|
+
search = "";
|
|
1936
|
+
}
|
|
1937
|
+
let selectedIds = [];
|
|
1938
|
+
if (options.selected) {
|
|
1939
|
+
if (Array.isArray(options.selected)) {
|
|
1940
|
+
selectedIds = options.selected.map((item) => {
|
|
1941
|
+
return item?.id ?? item;
|
|
1942
|
+
});
|
|
1943
|
+
} else if (options.selected?.id) {
|
|
1944
|
+
selectedIds = [options.selected.id];
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
overlay.tmp["activeChain"] = null;
|
|
1948
|
+
const remote = overlay.tmp["remote"] ?? { hasMore: true, emptySet: false, search: null, cached: -1 };
|
|
1949
|
+
if (remote.hasMore == false) {
|
|
1950
|
+
const len = remote.hasMore_search.length;
|
|
1951
|
+
if (search.substr(0, len) != remote.hasMore_search) {
|
|
1952
|
+
remote.hasMore = true;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
if (items == null && options.url && remote.hasMore && remote.search !== search) {
|
|
1956
|
+
let proceed = true;
|
|
1957
|
+
let msg = TsUtils.lang("Loading...");
|
|
1958
|
+
if (search.length < (options.minLength ?? 0) && remote.emptySet !== true) {
|
|
1959
|
+
msg = TsUtils.lang("${count} letters or more...", { count: String(options.minLength) });
|
|
1960
|
+
proceed = false;
|
|
1961
|
+
if (search === "") {
|
|
1962
|
+
msg = TsUtils.lang(options.msgSearch);
|
|
1963
|
+
}
|
|
1964
|
+
if ((options.items?.length ?? 0) > 0) {
|
|
1965
|
+
this.update(name, []);
|
|
1966
|
+
this.applyFilter(name, null, search);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
query2(overlay.box).find(".tsg-no-items").html(msg);
|
|
1970
|
+
remote.search = search;
|
|
1971
|
+
options.items = [];
|
|
1972
|
+
overlay.tmp["remote"] = remote;
|
|
1973
|
+
if (proceed) {
|
|
1974
|
+
this.request(overlay, search, debounce).then((remoteItems) => {
|
|
1975
|
+
overlay.tmp["_skip_filter"] = true;
|
|
1976
|
+
this.update(name, remoteItems);
|
|
1977
|
+
delete overlay.tmp["_skip_filter"];
|
|
1978
|
+
overlay.tmp["_new_search"] = true;
|
|
1979
|
+
this.applyFilter(name, remoteItems, search).then((data) => {
|
|
1980
|
+
this.getActiveChain(overlay.name, options.items);
|
|
1981
|
+
overlay.tmp["searchCount"] = data.count;
|
|
1982
|
+
overlay.tmp["search"] = data.search;
|
|
1983
|
+
if (options.prefilter || search !== "") {
|
|
1984
|
+
if (data.count === 0 || !this.getActiveChain(overlay.name, options.items).includes(overlay.selected)) {
|
|
1985
|
+
overlay.selected = null;
|
|
1986
|
+
}
|
|
1987
|
+
this.refreshSearch(overlay.name);
|
|
1988
|
+
}
|
|
1989
|
+
this.initControls(overlay);
|
|
1990
|
+
this.refreshIndex(overlay.name, true);
|
|
1991
|
+
resolve(data);
|
|
1992
|
+
});
|
|
1993
|
+
}).catch((error) => {
|
|
1994
|
+
console.log("Server Request error", error);
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
return prom;
|
|
1998
|
+
}
|
|
1999
|
+
let edata;
|
|
2000
|
+
if (items == null) {
|
|
2001
|
+
edata = this.trigger("search", { search, overlay, prom, resolve, reject });
|
|
2002
|
+
if (edata.isCancelled === true) {
|
|
2003
|
+
return prom;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
if (items == null) {
|
|
2007
|
+
items = overlay.options.items;
|
|
2008
|
+
}
|
|
2009
|
+
if (options.filter === false) {
|
|
2010
|
+
resolve({ count: -1, search });
|
|
2011
|
+
return prom;
|
|
2012
|
+
}
|
|
2013
|
+
items.forEach((item) => {
|
|
2014
|
+
if (options.match == "regex") {
|
|
2015
|
+
try {
|
|
2016
|
+
const re = new RegExp(search, "i");
|
|
2017
|
+
if (re.test(item.text) || item.text === "...") {
|
|
2018
|
+
item.hidden = false;
|
|
2019
|
+
} else {
|
|
2020
|
+
item.hidden = true;
|
|
2021
|
+
}
|
|
2022
|
+
} catch (e) {
|
|
2023
|
+
}
|
|
2024
|
+
} else {
|
|
2025
|
+
let prefix = "";
|
|
2026
|
+
let suffix = "";
|
|
2027
|
+
if (["is", "begins", "begins with"].indexOf(options.match ?? "") !== -1) prefix = "^";
|
|
2028
|
+
if (["is", "ends", "ends with"].indexOf(options.match ?? "") !== -1) suffix = "$";
|
|
2029
|
+
try {
|
|
2030
|
+
const re = new RegExp(prefix + search + suffix, "i");
|
|
2031
|
+
if (re.test(item.text) || item.text === "...") {
|
|
2032
|
+
item.hidden = false;
|
|
2033
|
+
} else {
|
|
2034
|
+
item.hidden = true;
|
|
2035
|
+
}
|
|
2036
|
+
} catch (e) {
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
if (options.hideSelected && selectedIds.includes(item.id)) {
|
|
2040
|
+
item.hidden = true;
|
|
2041
|
+
}
|
|
2042
|
+
if (Array.isArray(item.items) && item.items.length > 0) {
|
|
2043
|
+
delete item._noSearchInside;
|
|
2044
|
+
this.applyFilter(name, item.items, search).then((data) => {
|
|
2045
|
+
const subCount = data.count;
|
|
2046
|
+
if (subCount > 0) {
|
|
2047
|
+
count += subCount;
|
|
2048
|
+
if (item.hidden) item._noSearchInside = true;
|
|
2049
|
+
if (search) item.expanded = true;
|
|
2050
|
+
item.hidden = false;
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
if (item.hidden !== true) count++;
|
|
2055
|
+
});
|
|
2056
|
+
resolve({ count, search });
|
|
2057
|
+
edata?.finish();
|
|
2058
|
+
return prom;
|
|
2059
|
+
}
|
|
2060
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2061
|
+
request(overlay, search, debounce) {
|
|
2062
|
+
const options = overlay.options;
|
|
2063
|
+
const remote = overlay.tmp["remote"];
|
|
2064
|
+
let resolve, reject;
|
|
2065
|
+
if (options.items.length === 0 && remote.cached !== 0 || remote.cached == options.cacheMax && search.length > remote.search.length || search.length >= remote.search.length && search.substr(0, remote.search.length) !== remote.search || search.length < remote.search.length) {
|
|
2066
|
+
if (remote.controller) {
|
|
2067
|
+
remote.controller.abort();
|
|
2068
|
+
}
|
|
2069
|
+
remote.loading = true;
|
|
2070
|
+
clearTimeout(remote.timeout);
|
|
2071
|
+
remote.timeout = setTimeout(() => {
|
|
2072
|
+
let url = options.url;
|
|
2073
|
+
const postData = { search, max: options.cacheMax };
|
|
2074
|
+
Object.assign(postData, options.postData);
|
|
2075
|
+
const edata = this.trigger("request", {
|
|
2076
|
+
search,
|
|
2077
|
+
overlay,
|
|
2078
|
+
url,
|
|
2079
|
+
postData,
|
|
2080
|
+
httpMethod: options.method ?? "GET",
|
|
2081
|
+
httpHeaders: {}
|
|
2082
|
+
});
|
|
2083
|
+
if (edata.isCancelled === true) return;
|
|
2084
|
+
const detail = edata.detail;
|
|
2085
|
+
url = new URL(detail["url"], location.href);
|
|
2086
|
+
const fetchOptions = TsUtils.prepareParams(url, {
|
|
2087
|
+
method: detail["httpMethod"],
|
|
2088
|
+
headers: detail["httpHeaders"],
|
|
2089
|
+
body: detail["postData"]
|
|
2090
|
+
}, { caller: this, overlay, search });
|
|
2091
|
+
remote.controller = new AbortController();
|
|
2092
|
+
fetchOptions["signal"] = remote.controller.signal;
|
|
2093
|
+
fetch(url, fetchOptions).then((resp) => resp.json()).then((data) => {
|
|
2094
|
+
remote.controller = null;
|
|
2095
|
+
const edata2 = overlay.trigger("load", { search: postData.search, overlay, data });
|
|
2096
|
+
if (edata2.isCancelled === true) return;
|
|
2097
|
+
data = edata2.detail.data;
|
|
2098
|
+
if (typeof data === "string") data = JSON.parse(data);
|
|
2099
|
+
if (Array.isArray(data)) {
|
|
2100
|
+
data = { records: data };
|
|
2101
|
+
}
|
|
2102
|
+
if (data.records == null && data.items != null) {
|
|
2103
|
+
data.records = data.items;
|
|
2104
|
+
delete data.items;
|
|
2105
|
+
}
|
|
2106
|
+
if (!data.error && data.records == null) {
|
|
2107
|
+
data.records = [];
|
|
2108
|
+
}
|
|
2109
|
+
if (!Array.isArray(data.records)) {
|
|
2110
|
+
console.error(
|
|
2111
|
+
"ERROR: server did not return proper JSON data structure",
|
|
2112
|
+
"\n",
|
|
2113
|
+
" - it should return",
|
|
2114
|
+
{ records: [{ id: 1, text: "item" }] },
|
|
2115
|
+
"\n",
|
|
2116
|
+
" - or just an array ",
|
|
2117
|
+
[{ id: 1, text: "item" }],
|
|
2118
|
+
"\n",
|
|
2119
|
+
" - or if errorr ",
|
|
2120
|
+
{ error: true, message: "error message" }
|
|
2121
|
+
);
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
if (data.records.length >= options.cacheMax) {
|
|
2125
|
+
data.records.splice(options.cacheMax, data.records.length);
|
|
2126
|
+
remote.hasMore = true;
|
|
2127
|
+
} else {
|
|
2128
|
+
remote.hasMore = false;
|
|
2129
|
+
remote.hasMore_search = search;
|
|
2130
|
+
}
|
|
2131
|
+
if (options.recId == null && options.recid != null) options.recId = options.recid;
|
|
2132
|
+
if (options.recId || options.recText) {
|
|
2133
|
+
data.records.forEach((item) => {
|
|
2134
|
+
if (typeof options.recId === "string") item.id = item[options.recId];
|
|
2135
|
+
if (typeof options.recId === "function") item.id = options.recId(item);
|
|
2136
|
+
if (typeof options.recText === "string") item.text = item[options.recText];
|
|
2137
|
+
if (typeof options.recText === "function") item.text = options.recText(item);
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
remote.loading = false;
|
|
2141
|
+
remote.search = search;
|
|
2142
|
+
remote.cached = data.records.length == 0 ? -1 : data.records.length;
|
|
2143
|
+
remote.lastError = "";
|
|
2144
|
+
remote.emptySet = search === "" && data.records.length === 0 ? true : false;
|
|
2145
|
+
edata2.finish();
|
|
2146
|
+
resolve(TsUtils.normMenu(data.records, data));
|
|
2147
|
+
}).catch((error) => {
|
|
2148
|
+
const edata2 = this.trigger("error", { overlay, search, error });
|
|
2149
|
+
if (edata2.isCancelled === true) return;
|
|
2150
|
+
if (error?.name !== "AbortError") {
|
|
2151
|
+
console.error(
|
|
2152
|
+
"ERROR: Server communication failed.",
|
|
2153
|
+
"\n",
|
|
2154
|
+
" - it should return",
|
|
2155
|
+
{ records: [{ id: 1, text: "item" }] },
|
|
2156
|
+
"\n",
|
|
2157
|
+
" - or just an array ",
|
|
2158
|
+
[{ id: 1, text: "item" }],
|
|
2159
|
+
"\n",
|
|
2160
|
+
" - or if errorr ",
|
|
2161
|
+
{ error: true, message: "error message" }
|
|
2162
|
+
);
|
|
2163
|
+
}
|
|
2164
|
+
remote.loading = false;
|
|
2165
|
+
remote.search = "";
|
|
2166
|
+
remote.cached = -1;
|
|
2167
|
+
remote.emptySet = true;
|
|
2168
|
+
remote.lastError = edata2.detail["error"] || "Server communication failed";
|
|
2169
|
+
options.items = [];
|
|
2170
|
+
edata2.finish();
|
|
2171
|
+
reject();
|
|
2172
|
+
});
|
|
2173
|
+
edata.finish();
|
|
2174
|
+
}, debounce ? options.debounce ?? 350 : 0);
|
|
2175
|
+
}
|
|
2176
|
+
return new Promise((res, rej) => {
|
|
2177
|
+
resolve = res;
|
|
2178
|
+
reject = rej;
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Builds an array of item ids that sequencial order for navigation with up/down keys. Skips hidden and disabled items
|
|
2183
|
+
* and goes into nested structures. It will remember last active chain in 'overlay.tmp.activeChain'
|
|
2184
|
+
*/
|
|
2185
|
+
// any: parameter typed any — runtime dispatch by call site; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2186
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2187
|
+
getActiveChain(name, items, parents = [], res = [], noSave) {
|
|
2188
|
+
const overlay = Tooltip.active[name.replace(/[\s\.#]/g, "_")];
|
|
2189
|
+
if (overlay.tmp["activeChain"] != null) {
|
|
2190
|
+
return overlay.tmp["activeChain"];
|
|
2191
|
+
}
|
|
2192
|
+
if (items == null) items = overlay.options.items;
|
|
2193
|
+
items.forEach((item, ind) => {
|
|
2194
|
+
if (!item.hidden && !item.disabled && !item?.text?.startsWith?.("--")) {
|
|
2195
|
+
res.push(parents.concat([ind]).join("-"));
|
|
2196
|
+
if (Array.isArray(item.items) && item.items.length > 0 && item.expanded) {
|
|
2197
|
+
parents.push(ind);
|
|
2198
|
+
this.getActiveChain(name, item.items, parents, res, true);
|
|
2199
|
+
parents.pop();
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
if (noSave == null) {
|
|
2204
|
+
overlay.tmp["activeChain"] = res;
|
|
2205
|
+
}
|
|
2206
|
+
return res;
|
|
2207
|
+
}
|
|
2208
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2209
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2210
|
+
menuDown(overlay, event, index, parents) {
|
|
2211
|
+
const options = overlay.options;
|
|
2212
|
+
let items = options.items;
|
|
2213
|
+
const icon = query2(event.delegate).find(".tsg-icon");
|
|
2214
|
+
const menu = query2(event.target).closest(".tsg-menu:not(.tsg-sub-menu)");
|
|
2215
|
+
if (typeof items == "function") {
|
|
2216
|
+
items = items({ overlay, index, parents, event });
|
|
2217
|
+
}
|
|
2218
|
+
const item = items[index];
|
|
2219
|
+
if (item == null || item.disabled) {
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
const uncheck = (items2, parent) => {
|
|
2223
|
+
items2.forEach((other, ind) => {
|
|
2224
|
+
if (other.id == item.id) return;
|
|
2225
|
+
if (other.group === item.group && other.checked) {
|
|
2226
|
+
menu.find(`.tsg-menu-item[index="${(parent ? parent + "-" : "") + ind}"] .tsg-icon`).removeClass("tsg-icon-check").addClass("tsg-icon-empty");
|
|
2227
|
+
items2[ind].checked = false;
|
|
2228
|
+
}
|
|
2229
|
+
if (Array.isArray(other.items)) {
|
|
2230
|
+
uncheck(other.items, ind);
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
};
|
|
2234
|
+
if ((options.type === "check" || options.type === "radio") && item.group !== false && !query2(event.target).hasClass("menu-remove") && !query2(event.target).hasClass("menu-help") && !query2(event.target).closest(".tsg-menu-item").hasClass("has-sub-menu")) {
|
|
2235
|
+
item.checked = options.type == "radio" ? true : !item.checked;
|
|
2236
|
+
if (item.checked) {
|
|
2237
|
+
if (options.type === "radio") {
|
|
2238
|
+
query2(event.target).closest(".tsg-menu").find(".tsg-icon").removeClass("tsg-icon-check").addClass("tsg-icon-empty");
|
|
2239
|
+
}
|
|
2240
|
+
if (options.type === "check" && item.group != null) {
|
|
2241
|
+
uncheck(options.items);
|
|
2242
|
+
}
|
|
2243
|
+
icon.removeClass("tsg-icon-empty").addClass("tsg-icon-check");
|
|
2244
|
+
} else if (options.type === "check") {
|
|
2245
|
+
icon.removeClass("tsg-icon-check").addClass("tsg-icon-empty");
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (!query2(event.target).hasClass("menu-remove") && !query2(event.target).hasClass("menu-help")) {
|
|
2249
|
+
menu.find(".tsg-menu-item").removeClass("tsg-selected");
|
|
2250
|
+
if (!query2(event.delegate).hasClass("has-sub-menu")) {
|
|
2251
|
+
query2(event.delegate).addClass("tsg-selected");
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2256
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2257
|
+
menuClick(overlay, event, index, parents) {
|
|
2258
|
+
const options = overlay.options;
|
|
2259
|
+
let items = options.items;
|
|
2260
|
+
const $item = query2(event.delegate).closest(".tsg-menu-item");
|
|
2261
|
+
let keepOpen = options.hideOn.includes("select") ? false : true;
|
|
2262
|
+
if (event.shiftKey || event.metaKey || event.ctrlKey) {
|
|
2263
|
+
keepOpen = true;
|
|
2264
|
+
}
|
|
2265
|
+
if (typeof items == "function") {
|
|
2266
|
+
items = items({ overlay, index, parents, event });
|
|
2267
|
+
}
|
|
2268
|
+
const item = items[index];
|
|
2269
|
+
if (!item || item.disabled && !query2(event.target).hasClass("menu-remove")) {
|
|
2270
|
+
return;
|
|
2271
|
+
}
|
|
2272
|
+
let edata;
|
|
2273
|
+
const overlays = [overlay];
|
|
2274
|
+
let topOverlay = overlay;
|
|
2275
|
+
let parentOverlay;
|
|
2276
|
+
while (topOverlay.options.parentOverlay) {
|
|
2277
|
+
topOverlay = topOverlay.options.parentOverlay;
|
|
2278
|
+
parentOverlay ??= topOverlay;
|
|
2279
|
+
overlays.push(topOverlay);
|
|
2280
|
+
}
|
|
2281
|
+
if (query2(event.target).hasClass("menu-remove")) {
|
|
2282
|
+
edata = topOverlay.trigger("remove", {
|
|
2283
|
+
originalEvent: event,
|
|
2284
|
+
target: overlay.name,
|
|
2285
|
+
overlay,
|
|
2286
|
+
topOverlay,
|
|
2287
|
+
parentOverlay,
|
|
2288
|
+
item,
|
|
2289
|
+
index,
|
|
2290
|
+
el: $item[0],
|
|
2291
|
+
parents
|
|
2292
|
+
});
|
|
2293
|
+
if (edata.isCancelled === true) {
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
const items2 = options.items;
|
|
2297
|
+
const ind = items2.findIndex((it) => it.id == item.id);
|
|
2298
|
+
if (ind != -1) {
|
|
2299
|
+
const tmp = items2.splice(ind, 1);
|
|
2300
|
+
if (overlay.options.parents) {
|
|
2301
|
+
const pind = overlay.options.parents[overlay.options.parents.length - 1];
|
|
2302
|
+
const pitems = parentOverlay.options.items[pind].items;
|
|
2303
|
+
if (pitems[ind].id == tmp[0].id) {
|
|
2304
|
+
pitems.splice(ind, 1);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
keepOpen = !options.hideOn.includes("item-remove");
|
|
2309
|
+
const name = $item.closest(".tsg-overlay").attr("name");
|
|
2310
|
+
overlay.self.update(name, items2);
|
|
2311
|
+
} else if ($item.hasClass("has-sub-menu")) {
|
|
2312
|
+
edata = topOverlay.trigger("subMenu", {
|
|
2313
|
+
originalEvent: event,
|
|
2314
|
+
target: overlay.name,
|
|
2315
|
+
overlay,
|
|
2316
|
+
topOverlay,
|
|
2317
|
+
parentOverlay,
|
|
2318
|
+
item,
|
|
2319
|
+
index,
|
|
2320
|
+
el: $item[0],
|
|
2321
|
+
parents
|
|
2322
|
+
});
|
|
2323
|
+
if (edata.isCancelled === true) {
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
keepOpen = true;
|
|
2327
|
+
} else {
|
|
2328
|
+
const selected = this.findChecked(options.items);
|
|
2329
|
+
const a_index = $item.attr("index");
|
|
2330
|
+
overlay.selected = isNaN(Number(a_index)) ? a_index : parseInt(a_index);
|
|
2331
|
+
edata = topOverlay.trigger("select", {
|
|
2332
|
+
originalEvent: event,
|
|
2333
|
+
target: overlay.name,
|
|
2334
|
+
overlay,
|
|
2335
|
+
topOverlay,
|
|
2336
|
+
parentOverlay,
|
|
2337
|
+
item,
|
|
2338
|
+
index,
|
|
2339
|
+
selected,
|
|
2340
|
+
keepOpen,
|
|
2341
|
+
el: $item[0],
|
|
2342
|
+
parents
|
|
2343
|
+
});
|
|
2344
|
+
if (edata.isCancelled === true) {
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2347
|
+
if (item.keepOpen != null) {
|
|
2348
|
+
keepOpen = item.keepOpen;
|
|
2349
|
+
}
|
|
2350
|
+
if (["INPUT", "TEXTAREA"].includes(overlay.anchor.tagName)) {
|
|
2351
|
+
overlay.anchor.dataset.selected = item.id;
|
|
2352
|
+
overlay.anchor.dataset.selectedIndex = overlay.selected;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
if (!keepOpen) {
|
|
2356
|
+
overlays.forEach((overlay2) => this.hide(overlay2.name));
|
|
2357
|
+
}
|
|
2358
|
+
edata.finish();
|
|
2359
|
+
}
|
|
2360
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2361
|
+
findChecked(items) {
|
|
2362
|
+
let found = [];
|
|
2363
|
+
items.forEach((item) => {
|
|
2364
|
+
if (item.checked) found.push(item);
|
|
2365
|
+
if (Array.isArray(item.items)) {
|
|
2366
|
+
found = found.concat(this.findChecked(item.items));
|
|
2367
|
+
}
|
|
2368
|
+
});
|
|
2369
|
+
return found;
|
|
2370
|
+
}
|
|
2371
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2372
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2373
|
+
keyUp(overlay, event) {
|
|
2374
|
+
const options = overlay.options;
|
|
2375
|
+
const search = event.target.value;
|
|
2376
|
+
let filter = true;
|
|
2377
|
+
let refreshIndex = false;
|
|
2378
|
+
switch (event.keyCode) {
|
|
2379
|
+
case 46:
|
|
2380
|
+
// delete
|
|
2381
|
+
case 8: {
|
|
2382
|
+
if (search === "" && !overlay.displayed) filter = false;
|
|
2383
|
+
break;
|
|
2384
|
+
}
|
|
2385
|
+
case 13: {
|
|
2386
|
+
if (!overlay.displayed || !overlay.selected) return;
|
|
2387
|
+
const { index, parents } = this.getCurrent(overlay.name);
|
|
2388
|
+
event.delegate = query2(overlay.box).find(".tsg-selected").get(0);
|
|
2389
|
+
this.menuClick(overlay, event, parseInt(String(index)), parents);
|
|
2390
|
+
filter = false;
|
|
2391
|
+
break;
|
|
2392
|
+
}
|
|
2393
|
+
case 27: {
|
|
2394
|
+
filter = false;
|
|
2395
|
+
if (overlay.displayed) {
|
|
2396
|
+
this.hide(overlay.name);
|
|
2397
|
+
} else {
|
|
2398
|
+
const el = overlay.anchor;
|
|
2399
|
+
if (["INPUT", "TEXTAREA"].includes(el.tagName)) {
|
|
2400
|
+
el.value = "";
|
|
2401
|
+
delete el.dataset.selected;
|
|
2402
|
+
delete el.dataset.selectedIndex;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
break;
|
|
2406
|
+
}
|
|
2407
|
+
case 37: {
|
|
2408
|
+
if (!overlay.displayed) return;
|
|
2409
|
+
let { item, index, parents } = this.getCurrent(overlay.name);
|
|
2410
|
+
if (parents) {
|
|
2411
|
+
item = options.items[parseInt(parents)];
|
|
2412
|
+
index = parseInt(parents);
|
|
2413
|
+
parents = "";
|
|
2414
|
+
refreshIndex = true;
|
|
2415
|
+
}
|
|
2416
|
+
if (Array.isArray(item?.items) && item.items.length > 0 && item.expanded) {
|
|
2417
|
+
event.delegate = query2(overlay.box).find(`.tsg-menu-item[index="${index}"]`).get(0);
|
|
2418
|
+
overlay.selected = index;
|
|
2419
|
+
this.menuClick(overlay, event, parseInt(String(index)), parents);
|
|
2420
|
+
}
|
|
2421
|
+
filter = false;
|
|
2422
|
+
break;
|
|
2423
|
+
}
|
|
2424
|
+
case 39: {
|
|
2425
|
+
if (!overlay.displayed) return;
|
|
2426
|
+
const { item, index, parents } = this.getCurrent(overlay.name);
|
|
2427
|
+
if (Array.isArray(item?.items) && item.items.length > 0 && !item.expanded) {
|
|
2428
|
+
event.delegate = query2(overlay.box).find(".tsg-selected").get(0);
|
|
2429
|
+
this.menuClick(overlay, event, parseInt(String(index)), parents);
|
|
2430
|
+
}
|
|
2431
|
+
filter = false;
|
|
2432
|
+
break;
|
|
2433
|
+
}
|
|
2434
|
+
case 38: {
|
|
2435
|
+
if (!overlay.displayed) {
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
overlay.prev();
|
|
2439
|
+
filter = false;
|
|
2440
|
+
event.preventDefault();
|
|
2441
|
+
break;
|
|
2442
|
+
}
|
|
2443
|
+
case 40: {
|
|
2444
|
+
if (!overlay.displayed) {
|
|
2445
|
+
break;
|
|
2446
|
+
}
|
|
2447
|
+
overlay.next();
|
|
2448
|
+
filter = false;
|
|
2449
|
+
event.preventDefault();
|
|
2450
|
+
break;
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
if (filter && overlay.displayed && (options.filter && event._searchType == "filter" || options.search && event._searchType == "search")) {
|
|
2454
|
+
this.applyFilter(overlay.name, null, search, true).then((data) => {
|
|
2455
|
+
overlay.tmp.searchCount = data.count;
|
|
2456
|
+
overlay.tmp.search = data.search;
|
|
2457
|
+
if (data.count === 0 || !this.getActiveChain(overlay.name).includes(overlay.selected)) {
|
|
2458
|
+
overlay.selected = null;
|
|
2459
|
+
}
|
|
2460
|
+
this.refreshSearch(overlay.name);
|
|
2461
|
+
});
|
|
2462
|
+
}
|
|
2463
|
+
if (refreshIndex) {
|
|
2464
|
+
this.refreshIndex(overlay.name);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
};
|
|
2468
|
+
var DateTooltip = class extends Tooltip {
|
|
2469
|
+
daysCount;
|
|
2470
|
+
today;
|
|
2471
|
+
constructor() {
|
|
2472
|
+
super();
|
|
2473
|
+
const td = /* @__PURE__ */ new Date();
|
|
2474
|
+
this.daysCount = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
2475
|
+
this.today = td.getFullYear() + "/" + (Number(td.getMonth()) + 1) + "/" + td.getDate();
|
|
2476
|
+
this.defaults = TsUtils.extend({}, this.defaults, {
|
|
2477
|
+
position: "top|bottom",
|
|
2478
|
+
class: "tsg-calendar",
|
|
2479
|
+
type: "date",
|
|
2480
|
+
// can be date/time/datetime
|
|
2481
|
+
value: "",
|
|
2482
|
+
// initial date (in TsUtils.settings format)
|
|
2483
|
+
format: "",
|
|
2484
|
+
start: null,
|
|
2485
|
+
end: null,
|
|
2486
|
+
btnNow: false,
|
|
2487
|
+
blockDates: [],
|
|
2488
|
+
// array of blocked dates
|
|
2489
|
+
blockWeekdays: [],
|
|
2490
|
+
// blocked weekdays 0 - sunday, 1 - monday, etc
|
|
2491
|
+
colored: {},
|
|
2492
|
+
// ex: { '3/13/2022': 'bg-color|text-color' }
|
|
2493
|
+
arrowSize: 12,
|
|
2494
|
+
autoResize: false,
|
|
2495
|
+
anchorClass: "tsg-focus",
|
|
2496
|
+
autoShowOn: "focus",
|
|
2497
|
+
hideOn: ["doc-click", "focus-change"],
|
|
2498
|
+
onSelect: null
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2502
|
+
attach(anchor, text) {
|
|
2503
|
+
let options;
|
|
2504
|
+
if (arguments.length == 1 && anchor instanceof Object) {
|
|
2505
|
+
options = anchor;
|
|
2506
|
+
anchor = options.anchor;
|
|
2507
|
+
} else if (arguments.length === 2 && text != null && typeof text === "object") {
|
|
2508
|
+
options = text;
|
|
2509
|
+
options.anchor = anchor;
|
|
2510
|
+
}
|
|
2511
|
+
const prevHideOn = options.hideOn;
|
|
2512
|
+
options = TsUtils.extend({}, this.defaults, options || {});
|
|
2513
|
+
if (prevHideOn) {
|
|
2514
|
+
options.hideOn = prevHideOn;
|
|
2515
|
+
}
|
|
2516
|
+
if (!options.format) {
|
|
2517
|
+
const df = TsUtils.settings.dateFormat;
|
|
2518
|
+
const tf = TsUtils.settings.timeFormat;
|
|
2519
|
+
if (options.type == "date") {
|
|
2520
|
+
options.format = df;
|
|
2521
|
+
} else if (options.type == "time") {
|
|
2522
|
+
options.format = tf;
|
|
2523
|
+
} else {
|
|
2524
|
+
options.format = df + "|" + tf;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
const cal = options.type == "time" ? this.getHourHTML(options) : this.getMonthHTML(options, void 0, void 0);
|
|
2528
|
+
options.style += "; padding: 0;";
|
|
2529
|
+
options.html = cal.html;
|
|
2530
|
+
const ret = super.attach(options);
|
|
2531
|
+
const overlay = ret.overlay;
|
|
2532
|
+
Object.assign(overlay.tmp, cal);
|
|
2533
|
+
overlay.on("show.attach", (event) => {
|
|
2534
|
+
const overlay2 = event.detail.overlay;
|
|
2535
|
+
const anchor2 = overlay2.anchor;
|
|
2536
|
+
const options2 = overlay2.options;
|
|
2537
|
+
if (["INPUT", "TEXTAREA"].includes(anchor2.tagName) && !options2.value && anchor2.value) {
|
|
2538
|
+
overlay2.tmp.initValue = anchor2.value;
|
|
2539
|
+
}
|
|
2540
|
+
delete overlay2.newValue;
|
|
2541
|
+
delete overlay2.newDate;
|
|
2542
|
+
});
|
|
2543
|
+
overlay.on("show:after.attach", (_event) => {
|
|
2544
|
+
if (ret.overlay?.box) {
|
|
2545
|
+
this.initControls(ret.overlay);
|
|
2546
|
+
}
|
|
2547
|
+
});
|
|
2548
|
+
overlay.on("update:after.attach", (_event) => {
|
|
2549
|
+
if (ret.overlay?.box) {
|
|
2550
|
+
this.initControls(ret.overlay);
|
|
2551
|
+
}
|
|
2552
|
+
});
|
|
2553
|
+
overlay.on("hide.attach", (event) => {
|
|
2554
|
+
const overlay2 = event.detail.overlay;
|
|
2555
|
+
const anchor2 = overlay2.anchor;
|
|
2556
|
+
if (overlay2.newValue != null) {
|
|
2557
|
+
if (overlay2.newDate) {
|
|
2558
|
+
overlay2.newValue = overlay2.newDate + " " + overlay2.newValue;
|
|
2559
|
+
}
|
|
2560
|
+
if (["INPUT", "TEXTAREA"].includes(anchor2.tagName) && anchor2.value != overlay2.newValue) {
|
|
2561
|
+
anchor2.value = overlay2.newValue;
|
|
2562
|
+
}
|
|
2563
|
+
const edata = this.trigger("select", { date: overlay2.newValue, target: overlay2.name, overlay: overlay2 });
|
|
2564
|
+
if (edata.isCancelled === true) return;
|
|
2565
|
+
edata.finish();
|
|
2566
|
+
}
|
|
2567
|
+
});
|
|
2568
|
+
ret.select = (callback) => {
|
|
2569
|
+
overlay.on("select.attach", (event) => {
|
|
2570
|
+
callback(event);
|
|
2571
|
+
});
|
|
2572
|
+
return ret;
|
|
2573
|
+
};
|
|
2574
|
+
return ret;
|
|
2575
|
+
}
|
|
2576
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2577
|
+
initControls(overlay) {
|
|
2578
|
+
const options = overlay.options;
|
|
2579
|
+
const moveMonth = (inc) => {
|
|
2580
|
+
let { month, year } = overlay.tmp;
|
|
2581
|
+
month += inc;
|
|
2582
|
+
if (month > 12) {
|
|
2583
|
+
month = 1;
|
|
2584
|
+
year++;
|
|
2585
|
+
}
|
|
2586
|
+
if (month < 1) {
|
|
2587
|
+
month = 12;
|
|
2588
|
+
year--;
|
|
2589
|
+
}
|
|
2590
|
+
const cal = this.getMonthHTML(options, month, year);
|
|
2591
|
+
Object.assign(overlay.tmp, cal);
|
|
2592
|
+
query2(overlay.box).find(".tsg-overlay-body").html(cal.html);
|
|
2593
|
+
this.initControls(overlay);
|
|
2594
|
+
};
|
|
2595
|
+
const checkJump = (event, dblclick) => {
|
|
2596
|
+
query2(event.target).parent().find(".tsg-jump-month, .tsg-jump-year").removeClass("tsg-selected");
|
|
2597
|
+
query2(event.target).addClass("tsg-selected");
|
|
2598
|
+
const dt = /* @__PURE__ */ new Date();
|
|
2599
|
+
let { jumpMonth, jumpYear } = overlay.tmp;
|
|
2600
|
+
if (dblclick) {
|
|
2601
|
+
if (jumpYear == null) jumpYear = dt.getFullYear();
|
|
2602
|
+
if (jumpMonth == null) jumpMonth = dt.getMonth() + 1;
|
|
2603
|
+
}
|
|
2604
|
+
if (jumpMonth && jumpYear) {
|
|
2605
|
+
const cal = this.getMonthHTML(options, jumpMonth, jumpYear);
|
|
2606
|
+
Object.assign(overlay.tmp, cal);
|
|
2607
|
+
query2(overlay.box).find(".tsg-overlay-body").html(cal.html);
|
|
2608
|
+
overlay.tmp.jump = false;
|
|
2609
|
+
this.initControls(overlay);
|
|
2610
|
+
}
|
|
2611
|
+
};
|
|
2612
|
+
query2(overlay.box).find(".tsg-cal-title").off(".calendar").on("click.calendar", (event) => {
|
|
2613
|
+
if (options.draggable && overlay.tmp?.moved) {
|
|
2614
|
+
event.stopPropagation();
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2617
|
+
Object.assign(overlay.tmp, { jumpYear: null, jumpMonth: null });
|
|
2618
|
+
if (overlay.tmp.jump) {
|
|
2619
|
+
const { month, year } = overlay.tmp;
|
|
2620
|
+
const cal = this.getMonthHTML(options, month, year);
|
|
2621
|
+
query2(overlay.box).find(".tsg-overlay-body").html(cal.html);
|
|
2622
|
+
overlay.tmp.jump = false;
|
|
2623
|
+
} else {
|
|
2624
|
+
query2(overlay.box).find(".tsg-overlay-body .tsg-cal-days").replace(this.getYearHTML());
|
|
2625
|
+
const el = query2(overlay.box).find(`[name="${overlay.tmp.year}"]`).get(0);
|
|
2626
|
+
if (el) el.scrollIntoView(true);
|
|
2627
|
+
overlay.tmp.jump = true;
|
|
2628
|
+
}
|
|
2629
|
+
this.initControls(overlay);
|
|
2630
|
+
event.stopPropagation();
|
|
2631
|
+
}).find(".tsg-cal-previous").off(".calendar").on("click.calendar", (event) => {
|
|
2632
|
+
moveMonth(-1);
|
|
2633
|
+
event.stopPropagation();
|
|
2634
|
+
}).parent().find(".tsg-cal-next").off(".calendar").on("click.calendar", (event) => {
|
|
2635
|
+
moveMonth(1);
|
|
2636
|
+
event.stopPropagation();
|
|
2637
|
+
});
|
|
2638
|
+
query2(overlay.box).find(".tsg-cal-now").off(".calendar").on("click.calendar", (_event) => {
|
|
2639
|
+
if (options.type == "datetime") {
|
|
2640
|
+
if (overlay.newDate) {
|
|
2641
|
+
overlay.newValue = TsUtils.formatTime(/* @__PURE__ */ new Date(), options.format.split("|")[1]);
|
|
2642
|
+
} else {
|
|
2643
|
+
overlay.newValue = TsUtils.formatDateTime(/* @__PURE__ */ new Date(), options.format);
|
|
2644
|
+
}
|
|
2645
|
+
} else if (options.type == "date") {
|
|
2646
|
+
overlay.newValue = TsUtils.formatDate(/* @__PURE__ */ new Date(), options.format);
|
|
2647
|
+
} else if (options.type == "time") {
|
|
2648
|
+
overlay.newValue = TsUtils.formatTime(/* @__PURE__ */ new Date(), options.format);
|
|
2649
|
+
}
|
|
2650
|
+
this.hide(overlay.name);
|
|
2651
|
+
});
|
|
2652
|
+
query2(overlay.box).off(".calendar").on("contextmenu.calendar", (event) => {
|
|
2653
|
+
event.preventDefault();
|
|
2654
|
+
}).on("click.calendar", { delegate: ".tsg-day.tsg-date" }, (event) => {
|
|
2655
|
+
if (options.type == "datetime") {
|
|
2656
|
+
overlay.newDate = query2(event.target).attr("date");
|
|
2657
|
+
query2(overlay.box).find(".tsg-overlay-body").html(this.getHourHTML(overlay.options).html);
|
|
2658
|
+
this.initControls(overlay);
|
|
2659
|
+
} else {
|
|
2660
|
+
overlay.newValue = query2(event.target).attr("date");
|
|
2661
|
+
this.hide(overlay.name);
|
|
2662
|
+
}
|
|
2663
|
+
}).on("click.calendar", { delegate: ".tsg-jump-month" }, (event) => {
|
|
2664
|
+
overlay.tmp.jumpMonth = parseInt(query2(event.target).attr("name") ?? "0");
|
|
2665
|
+
checkJump(event);
|
|
2666
|
+
}).on("dblclick.calendar", { delegate: ".tsg-jump-month" }, (event) => {
|
|
2667
|
+
overlay.tmp.jumpMonth = parseInt(query2(event.target).attr("name") ?? "0");
|
|
2668
|
+
checkJump(event, true);
|
|
2669
|
+
}).on("click.calendar", { delegate: ".tsg-jump-year" }, (event) => {
|
|
2670
|
+
overlay.tmp.jumpYear = parseInt(query2(event.target).attr("name") ?? "0");
|
|
2671
|
+
checkJump(event);
|
|
2672
|
+
}).on("dblclick.calendar", { delegate: ".tsg-jump-year" }, (event) => {
|
|
2673
|
+
overlay.tmp.jumpYear = parseInt(query2(event.target).attr("name") ?? "0");
|
|
2674
|
+
checkJump(event, true);
|
|
2675
|
+
}).on("click.calendar", { delegate: ".tsg-time.hour" }, (event) => {
|
|
2676
|
+
const hour = Number(query2(event.target).attr("hour"));
|
|
2677
|
+
let min = (this.str2min(options.value) ?? 0) % 60;
|
|
2678
|
+
if (overlay.tmp.initValue && !options.value) {
|
|
2679
|
+
min = (this.str2min(overlay.tmp.initValue) ?? 0) % 60;
|
|
2680
|
+
}
|
|
2681
|
+
if (options.noMinutes) {
|
|
2682
|
+
overlay.newValue = this.min2str(hour * 60, options.format);
|
|
2683
|
+
this.hide(overlay.name);
|
|
2684
|
+
} else {
|
|
2685
|
+
overlay.newValue = hour + ":" + min;
|
|
2686
|
+
const html = this.getMinHTML(hour, options).html;
|
|
2687
|
+
query2(overlay.box).find(".tsg-overlay-body").html(html);
|
|
2688
|
+
this.initControls(overlay);
|
|
2689
|
+
}
|
|
2690
|
+
}).on("click.calendar", { delegate: ".tsg-time.min" }, (event) => {
|
|
2691
|
+
const hour = Math.floor((this.str2min(overlay.newValue) ?? 0) / 60);
|
|
2692
|
+
const time = hour * 60 + parseInt(query2(event.target).attr("min"));
|
|
2693
|
+
overlay.newValue = this.min2str(time, options.format);
|
|
2694
|
+
this.hide(overlay.name);
|
|
2695
|
+
});
|
|
2696
|
+
TsUtils.bindEvents(query2(overlay.box).find(".tsg-eaction"), this);
|
|
2697
|
+
}
|
|
2698
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2699
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2700
|
+
getMonthHTML(options, month, year) {
|
|
2701
|
+
const days = TsUtils.settings.fulldays.slice();
|
|
2702
|
+
const sdays = TsUtils.settings.shortdays.slice();
|
|
2703
|
+
if (TsUtils.settings.weekStarts !== "M") {
|
|
2704
|
+
days.unshift(days.pop());
|
|
2705
|
+
sdays.unshift(sdays.pop());
|
|
2706
|
+
}
|
|
2707
|
+
let DT = /* @__PURE__ */ new Date();
|
|
2708
|
+
const dayLengthMil = 1e3 * 60 * 60 * 24;
|
|
2709
|
+
const selected = options.type === "datetime" ? TsUtils.isDateTime(options.value, options.format, true) : TsUtils.isDate(options.value, options.format, true);
|
|
2710
|
+
const selected_dsp = TsUtils.formatDate(selected);
|
|
2711
|
+
if (month == null || year == null) {
|
|
2712
|
+
const selDate = selected instanceof Date ? selected : DT;
|
|
2713
|
+
year = selDate.getFullYear();
|
|
2714
|
+
month = selDate.getMonth() + 1;
|
|
2715
|
+
}
|
|
2716
|
+
if (month > 12) {
|
|
2717
|
+
month -= 12;
|
|
2718
|
+
year++;
|
|
2719
|
+
}
|
|
2720
|
+
if (month < 1 || month === 0) {
|
|
2721
|
+
month += 12;
|
|
2722
|
+
year--;
|
|
2723
|
+
}
|
|
2724
|
+
if (year / 4 == Math.floor(year / 4)) {
|
|
2725
|
+
this.daysCount[1] = 29;
|
|
2726
|
+
} else {
|
|
2727
|
+
this.daysCount[1] = 28;
|
|
2728
|
+
}
|
|
2729
|
+
options.current = month + "/" + year;
|
|
2730
|
+
let weekDaysHeaderHTML = "";
|
|
2731
|
+
const st = TsUtils.settings.weekStarts;
|
|
2732
|
+
for (let i = 0; i < sdays.length; i++) {
|
|
2733
|
+
const isSat = st == "M" && i == 5 || st != "M" && i == 6 ? true : false;
|
|
2734
|
+
const isSun = st == "M" && i == 6 || st != "M" && i == 0 ? true : false;
|
|
2735
|
+
weekDaysHeaderHTML += `<div class="tsg-day tsg-weekday ${isSat ? "tsg-sunday" : ""} ${isSun ? "tsg-saturday" : ""}">${sdays[i]}</div>`;
|
|
2736
|
+
}
|
|
2737
|
+
const calTitleClass = "tsg-cal-title" + (options.draggable ? " tsg-eaction tsg-draggable" : "");
|
|
2738
|
+
const calTitleData = options.draggable ? ' data-mousedown="startDrag|event"' : "";
|
|
2739
|
+
let html = `
|
|
2740
|
+
<div class="${calTitleClass}"${calTitleData}>
|
|
2741
|
+
<div class="tsg-cal-previous tsg-eaction" data-mousedown="stop">
|
|
2742
|
+
<div></div>
|
|
2743
|
+
</div>
|
|
2744
|
+
<div class="tsg-cal-next tsg-eaction" data-mousedown="stop">
|
|
2745
|
+
<div></div>
|
|
2746
|
+
</div>
|
|
2747
|
+
${TsUtils.settings.fullmonths[month - 1]}, ${year}
|
|
2748
|
+
<span class="arrow-down"></span>
|
|
2749
|
+
</div>
|
|
2750
|
+
<div class="tsg-cal-days">
|
|
2751
|
+
${weekDaysHeaderHTML}
|
|
2752
|
+
`;
|
|
2753
|
+
DT = new Date(year, month - 1, 1);
|
|
2754
|
+
DT = new Date(DT.getTime() + dayLengthMil * 0.5);
|
|
2755
|
+
let weekDayOffset = DT.getDay();
|
|
2756
|
+
if (TsUtils.settings.weekStarts == "M") {
|
|
2757
|
+
weekDayOffset = weekDayOffset > 0 ? weekDayOffset - 1 : 6;
|
|
2758
|
+
}
|
|
2759
|
+
DT = new Date(DT.getTime() - weekDayOffset * dayLengthMil);
|
|
2760
|
+
const DaySat = 6, DaySun = 0;
|
|
2761
|
+
for (let ci = 0; ci < 42; ci++) {
|
|
2762
|
+
const className = [];
|
|
2763
|
+
const dt = `${DT.getFullYear()}/${DT.getMonth() + 1}/${DT.getDate()}`;
|
|
2764
|
+
if (DT.getDay() === DaySat) className.push("tsg-saturday");
|
|
2765
|
+
if (DT.getDay() === DaySun) className.push("tsg-sunday");
|
|
2766
|
+
if (DT.getMonth() + 1 !== month) className.push("outside");
|
|
2767
|
+
if (dt == this.today) className.push("tsg-today");
|
|
2768
|
+
const dspDay = DT.getDate();
|
|
2769
|
+
let col = "";
|
|
2770
|
+
let bgcol = "";
|
|
2771
|
+
let tmp_dt, tmp_dt_fmt;
|
|
2772
|
+
if (options.type === "datetime") {
|
|
2773
|
+
tmp_dt = TsUtils.formatDateTime(dt, options.format);
|
|
2774
|
+
tmp_dt_fmt = TsUtils.formatDate(dt, TsUtils.settings.dateFormat);
|
|
2775
|
+
} else {
|
|
2776
|
+
tmp_dt = TsUtils.formatDate(dt, options.format);
|
|
2777
|
+
tmp_dt_fmt = tmp_dt;
|
|
2778
|
+
}
|
|
2779
|
+
if (options.colored && options.colored[tmp_dt_fmt] !== void 0) {
|
|
2780
|
+
const tmp = options.colored[tmp_dt_fmt].split("|");
|
|
2781
|
+
bgcol = "background-color: " + tmp[0] + ";";
|
|
2782
|
+
col = "color: " + tmp[1] + ";";
|
|
2783
|
+
}
|
|
2784
|
+
html += `<div class="tsg-day ${this.inRange(tmp_dt, options, true) ? "tsg-date " + (tmp_dt_fmt == selected_dsp ? "tsg-selected" : "") : "tsg-blocked"} ${className.join(" ")}"
|
|
2785
|
+
style="${col + bgcol}" date="${tmp_dt_fmt}" data-date="${DT.getTime()}">
|
|
2786
|
+
${dspDay}
|
|
2787
|
+
</div>`;
|
|
2788
|
+
DT = new Date(DT.getTime() + dayLengthMil);
|
|
2789
|
+
}
|
|
2790
|
+
html += "</div>";
|
|
2791
|
+
if (options.btnNow) {
|
|
2792
|
+
const label = TsUtils.lang("Today" + (options.type == "datetime" ? " & Now" : ""));
|
|
2793
|
+
html += `<div class="tsg-cal-now">${label}</div>`;
|
|
2794
|
+
}
|
|
2795
|
+
return { html, month, year };
|
|
2796
|
+
}
|
|
2797
|
+
getYearHTML() {
|
|
2798
|
+
let mhtml = "";
|
|
2799
|
+
let yhtml = "";
|
|
2800
|
+
for (let m = 0; m < TsUtils.settings.fullmonths.length; m++) {
|
|
2801
|
+
mhtml += `<div class="tsg-jump-month" name="${m + 1}">${TsUtils.settings.shortmonths[m]}</div>`;
|
|
2802
|
+
}
|
|
2803
|
+
for (let y = TsUtils.settings.dateStartYear; y <= TsUtils.settings.dateEndYear; y++) {
|
|
2804
|
+
yhtml += `<div class="tsg-jump-year" name="${y}">${y}</div>`;
|
|
2805
|
+
}
|
|
2806
|
+
return `<div class="tsg-cal-jump">
|
|
2807
|
+
<div id="tsg-jump-month">${mhtml}</div>
|
|
2808
|
+
<div id="tsg-jump-year">${yhtml}</div>
|
|
2809
|
+
</div>`;
|
|
2810
|
+
}
|
|
2811
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2812
|
+
getHourHTML(options) {
|
|
2813
|
+
options = options ?? {};
|
|
2814
|
+
if (!options.format) options.format = TsUtils.settings.timeFormat;
|
|
2815
|
+
const h24 = options.format.indexOf("h24") > -1;
|
|
2816
|
+
const value = options.value ? options.value : options.anchor ? options.anchor.value : "";
|
|
2817
|
+
const tmp = [];
|
|
2818
|
+
for (let a = 0; a < 24; a++) {
|
|
2819
|
+
let time = (a >= 12 && !h24 ? a - 12 : a) + ":00" + (!h24 ? a < 12 ? " am" : " pm" : "");
|
|
2820
|
+
if (a == 12 && !h24) time = "12:00 pm";
|
|
2821
|
+
if (!tmp[Math.floor(a / 8)]) tmp[Math.floor(a / 8)] = "";
|
|
2822
|
+
let tm1 = this.min2str(this.str2min(time) ?? 0);
|
|
2823
|
+
let tm2 = this.min2str((this.str2min(time) ?? 0) + 59);
|
|
2824
|
+
if (options.type === "datetime") {
|
|
2825
|
+
const dt = TsUtils.isDateTime(value, options.format, true);
|
|
2826
|
+
const fm = options.format.split("|")[0].trim();
|
|
2827
|
+
tm1 = TsUtils.formatDate(dt, fm) + " " + tm1;
|
|
2828
|
+
tm2 = TsUtils.formatDate(dt, fm) + " " + tm2;
|
|
2829
|
+
}
|
|
2830
|
+
const valid = this.inRange(tm1, options) || this.inRange(tm2, options);
|
|
2831
|
+
tmp[Math.floor(a / 8)] += `<span hour="${a}"
|
|
2832
|
+
class="hour ${valid ? "tsg-time " : "tsg-blocked"}">${time}</span>`;
|
|
2833
|
+
}
|
|
2834
|
+
const timeTitleClass = "tsg-time-title" + (options.draggable ? " tsg-eaction tsg-draggable" : "");
|
|
2835
|
+
const timeTitleData = options.draggable ? ' data-mousedown="startDrag|event"' : "";
|
|
2836
|
+
const html = `<div class="tsg-calendar">
|
|
2837
|
+
<div class="${timeTitleClass}"${timeTitleData}>${TsUtils.lang("Select Hour")}</div>
|
|
2838
|
+
<div class="tsg-cal-time">
|
|
2839
|
+
<div class="tsg-cal-column">${tmp[0]}</div>
|
|
2840
|
+
<div class="tsg-cal-column">${tmp[1]}</div>
|
|
2841
|
+
<div class="tsg-cal-column">${tmp[2]}</div>
|
|
2842
|
+
</div>
|
|
2843
|
+
${options.btnNow ? `<div class="tsg-cal-now">${TsUtils.lang("Now")}</div>` : ""}
|
|
2844
|
+
</div>`;
|
|
2845
|
+
return { html };
|
|
2846
|
+
}
|
|
2847
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2848
|
+
getMinHTML(hour, options) {
|
|
2849
|
+
if (hour == null) hour = 0;
|
|
2850
|
+
options = options ?? {};
|
|
2851
|
+
if (!options.format) options.format = TsUtils.settings.timeFormat;
|
|
2852
|
+
const h24 = options.format.indexOf("h24") > -1;
|
|
2853
|
+
const value = options.value ? options.value : options.anchor ? options.anchor.value : "";
|
|
2854
|
+
const tmp = [];
|
|
2855
|
+
for (let a = 0; a < 60; a += 5) {
|
|
2856
|
+
const time = (hour > 12 && !h24 ? hour - 12 : hour) + ":" + (a < 10 ? 0 : "") + a + " " + (!h24 ? hour < 12 ? "am" : "pm" : "");
|
|
2857
|
+
let tm = time;
|
|
2858
|
+
const ind = a < 20 ? 0 : a < 40 ? 1 : 2;
|
|
2859
|
+
if (!tmp[ind]) tmp[ind] = "";
|
|
2860
|
+
if (options.type === "datetime") {
|
|
2861
|
+
const dt = TsUtils.isDateTime(value, options.format, true);
|
|
2862
|
+
const fm = options.format.split("|")[0].trim();
|
|
2863
|
+
tm = TsUtils.formatDate(dt, fm) + " " + tm;
|
|
2864
|
+
}
|
|
2865
|
+
tmp[ind] += `<span min="${a}" class="min ${this.inRange(tm, options) ? "tsg-time " : "tsg-blocked"}">${time}</span>`;
|
|
2866
|
+
}
|
|
2867
|
+
const timeTitleClass = "tsg-time-title" + (options.draggable ? " tsg-eaction tsg-draggable" : "");
|
|
2868
|
+
const timeTitleData = options.draggable ? ' data-mousedown="startDrag|event"' : "";
|
|
2869
|
+
const html = `<div class="tsg-calendar">
|
|
2870
|
+
<div class="${timeTitleClass}"${timeTitleData}>${TsUtils.lang("Select Minute")}</div>
|
|
2871
|
+
<div class="tsg-cal-time">
|
|
2872
|
+
<div class="tsg-cal-column">${tmp[0]}</div>
|
|
2873
|
+
<div class="tsg-cal-column">${tmp[1]}</div>
|
|
2874
|
+
<div class="tsg-cal-column">${tmp[2]}</div>
|
|
2875
|
+
</div>
|
|
2876
|
+
${options.btnNow ? `<div class="tsg-cal-now">${TsUtils.lang("Now")}</div>` : ""}
|
|
2877
|
+
</div>`;
|
|
2878
|
+
return { html };
|
|
2879
|
+
}
|
|
2880
|
+
// checks if date is in range (loost at start, end, blockDates, blockWeekdays)
|
|
2881
|
+
// any: parameter typed any — runtime dispatch by call site; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2882
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2883
|
+
inRange(str, options, dateOnly) {
|
|
2884
|
+
let inRange = false;
|
|
2885
|
+
if (options.type === "date") {
|
|
2886
|
+
const dt = TsUtils.isDate(str, options.format, true);
|
|
2887
|
+
if (dt) {
|
|
2888
|
+
if (options.start || options.end) {
|
|
2889
|
+
const st = typeof options.start === "string" ? options.start : query2(options.start).val();
|
|
2890
|
+
const en = typeof options.end === "string" ? options.end : query2(options.end).val();
|
|
2891
|
+
let start = TsUtils.isDate(st, options.format, true);
|
|
2892
|
+
let end = TsUtils.isDate(en, options.format, true);
|
|
2893
|
+
const dtDate = dt instanceof Date ? dt : /* @__PURE__ */ new Date();
|
|
2894
|
+
const current = new Date(dtDate);
|
|
2895
|
+
if (!start) start = current;
|
|
2896
|
+
if (!end) end = current;
|
|
2897
|
+
if (current >= start && current <= end) inRange = true;
|
|
2898
|
+
} else {
|
|
2899
|
+
inRange = true;
|
|
2900
|
+
}
|
|
2901
|
+
if (Array.isArray(options.blockDates) && options.blockDates.includes(str)) inRange = false;
|
|
2902
|
+
if (Array.isArray(options.blockWeekdays) && options.blockWeekdays.includes((dt instanceof Date ? dt : /* @__PURE__ */ new Date()).getDay())) inRange = false;
|
|
2903
|
+
}
|
|
2904
|
+
} else if (options.type === "time") {
|
|
2905
|
+
if (options.start || options.end) {
|
|
2906
|
+
const tm = this.str2min(str) ?? 0;
|
|
2907
|
+
let tm1 = this.str2min(options.start) ?? tm;
|
|
2908
|
+
let tm2 = this.str2min(options.end) ?? tm;
|
|
2909
|
+
if (!tm1) tm1 = tm;
|
|
2910
|
+
if (!tm2) tm2 = tm;
|
|
2911
|
+
if (tm >= tm1 && tm <= tm2) inRange = true;
|
|
2912
|
+
} else {
|
|
2913
|
+
inRange = true;
|
|
2914
|
+
}
|
|
2915
|
+
} else if (options.type === "datetime") {
|
|
2916
|
+
const dt = TsUtils.isDateTime(str, options.format, true);
|
|
2917
|
+
if (dt) {
|
|
2918
|
+
const format = options.format.split("|").map((format2) => format2.trim());
|
|
2919
|
+
if (dateOnly) {
|
|
2920
|
+
const date = TsUtils.formatDate(dt, format[0]);
|
|
2921
|
+
const opts = TsUtils.extend({}, options, { type: "date", format: format[0] });
|
|
2922
|
+
if (this.inRange(date, opts)) inRange = true;
|
|
2923
|
+
} else {
|
|
2924
|
+
const time = TsUtils.formatTime(dt, format[1]);
|
|
2925
|
+
const opts = { type: "time", format: format[1], start: options.startTime, end: options.endTime };
|
|
2926
|
+
if (this.inRange(time, opts)) inRange = true;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return inRange;
|
|
2931
|
+
}
|
|
2932
|
+
// converts time into number of minutes since midnight -- '11:50am' => 710
|
|
2933
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2934
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2935
|
+
str2min(str) {
|
|
2936
|
+
if (typeof str !== "string") return null;
|
|
2937
|
+
const tmp = str.split(":");
|
|
2938
|
+
if (tmp.length === 2) {
|
|
2939
|
+
tmp[0] = parseInt(tmp[0]);
|
|
2940
|
+
tmp[1] = parseInt(tmp[1]);
|
|
2941
|
+
if (str.indexOf("pm") !== -1 && tmp[0] !== 12) tmp[0] += 12;
|
|
2942
|
+
if (str.includes("am") && tmp[0] == 12) tmp[0] = 0;
|
|
2943
|
+
} else {
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
return tmp[0] * 60 + tmp[1];
|
|
2947
|
+
}
|
|
2948
|
+
// converts minutes since midnight into time str -- 710 => '11:50am'
|
|
2949
|
+
// any: callback parameter — caller signature varies; TsTooltip overlay options merge from multiple user sources at runtime
|
|
2950
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2951
|
+
min2str(time, format) {
|
|
2952
|
+
let ret = "";
|
|
2953
|
+
if (time >= 24 * 60) time = time % (24 * 60);
|
|
2954
|
+
if (time < 0) time = 24 * 60 + time;
|
|
2955
|
+
const hour = Math.floor(time / 60);
|
|
2956
|
+
const min = (time % 60 < 10 ? "0" : "") + time % 60;
|
|
2957
|
+
if (!format) {
|
|
2958
|
+
format = TsUtils.settings.timeFormat;
|
|
2959
|
+
}
|
|
2960
|
+
if (format.indexOf("h24") !== -1) {
|
|
2961
|
+
ret = hour + ":" + min;
|
|
2962
|
+
} else {
|
|
2963
|
+
ret = (hour <= 12 ? hour : hour - 12) + ":" + min + " " + (hour >= 12 ? "pm" : "am");
|
|
2964
|
+
}
|
|
2965
|
+
return ret;
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
var TsTooltip = new Tooltip();
|
|
2969
|
+
var TsMenu = new MenuTooltip();
|
|
2970
|
+
var TsColor = new ColorTooltip();
|
|
2971
|
+
var TsDate = new DateTooltip();
|
|
2972
|
+
|
|
2973
|
+
export {
|
|
2974
|
+
Tooltip,
|
|
2975
|
+
TsTooltip,
|
|
2976
|
+
TsMenu,
|
|
2977
|
+
TsColor,
|
|
2978
|
+
TsDate
|
|
2979
|
+
};
|
|
2980
|
+
//# sourceMappingURL=chunk-OFASTA2A.js.map
|