fwtoolkit 0.1.0-alpha.6 → 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.
Files changed (122) hide show
  1. package/css/alerts.css +7 -0
  2. package/css/dialog.css +62 -0
  3. package/css/overview_menu.css +7 -0
  4. package/dist/basic.d.ts +49 -36
  5. package/dist/basic.d.ts.map +1 -1
  6. package/dist/basic.js +58 -39
  7. package/dist/basic.js.map +1 -1
  8. package/dist/blob.d.ts +1 -1
  9. package/dist/blob.d.ts.map +1 -1
  10. package/dist/blob.js +0 -1
  11. package/dist/blob.js.map +1 -1
  12. package/dist/content_menu.d.ts +63 -20
  13. package/dist/content_menu.d.ts.map +1 -1
  14. package/dist/content_menu.js +23 -20
  15. package/dist/content_menu.js.map +1 -1
  16. package/dist/datatable_bulk.d.ts +34 -6
  17. package/dist/datatable_bulk.d.ts.map +1 -1
  18. package/dist/datatable_bulk.js +4 -5
  19. package/dist/datatable_bulk.js.map +1 -1
  20. package/dist/dialog.d.ts +82 -7
  21. package/dist/dialog.d.ts.map +1 -1
  22. package/dist/dialog.js +21 -16
  23. package/dist/dialog.js.map +1 -1
  24. package/dist/events.d.ts +1 -1
  25. package/dist/events.d.ts.map +1 -1
  26. package/dist/events.js +3 -3
  27. package/dist/events.js.map +1 -1
  28. package/dist/faq_dialog.d.ts +13 -4
  29. package/dist/faq_dialog.d.ts.map +1 -1
  30. package/dist/faq_dialog.js +4 -2
  31. package/dist/faq_dialog.js.map +1 -1
  32. package/dist/file/dialog.d.ts +33 -13
  33. package/dist/file/dialog.d.ts.map +1 -1
  34. package/dist/file/dialog.js +6 -8
  35. package/dist/file/dialog.js.map +1 -1
  36. package/dist/file/index.d.ts.map +1 -1
  37. package/dist/file/index.js +0 -1
  38. package/dist/file/index.js.map +1 -1
  39. package/dist/file/new_folder_dialog.d.ts +5 -2
  40. package/dist/file/new_folder_dialog.d.ts.map +1 -1
  41. package/dist/file/new_folder_dialog.js +1 -2
  42. package/dist/file/new_folder_dialog.js.map +1 -1
  43. package/dist/file/selector.d.ts +47 -14
  44. package/dist/file/selector.d.ts.map +1 -1
  45. package/dist/file/selector.js +11 -9
  46. package/dist/file/selector.js.map +1 -1
  47. package/dist/file/templates.d.ts +1 -1
  48. package/dist/file/templates.d.ts.map +1 -1
  49. package/dist/file/templates.js +0 -1
  50. package/dist/file/templates.js.map +1 -1
  51. package/dist/file/tools.d.ts +4 -4
  52. package/dist/file/tools.d.ts.map +1 -1
  53. package/dist/file/tools.js +4 -4
  54. package/dist/file/tools.js.map +1 -1
  55. package/dist/focus.d.ts +1 -1
  56. package/dist/focus.d.ts.map +1 -1
  57. package/dist/focus.js +5 -5
  58. package/dist/focus.js.map +1 -1
  59. package/dist/index.d.ts +0 -2
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +0 -3
  62. package/dist/index.js.map +1 -1
  63. package/dist/network.d.ts +19 -7
  64. package/dist/network.d.ts.map +1 -1
  65. package/dist/network.js +15 -12
  66. package/dist/network.js.map +1 -1
  67. package/dist/overview_menu.d.ts +77 -18
  68. package/dist/overview_menu.d.ts.map +1 -1
  69. package/dist/overview_menu.js +54 -35
  70. package/dist/overview_menu.js.map +1 -1
  71. package/dist/settings.d.ts +7 -2
  72. package/dist/settings.d.ts.map +1 -1
  73. package/dist/settings.js +0 -1
  74. package/dist/settings.js.map +1 -1
  75. package/dist/user.d.ts +8 -2
  76. package/dist/user.d.ts.map +1 -1
  77. package/dist/user.js +1 -2
  78. package/dist/user.js.map +1 -1
  79. package/dist/worker.d.ts +1 -1
  80. package/dist/worker.d.ts.map +1 -1
  81. package/dist/worker.js +1 -2
  82. package/dist/worker.js.map +1 -1
  83. package/dist/ws.d.ts +59 -25
  84. package/dist/ws.d.ts.map +1 -1
  85. package/dist/ws.js +19 -15
  86. package/dist/ws.js.map +1 -1
  87. package/package.json +2 -1
  88. package/src/basic.ts +136 -69
  89. package/src/blob.ts +1 -2
  90. package/src/content_menu.ts +127 -44
  91. package/src/datatable_bulk.ts +72 -35
  92. package/src/dialog.ts +156 -61
  93. package/src/diff-dom.d.ts +16 -0
  94. package/src/events.ts +3 -3
  95. package/src/faq_dialog.ts +25 -11
  96. package/src/file/dialog.ts +48 -14
  97. package/src/file/index.ts +0 -1
  98. package/src/file/new_folder_dialog.ts +7 -5
  99. package/src/file/selector.ts +86 -36
  100. package/src/file/templates.ts +2 -3
  101. package/src/file/tools.ts +17 -8
  102. package/src/focus.ts +11 -13
  103. package/src/global.d.ts +11 -4
  104. package/src/index.ts +0 -3
  105. package/src/network.ts +58 -20
  106. package/src/overview_menu.ts +183 -109
  107. package/src/settings.ts +9 -4
  108. package/src/user.ts +10 -5
  109. package/src/w3c-keyname.d.ts +3 -0
  110. package/src/worker.ts +1 -2
  111. package/src/ws.ts +115 -50
  112. package/css/ui_dialogs.css +0 -144
  113. package/dist/templates.d.ts +0 -7
  114. package/dist/templates.d.ts.map +0 -1
  115. package/dist/templates.js +0 -43
  116. package/dist/templates.js.map +0 -1
  117. package/dist/user_util.d.ts +0 -7
  118. package/dist/user_util.d.ts.map +0 -1
  119. package/dist/user_util.js +0 -19
  120. package/dist/user_util.js.map +0 -1
  121. package/src/templates.ts +0 -43
  122. package/src/user_util.ts +0 -17
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
- constructor(options) {
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
- false
123
- this.dialogEl = false
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").id = "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").innerHTML =
231
- buttonsTemplate({buttons: this.buttons})
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").innerHTML = noteTemplate(
236
- this.note
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.removeChild(this.dialogEl)
474
- this.backdropEl.parentElement.removeChild(this.backdropEl)
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
- // @ts-nocheck
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" || event.key === " "
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
- const faqTemplate = ({escapedQuestions}) =>
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
- constructor({title = "", questions = []}) {
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
- answer = interpolate(...q.slice(1, q.length), true)
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")
@@ -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 = (_file, _path) => {}, // Callback on success
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 fileName = this.dialog.dialogEl
53
- .querySelector("#path")
54
- .value.split("/")
55
- .pop()
56
- this.dialog.dialogEl.querySelector("#path").value = path + fileName
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.querySelector("#path").value
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.querySelector(".file-selector"),
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
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  export {FileDialog} from "./dialog.js"
3
2
  export {FileSelector} from "./selector.js"
4
3
  export {