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.
Files changed (107) hide show
  1. package/dist/basic.d.ts +49 -36
  2. package/dist/basic.d.ts.map +1 -1
  3. package/dist/basic.js +58 -39
  4. package/dist/basic.js.map +1 -1
  5. package/dist/blob.d.ts +1 -1
  6. package/dist/blob.d.ts.map +1 -1
  7. package/dist/blob.js +0 -1
  8. package/dist/blob.js.map +1 -1
  9. package/dist/content_menu.d.ts +63 -20
  10. package/dist/content_menu.d.ts.map +1 -1
  11. package/dist/content_menu.js +21 -18
  12. package/dist/content_menu.js.map +1 -1
  13. package/dist/datatable_bulk.d.ts +34 -6
  14. package/dist/datatable_bulk.d.ts.map +1 -1
  15. package/dist/datatable_bulk.js +4 -5
  16. package/dist/datatable_bulk.js.map +1 -1
  17. package/dist/dialog.d.ts +82 -7
  18. package/dist/dialog.d.ts.map +1 -1
  19. package/dist/dialog.js +21 -16
  20. package/dist/dialog.js.map +1 -1
  21. package/dist/events.d.ts +1 -1
  22. package/dist/events.d.ts.map +1 -1
  23. package/dist/events.js +3 -3
  24. package/dist/events.js.map +1 -1
  25. package/dist/faq_dialog.d.ts +13 -4
  26. package/dist/faq_dialog.d.ts.map +1 -1
  27. package/dist/faq_dialog.js +4 -2
  28. package/dist/faq_dialog.js.map +1 -1
  29. package/dist/file/dialog.d.ts +33 -13
  30. package/dist/file/dialog.d.ts.map +1 -1
  31. package/dist/file/dialog.js +6 -8
  32. package/dist/file/dialog.js.map +1 -1
  33. package/dist/file/index.d.ts.map +1 -1
  34. package/dist/file/index.js +0 -1
  35. package/dist/file/index.js.map +1 -1
  36. package/dist/file/new_folder_dialog.d.ts +5 -2
  37. package/dist/file/new_folder_dialog.d.ts.map +1 -1
  38. package/dist/file/new_folder_dialog.js +1 -2
  39. package/dist/file/new_folder_dialog.js.map +1 -1
  40. package/dist/file/selector.d.ts +47 -14
  41. package/dist/file/selector.d.ts.map +1 -1
  42. package/dist/file/selector.js +11 -9
  43. package/dist/file/selector.js.map +1 -1
  44. package/dist/file/templates.d.ts +1 -1
  45. package/dist/file/templates.d.ts.map +1 -1
  46. package/dist/file/templates.js +0 -1
  47. package/dist/file/templates.js.map +1 -1
  48. package/dist/file/tools.d.ts +4 -4
  49. package/dist/file/tools.d.ts.map +1 -1
  50. package/dist/file/tools.js +4 -4
  51. package/dist/file/tools.js.map +1 -1
  52. package/dist/focus.d.ts +1 -1
  53. package/dist/focus.d.ts.map +1 -1
  54. package/dist/focus.js +5 -5
  55. package/dist/focus.js.map +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +0 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/network.d.ts +19 -7
  60. package/dist/network.d.ts.map +1 -1
  61. package/dist/network.js +15 -12
  62. package/dist/network.js.map +1 -1
  63. package/dist/overview_menu.d.ts +77 -18
  64. package/dist/overview_menu.d.ts.map +1 -1
  65. package/dist/overview_menu.js +53 -34
  66. package/dist/overview_menu.js.map +1 -1
  67. package/dist/settings.d.ts +7 -2
  68. package/dist/settings.d.ts.map +1 -1
  69. package/dist/settings.js +0 -1
  70. package/dist/settings.js.map +1 -1
  71. package/dist/user.d.ts +8 -2
  72. package/dist/user.d.ts.map +1 -1
  73. package/dist/user.js +1 -2
  74. package/dist/user.js.map +1 -1
  75. package/dist/worker.d.ts +1 -1
  76. package/dist/worker.d.ts.map +1 -1
  77. package/dist/worker.js +1 -2
  78. package/dist/worker.js.map +1 -1
  79. package/dist/ws.d.ts +59 -25
  80. package/dist/ws.d.ts.map +1 -1
  81. package/dist/ws.js +19 -15
  82. package/dist/ws.js.map +1 -1
  83. package/package.json +1 -1
  84. package/src/basic.ts +136 -69
  85. package/src/blob.ts +1 -2
  86. package/src/content_menu.ts +125 -42
  87. package/src/datatable_bulk.ts +72 -35
  88. package/src/dialog.ts +156 -61
  89. package/src/diff-dom.d.ts +16 -0
  90. package/src/events.ts +3 -3
  91. package/src/faq_dialog.ts +25 -11
  92. package/src/file/dialog.ts +48 -14
  93. package/src/file/index.ts +0 -1
  94. package/src/file/new_folder_dialog.ts +7 -5
  95. package/src/file/selector.ts +86 -36
  96. package/src/file/templates.ts +2 -3
  97. package/src/file/tools.ts +17 -8
  98. package/src/focus.ts +11 -13
  99. package/src/global.d.ts +11 -4
  100. package/src/index.ts +0 -1
  101. package/src/network.ts +58 -20
  102. package/src/overview_menu.ts +182 -108
  103. package/src/settings.ts +9 -4
  104. package/src/user.ts +10 -5
  105. package/src/w3c-keyname.d.ts +3 -0
  106. package/src/worker.ts +1 -2
  107. package/src/ws.ts +115 -50
@@ -1,10 +1,77 @@
1
- // @ts-nocheck
2
1
  import {DiffDOM} from "diff-dom"
3
2
  import {keyName} from "w3c-keyname"
3
+
4
4
  import {escapeText, whenReady} from "./basic.js"
5
5
 
6
+ export interface OverviewMenuDropdownOption {
7
+ title: string
8
+ action?: (overview: unknown) => void
9
+ [key: string]: unknown
10
+ }
11
+
12
+ export interface OverviewMenuBaseItem {
13
+ id?: string
14
+ title?: string
15
+ keys?: string
16
+ action?: (overview: unknown) => void
17
+ [key: string]: unknown
18
+ }
19
+
20
+ export interface OverviewMenuDropdownItem extends OverviewMenuBaseItem {
21
+ type: "dropdown"
22
+ open?: boolean
23
+ selectedIndex?: number
24
+ content: OverviewMenuDropdownOption[]
25
+ }
26
+
27
+ export interface OverviewMenuSelectActionDropdownItem extends OverviewMenuBaseItem {
28
+ type: "select-action-dropdown"
29
+ open?: boolean
30
+ checked?: boolean
31
+ content: OverviewMenuDropdownOption[]
32
+ checkAction?: (overview: unknown) => void
33
+ uncheckAction?: (overview: unknown) => void
34
+ }
35
+
36
+ export interface OverviewMenuTextItem extends OverviewMenuBaseItem {
37
+ type: "text"
38
+ action?: (overview: unknown) => void
39
+ }
40
+
41
+ export interface OverviewMenuButtonItem extends OverviewMenuBaseItem {
42
+ type: "button"
43
+ action?: (overview: unknown) => void
44
+ icon?: string
45
+ }
46
+
47
+ export interface OverviewMenuSearchItem extends OverviewMenuBaseItem {
48
+ type: "search"
49
+ placeholder?: string
50
+ icon?: string
51
+ input?: (overview: unknown, value: string) => void
52
+ }
53
+
54
+ export type OverviewMenuItem =
55
+ | OverviewMenuDropdownItem
56
+ | OverviewMenuSelectActionDropdownItem
57
+ | OverviewMenuTextItem
58
+ | OverviewMenuButtonItem
59
+ | OverviewMenuSearchItem
60
+
61
+ export interface OverviewMenuModel {
62
+ content: OverviewMenuItem[]
63
+ }
64
+
6
65
  export class OverviewMenuView {
7
- constructor(overview, model) {
66
+ overview: unknown
67
+ model: OverviewMenuModel
68
+ dd: DiffDOM
69
+ openedMenu: number | false
70
+ listeners: Record<string, (event: Event) => void>
71
+ keyboardShortcuts: Map<string, OverviewMenuItem>
72
+ menuEl: HTMLElement | null
73
+
74
+ constructor(overview: unknown, model: () => OverviewMenuModel) {
8
75
  this.overview = overview
9
76
  this.model = model()
10
77
  this.dd = new DiffDOM({
@@ -13,9 +80,10 @@ export class OverviewMenuView {
13
80
  this.openedMenu = false
14
81
  this.listeners = {}
15
82
  this.keyboardShortcuts = new Map()
83
+ this.menuEl = null
16
84
  }
17
85
 
18
- init() {
86
+ init(): void {
19
87
  whenReady().then(() => {
20
88
  this.addMissingIds(this.model)
21
89
  this.bindEvents()
@@ -23,32 +91,32 @@ export class OverviewMenuView {
23
91
  })
24
92
  }
25
93
 
26
- addMissingIds(menu) {
94
+ addMissingIds(menu: {content: Array<{id?: string; type?: string; content?: unknown[]}>}): void {
27
95
  // Add missing ids to menu items that don't have an ID.
28
96
  menu.content.forEach(item => {
29
97
  if (!item.id) {
30
98
  item.id = Math.random().toString(36).substring(2)
31
99
  }
32
100
  if (item.type === "dropdown") {
33
- this.addMissingIds(item)
101
+ this.addMissingIds(item as {content: Array<{id?: string; type?: string; content?: unknown[]}>})
34
102
  }
35
103
  })
36
104
  }
37
105
 
38
- bindEvents() {
106
+ bindEvents(): void {
39
107
  this.menuEl = document.getElementById("fw-overview-menu")
40
- this.listeners.onclick = event => this.onclick(event)
108
+ this.listeners.onclick = event => this.onclick(event as MouseEvent)
41
109
  document.body.addEventListener("click", this.listeners.onclick)
42
- this.listeners.oninput = event => this.oninput(event)
110
+ this.listeners.oninput = event => this.oninput(event as InputEvent)
43
111
  document.body.addEventListener("input", this.listeners.oninput)
44
- this.listeners.onKeydown = event => this.onKeydown(event)
112
+ this.listeners.onKeydown = event => this.onKeydown(event as KeyboardEvent)
45
113
  document.body.addEventListener("keydown", this.listeners.onKeydown)
46
- this.listeners.onFocus = event => this.onFocus(event)
114
+ this.listeners.onFocus = event => this.onFocus(event as FocusEvent)
47
115
  document.body.addEventListener("focus", this.listeners.onFocus, true)
48
116
  this.update()
49
117
  }
50
118
 
51
- setupKeyboardShortcuts() {
119
+ setupKeyboardShortcuts(): void {
52
120
  // Map all keyboard shortcuts from the menu model
53
121
  this.model.content.forEach(menuItem => {
54
122
  if (menuItem.keys) {
@@ -60,7 +128,7 @@ export class OverviewMenuView {
60
128
  })
61
129
  }
62
130
 
63
- onKeydown(event) {
131
+ onKeydown(event: KeyboardEvent): void {
64
132
  let name = keyName(event)
65
133
  if (event.altKey) {
66
134
  name = "alt-" + name.toLowerCase()
@@ -83,21 +151,21 @@ export class OverviewMenuView {
83
151
  if (
84
152
  this.openedMenu === this.model.content.indexOf(menuItem)
85
153
  ) {
86
- menuItem.open = false
154
+ ;(menuItem as OverviewMenuDropdownItem).open = false
87
155
  this.openedMenu = false
88
156
  this.update()
89
157
  } else {
90
158
  if (this.openedMenu !== false) {
91
- this.model.content[this.openedMenu].open = false
159
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
92
160
  }
93
- menuItem.open = true
161
+ ;(menuItem as OverviewMenuDropdownItem).open = true
94
162
  this.openedMenu = this.model.content.indexOf(menuItem)
95
163
  this.update()
96
- const firstDropdownItem = this.menuEl.querySelector(
164
+ const firstDropdownItem = this.menuEl!.querySelector(
97
165
  `.fw-pulldown-item.selected`
98
166
  )
99
167
  if (firstDropdownItem) {
100
- firstDropdownItem.focus()
168
+ (firstDropdownItem as HTMLElement).focus()
101
169
  }
102
170
  }
103
171
  } else if (menuItem.action) {
@@ -110,15 +178,15 @@ export class OverviewMenuView {
110
178
  // Handle horizontal navigation between menu items
111
179
  if (name === "ArrowLeft" || name === "ArrowRight") {
112
180
  const menuItems = Array.from(
113
- this.menuEl.querySelectorAll("#fw-overview-menu > li")
181
+ this.menuEl!.querySelectorAll("#fw-overview-menu > li")
114
182
  )
115
183
  const focusedElement = document.activeElement
116
- const currentMenuItem = focusedElement.closest("li")
184
+ const currentMenuItem = focusedElement?.closest("li")
117
185
 
118
186
  if (currentMenuItem) {
119
187
  event.preventDefault()
120
188
  const currentIndex = menuItems.indexOf(currentMenuItem)
121
- let newIndex
189
+ let newIndex: number
122
190
 
123
191
  if (name === "ArrowLeft") {
124
192
  newIndex =
@@ -136,7 +204,7 @@ export class OverviewMenuView {
136
204
  ".fw-dropdown-menu, .fw-text-menu, button, input"
137
205
  )
138
206
  if (nextMenuItem) {
139
- nextMenuItem.focus()
207
+ (nextMenuItem as HTMLElement).focus()
140
208
  }
141
209
  }
142
210
  return
@@ -145,23 +213,23 @@ export class OverviewMenuView {
145
213
  // Handle Enter and Space to open dropdown menus
146
214
  if (name === "Enter" || name === " ") {
147
215
  const focusedElement = document.activeElement
148
- if (focusedElement.matches(".fw-dropdown-menu")) {
216
+ if (focusedElement?.matches(".fw-dropdown-menu")) {
149
217
  event.preventDefault()
150
218
  const menuItem = this.findMenuItemFromElement(focusedElement)
151
219
  if (menuItem && menuItem.type === "dropdown") {
152
220
  if (this.openedMenu !== false) {
153
- this.model.content[this.openedMenu].open = false
221
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
154
222
  }
155
- menuItem.open = true
223
+ ;(menuItem as OverviewMenuDropdownItem).open = true
156
224
  this.openedMenu = this.model.content.indexOf(menuItem)
157
- menuItem.selectedIndex = 0
225
+ ;(menuItem as OverviewMenuDropdownItem).selectedIndex = 0
158
226
  this.update()
159
227
 
160
- const firstDropdownItem = this.menuEl.querySelector(
228
+ const firstDropdownItem = this.menuEl!.querySelector(
161
229
  `.fw-pulldown-item.selected`
162
230
  )
163
231
  if (firstDropdownItem) {
164
- firstDropdownItem.focus()
232
+ (firstDropdownItem as HTMLElement).focus()
165
233
  }
166
234
  }
167
235
  return
@@ -172,62 +240,63 @@ export class OverviewMenuView {
172
240
  const menuItem = this.model.content[this.openedMenu]
173
241
 
174
242
  if (menuItem.type === "dropdown") {
243
+ const dropdownItem = menuItem as OverviewMenuDropdownItem
175
244
  if (name === "ArrowDown" || name === "ArrowUp") {
176
245
  event.preventDefault()
177
246
  event.stopPropagation()
178
247
 
179
248
  // Find currently selected item
180
249
  let selectedIndex = -1
181
- if (menuItem.selectedIndex !== undefined) {
182
- selectedIndex = menuItem.selectedIndex
250
+ if (dropdownItem.selectedIndex !== undefined) {
251
+ selectedIndex = dropdownItem.selectedIndex
183
252
  }
184
253
 
185
254
  // Calculate new index
186
255
  if (name === "ArrowDown") {
187
256
  selectedIndex =
188
- selectedIndex < menuItem.content.length - 1
257
+ selectedIndex < dropdownItem.content.length - 1
189
258
  ? selectedIndex + 1
190
259
  : 0
191
260
  } else {
192
261
  selectedIndex -= 1
193
262
  if (selectedIndex < 0) {
194
263
  // Close menu
195
- menuItem.open = false
264
+ dropdownItem.open = false
196
265
  this.openedMenu = false
197
- delete menuItem.selectedIndex
266
+ delete dropdownItem.selectedIndex
198
267
  this.update()
199
- const dropdownButton = this.menuEl.querySelector(
268
+ const dropdownButton = this.menuEl!.querySelector(
200
269
  `#${menuItem.id}-button`
201
270
  )
202
271
  if (dropdownButton) {
203
- dropdownButton.focus()
272
+ (dropdownButton as HTMLElement).focus()
204
273
  }
205
274
  }
206
275
  }
207
276
 
208
- menuItem.selectedIndex = selectedIndex
277
+ dropdownItem.selectedIndex = selectedIndex
209
278
  this.update()
210
- const selectedEl = this.menuEl.querySelector(
279
+ const selectedEl = this.menuEl!.querySelector(
211
280
  `.fw-pulldown-item.selected`
212
281
  )
213
282
  if (selectedEl) {
214
- selectedEl.focus()
283
+ (selectedEl as HTMLElement).focus()
215
284
  }
216
285
  } else if (name === "Enter" || name === " ") {
217
286
  event.preventDefault()
218
287
  event.stopPropagation()
219
288
 
220
289
  if (
221
- menuItem.selectedIndex !== undefined &&
222
- menuItem.content[menuItem.selectedIndex]
290
+ dropdownItem.selectedIndex !== undefined &&
291
+ dropdownItem.content[dropdownItem.selectedIndex]
223
292
  ) {
224
293
  const selectedItem =
225
- menuItem.content[menuItem.selectedIndex]
294
+ dropdownItem.content[dropdownItem.selectedIndex]
226
295
  if (selectedItem.action) {
227
296
  selectedItem.action(this.overview)
228
- menuItem.open = false
297
+ dropdownItem.open = false
229
298
  this.openedMenu = false
230
- delete menuItem.selectedIndex
299
+ delete dropdownItem.selectedIndex
231
300
  this.update()
232
301
  }
233
302
  }
@@ -235,9 +304,9 @@ export class OverviewMenuView {
235
304
  event.preventDefault()
236
305
  event.stopPropagation()
237
306
 
238
- menuItem.open = false
307
+ dropdownItem.open = false
239
308
  this.openedMenu = false
240
- delete menuItem.selectedIndex
309
+ delete dropdownItem.selectedIndex
241
310
  this.update()
242
311
  const dropdownButton = document.getElementById(
243
312
  `${menuItem.id}-button`
@@ -250,28 +319,28 @@ export class OverviewMenuView {
250
319
  }
251
320
  }
252
321
 
253
- onFocus(event) {
322
+ onFocus(event: FocusEvent): void {
254
323
  // Ignore if the focus event is triggered by JavaScript
255
324
  if (event.isTrusted === false) {
256
325
  return
257
326
  }
258
- const target = event.target
327
+ const target = event.target as Element
259
328
  if (this.openedMenu !== false) {
260
329
  if (target.matches("#fw-overview-menu li .fw-pulldown-item")) {
261
330
  const menuItem = this.model.content[this.openedMenu]
262
331
  if (menuItem) {
263
332
  const itemNumber = Array.from(
264
- target.parentElement.parentElement.children
265
- ).indexOf(target.parentElement)
266
- menuItem.selectedIndex = itemNumber
333
+ target.parentElement!.parentElement!.children
334
+ ).indexOf(target.parentElement as Element)
335
+ ;(menuItem as OverviewMenuDropdownItem).selectedIndex = itemNumber
267
336
  this.update()
268
337
  }
269
338
  } else {
270
339
  // Close dropdown menu if focus is outside of the dropdown
271
340
  const menuItem = this.model.content[this.openedMenu]
272
341
  if (menuItem) {
273
- menuItem.open = false
274
- delete menuItem.selectedIndex
342
+ ;(menuItem as OverviewMenuDropdownItem).open = false
343
+ delete (menuItem as OverviewMenuDropdownItem).selectedIndex
275
344
  this.openedMenu = false
276
345
  this.update()
277
346
  }
@@ -279,14 +348,14 @@ export class OverviewMenuView {
279
348
  }
280
349
  }
281
350
 
282
- findMenuItemFromElement(element) {
351
+ findMenuItemFromElement(element: Element): OverviewMenuItem | null {
283
352
  const menuItem = element.closest("li")
284
353
  if (!menuItem) {
285
354
  return null
286
355
  }
287
356
 
288
357
  let menuNumber = 0
289
- let seekItem = menuItem
358
+ let seekItem: Element | null = menuItem
290
359
  while (seekItem.previousElementSibling) {
291
360
  menuNumber++
292
361
  seekItem = seekItem.previousElementSibling
@@ -294,59 +363,60 @@ export class OverviewMenuView {
294
363
  return this.model.content[menuNumber]
295
364
  }
296
365
 
297
- focusMenuItem(menuItem) {
298
- const menuEl = this.menuEl.querySelector(`#${menuItem.id}`)
366
+ focusMenuItem(menuItem: OverviewMenuItem): void {
367
+ const menuEl = this.menuEl!.querySelector(`#${menuItem.id}`)
299
368
  if (menuEl) {
300
- menuEl.focus()
369
+ (menuEl as HTMLElement).focus()
301
370
  }
302
371
  }
303
372
 
304
- oninput(event) {
305
- const target = event.target
373
+ oninput(event: InputEvent): void {
374
+ const target = event.target as Element
306
375
  if (target.matches("#fw-overview-menu > li > .fw-button > input")) {
307
376
  // A text was entered in a top entry. we find which one.
308
377
  let menuNumber = 0
309
- let seekItem = target.closest("li")
310
- while (seekItem.previousElementSibling) {
378
+ let seekItem: Element | null = target.closest("li")
379
+ while (seekItem?.previousElementSibling) {
311
380
  menuNumber++
312
381
  seekItem = seekItem.previousElementSibling
313
382
  }
314
383
  const menuItem = this.model.content[menuNumber]
315
- if (menuItem.input) {
316
- menuItem.input(this.overview, target.value)
317
- target.focus()
384
+ if (menuItem.type === "search" && menuItem.input) {
385
+ menuItem.input(this.overview, (target as HTMLInputElement).value)
386
+ ;(target as HTMLElement).focus()
318
387
  }
319
388
  }
320
389
  }
321
390
 
322
- onclick(event) {
323
- const target = event.target
391
+ onclick(event: MouseEvent): void | false | true {
392
+ const target = event.target as Element
324
393
  if (
325
394
  target.matches("#fw-overview-menu li li, #fw-overview-menu li li *")
326
395
  ) {
327
396
  event.preventDefault()
328
397
  let itemNumber = 0
329
- let seekItem = target.closest("li")
330
- while (seekItem.previousElementSibling) {
398
+ let seekItem: Element | null = target.closest("li")
399
+ while (seekItem?.previousElementSibling) {
331
400
  itemNumber++
332
401
  seekItem = seekItem.previousElementSibling
333
402
  }
334
403
  let menuNumber = 0
335
- seekItem = seekItem.parentElement.parentElement.parentElement
336
- while (seekItem.previousElementSibling) {
404
+ seekItem = seekItem!.parentElement!.parentElement!.parentElement
405
+ while (seekItem?.previousElementSibling) {
337
406
  menuNumber++
338
407
  seekItem = seekItem.previousElementSibling
339
408
  }
340
- this.model.content[menuNumber].content[itemNumber].action(
341
- this.overview
342
- )
343
- this.model.content[menuNumber].open = false
409
+ const menuItem = this.model.content[menuNumber]
410
+ if (menuItem.type === "dropdown") {
411
+ menuItem.content[itemNumber].action!(this.overview)
412
+ menuItem.open = false
344
413
 
345
- if (this.model.content[menuNumber].type === "dropdown") {
346
- this.model.content[menuNumber].title =
347
- this.model.content[menuNumber].content[itemNumber].title
348
- this.openedMenu = false
349
- this.update()
414
+ if (menuItem.type === "dropdown") {
415
+ menuItem.title =
416
+ menuItem.content[itemNumber].title
417
+ this.openedMenu = false
418
+ this.update()
419
+ }
350
420
  }
351
421
  return false
352
422
  } else if (
@@ -360,19 +430,23 @@ export class OverviewMenuView {
360
430
  // A toolbar dropdown menu item was clicked. We just need to
361
431
  // find out which one
362
432
  let menuNumber = 0
363
- let seekItem = target.closest("li")
364
- while (seekItem.previousElementSibling) {
433
+ let seekItem: Element | null = target.closest("li")
434
+ while (seekItem?.previousElementSibling) {
365
435
  menuNumber++
366
436
  seekItem = seekItem.previousElementSibling
367
437
  }
368
- const menuItem = this.model.content[menuNumber]
438
+ const menuItem = this.model.content[menuNumber] as OverviewMenuSelectActionDropdownItem
369
439
 
370
440
  if (menuItem.checked === true) {
371
441
  menuItem.checked = false
372
- menuItem.uncheckAction(this.overview)
442
+ if (menuItem.uncheckAction) {
443
+ menuItem.uncheckAction(this.overview)
444
+ }
373
445
  } else {
374
446
  menuItem.checked = true
375
- menuItem.checkAction(this.overview)
447
+ if (menuItem.checkAction) {
448
+ menuItem.checkAction(this.overview)
449
+ }
376
450
  }
377
451
  return true
378
452
  } else if (
@@ -381,8 +455,8 @@ export class OverviewMenuView {
381
455
  // A toolbar dropdown menu item was clicked. We just need to
382
456
  // find out which one
383
457
  let menuNumber = 0
384
- let seekItem = target.closest("li")
385
- while (seekItem.previousElementSibling) {
458
+ let seekItem: Element | null = target.closest("li")
459
+ while (seekItem?.previousElementSibling) {
386
460
  menuNumber++
387
461
  seekItem = seekItem.previousElementSibling
388
462
  }
@@ -390,17 +464,17 @@ export class OverviewMenuView {
390
464
  // if it is a dropdown menu, open it. Otherwise execute an
391
465
  // associated action.
392
466
  if (
393
- ["dropdown", "select-action-dropdown"].includes(menuItem.type)
467
+ ["dropdown", "select-action-dropdown"].includes(menuItem.type || "")
394
468
  ) {
395
469
  event.preventDefault()
396
470
  if (this.openedMenu === menuNumber) {
397
- this.model.content[this.openedMenu].open = false
471
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
398
472
  this.openedMenu = false
399
473
  } else {
400
474
  if (this.openedMenu !== false) {
401
- this.model.content[this.openedMenu].open = false
475
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
402
476
  }
403
- menuItem.open = true
477
+ ;(menuItem as OverviewMenuDropdownItem).open = true
404
478
  this.openedMenu = menuNumber
405
479
  }
406
480
  this.update()
@@ -409,20 +483,20 @@ export class OverviewMenuView {
409
483
  menuItem.action(this.overview)
410
484
  this.announceForScreenReader(gettext("Action completed"))
411
485
  if (this.openedMenu !== false) {
412
- this.model.content[this.openedMenu].open = false
486
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
413
487
  this.openedMenu = false
414
488
  }
415
489
  this.update()
416
490
  }
417
491
  return false
418
492
  } else if (this.openedMenu !== false) {
419
- this.model.content[this.openedMenu].open = false
493
+ ;(this.model.content[this.openedMenu] as OverviewMenuDropdownItem).open = false
420
494
  this.openedMenu = false
421
495
  this.update()
422
496
  }
423
497
  }
424
498
 
425
- update() {
499
+ update(): void {
426
500
  if (!this.menuEl) {
427
501
  // page has not yet been loaded. abort
428
502
  return
@@ -431,7 +505,7 @@ export class OverviewMenuView {
431
505
  this.dd.apply(this.menuEl, diff)
432
506
  }
433
507
 
434
- getMenuHTML() {
508
+ getMenuHTML(): string {
435
509
  return `<ul id="fw-overview-menu">${this.model.content
436
510
  .map(
437
511
  menuItem =>
@@ -443,7 +517,7 @@ export class OverviewMenuView {
443
517
  }
444
518
 
445
519
  // Underline access keys
446
- getAccessKeyHTML(title, accessKey) {
520
+ getAccessKeyHTML(title: string, accessKey: string | undefined): string {
447
521
  if (!accessKey) {
448
522
  return escapeText(title)
449
523
  }
@@ -456,8 +530,8 @@ export class OverviewMenuView {
456
530
  )}</span>${escapeText(title.substring(index + 1))}`
457
531
  }
458
532
 
459
- getMenuItemHTML(menuItem) {
460
- let returnValue
533
+ getMenuItemHTML(menuItem: OverviewMenuItem): string {
534
+ let returnValue: string
461
535
  switch (menuItem.type) {
462
536
  case "dropdown":
463
537
  returnValue = this.getDropdownHTML(menuItem)
@@ -481,7 +555,7 @@ export class OverviewMenuView {
481
555
  return returnValue
482
556
  }
483
557
 
484
- getSelectionActionDropdownHTML(menuItem) {
558
+ getSelectionActionDropdownHTML(menuItem: OverviewMenuSelectActionDropdownItem): string {
485
559
  return `
486
560
  <div class="select-action fw-button fw-light fw-large">
487
561
  <input type="checkbox" ${menuItem.checked ? "checked" : ""}>
@@ -491,7 +565,7 @@ export class OverviewMenuView {
491
565
  `
492
566
  }
493
567
 
494
- getDropdownHTML(menuItem) {
568
+ getDropdownHTML(menuItem: OverviewMenuDropdownItem): string {
495
569
  const accessKey = menuItem.keys?.split("-")[1]
496
570
  return `
497
571
  <div class="dropdown fw-dropdown-menu"
@@ -518,7 +592,7 @@ export class OverviewMenuView {
518
592
  `
519
593
  }
520
594
 
521
- getDropdownListHTML(menuItem) {
595
+ getDropdownListHTML(menuItem: OverviewMenuDropdownItem | OverviewMenuSelectActionDropdownItem): string {
522
596
  if (menuItem.open) {
523
597
  return `<div class="fw-pulldown fw-left"
524
598
  role="menu"
@@ -535,8 +609,8 @@ export class OverviewMenuView {
535
609
  }
536
610
  }
537
611
 
538
- getDropdownOptionHTML(menuOption, index) {
539
- const menuItem = this.model.content[this.openedMenu]
612
+ getDropdownOptionHTML(menuOption: OverviewMenuDropdownOption, index: number): string {
613
+ const menuItem = this.model.content[this.openedMenu as number] as OverviewMenuDropdownItem
540
614
  const isSelected = menuItem.selectedIndex === index
541
615
  return `
542
616
  <li role="none">
@@ -548,7 +622,7 @@ export class OverviewMenuView {
548
622
  `
549
623
  }
550
624
 
551
- getButtonHTML(menuItem) {
625
+ getButtonHTML(menuItem: OverviewMenuButtonItem): string {
552
626
  return `
553
627
  <button class="fw-button fw-light fw-large"
554
628
  title="${menuItem.title}"
@@ -559,7 +633,7 @@ export class OverviewMenuView {
559
633
  </button>`
560
634
  }
561
635
 
562
- announceForScreenReader(message) {
636
+ announceForScreenReader(message: string): void {
563
637
  const announcement = document.createElement("div")
564
638
  announcement.setAttribute("aria-live", "polite")
565
639
  announcement.classList.add("sr-only") // CSS to visually hide but keep available to screen readers
@@ -568,22 +642,22 @@ export class OverviewMenuView {
568
642
  setTimeout(() => announcement.remove(), 1000)
569
643
  }
570
644
 
571
- getTextHTML(menuItem) {
645
+ getTextHTML(menuItem: OverviewMenuTextItem): string {
572
646
  const accessKey = menuItem.keys?.split("-")[1]
573
647
  return `
574
648
  <button class="fw-text-menu"
575
649
  title="${menuItem.title}${menuItem.keys ? ` (${menuItem.keys})` : ""}"
576
650
  >
577
- ${this.getAccessKeyHTML(menuItem.title, accessKey)}
651
+ ${this.getAccessKeyHTML(menuItem.title || "", accessKey)}
578
652
  </button>`
579
653
  }
580
654
 
581
- getSearchHTML(menuItem) {
655
+ getSearchHTML(menuItem: OverviewMenuSearchItem): string {
582
656
  const accessKey = menuItem.keys?.split("-")[1]
583
657
  return `
584
658
  <div class="fw-button fw-light fw-large disabled fw-search-field-container">
585
659
  <label for="${menuItem.id}-input" class="fw-search-label">
586
- ${this.getAccessKeyHTML(menuItem.title, accessKey)}
660
+ ${this.getAccessKeyHTML(menuItem.title || "", accessKey)}
587
661
  </label>
588
662
  <input type="search"
589
663
  class="fw-search-field"
@@ -596,7 +670,7 @@ export class OverviewMenuView {
596
670
  </div>`
597
671
  }
598
672
 
599
- destroy() {
673
+ destroy(): void {
600
674
  // Remove all event listeners
601
675
  document.body.removeEventListener("click", this.listeners.onclick)
602
676
  document.body.removeEventListener("input", this.listeners.oninput)
package/src/settings.ts CHANGED
@@ -1,7 +1,12 @@
1
- // @ts-nocheck
2
- let _settings = null
1
+ export interface Settings {
2
+ apiUrl: (url: string) => string
3
+ getCsrfToken: () => string
4
+ [key: string]: unknown
5
+ }
6
+
7
+ let _settings: Settings | null = null
3
8
 
4
- export function initSettings(rawSettings) {
9
+ export function initSettings(rawSettings: Settings): void {
5
10
  if (_settings) {
6
11
  throw new Error("Settings already initialized")
7
12
  }
@@ -9,7 +14,7 @@ export function initSettings(rawSettings) {
9
14
  _settings = Object.freeze({...rawSettings})
10
15
  }
11
16
 
12
- export function getSettings() {
17
+ export function getSettings(): Settings {
13
18
  if (!_settings) {
14
19
  throw new Error(
15
20
  "App settings not initialized. Call initSettings() first."