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/dialog.ts
CHANGED
|
@@ -1,8 +1,51 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import {keyName} from "w3c-keyname"
|
|
3
2
|
|
|
4
3
|
import {findTarget} from "./basic.js"
|
|
5
4
|
|
|
5
|
+
export interface DialogButtonSpec {
|
|
6
|
+
type?: "close" | "cancel" | "ok"
|
|
7
|
+
text?: string
|
|
8
|
+
classes?: string
|
|
9
|
+
click?: (event?: Event) => unknown
|
|
10
|
+
icon?: string
|
|
11
|
+
dropdown?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DialogOptions {
|
|
15
|
+
id?: string | false
|
|
16
|
+
classes?: string | false
|
|
17
|
+
title?: string
|
|
18
|
+
body?: string
|
|
19
|
+
restoreActiveElement?: boolean
|
|
20
|
+
height?: number | false
|
|
21
|
+
width?: number | false
|
|
22
|
+
canClose?: boolean
|
|
23
|
+
help?: (() => void) | false
|
|
24
|
+
note?: {text?: string; display?: boolean}
|
|
25
|
+
blur?: boolean
|
|
26
|
+
buttons?: DialogButtonSpec[]
|
|
27
|
+
beforeClose?: (() => void) | false
|
|
28
|
+
onClose?: (() => void) | false
|
|
29
|
+
icon?: string | false
|
|
30
|
+
scroll?: boolean | false
|
|
31
|
+
canEscape?: boolean
|
|
32
|
+
fullScreen?: boolean | false
|
|
33
|
+
initialFocus?: string | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface InternalDialogButton {
|
|
37
|
+
text: string
|
|
38
|
+
classes: string | false
|
|
39
|
+
click: (event?: Event) => unknown
|
|
40
|
+
icon: string | false
|
|
41
|
+
dropdown: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface NoteSpec {
|
|
45
|
+
text?: string
|
|
46
|
+
display?: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
6
49
|
const dialogTemplate = ({
|
|
7
50
|
id,
|
|
8
51
|
classes,
|
|
@@ -18,6 +61,21 @@ const dialogTemplate = ({
|
|
|
18
61
|
canClose,
|
|
19
62
|
note,
|
|
20
63
|
blur
|
|
64
|
+
}: {
|
|
65
|
+
id: string | false
|
|
66
|
+
classes: string | false
|
|
67
|
+
title: string
|
|
68
|
+
height: string
|
|
69
|
+
width: string
|
|
70
|
+
icon: string | false
|
|
71
|
+
buttons: InternalDialogButton[]
|
|
72
|
+
zIndex: number
|
|
73
|
+
body: string
|
|
74
|
+
scroll: boolean | false
|
|
75
|
+
help: (() => void) | false
|
|
76
|
+
canClose: boolean
|
|
77
|
+
note: NoteSpec
|
|
78
|
+
blur: boolean
|
|
21
79
|
}) =>
|
|
22
80
|
`<div tabindex="-1" role="dialog"
|
|
23
81
|
class="ui-dialog ui-corner-all ui-widget ui-widget-content ui-front ui-dialog-buttons"
|
|
@@ -55,13 +113,13 @@ const dialogTemplate = ({
|
|
|
55
113
|
</div>
|
|
56
114
|
<div class="ui-widget-overlay ui-front${blur === false ? " no-blur" : ""}" style="z-index: ${zIndex - 1}"></div>`
|
|
57
115
|
|
|
58
|
-
const noteTemplate = note => {
|
|
116
|
+
const noteTemplate = (note: NoteSpec): string => {
|
|
59
117
|
return note.text
|
|
60
118
|
? `<p class="noteEl ${note.display ? "" : "hide"}">${note.text}</p>`
|
|
61
119
|
: ""
|
|
62
120
|
}
|
|
63
121
|
|
|
64
|
-
const buttonsTemplate = ({buttons}) =>
|
|
122
|
+
const buttonsTemplate = ({buttons}: {buttons: InternalDialogButton[]}): string =>
|
|
65
123
|
buttons.map(button => buttonTemplate(button)).join("")
|
|
66
124
|
|
|
67
125
|
const buttonTemplate = ({
|
|
@@ -69,13 +127,16 @@ const buttonTemplate = ({
|
|
|
69
127
|
classes,
|
|
70
128
|
icon,
|
|
71
129
|
dropdown
|
|
72
|
-
}) => `<button type="button" class="${classes ? classes : "fw-light"} fw-button ui-button ui-corner-all ui-widget">
|
|
130
|
+
}: InternalDialogButton): string => `<button type="button" class="${classes ? classes : "fw-light"} fw-button ui-button ui-corner-all ui-widget">
|
|
73
131
|
${icon ? `<i class="fa fa-${icon}" aria-hidden="true"></i>` : ""}
|
|
74
132
|
${text}
|
|
75
133
|
${dropdown ? '<i class="fa fa-caret-down" aria-hidden="true"></i>' : ""}
|
|
76
134
|
</button>`
|
|
77
135
|
|
|
78
|
-
const BUTTON_TYPES
|
|
136
|
+
const BUTTON_TYPES: Record<
|
|
137
|
+
"close" | "cancel" | "ok",
|
|
138
|
+
{text: string; classes: string; click: (dialog: Dialog) => () => void}
|
|
139
|
+
> = {
|
|
79
140
|
close: {
|
|
80
141
|
text: gettext("Close"),
|
|
81
142
|
classes: "fw-orange",
|
|
@@ -94,7 +155,37 @@ const BUTTON_TYPES = {
|
|
|
94
155
|
}
|
|
95
156
|
|
|
96
157
|
export class Dialog {
|
|
97
|
-
|
|
158
|
+
id: string | false
|
|
159
|
+
classes: string | false
|
|
160
|
+
title: string
|
|
161
|
+
body: string
|
|
162
|
+
restoreActiveElement: boolean
|
|
163
|
+
height: string
|
|
164
|
+
width: string
|
|
165
|
+
canClose: boolean
|
|
166
|
+
help: (() => void) | false
|
|
167
|
+
note: NoteSpec
|
|
168
|
+
blur: boolean
|
|
169
|
+
buttons: InternalDialogButton[]
|
|
170
|
+
beforeClose: (() => void) | false
|
|
171
|
+
onClose: (() => void) | false
|
|
172
|
+
icon: string | false
|
|
173
|
+
scroll: boolean | false
|
|
174
|
+
canEscape: boolean
|
|
175
|
+
dialogEl!: HTMLElement
|
|
176
|
+
backdropEl!: HTMLElement
|
|
177
|
+
dragging: {x: number; y: number} | false
|
|
178
|
+
hasBeenMoved: boolean
|
|
179
|
+
listeners: Record<string, (event: Event) => void>
|
|
180
|
+
fullScreen: boolean | false
|
|
181
|
+
initialFocus: string | null
|
|
182
|
+
|
|
183
|
+
previousActiveElement: Element | null
|
|
184
|
+
firstFocusableEl: Element | null
|
|
185
|
+
lastFocusableEl: Element | null
|
|
186
|
+
focusableEls: Element[] | null
|
|
187
|
+
|
|
188
|
+
constructor(options: DialogOptions) {
|
|
98
189
|
this.id = options.id || false
|
|
99
190
|
this.classes = options.classes || false
|
|
100
191
|
this.title = options.title || ""
|
|
@@ -102,10 +193,10 @@ export class Dialog {
|
|
|
102
193
|
this.restoreActiveElement = options.restoreActiveElement !== false // default is true
|
|
103
194
|
this.height = options.height ? `${options.height}px` : "auto"
|
|
104
195
|
this.width = options.width ? `${options.width}px` : "auto"
|
|
105
|
-
this.canClose = "canClose" in options ? options.canClose : true
|
|
106
|
-
this.help = "help" in options ? options.help : false
|
|
107
|
-
this.note = "note" in options ? options.note : {}
|
|
108
|
-
this.blur = "blur" in options ? options.blur : true
|
|
196
|
+
this.canClose = "canClose" in options ? options.canClose! : true
|
|
197
|
+
this.help = "help" in options ? options.help! : false
|
|
198
|
+
this.note = "note" in options ? options.note! : {}
|
|
199
|
+
this.blur = "blur" in options ? options.blur! : true
|
|
109
200
|
this.buttons = []
|
|
110
201
|
if (options.buttons) {
|
|
111
202
|
this.setButtons(options.buttons)
|
|
@@ -116,12 +207,11 @@ export class Dialog {
|
|
|
116
207
|
this.scroll = options.scroll || false
|
|
117
208
|
this.canEscape =
|
|
118
209
|
options.canEscape ??
|
|
119
|
-
options.buttons?.find(button =>
|
|
120
|
-
["cancel", "close"].includes(button.type)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
this.
|
|
124
|
-
this.backdropEl = false
|
|
210
|
+
!!options.buttons?.find(button =>
|
|
211
|
+
["cancel", "close"].includes(button.type || "")
|
|
212
|
+
)
|
|
213
|
+
this.dialogEl = null!
|
|
214
|
+
this.backdropEl = null!
|
|
125
215
|
this.dragging = false
|
|
126
216
|
this.hasBeenMoved = false
|
|
127
217
|
this.listeners = {}
|
|
@@ -134,7 +224,7 @@ export class Dialog {
|
|
|
134
224
|
this.focusableEls = null
|
|
135
225
|
}
|
|
136
226
|
|
|
137
|
-
setButtons(buttons) {
|
|
227
|
+
setButtons(buttons: DialogButtonSpec[]): void {
|
|
138
228
|
this.buttons = buttons.map(button => ({
|
|
139
229
|
text: button.text
|
|
140
230
|
? button.text
|
|
@@ -150,13 +240,13 @@ export class Dialog {
|
|
|
150
240
|
? button.click
|
|
151
241
|
: button.type
|
|
152
242
|
? BUTTON_TYPES[button.type].click(this)
|
|
153
|
-
:
|
|
243
|
+
: () => {},
|
|
154
244
|
icon: button.icon ? button.icon : false,
|
|
155
245
|
dropdown: button.dropdown ? true : false
|
|
156
246
|
}))
|
|
157
247
|
}
|
|
158
248
|
|
|
159
|
-
open() {
|
|
249
|
+
open(): void {
|
|
160
250
|
if (this.dialogEl) {
|
|
161
251
|
return
|
|
162
252
|
}
|
|
@@ -189,8 +279,8 @@ export class Dialog {
|
|
|
189
279
|
blur: this.blur
|
|
190
280
|
})
|
|
191
281
|
)
|
|
192
|
-
this.backdropEl = document.body.lastElementChild
|
|
193
|
-
this.dialogEl = this.backdropEl.previousElementSibling
|
|
282
|
+
this.backdropEl = document.body.lastElementChild as HTMLElement
|
|
283
|
+
this.dialogEl = this.backdropEl.previousElementSibling as HTMLElement
|
|
194
284
|
if (this.fullScreen) {
|
|
195
285
|
this.dialogEl.style.width = "98%"
|
|
196
286
|
this.dialogEl.style.height = "100%"
|
|
@@ -205,20 +295,21 @@ export class Dialog {
|
|
|
205
295
|
this.dialogEl.setAttribute("aria-modal", "true")
|
|
206
296
|
if (this.title) {
|
|
207
297
|
this.dialogEl.setAttribute("aria-labelledby", "dialog-title")
|
|
208
|
-
this.dialogEl.querySelector(".ui-dialog-title")
|
|
298
|
+
const titleEl = this.dialogEl.querySelector(".ui-dialog-title") as HTMLElement
|
|
299
|
+
titleEl.id = "dialog-title"
|
|
209
300
|
}
|
|
210
301
|
|
|
211
302
|
// Get all focusable elements
|
|
212
303
|
this.focusableEls = this.getFocusableElements()
|
|
213
|
-
this.firstFocusableEl = this.focusableEls[0]
|
|
214
|
-
this.lastFocusableEl = this.focusableEls[this.focusableEls.length - 1]
|
|
304
|
+
this.firstFocusableEl = this.focusableEls[0] || null
|
|
305
|
+
this.lastFocusableEl = this.focusableEls[this.focusableEls.length - 1] || null
|
|
215
306
|
|
|
216
307
|
// Set initial focus to the most appropriate element
|
|
217
308
|
const initialFocusElement = this.getInitialFocusElement()
|
|
218
309
|
if (initialFocusElement) {
|
|
219
|
-
setTimeout(() => initialFocusElement.focus(), 0)
|
|
310
|
+
setTimeout(() => (initialFocusElement as HTMLElement).focus(), 0)
|
|
220
311
|
} else if (this.firstFocusableEl) {
|
|
221
|
-
this.firstFocusableEl.focus()
|
|
312
|
+
(this.firstFocusableEl as HTMLElement).focus()
|
|
222
313
|
} else {
|
|
223
314
|
this.dialogEl.focus()
|
|
224
315
|
}
|
|
@@ -226,18 +317,17 @@ export class Dialog {
|
|
|
226
317
|
this.bind()
|
|
227
318
|
}
|
|
228
319
|
|
|
229
|
-
refreshButtons() {
|
|
230
|
-
this.dialogEl.querySelector(".ui-dialog-buttonset")
|
|
231
|
-
|
|
320
|
+
refreshButtons(): void {
|
|
321
|
+
const buttonSet = this.dialogEl.querySelector(".ui-dialog-buttonset")!
|
|
322
|
+
buttonSet.innerHTML = buttonsTemplate({buttons: this.buttons})
|
|
232
323
|
}
|
|
233
324
|
|
|
234
|
-
refreshNote() {
|
|
235
|
-
this.dialogEl.querySelector(".note-container")
|
|
236
|
-
|
|
237
|
-
)
|
|
325
|
+
refreshNote(): void {
|
|
326
|
+
const noteContainer = this.dialogEl.querySelector(".note-container")!
|
|
327
|
+
noteContainer.innerHTML = noteTemplate(this.note)
|
|
238
328
|
}
|
|
239
329
|
|
|
240
|
-
centerDialog() {
|
|
330
|
+
centerDialog(): void {
|
|
241
331
|
const totalWidth = window.innerWidth,
|
|
242
332
|
totalHeight = window.innerHeight,
|
|
243
333
|
dialogWidth = this.dialogEl.clientWidth,
|
|
@@ -249,7 +339,7 @@ export class Dialog {
|
|
|
249
339
|
this.dialogEl.style.left = `${(totalWidth - dialogWidth) / 2 + scrollLeftOffset}px`
|
|
250
340
|
}
|
|
251
341
|
|
|
252
|
-
adjustDialogToScroll() {
|
|
342
|
+
adjustDialogToScroll(): void {
|
|
253
343
|
this.dialogEl.style.top = `${Math.max(
|
|
254
344
|
Math.min(
|
|
255
345
|
this.dialogEl.offsetTop,
|
|
@@ -261,7 +351,10 @@ export class Dialog {
|
|
|
261
351
|
)}px`
|
|
262
352
|
}
|
|
263
353
|
|
|
264
|
-
moveDialog(x, y) {
|
|
354
|
+
moveDialog(x: number, y: number): void {
|
|
355
|
+
if (!this.dragging) {
|
|
356
|
+
return
|
|
357
|
+
}
|
|
265
358
|
this.dialogEl.style.top = `${Math.min(
|
|
266
359
|
Math.max(y - this.dragging.y, 0),
|
|
267
360
|
this.backdropEl.scrollHeight -
|
|
@@ -275,7 +368,7 @@ export class Dialog {
|
|
|
275
368
|
this.hasBeenMoved = true
|
|
276
369
|
}
|
|
277
370
|
|
|
278
|
-
onScroll(_event) {
|
|
371
|
+
onScroll(_event: Event): void {
|
|
279
372
|
if (this.hasBeenMoved) {
|
|
280
373
|
// The dialog has been moved manually. We just adjust the position to make it stay in the view.
|
|
281
374
|
this.adjustDialogToScroll()
|
|
@@ -284,7 +377,7 @@ export class Dialog {
|
|
|
284
377
|
}
|
|
285
378
|
}
|
|
286
379
|
|
|
287
|
-
onKeydown(event) {
|
|
380
|
+
onKeydown(event: KeyboardEvent): void {
|
|
288
381
|
let name = keyName(event)
|
|
289
382
|
if (event.altKey) {
|
|
290
383
|
name = "Alt-" + name
|
|
@@ -305,26 +398,26 @@ export class Dialog {
|
|
|
305
398
|
} else if (name === "Tab") {
|
|
306
399
|
if (document.activeElement === this.lastFocusableEl) {
|
|
307
400
|
event.preventDefault()
|
|
308
|
-
this.firstFocusableEl.focus()
|
|
401
|
+
;(this.firstFocusableEl as HTMLElement).focus()
|
|
309
402
|
}
|
|
310
403
|
} else if (name === "Shift-Tab") {
|
|
311
404
|
if (document.activeElement === this.firstFocusableEl) {
|
|
312
405
|
event.preventDefault()
|
|
313
|
-
this.lastFocusableEl.focus()
|
|
406
|
+
;(this.lastFocusableEl as HTMLElement).focus()
|
|
314
407
|
}
|
|
315
408
|
}
|
|
316
409
|
}
|
|
317
410
|
|
|
318
|
-
bind() {
|
|
319
|
-
this.listeners.onKeydown = event => this.onKeydown(event)
|
|
411
|
+
bind(): void {
|
|
412
|
+
this.listeners.onKeydown = event => this.onKeydown(event as KeyboardEvent)
|
|
320
413
|
document.body.addEventListener("keydown", this.listeners.onKeydown)
|
|
321
414
|
this.dialogEl.addEventListener("click", event => {
|
|
322
|
-
const el = {}
|
|
415
|
+
const el: {target?: Element | null} = {}
|
|
323
416
|
switch (true) {
|
|
324
417
|
case findTarget(event, ".ui-dialog-buttonpane button", el): {
|
|
325
418
|
event.preventDefault()
|
|
326
419
|
let buttonNumber = 0
|
|
327
|
-
let seekItem = el.target
|
|
420
|
+
let seekItem = el.target as Element
|
|
328
421
|
while (seekItem.previousElementSibling) {
|
|
329
422
|
buttonNumber++
|
|
330
423
|
seekItem = seekItem.previousElementSibling
|
|
@@ -338,7 +431,9 @@ export class Dialog {
|
|
|
338
431
|
break
|
|
339
432
|
case findTarget(event, ".ui-dialog-titlebar-help", el):
|
|
340
433
|
event.preventDefault()
|
|
341
|
-
this.help
|
|
434
|
+
if (this.help) {
|
|
435
|
+
this.help()
|
|
436
|
+
}
|
|
342
437
|
break
|
|
343
438
|
default:
|
|
344
439
|
break
|
|
@@ -348,12 +443,12 @@ export class Dialog {
|
|
|
348
443
|
this.listeners.onScroll = event => this.onScroll(event)
|
|
349
444
|
window.addEventListener("scroll", this.listeners.onScroll, false)
|
|
350
445
|
this.dialogEl.addEventListener("mousedown", event => {
|
|
351
|
-
const el = {}
|
|
446
|
+
const el: {target?: Element | null} = {}
|
|
352
447
|
switch (true) {
|
|
353
448
|
case findTarget(event, ".ui-dialog-titlebar", el):
|
|
354
449
|
this.dragging = {
|
|
355
|
-
x: event.clientX - this.dialogEl.offsetLeft,
|
|
356
|
-
y: event.clientY - this.dialogEl.offsetTop
|
|
450
|
+
x: (event as MouseEvent).clientX - this.dialogEl.offsetLeft,
|
|
451
|
+
y: (event as MouseEvent).clientY - this.dialogEl.offsetTop
|
|
357
452
|
}
|
|
358
453
|
break
|
|
359
454
|
default:
|
|
@@ -361,7 +456,7 @@ export class Dialog {
|
|
|
361
456
|
}
|
|
362
457
|
})
|
|
363
458
|
this.dialogEl.addEventListener("mouseup", event => {
|
|
364
|
-
const el = {}
|
|
459
|
+
const el: {target?: Element | null} = {}
|
|
365
460
|
switch (true) {
|
|
366
461
|
case findTarget(event, ".ui-dialog-titlebar", el):
|
|
367
462
|
this.dragging = false
|
|
@@ -374,7 +469,7 @@ export class Dialog {
|
|
|
374
469
|
if (!this.dragging) {
|
|
375
470
|
return
|
|
376
471
|
}
|
|
377
|
-
this.moveDialog(event.clientX, event.clientY)
|
|
472
|
+
this.moveDialog((event as MouseEvent).clientX, (event as MouseEvent).clientY)
|
|
378
473
|
})
|
|
379
474
|
}
|
|
380
475
|
|
|
@@ -392,19 +487,19 @@ export class Dialog {
|
|
|
392
487
|
})
|
|
393
488
|
}
|
|
394
489
|
|
|
395
|
-
nextDialogZIndex() {
|
|
490
|
+
nextDialogZIndex(): number {
|
|
396
491
|
let zIndex = 100
|
|
397
492
|
document
|
|
398
493
|
.querySelectorAll("div.ui-dialog")
|
|
399
494
|
.forEach(
|
|
400
|
-
dialogEl => (zIndex = Math.max(zIndex, dialogEl.style.zIndex))
|
|
495
|
+
dialogEl => (zIndex = Math.max(zIndex, parseInt((dialogEl as HTMLElement).style.zIndex) || 100))
|
|
401
496
|
)
|
|
402
497
|
zIndex += 2
|
|
403
|
-
document.body.style.setProperty("--highest-dialog-z-index", zIndex)
|
|
498
|
+
document.body.style.setProperty("--highest-dialog-z-index", String(zIndex))
|
|
404
499
|
return zIndex
|
|
405
500
|
}
|
|
406
501
|
|
|
407
|
-
getFocusableElements() {
|
|
502
|
+
getFocusableElements(): Element[] {
|
|
408
503
|
// Get all focusable elements
|
|
409
504
|
const focusableSelectors = [
|
|
410
505
|
"button:not([disabled])",
|
|
@@ -426,7 +521,7 @@ export class Dialog {
|
|
|
426
521
|
})
|
|
427
522
|
}
|
|
428
523
|
|
|
429
|
-
getInitialFocusElement() {
|
|
524
|
+
getInitialFocusElement(): Element | undefined {
|
|
430
525
|
if (this.initialFocus) {
|
|
431
526
|
const customFocusElement = this.dialogEl.querySelector(
|
|
432
527
|
this.initialFocus
|
|
@@ -441,7 +536,7 @@ export class Dialog {
|
|
|
441
536
|
// Try to find the most appropriate initial focus target
|
|
442
537
|
const priorityElements = [
|
|
443
538
|
// First try to find a text input
|
|
444
|
-
elements.find(el => el.tagName === "INPUT" && el.type === "text"),
|
|
539
|
+
elements.find(el => el.tagName === "INPUT" && (el as HTMLInputElement).type === "text"),
|
|
445
540
|
// Then try to find the first button in the button pane
|
|
446
541
|
elements.find(el => el.closest(".ui-dialog-buttonpane")),
|
|
447
542
|
// Then try to find any input
|
|
@@ -459,7 +554,7 @@ export class Dialog {
|
|
|
459
554
|
return priorityElements.find(el => el) || elements[0]
|
|
460
555
|
}
|
|
461
556
|
|
|
462
|
-
close() {
|
|
557
|
+
close(): void {
|
|
463
558
|
if (!this.dialogEl) {
|
|
464
559
|
return
|
|
465
560
|
}
|
|
@@ -470,12 +565,12 @@ export class Dialog {
|
|
|
470
565
|
if (this.beforeClose) {
|
|
471
566
|
this.beforeClose()
|
|
472
567
|
}
|
|
473
|
-
this.dialogEl.parentElement
|
|
474
|
-
this.backdropEl.parentElement
|
|
568
|
+
this.dialogEl.parentElement!.removeChild(this.dialogEl)
|
|
569
|
+
this.backdropEl.parentElement!.removeChild(this.backdropEl)
|
|
475
570
|
|
|
476
571
|
// Restore focus to previous element
|
|
477
|
-
if (this.previousActiveElement && this.previousActiveElement.focus) {
|
|
478
|
-
this.previousActiveElement.focus()
|
|
572
|
+
if (this.previousActiveElement && (this.previousActiveElement as HTMLElement).focus) {
|
|
573
|
+
(this.previousActiveElement as HTMLElement).focus()
|
|
479
574
|
}
|
|
480
575
|
|
|
481
576
|
if (this.onClose) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare module "diff-dom" {
|
|
2
|
+
export interface DiffDOMOptions {
|
|
3
|
+
valueDiffing?: boolean
|
|
4
|
+
// TODO: add additional options as they become known
|
|
5
|
+
[key: string]: unknown
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type Diff = unknown
|
|
9
|
+
|
|
10
|
+
export class DiffDOM {
|
|
11
|
+
constructor(options?: DiffDOMOptions)
|
|
12
|
+
diff(node1: Node | string, node2: Node | string): Diff[]
|
|
13
|
+
apply(node: Node, diff: Diff[]): void
|
|
14
|
+
undo(node: Node, diff: Diff[]): void
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/events.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
export const isActivationEvent = event => {
|
|
1
|
+
export const isActivationEvent = (event: Event): boolean => {
|
|
3
2
|
if (event.type === "click") {
|
|
4
3
|
return true
|
|
5
4
|
}
|
|
6
5
|
if (event.type === "keydown") {
|
|
7
|
-
return event.key === "Enter" ||
|
|
6
|
+
return (event as KeyboardEvent).key === "Enter" ||
|
|
7
|
+
(event as KeyboardEvent).key === " "
|
|
8
8
|
}
|
|
9
9
|
return false
|
|
10
10
|
}
|
package/src/faq_dialog.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import {escapeText} from "./basic.js"
|
|
3
2
|
import {Dialog} from "./dialog.js"
|
|
4
3
|
import {ensureCSS} from "./network.js"
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
export interface FAQQuestion extends Array<string | {hasImage?: boolean}> {
|
|
6
|
+
0: string
|
|
7
|
+
1: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FAQDialogOptions {
|
|
11
|
+
title?: string
|
|
12
|
+
questions?: FAQQuestion[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const faqTemplate = ({escapedQuestions}: {escapedQuestions: [string, string][]}) =>
|
|
7
16
|
`<div class="faq">
|
|
8
17
|
<ol class="faq-list">
|
|
9
18
|
${escapedQuestions
|
|
@@ -20,16 +29,21 @@ const faqTemplate = ({escapedQuestions}) =>
|
|
|
20
29
|
</div>`
|
|
21
30
|
|
|
22
31
|
export class faqDialog {
|
|
23
|
-
|
|
32
|
+
faqDialog: Dialog
|
|
33
|
+
|
|
34
|
+
constructor({title = "", questions = []}: FAQDialogOptions = {}) {
|
|
24
35
|
ensureCSS(staticUrl("css/faq_dialog.css"))
|
|
25
|
-
const escapedQuestions = []
|
|
36
|
+
const escapedQuestions: [string, string][] = []
|
|
26
37
|
|
|
27
38
|
questions.forEach(q => {
|
|
28
39
|
const question = escapeText(q[0])
|
|
29
|
-
let answer
|
|
40
|
+
let answer: string
|
|
30
41
|
q[1] = escapeText(q[1])
|
|
31
|
-
if (q[q.length - 1].hasImage) {
|
|
32
|
-
|
|
42
|
+
if ((q[q.length - 1] as {hasImage?: boolean}).hasImage) {
|
|
43
|
+
// TODO: the original runtime spreads the tail of the question
|
|
44
|
+
// array into interpolate; keep this behavior but type loosely.
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
answer = (interpolate as any)(...q.slice(1, q.length), true)
|
|
33
47
|
} else {
|
|
34
48
|
answer = q[1]
|
|
35
49
|
}
|
|
@@ -45,14 +59,14 @@ export class faqDialog {
|
|
|
45
59
|
})
|
|
46
60
|
}
|
|
47
61
|
|
|
48
|
-
open() {
|
|
62
|
+
open(): void {
|
|
49
63
|
this.faqDialog.open()
|
|
50
|
-
this.faqDialog.dialogEl
|
|
64
|
+
this.faqDialog.dialogEl!
|
|
51
65
|
.querySelectorAll(".faq-question")
|
|
52
66
|
.forEach(element => {
|
|
53
67
|
element.addEventListener("click", () => {
|
|
54
|
-
const iconEle = element.firstElementChild
|
|
55
|
-
const answerEle = element.nextElementSibling
|
|
68
|
+
const iconEle = element.firstElementChild as HTMLElement
|
|
69
|
+
const answerEle = element.nextElementSibling as HTMLElement
|
|
56
70
|
if (answerEle.style.display == "") {
|
|
57
71
|
iconEle.classList.remove("fa-minus-circle")
|
|
58
72
|
iconEle.classList.add("fa-plus-circle")
|
package/src/file/dialog.ts
CHANGED
|
@@ -1,15 +1,46 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import {Dialog} from "../dialog.js"
|
|
3
2
|
import {FileSelector} from "./selector.js"
|
|
4
3
|
import {addAlert} from "../basic.js"
|
|
5
4
|
import {NewFolderDialog} from "./new_folder_dialog.js"
|
|
6
5
|
import {moveTemplate} from "./templates.js"
|
|
7
6
|
import {moveFile, shortFileTitle} from "./tools.js"
|
|
7
|
+
|
|
8
|
+
export interface MovingFile {
|
|
9
|
+
id: number
|
|
10
|
+
title: string
|
|
11
|
+
path: string
|
|
12
|
+
[key: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FileDialogOptions {
|
|
16
|
+
title?: string
|
|
17
|
+
movingFiles?: MovingFile[]
|
|
18
|
+
allFiles?: import("./selector.js").FileDescriptor[]
|
|
19
|
+
moveUrl?: string
|
|
20
|
+
successMessage?: string
|
|
21
|
+
errorMessage?: string
|
|
22
|
+
succcessCallback?: (file: MovingFile, path: string) => void
|
|
23
|
+
fileIcon?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
8
26
|
/**
|
|
9
27
|
* Functions for the document move dialog.
|
|
10
28
|
*/
|
|
11
29
|
|
|
12
30
|
export class FileDialog {
|
|
31
|
+
title: string
|
|
32
|
+
movingFiles: MovingFile[]
|
|
33
|
+
allFiles: import("./selector.js").FileDescriptor[]
|
|
34
|
+
moveUrl: string
|
|
35
|
+
successMessage: string
|
|
36
|
+
errorMessage: string
|
|
37
|
+
succcessCallback: (file: MovingFile, path: string) => void
|
|
38
|
+
fileIcon: string
|
|
39
|
+
|
|
40
|
+
path: string
|
|
41
|
+
dialog: Dialog
|
|
42
|
+
fileSelector: FileSelector | false
|
|
43
|
+
|
|
13
44
|
constructor({
|
|
14
45
|
title = "", // Dialog title
|
|
15
46
|
movingFiles = [], // Array of all files that are to be moved.
|
|
@@ -17,9 +48,9 @@ export class FileDialog {
|
|
|
17
48
|
moveUrl = "", // URL to use for moving files
|
|
18
49
|
successMessage = "", // Message for success
|
|
19
50
|
errorMessage = "", // Message for failure
|
|
20
|
-
succcessCallback = (
|
|
51
|
+
succcessCallback = () => {}, // Callback on success
|
|
21
52
|
fileIcon = "far fa-file-alt"
|
|
22
|
-
}) {
|
|
53
|
+
}: FileDialogOptions = {}) {
|
|
23
54
|
this.title = title
|
|
24
55
|
this.movingFiles = movingFiles
|
|
25
56
|
this.allFiles = allFiles
|
|
@@ -31,9 +62,10 @@ export class FileDialog {
|
|
|
31
62
|
|
|
32
63
|
this.path = this.getPath()
|
|
33
64
|
this.fileSelector = false
|
|
65
|
+
this.dialog = new Dialog({body: ""}) // placeholder, replaced in init()
|
|
34
66
|
}
|
|
35
67
|
|
|
36
|
-
getPath() {
|
|
68
|
+
getPath(): string {
|
|
37
69
|
if (this.movingFiles.length === 1) {
|
|
38
70
|
let path = this.movingFiles[0].path
|
|
39
71
|
if (path.endsWith("/")) {
|
|
@@ -48,15 +80,15 @@ export class FileDialog {
|
|
|
48
80
|
return this.movingFiles[0].path.split("/").slice(0, -1).join("/") + "/"
|
|
49
81
|
}
|
|
50
82
|
|
|
51
|
-
updatePathDir(path) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
updatePathDir(path: string): void {
|
|
84
|
+
const pathInput = this.dialog.dialogEl!.querySelector(
|
|
85
|
+
"#path"
|
|
86
|
+
) as HTMLInputElement
|
|
87
|
+
const fileName = pathInput.value.split("/").pop() || ""
|
|
88
|
+
pathInput.value = path + fileName
|
|
57
89
|
}
|
|
58
90
|
|
|
59
|
-
init() {
|
|
91
|
+
init(): void {
|
|
60
92
|
this.dialog = new Dialog({
|
|
61
93
|
title: this.title,
|
|
62
94
|
id: "move-dialog",
|
|
@@ -86,7 +118,9 @@ export class FileDialog {
|
|
|
86
118
|
click: () => {
|
|
87
119
|
//apply the current state to server
|
|
88
120
|
let path =
|
|
89
|
-
this.dialog.dialogEl
|
|
121
|
+
(this.dialog.dialogEl!.querySelector(
|
|
122
|
+
"#path"
|
|
123
|
+
) as HTMLInputElement).value
|
|
90
124
|
this.dialog.close()
|
|
91
125
|
|
|
92
126
|
if (path === this.path) {
|
|
@@ -115,7 +149,7 @@ export class FileDialog {
|
|
|
115
149
|
this.dialog.open()
|
|
116
150
|
|
|
117
151
|
this.fileSelector = new FileSelector({
|
|
118
|
-
dom: this.dialog.dialogEl
|
|
152
|
+
dom: this.dialog.dialogEl!.querySelector(".file-selector") as HTMLElement,
|
|
119
153
|
files: this.allFiles,
|
|
120
154
|
showFiles: false,
|
|
121
155
|
selectDir: path => this.updatePathDir(path),
|
|
@@ -124,7 +158,7 @@ export class FileDialog {
|
|
|
124
158
|
this.fileSelector.init()
|
|
125
159
|
}
|
|
126
160
|
|
|
127
|
-
moveFile(file, requestedPath) {
|
|
161
|
+
moveFile(file: MovingFile, requestedPath: string): Promise<void> {
|
|
128
162
|
return moveFile(file.id, file.title, requestedPath, this.moveUrl)
|
|
129
163
|
.then(path => {
|
|
130
164
|
addAlert(
|
package/src/file/index.ts
CHANGED