fwtoolkit 0.1.0-alpha.7 → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/basic.d.ts +49 -36
- package/dist/basic.d.ts.map +1 -1
- package/dist/basic.js +58 -39
- package/dist/basic.js.map +1 -1
- package/dist/blob.d.ts +1 -1
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +0 -1
- package/dist/blob.js.map +1 -1
- package/dist/content_menu.d.ts +63 -20
- package/dist/content_menu.d.ts.map +1 -1
- package/dist/content_menu.js +21 -18
- package/dist/content_menu.js.map +1 -1
- package/dist/datatable_bulk.d.ts +34 -6
- package/dist/datatable_bulk.d.ts.map +1 -1
- package/dist/datatable_bulk.js +4 -5
- package/dist/datatable_bulk.js.map +1 -1
- package/dist/dialog.d.ts +82 -7
- package/dist/dialog.d.ts.map +1 -1
- package/dist/dialog.js +21 -16
- package/dist/dialog.js.map +1 -1
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +3 -3
- package/dist/events.js.map +1 -1
- package/dist/faq_dialog.d.ts +13 -4
- package/dist/faq_dialog.d.ts.map +1 -1
- package/dist/faq_dialog.js +4 -2
- package/dist/faq_dialog.js.map +1 -1
- package/dist/file/dialog.d.ts +33 -13
- package/dist/file/dialog.d.ts.map +1 -1
- package/dist/file/dialog.js +6 -8
- package/dist/file/dialog.js.map +1 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +0 -1
- package/dist/file/index.js.map +1 -1
- package/dist/file/new_folder_dialog.d.ts +5 -2
- package/dist/file/new_folder_dialog.d.ts.map +1 -1
- package/dist/file/new_folder_dialog.js +1 -2
- package/dist/file/new_folder_dialog.js.map +1 -1
- package/dist/file/selector.d.ts +47 -14
- package/dist/file/selector.d.ts.map +1 -1
- package/dist/file/selector.js +11 -9
- package/dist/file/selector.js.map +1 -1
- package/dist/file/templates.d.ts +1 -1
- package/dist/file/templates.d.ts.map +1 -1
- package/dist/file/templates.js +0 -1
- package/dist/file/templates.js.map +1 -1
- package/dist/file/tools.d.ts +4 -4
- package/dist/file/tools.d.ts.map +1 -1
- package/dist/file/tools.js +4 -4
- package/dist/file/tools.js.map +1 -1
- package/dist/focus.d.ts +1 -1
- package/dist/focus.d.ts.map +1 -1
- package/dist/focus.js +5 -5
- package/dist/focus.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/network.d.ts +19 -7
- package/dist/network.d.ts.map +1 -1
- package/dist/network.js +15 -12
- package/dist/network.js.map +1 -1
- package/dist/overview_menu.d.ts +77 -18
- package/dist/overview_menu.d.ts.map +1 -1
- package/dist/overview_menu.js +53 -34
- package/dist/overview_menu.js.map +1 -1
- package/dist/settings.d.ts +7 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +0 -1
- package/dist/settings.js.map +1 -1
- package/dist/user.d.ts +8 -2
- package/dist/user.d.ts.map +1 -1
- package/dist/user.js +1 -2
- package/dist/user.js.map +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +1 -2
- package/dist/worker.js.map +1 -1
- package/dist/ws.d.ts +59 -25
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +19 -15
- package/dist/ws.js.map +1 -1
- package/package.json +1 -1
- package/src/basic.ts +136 -69
- package/src/blob.ts +1 -2
- package/src/content_menu.ts +125 -42
- package/src/datatable_bulk.ts +72 -35
- package/src/dialog.ts +156 -61
- package/src/diff-dom.d.ts +16 -0
- package/src/events.ts +3 -3
- package/src/faq_dialog.ts +25 -11
- package/src/file/dialog.ts +48 -14
- package/src/file/index.ts +0 -1
- package/src/file/new_folder_dialog.ts +7 -5
- package/src/file/selector.ts +86 -36
- package/src/file/templates.ts +2 -3
- package/src/file/tools.ts +17 -8
- package/src/focus.ts +11 -13
- package/src/global.d.ts +11 -4
- package/src/index.ts +0 -1
- package/src/network.ts +58 -20
- package/src/overview_menu.ts +182 -108
- package/src/settings.ts +9 -4
- package/src/user.ts +10 -5
- package/src/w3c-keyname.d.ts +3 -0
- package/src/worker.ts +1 -2
- package/src/ws.ts +115 -50
package/src/basic.ts
CHANGED
|
@@ -1,23 +1,41 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import {keyName} from "w3c-keyname"
|
|
3
2
|
|
|
4
|
-
import {ContentMenu} from "./content_menu.js"
|
|
3
|
+
import {ContentMenu, ContentMenuInit} from "./content_menu.js"
|
|
5
4
|
import {Dialog} from "./dialog.js"
|
|
6
5
|
import {isActivationEvent} from "./events.js"
|
|
7
6
|
|
|
7
|
+
export interface DropdownSelectOptions {
|
|
8
|
+
onChange?: (value: string | false) => void
|
|
9
|
+
width?: number | string | false
|
|
10
|
+
value?: string | false
|
|
11
|
+
button?: HTMLElement | false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DropdownSelectAPI {
|
|
15
|
+
setValue: (newValue: string | false) => void
|
|
16
|
+
getValue: () => string | false
|
|
17
|
+
enable: () => void
|
|
18
|
+
disable: () => void
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
/** Creates a styled select with a contentmenu from a select tag.
|
|
9
22
|
* @param select The select-tag which is to be replaced.
|
|
10
23
|
* @param options
|
|
11
24
|
*/
|
|
12
25
|
|
|
13
26
|
export const dropdownSelect = (
|
|
14
|
-
selectDOM,
|
|
15
|
-
{
|
|
16
|
-
) => {
|
|
27
|
+
selectDOM: HTMLSelectElement,
|
|
28
|
+
{
|
|
29
|
+
onChange = () => {},
|
|
30
|
+
width = false,
|
|
31
|
+
value = false,
|
|
32
|
+
button = false
|
|
33
|
+
}: DropdownSelectOptions = {}
|
|
34
|
+
): DropdownSelectAPI | undefined => {
|
|
17
35
|
if (!selectDOM.parentElement) {
|
|
18
36
|
return
|
|
19
37
|
}
|
|
20
|
-
let buttonDOM
|
|
38
|
+
let buttonDOM: HTMLElement
|
|
21
39
|
if (button) {
|
|
22
40
|
buttonDOM = button
|
|
23
41
|
selectDOM.parentElement.removeChild(selectDOM) // Remove the <select> from the main dom.
|
|
@@ -32,9 +50,9 @@ export const dropdownSelect = (
|
|
|
32
50
|
"fw-dropdown"
|
|
33
51
|
)
|
|
34
52
|
if (width) {
|
|
35
|
-
buttonDOM.style.width = Number.isInteger(width)
|
|
53
|
+
buttonDOM.style.width = Number.isInteger(width as number)
|
|
36
54
|
? `${width}px`
|
|
37
|
-
: width
|
|
55
|
+
: (width as string)
|
|
38
56
|
}
|
|
39
57
|
selectDOM.classList.forEach(className =>
|
|
40
58
|
buttonDOM.classList.add(className)
|
|
@@ -55,46 +73,51 @@ export const dropdownSelect = (
|
|
|
55
73
|
// There are no options, so we only create the button.
|
|
56
74
|
return {
|
|
57
75
|
setValue: () => {},
|
|
58
|
-
getValue: () => false
|
|
76
|
+
getValue: () => false,
|
|
77
|
+
enable: () => {},
|
|
78
|
+
disable: () => {}
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
|
-
let selected
|
|
62
|
-
const menu = {
|
|
81
|
+
let selected: HTMLOptionElement | undefined
|
|
82
|
+
const menu: ContentMenuInit = {
|
|
63
83
|
content: options.map((option, order) => {
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
const optionEl = option as HTMLOptionElement
|
|
85
|
+
if (optionEl.selected || optionEl.value === value) {
|
|
86
|
+
selected = optionEl
|
|
66
87
|
}
|
|
67
88
|
return {
|
|
68
|
-
title:
|
|
89
|
+
title: optionEl.innerHTML,
|
|
69
90
|
type: "action",
|
|
70
|
-
tooltip:
|
|
91
|
+
tooltip: optionEl.title || "",
|
|
71
92
|
order,
|
|
72
93
|
action: () => {
|
|
73
94
|
if (!button) {
|
|
74
|
-
buttonDOM.firstElementChild.innerText =
|
|
95
|
+
;(buttonDOM.firstElementChild as HTMLElement).innerText =
|
|
96
|
+
optionEl.innerText
|
|
75
97
|
}
|
|
76
|
-
value =
|
|
98
|
+
value = optionEl.value || optionEl.dataset.value || false
|
|
77
99
|
onChange(value)
|
|
78
100
|
menu.content.forEach(item => (item.selected = false))
|
|
79
101
|
menu.content[order].selected = true
|
|
80
102
|
return false
|
|
81
103
|
},
|
|
82
|
-
selected: !!(
|
|
104
|
+
selected: !!(optionEl.selected || optionEl.dataset.selected)
|
|
83
105
|
}
|
|
84
106
|
})
|
|
85
107
|
}
|
|
86
108
|
if (!selected && !button) {
|
|
87
|
-
selected = selectDOM.firstElementChild
|
|
109
|
+
selected = selectDOM.firstElementChild as HTMLOptionElement
|
|
88
110
|
menu.content[0].selected = true
|
|
89
111
|
}
|
|
90
112
|
|
|
91
113
|
if (!button) {
|
|
92
|
-
buttonDOM.firstElementChild.innerText =
|
|
114
|
+
;(buttonDOM.firstElementChild as HTMLElement).innerText =
|
|
115
|
+
selected ? selected.innerText : ""
|
|
93
116
|
}
|
|
94
117
|
|
|
95
118
|
value = selected ? selected.value : false
|
|
96
119
|
|
|
97
|
-
const openMenu = event => {
|
|
120
|
+
const openMenu = (event: Event) => {
|
|
98
121
|
if (!isActivationEvent(event)) {
|
|
99
122
|
return
|
|
100
123
|
}
|
|
@@ -105,9 +128,10 @@ export const dropdownSelect = (
|
|
|
105
128
|
return
|
|
106
129
|
}
|
|
107
130
|
// Determine menu position
|
|
108
|
-
let menuPos
|
|
131
|
+
let menuPos: {X: number; Y: number}
|
|
109
132
|
if (event.type === "click") {
|
|
110
|
-
|
|
133
|
+
const mouseEvent = event as MouseEvent
|
|
134
|
+
menuPos = {X: mouseEvent.pageX, Y: mouseEvent.pageY}
|
|
111
135
|
} else {
|
|
112
136
|
// Keyboard event
|
|
113
137
|
const rect = buttonDOM.getBoundingClientRect()
|
|
@@ -132,16 +156,17 @@ export const dropdownSelect = (
|
|
|
132
156
|
return {
|
|
133
157
|
setValue: newValue => {
|
|
134
158
|
const optionIndex = options.findIndex(
|
|
135
|
-
option => option.value === newValue
|
|
136
|
-
)
|
|
159
|
+
option => (option as HTMLOptionElement).value === newValue
|
|
160
|
+
) as number | undefined
|
|
137
161
|
if (optionIndex === undefined) {
|
|
138
162
|
return
|
|
139
163
|
}
|
|
140
164
|
menu.content.forEach(item => (item.selected = false))
|
|
141
165
|
menu.content[optionIndex].selected = true
|
|
142
|
-
const option = options[optionIndex]
|
|
166
|
+
const option = options[optionIndex] as HTMLOptionElement
|
|
143
167
|
if (!button) {
|
|
144
|
-
buttonDOM.firstElementChild.innerText =
|
|
168
|
+
;(buttonDOM.firstElementChild as HTMLElement).innerText =
|
|
169
|
+
option.innerText
|
|
145
170
|
}
|
|
146
171
|
value = newValue
|
|
147
172
|
},
|
|
@@ -154,7 +179,7 @@ export const dropdownSelect = (
|
|
|
154
179
|
/** Checks or unchecks a checkable label. This is used for example for bibliography categories when editing bibliography items.
|
|
155
180
|
* @param label The node who's parent has to be checked or unchecked.
|
|
156
181
|
*/
|
|
157
|
-
export const setCheckableLabel = labelEl => {
|
|
182
|
+
export const setCheckableLabel = (labelEl: HTMLElement): void => {
|
|
158
183
|
if (labelEl.classList.contains("checked")) {
|
|
159
184
|
labelEl.classList.remove("checked")
|
|
160
185
|
} else {
|
|
@@ -162,49 +187,51 @@ export const setCheckableLabel = labelEl => {
|
|
|
162
187
|
}
|
|
163
188
|
}
|
|
164
189
|
|
|
165
|
-
let messageWaiter = false
|
|
190
|
+
let messageWaiter: number | false = false
|
|
166
191
|
let waitMessage = ""
|
|
167
192
|
/** Cover the page signaling to the user to wait.
|
|
168
193
|
*/
|
|
169
|
-
export const activateWait = (full = false, message = "") => {
|
|
194
|
+
export const activateWait = (full = false, message = ""): void => {
|
|
170
195
|
const waitEl = document.getElementById("wait")
|
|
196
|
+
if (!waitEl) {
|
|
197
|
+
return
|
|
198
|
+
}
|
|
171
199
|
if (message) {
|
|
172
200
|
let messageEl = waitEl.querySelector("span.message")
|
|
173
201
|
if (messageEl) {
|
|
174
202
|
// Another message is already showing. We update directly.
|
|
175
|
-
messageEl.innerText = message
|
|
203
|
+
;(messageEl as HTMLElement).innerText = message
|
|
176
204
|
} else {
|
|
177
205
|
waitMessage = message // We update the message if there is one waiting already
|
|
178
206
|
if (!messageWaiter) {
|
|
179
|
-
messageWaiter = setTimeout(() => {
|
|
207
|
+
messageWaiter = window.setTimeout(() => {
|
|
180
208
|
messageEl = document.createElement("span")
|
|
181
209
|
messageEl.classList.add("message")
|
|
182
|
-
messageEl.innerText = waitMessage
|
|
210
|
+
;(messageEl as HTMLElement).innerText = waitMessage
|
|
183
211
|
waitEl.appendChild(messageEl)
|
|
184
212
|
messageWaiter = false
|
|
185
213
|
}, 2000)
|
|
186
214
|
}
|
|
187
215
|
}
|
|
188
216
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
waitEl.classList.add("full")
|
|
193
|
-
}
|
|
217
|
+
waitEl.classList.add("active")
|
|
218
|
+
if (full) {
|
|
219
|
+
waitEl.classList.add("full")
|
|
194
220
|
}
|
|
195
221
|
}
|
|
196
222
|
|
|
197
223
|
/** Remove the wait cover.
|
|
198
224
|
*/
|
|
199
|
-
export const deactivateWait = () => {
|
|
225
|
+
export const deactivateWait = (): void => {
|
|
200
226
|
const waitEl = document.getElementById("wait")
|
|
201
|
-
if (waitEl) {
|
|
202
|
-
|
|
203
|
-
waitEl.classList.remove("full")
|
|
227
|
+
if (!waitEl) {
|
|
228
|
+
return
|
|
204
229
|
}
|
|
230
|
+
waitEl.classList.remove("active")
|
|
231
|
+
waitEl.classList.remove("full")
|
|
205
232
|
const messageEl = waitEl.querySelector("span.message")
|
|
206
233
|
if (messageEl) {
|
|
207
|
-
messageEl.parentElement
|
|
234
|
+
messageEl.parentElement?.removeChild(messageEl)
|
|
208
235
|
}
|
|
209
236
|
if (messageWaiter) {
|
|
210
237
|
clearTimeout(messageWaiter)
|
|
@@ -216,11 +243,14 @@ export const deactivateWait = () => {
|
|
|
216
243
|
* @param alertType The type of message that is shown (error, warning, info or success).
|
|
217
244
|
* @param alertMsg The message text.
|
|
218
245
|
*/
|
|
219
|
-
export const addAlert = (
|
|
246
|
+
export const addAlert = (
|
|
247
|
+
alertType: "error" | "warning" | "info" | "success",
|
|
248
|
+
alertMsg: string
|
|
249
|
+
): void => {
|
|
220
250
|
if (!document.body) {
|
|
221
251
|
return
|
|
222
252
|
}
|
|
223
|
-
const iconNames = {
|
|
253
|
+
const iconNames: Record<typeof alertType, string> = {
|
|
224
254
|
error: "circle-exclamation",
|
|
225
255
|
warning: "circle-exclamation",
|
|
226
256
|
info: "circle-info",
|
|
@@ -233,11 +263,17 @@ export const addAlert = (alertType, alertMsg) => {
|
|
|
233
263
|
)
|
|
234
264
|
}
|
|
235
265
|
const alertsWrapper = document.getElementById("alerts-wrapper")
|
|
266
|
+
if (!alertsWrapper) {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
236
269
|
alertsWrapper.insertAdjacentHTML(
|
|
237
270
|
"beforeend",
|
|
238
271
|
`<li class="alerts-${alertType} fa-before fa-${iconNames[alertType]}">${alertMsg}</li>`
|
|
239
272
|
)
|
|
240
273
|
const alertBox = alertsWrapper.lastElementChild
|
|
274
|
+
if (!alertBox) {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
241
277
|
setTimeout(() => {
|
|
242
278
|
alertBox.classList.add("visible")
|
|
243
279
|
setTimeout(() => {
|
|
@@ -247,8 +283,20 @@ export const addAlert = (alertType, alertMsg) => {
|
|
|
247
283
|
}, 1)
|
|
248
284
|
}
|
|
249
285
|
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
export interface DialogButtonSpec {
|
|
287
|
+
type?: "close" | "cancel" | "ok"
|
|
288
|
+
text?: string
|
|
289
|
+
classes?: string
|
|
290
|
+
click?: (event?: Event) => void
|
|
291
|
+
icon?: string
|
|
292
|
+
dropdown?: boolean
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Used for system messages
|
|
296
|
+
export const showSystemMessage = (
|
|
297
|
+
message: string,
|
|
298
|
+
buttons: DialogButtonSpec[] = [{type: "close"}]
|
|
299
|
+
): Dialog => {
|
|
252
300
|
const dialog = new Dialog({
|
|
253
301
|
title: gettext("System message"),
|
|
254
302
|
body: `<p>${escapeText(message)}</p>`,
|
|
@@ -259,22 +307,27 @@ export const showSystemMessage = (message, buttons = [{type: "close"}]) => {
|
|
|
259
307
|
}
|
|
260
308
|
|
|
261
309
|
/** Turn milliseconds since epoch (UTC) into a local date string.
|
|
262
|
-
* @param
|
|
263
|
-
* @param
|
|
310
|
+
* @param milliseconds Number of milliseconds since epoch (1/1/1970 midnight, UTC).
|
|
311
|
+
* @param type 'full' for full date (default), 'sortable-date' for sortable date, 'minutes' for minute accuracy
|
|
264
312
|
*/
|
|
265
|
-
|
|
313
|
+
type DateType = "sortable-date" | "minutes" | "full"
|
|
314
|
+
|
|
315
|
+
const CACHED_DATES: Record<DateType, Record<number, string>> = {
|
|
266
316
|
"sortable-date": {},
|
|
267
317
|
minutes: {},
|
|
268
318
|
full: {}
|
|
269
319
|
}
|
|
270
|
-
export const localizeDate = (
|
|
320
|
+
export const localizeDate = (
|
|
321
|
+
milliseconds: number,
|
|
322
|
+
type: DateType = "full"
|
|
323
|
+
): string => {
|
|
271
324
|
if (milliseconds === 0) {
|
|
272
325
|
return ""
|
|
273
326
|
} else if (CACHED_DATES[type][milliseconds]) {
|
|
274
327
|
return CACHED_DATES[type][milliseconds]
|
|
275
328
|
}
|
|
276
329
|
const theDate = new Date(milliseconds)
|
|
277
|
-
let returnValue
|
|
330
|
+
let returnValue: string
|
|
278
331
|
switch (type) {
|
|
279
332
|
case "sortable-date": {
|
|
280
333
|
const yyyy = theDate.getFullYear()
|
|
@@ -306,7 +359,10 @@ export const localizeDate = (milliseconds, type = "full") => {
|
|
|
306
359
|
* Turn string literals into single line, removing spaces at start of line
|
|
307
360
|
*/
|
|
308
361
|
|
|
309
|
-
export const noSpaceTmp = (
|
|
362
|
+
export const noSpaceTmp = (
|
|
363
|
+
strings: TemplateStringsArray,
|
|
364
|
+
...values: unknown[]
|
|
365
|
+
): string => {
|
|
310
366
|
const tmpStrings = Array.from(strings)
|
|
311
367
|
|
|
312
368
|
let combined = ""
|
|
@@ -315,7 +371,8 @@ export const noSpaceTmp = (strings, ...values) => {
|
|
|
315
371
|
combined += tmpStrings.shift()
|
|
316
372
|
}
|
|
317
373
|
if (values.length > 0) {
|
|
318
|
-
|
|
374
|
+
const value = values.shift()
|
|
375
|
+
combined += value !== undefined && value !== null ? String(value) : ""
|
|
319
376
|
}
|
|
320
377
|
}
|
|
321
378
|
|
|
@@ -326,7 +383,7 @@ export const noSpaceTmp = (strings, ...values) => {
|
|
|
326
383
|
return out
|
|
327
384
|
}
|
|
328
385
|
|
|
329
|
-
export const escapeText = text => {
|
|
386
|
+
export const escapeText = (text: string): string => {
|
|
330
387
|
return text
|
|
331
388
|
.replace(/&/g, "&")
|
|
332
389
|
.replace(/</g, "<")
|
|
@@ -340,13 +397,13 @@ export const escapeText = text => {
|
|
|
340
397
|
* Return an inline info-icon with a hover tooltip containing the given HTML.
|
|
341
398
|
* Use only with trusted HTML content.
|
|
342
399
|
*
|
|
343
|
-
* @param
|
|
344
|
-
* @returns
|
|
400
|
+
* @param html - The tooltip content (HTML string)
|
|
401
|
+
* @returns HTML for the info tooltip
|
|
345
402
|
*/
|
|
346
|
-
export const infoTooltip = html =>
|
|
403
|
+
export const infoTooltip = (html: string): string =>
|
|
347
404
|
`<span class="fw-info-tooltip"><i class="fa-solid fa-info-circle"></i><span class="fw-info-tooltip-text">${html}</span></span>`
|
|
348
405
|
|
|
349
|
-
export const unescapeText = text =>
|
|
406
|
+
export const unescapeText = (text: string): string =>
|
|
350
407
|
text
|
|
351
408
|
.replace(/</g, "<")
|
|
352
409
|
.replace(/>/g, ">")
|
|
@@ -357,12 +414,16 @@ export const unescapeText = text =>
|
|
|
357
414
|
* ES6 promises are not (yet) cancelable.
|
|
358
415
|
*/
|
|
359
416
|
|
|
360
|
-
export const cancelPromise = () => new Promise(() => {})
|
|
417
|
+
export const cancelPromise = (): Promise<never> => new Promise(() => {})
|
|
361
418
|
|
|
362
419
|
// Check if selector matches one of the ancestors of the event target.
|
|
363
420
|
// Used in switch statements of document event listeners.
|
|
364
|
-
export const findTarget = (
|
|
365
|
-
|
|
421
|
+
export const findTarget = (
|
|
422
|
+
event: Event,
|
|
423
|
+
selector: string,
|
|
424
|
+
el: {target?: Element | null}
|
|
425
|
+
): boolean => {
|
|
426
|
+
el.target = (event.target as Element).closest(selector)
|
|
366
427
|
if (el.target) {
|
|
367
428
|
event.stopPropagation()
|
|
368
429
|
return true
|
|
@@ -371,7 +432,7 @@ export const findTarget = (event, selector, el = {}) => {
|
|
|
371
432
|
}
|
|
372
433
|
|
|
373
434
|
// Promise when page has been loaded.
|
|
374
|
-
export const whenReady = () => {
|
|
435
|
+
export const whenReady = (): Promise<void> => {
|
|
375
436
|
if (document.readyState === "complete") {
|
|
376
437
|
return Promise.resolve()
|
|
377
438
|
} else {
|
|
@@ -385,14 +446,14 @@ export const whenReady = () => {
|
|
|
385
446
|
}
|
|
386
447
|
}
|
|
387
448
|
|
|
388
|
-
export const setDocTitle = (title, app) => {
|
|
449
|
+
export const setDocTitle = (title: string, app: {name: string}): void => {
|
|
389
450
|
const titleText = `${title} - ${app.name}`
|
|
390
451
|
if (document.title !== titleText) {
|
|
391
452
|
document.title = titleText
|
|
392
453
|
}
|
|
393
454
|
}
|
|
394
455
|
|
|
395
|
-
const LANGUAGES = {
|
|
456
|
+
const LANGUAGES: Record<string, string> = {
|
|
396
457
|
ar: "العربية",
|
|
397
458
|
bg: "Български",
|
|
398
459
|
cs: "Čeština",
|
|
@@ -415,16 +476,19 @@ const LANGUAGES = {
|
|
|
415
476
|
"zh-hans": "简体中文"
|
|
416
477
|
}
|
|
417
478
|
|
|
418
|
-
export const langName = code => {
|
|
479
|
+
export const langName = (code: string): string => {
|
|
419
480
|
return LANGUAGES[code] || code
|
|
420
481
|
}
|
|
421
482
|
|
|
422
483
|
/** Enable ISO date picker on a text input by overlaying a native date picker.
|
|
423
484
|
* The text input displays ISO format (YYYY-MM-DD) while using the native picker for selection.
|
|
424
|
-
* @param
|
|
425
|
-
* @param
|
|
485
|
+
* @param inputEl - The text input element to enhance
|
|
486
|
+
* @param minToday - If true, sets min date to today (default: false)
|
|
426
487
|
*/
|
|
427
|
-
export const enableDatePicker = (
|
|
488
|
+
export const enableDatePicker = (
|
|
489
|
+
inputEl: HTMLInputElement,
|
|
490
|
+
minToday = false
|
|
491
|
+
): void => {
|
|
428
492
|
const datePicker = document.createElement("input")
|
|
429
493
|
datePicker.type = "date"
|
|
430
494
|
if (minToday) {
|
|
@@ -435,6 +499,9 @@ export const enableDatePicker = (inputEl, minToday = false) => {
|
|
|
435
499
|
datePicker.style.pointerEvents = "none"
|
|
436
500
|
|
|
437
501
|
const parent = inputEl.parentElement
|
|
502
|
+
if (!parent) {
|
|
503
|
+
return
|
|
504
|
+
}
|
|
438
505
|
parent.style.position = "relative"
|
|
439
506
|
parent.appendChild(datePicker)
|
|
440
507
|
|
package/src/blob.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export function convertDataURIToBlob(dataURI) {
|
|
1
|
+
export function convertDataURIToBlob(dataURI: string): Blob {
|
|
3
2
|
const byteString = atob(dataURI.split(",")[1])
|
|
4
3
|
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0]
|
|
5
4
|
const ab = new ArrayBuffer(byteString.length)
|