@fiduswriter/image-manager 0.1.4 → 0.1.6
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/README.md +53 -3
- package/dist/copyright_dialog/index.d.ts +10 -13
- package/dist/copyright_dialog/index.d.ts.map +1 -1
- package/dist/copyright_dialog/index.js +32 -14
- package/dist/copyright_dialog/index.js.map +1 -1
- package/dist/copyright_dialog/templates.d.ts +16 -12
- package/dist/copyright_dialog/templates.d.ts.map +1 -1
- package/dist/copyright_dialog/templates.js.map +1 -1
- package/dist/database.d.ts +7 -6
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +17 -11
- package/dist/database.js.map +1 -1
- package/dist/edit_dialog/index.d.ts +22 -19
- package/dist/edit_dialog/index.d.ts.map +1 -1
- package/dist/edit_dialog/index.js +65 -33
- package/dist/edit_dialog/index.js.map +1 -1
- package/dist/edit_dialog/model.d.ts +2 -19
- package/dist/edit_dialog/model.d.ts.map +1 -1
- package/dist/edit_dialog/model.js +51 -31
- package/dist/edit_dialog/model.js.map +1 -1
- package/dist/edit_dialog/templates.d.ts +7 -4
- package/dist/edit_dialog/templates.d.ts.map +1 -1
- package/dist/edit_dialog/templates.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/overview/categories.d.ts +7 -5
- package/dist/overview/categories.d.ts.map +1 -1
- package/dist/overview/categories.js +18 -13
- package/dist/overview/categories.js.map +1 -1
- package/dist/overview/index.d.ts +31 -27
- package/dist/overview/index.d.ts.map +1 -1
- package/dist/overview/index.js +64 -33
- package/dist/overview/index.js.map +1 -1
- package/dist/overview/menu.d.ts +4 -47
- package/dist/overview/menu.d.ts.map +1 -1
- package/dist/overview/menu.js +13 -8
- package/dist/overview/menu.js.map +1 -1
- package/dist/overview/templates.d.ts +7 -3
- package/dist/overview/templates.d.ts.map +1 -1
- package/dist/overview/templates.js.map +1 -1
- package/dist/selection_dialog/index.d.ts +17 -15
- package/dist/selection_dialog/index.d.ts.map +1 -1
- package/dist/selection_dialog/index.js +18 -8
- package/dist/selection_dialog/index.js.map +1 -1
- package/dist/types.d.ts +118 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +94 -78
- package/src/copyright_dialog/{index.js → index.ts} +70 -38
- package/src/copyright_dialog/{templates.js → templates.ts} +19 -3
- package/src/database.ts +83 -0
- package/src/edit_dialog/{index.js → index.ts} +110 -45
- package/src/edit_dialog/{model.js → model.ts} +95 -46
- package/src/edit_dialog/{templates.js → templates.ts} +13 -2
- package/src/global.d.ts +37 -0
- package/src/overview/{categories.js → categories.ts} +34 -21
- package/src/overview/{index.js → index.ts} +157 -75
- package/src/overview/menu.ts +85 -0
- package/src/overview/{templates.js → templates.ts} +16 -2
- package/src/selection_dialog/{index.js → index.ts} +85 -49
- package/src/types.ts +133 -0
- package/src/database.js +0 -57
- package/src/overview/menu.js +0 -75
- /package/src/{index.js → index.ts} +0 -0
|
@@ -6,39 +6,51 @@ import {
|
|
|
6
6
|
gettext,
|
|
7
7
|
postJson
|
|
8
8
|
} from "fwtoolkit"
|
|
9
|
+
import type {OverviewMenuDropdownItem} from "fwtoolkit/overview_menu"
|
|
10
|
+
|
|
9
11
|
import {usermediaEditcategoriesTemplate} from "./templates.js"
|
|
12
|
+
import type {ImageOverview} from "./index.js"
|
|
13
|
+
import type {
|
|
14
|
+
ImageCategory,
|
|
15
|
+
SaveCategoriesRequest,
|
|
16
|
+
SaveCategoriesResponse
|
|
17
|
+
} from "../types.js"
|
|
10
18
|
|
|
11
19
|
export class ImageOverviewCategories {
|
|
12
|
-
|
|
20
|
+
imageOverview: ImageOverview
|
|
21
|
+
|
|
22
|
+
constructor(imageOverview: ImageOverview) {
|
|
13
23
|
this.imageOverview = imageOverview
|
|
14
24
|
imageOverview.mod.categories = this
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
//save changes or create a new category
|
|
18
|
-
saveCategories(cats) {
|
|
28
|
+
saveCategories(cats: SaveCategoriesRequest): void {
|
|
19
29
|
activateWait()
|
|
20
30
|
|
|
21
|
-
postJson("/api/usermedia/save_category/",
|
|
22
|
-
ids: cats.ids,
|
|
23
|
-
titles: cats.titles
|
|
24
|
-
})
|
|
31
|
+
postJson("/api/usermedia/save_category/", cats as unknown as Record<string, unknown>)
|
|
25
32
|
.catch(error => {
|
|
26
33
|
addAlert("error", gettext("Could not update categories"))
|
|
27
34
|
deactivateWait()
|
|
28
35
|
throw error
|
|
29
36
|
})
|
|
30
37
|
.then(({json}) => {
|
|
31
|
-
|
|
32
|
-
this.
|
|
38
|
+
const response = json as SaveCategoriesResponse
|
|
39
|
+
this.imageOverview.app.imageDB.cats = response.entries
|
|
40
|
+
this.setImageCategoryList(response.entries)
|
|
33
41
|
addAlert("success", gettext("The categories have been updated"))
|
|
34
42
|
deactivateWait()
|
|
35
43
|
})
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
setImageCategoryList(imageCategories) {
|
|
46
|
+
setImageCategoryList(imageCategories: ImageCategory[]): void {
|
|
39
47
|
const catSelector = this.imageOverview.menu.model.content.find(
|
|
40
|
-
menuItem
|
|
48
|
+
(menuItem): menuItem is OverviewMenuDropdownItem =>
|
|
49
|
+
menuItem.id === "cat_selector"
|
|
41
50
|
)
|
|
51
|
+
if (!catSelector) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
42
54
|
catSelector.content = catSelector.content.filter(
|
|
43
55
|
cat => cat.type !== "category"
|
|
44
56
|
)
|
|
@@ -46,19 +58,19 @@ export class ImageOverviewCategories {
|
|
|
46
58
|
imageCategories.map(cat => ({
|
|
47
59
|
type: "category",
|
|
48
60
|
title: cat.category_title,
|
|
49
|
-
action: _overview => {
|
|
61
|
+
action: (_overview: unknown) => {
|
|
50
62
|
const trs = document.querySelectorAll(
|
|
51
63
|
"#imagelist > tbody > tr"
|
|
52
64
|
)
|
|
53
65
|
trs.forEach(tr => {
|
|
66
|
+
const imageCell = tr.querySelector(".fw-usermedia-image")
|
|
54
67
|
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.classList.contains(`cat_${cat.id}`)
|
|
68
|
+
imageCell &&
|
|
69
|
+
imageCell.classList.contains(`cat_${cat.id}`)
|
|
58
70
|
) {
|
|
59
|
-
tr.style.display = ""
|
|
71
|
+
;(tr as HTMLElement).style.display = ""
|
|
60
72
|
} else {
|
|
61
|
-
tr.style.display = "none"
|
|
73
|
+
;(tr as HTMLElement).style.display = "none"
|
|
62
74
|
}
|
|
63
75
|
})
|
|
64
76
|
}
|
|
@@ -68,21 +80,22 @@ export class ImageOverviewCategories {
|
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
//open a dialog for editing categories
|
|
71
|
-
editCategoryDialog() {
|
|
83
|
+
editCategoryDialog(): void {
|
|
72
84
|
const buttons = [
|
|
73
85
|
{
|
|
74
86
|
text: gettext("Submit"),
|
|
75
87
|
classes: "fw-dark",
|
|
76
88
|
click: () => {
|
|
77
|
-
const cats = {
|
|
89
|
+
const cats: SaveCategoriesRequest = {
|
|
78
90
|
ids: [],
|
|
79
91
|
titles: []
|
|
80
92
|
}
|
|
81
93
|
document
|
|
82
94
|
.querySelectorAll("#edit-categories .category-form")
|
|
83
95
|
.forEach(el => {
|
|
84
|
-
const
|
|
85
|
-
|
|
96
|
+
const input = el as HTMLInputElement
|
|
97
|
+
const thisVal = input.value.trim()
|
|
98
|
+
let thisId: string | number = input.dataset.id || "0"
|
|
86
99
|
if ("undefined" == typeof thisId) {
|
|
87
100
|
thisId = 0
|
|
88
101
|
}
|
|
@@ -96,7 +109,7 @@ export class ImageOverviewCategories {
|
|
|
96
109
|
}
|
|
97
110
|
},
|
|
98
111
|
{
|
|
99
|
-
type: "cancel"
|
|
112
|
+
type: "cancel" as const
|
|
100
113
|
}
|
|
101
114
|
]
|
|
102
115
|
|
|
@@ -19,12 +19,67 @@ import {
|
|
|
19
19
|
staticUrl,
|
|
20
20
|
whenReady
|
|
21
21
|
} from "fwtoolkit"
|
|
22
|
+
import type {DataTable} from "simple-datatables"
|
|
23
|
+
|
|
22
24
|
import {ImageOverviewCategories} from "./categories.js"
|
|
23
25
|
import {bulkMenuModel, menuModel} from "./menu.js"
|
|
26
|
+
import type {
|
|
27
|
+
ImageManagerApp,
|
|
28
|
+
ImageManagerPage,
|
|
29
|
+
ImageOverviewPlugin,
|
|
30
|
+
ImageOverviewPluginConstructor,
|
|
31
|
+
ImageTableRow
|
|
32
|
+
} from "../types.js"
|
|
33
|
+
|
|
34
|
+
interface DataTableRow {
|
|
35
|
+
cells: {data: unknown; text?: string}[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface VirtualNode {
|
|
39
|
+
nodeName: string
|
|
40
|
+
attributes?: Record<string, string | boolean>
|
|
41
|
+
childNodes?: VirtualNode[]
|
|
42
|
+
}
|
|
43
|
+
|
|
24
44
|
/** Helper functions for user added images/SVGs.*/
|
|
25
45
|
|
|
26
46
|
export class ImageOverview {
|
|
27
|
-
|
|
47
|
+
app: ImageManagerApp
|
|
48
|
+
|
|
49
|
+
user: unknown
|
|
50
|
+
|
|
51
|
+
plugins: [string, Record<string, ImageOverviewPluginConstructor>][]
|
|
52
|
+
|
|
53
|
+
mod: {
|
|
54
|
+
categories?: ImageOverviewCategories
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
lastSort: {
|
|
58
|
+
column: number
|
|
59
|
+
dir: "asc" | "desc"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pluginsActivated = false
|
|
63
|
+
|
|
64
|
+
dom!: HTMLBodyElement
|
|
65
|
+
|
|
66
|
+
menu!: OverviewMenuView
|
|
67
|
+
|
|
68
|
+
overviewTable: OverviewDataTable | null = null
|
|
69
|
+
|
|
70
|
+
table: DataTable | null = null
|
|
71
|
+
|
|
72
|
+
dtBulk: import("fwtoolkit").DatatableBulk | null = null
|
|
73
|
+
|
|
74
|
+
constructor({
|
|
75
|
+
app,
|
|
76
|
+
user,
|
|
77
|
+
plugins = []
|
|
78
|
+
}: {
|
|
79
|
+
app: ImageManagerApp
|
|
80
|
+
user: unknown
|
|
81
|
+
plugins?: [string, Record<string, ImageOverviewPluginConstructor>][]
|
|
82
|
+
}) {
|
|
28
83
|
this.app = app
|
|
29
84
|
this.user = user
|
|
30
85
|
this.plugins = plugins
|
|
@@ -33,7 +88,7 @@ export class ImageOverview {
|
|
|
33
88
|
this.lastSort = {column: 0, dir: "asc"}
|
|
34
89
|
}
|
|
35
90
|
|
|
36
|
-
init() {
|
|
91
|
+
init(): Promise<void> {
|
|
37
92
|
ensureCSS([
|
|
38
93
|
staticUrl("css/dialog_usermedia.css"),
|
|
39
94
|
staticUrl("css/dot_menu.css")
|
|
@@ -48,7 +103,7 @@ export class ImageOverview {
|
|
|
48
103
|
this.menu.init()
|
|
49
104
|
this.activatePlugins()
|
|
50
105
|
this.bindEvents()
|
|
51
|
-
this.mod.categories
|
|
106
|
+
this.mod.categories!.setImageCategoryList(this.app.imageDB.cats)
|
|
52
107
|
this.initTable(Object.keys(this.app.imageDB.db))
|
|
53
108
|
// Reset scroll position to top to prevent Safari from auto-scrolling
|
|
54
109
|
// to the focused table element, which would hide the header/menu
|
|
@@ -56,7 +111,7 @@ export class ImageOverview {
|
|
|
56
111
|
})
|
|
57
112
|
}
|
|
58
113
|
|
|
59
|
-
render() {
|
|
114
|
+
render(): void {
|
|
60
115
|
this.dom = document.createElement("body")
|
|
61
116
|
this.dom.innerHTML = baseBodyTemplate({
|
|
62
117
|
contents: "",
|
|
@@ -71,14 +126,14 @@ export class ImageOverview {
|
|
|
71
126
|
feedbackTab.init()
|
|
72
127
|
}
|
|
73
128
|
|
|
74
|
-
activatePlugins() {
|
|
129
|
+
activatePlugins(): Promise<void> {
|
|
75
130
|
if (this.pluginsActivated) {
|
|
76
131
|
// Plugins have been activated already
|
|
77
|
-
return
|
|
132
|
+
return Promise.resolve()
|
|
78
133
|
}
|
|
79
134
|
this.pluginsActivated = true
|
|
80
135
|
// Add plugins.
|
|
81
|
-
const pluginInstances = {}
|
|
136
|
+
const pluginInstances: Record<string, ImageOverviewPlugin> = {}
|
|
82
137
|
|
|
83
138
|
return Promise.all(
|
|
84
139
|
this.plugins.map(([app, plugin]) => {
|
|
@@ -88,11 +143,10 @@ export class ImageOverview {
|
|
|
88
143
|
return Promise.all(
|
|
89
144
|
Object.values(plugin).map(pluginExport => {
|
|
90
145
|
if (typeof pluginExport === "function") {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
146
|
+
const Plugin = pluginExport as ImageOverviewPluginConstructor
|
|
147
|
+
pluginInstances[Plugin.name] = new Plugin(this)
|
|
94
148
|
return (
|
|
95
|
-
pluginInstances[
|
|
149
|
+
pluginInstances[Plugin.name].init?.() ||
|
|
96
150
|
Promise.resolve()
|
|
97
151
|
)
|
|
98
152
|
}
|
|
@@ -100,12 +154,12 @@ export class ImageOverview {
|
|
|
100
154
|
})
|
|
101
155
|
)
|
|
102
156
|
})
|
|
103
|
-
)
|
|
157
|
+
).then(() => undefined)
|
|
104
158
|
}
|
|
105
159
|
|
|
106
160
|
//delete image
|
|
107
|
-
deleteImage(ids) {
|
|
108
|
-
|
|
161
|
+
deleteImage(ids: (string | number)[]): void {
|
|
162
|
+
const numericIds = ids.map(id => Number.parseInt(String(id)))
|
|
109
163
|
if (this.app.isOffline()) {
|
|
110
164
|
addAlert(
|
|
111
165
|
"error",
|
|
@@ -116,7 +170,7 @@ export class ImageOverview {
|
|
|
116
170
|
return
|
|
117
171
|
}
|
|
118
172
|
activateWait()
|
|
119
|
-
post("/api/usermedia/delete/", {ids})
|
|
173
|
+
post("/api/usermedia/delete/", {ids: numericIds})
|
|
120
174
|
.catch(error => {
|
|
121
175
|
addAlert("error", gettext("The image(s) could not be deleted"))
|
|
122
176
|
deactivateWait()
|
|
@@ -132,14 +186,14 @@ export class ImageOverview {
|
|
|
132
186
|
}
|
|
133
187
|
})
|
|
134
188
|
.then(() => {
|
|
135
|
-
|
|
136
|
-
this.removeTableRows(
|
|
189
|
+
numericIds.forEach(id => delete this.app.imageDB.db[id])
|
|
190
|
+
this.removeTableRows(numericIds)
|
|
137
191
|
addAlert("success", gettext("The image(s) have been deleted"))
|
|
138
192
|
})
|
|
139
193
|
.then(() => deactivateWait())
|
|
140
194
|
}
|
|
141
195
|
|
|
142
|
-
deleteImageDialog(ids) {
|
|
196
|
+
deleteImageDialog(ids: (string | number)[]): void {
|
|
143
197
|
const buttons = [
|
|
144
198
|
{
|
|
145
199
|
text: gettext("Delete"),
|
|
@@ -150,7 +204,7 @@ export class ImageOverview {
|
|
|
150
204
|
}
|
|
151
205
|
},
|
|
152
206
|
{
|
|
153
|
-
type: "cancel"
|
|
207
|
+
type: "cancel" as const
|
|
154
208
|
}
|
|
155
209
|
]
|
|
156
210
|
const dialog = new Dialog({
|
|
@@ -163,24 +217,29 @@ export class ImageOverview {
|
|
|
163
217
|
dialog.open()
|
|
164
218
|
}
|
|
165
219
|
|
|
166
|
-
updateTable(ids) {
|
|
220
|
+
updateTable(ids: (string | number)[]): void {
|
|
167
221
|
// Remove items that already exist
|
|
168
222
|
this.removeTableRows(ids)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
223
|
+
if (this.table) {
|
|
224
|
+
this.table.insert({
|
|
225
|
+
data: ids.map(id => this.createTableRow(Number(id)))
|
|
226
|
+
})
|
|
227
|
+
// Redo last sort
|
|
228
|
+
this.table.columns.sort(this.lastSort.column, this.lastSort.dir)
|
|
229
|
+
}
|
|
172
230
|
}
|
|
173
231
|
|
|
174
|
-
createTableRow(id) {
|
|
232
|
+
createTableRow(id: number): ImageTableRow {
|
|
175
233
|
const image = this.app.imageDB.db[id]
|
|
176
234
|
const cats = image.cats.map(cat => `cat_${cat}`)
|
|
177
235
|
|
|
178
|
-
|
|
236
|
+
const fileTypeParts = image.file_type.split("/")
|
|
179
237
|
|
|
180
|
-
|
|
181
|
-
|
|
238
|
+
let fileType: string
|
|
239
|
+
if (1 < fileTypeParts.length) {
|
|
240
|
+
fileType = fileTypeParts[1].toUpperCase()
|
|
182
241
|
} else {
|
|
183
|
-
fileType =
|
|
242
|
+
fileType = fileTypeParts[0].toUpperCase()
|
|
184
243
|
}
|
|
185
244
|
|
|
186
245
|
return [
|
|
@@ -203,26 +262,32 @@ export class ImageOverview {
|
|
|
203
262
|
]
|
|
204
263
|
}
|
|
205
264
|
|
|
206
|
-
removeTableRows(ids) {
|
|
207
|
-
|
|
265
|
+
removeTableRows(ids: (string | number)[]): void {
|
|
266
|
+
const numericIds = ids.map(id => Number.parseInt(String(id)))
|
|
267
|
+
|
|
268
|
+
if (!this.table) {
|
|
269
|
+
return
|
|
270
|
+
}
|
|
208
271
|
|
|
209
272
|
const existingRows = this.table.data.data
|
|
210
|
-
.map((row, index) => {
|
|
211
|
-
const id = row.cells[0].data
|
|
212
|
-
if (
|
|
273
|
+
.map((row: DataTableRow, index: number) => {
|
|
274
|
+
const id = Number(row.cells[0].data)
|
|
275
|
+
if (numericIds.includes(id)) {
|
|
213
276
|
return index
|
|
214
277
|
} else {
|
|
215
278
|
return false
|
|
216
279
|
}
|
|
217
280
|
})
|
|
218
|
-
.filter(
|
|
281
|
+
.filter(
|
|
282
|
+
(rowIndex): rowIndex is number => rowIndex !== false
|
|
283
|
+
)
|
|
219
284
|
|
|
220
285
|
if (existingRows.length) {
|
|
221
286
|
this.table.rows.remove(existingRows)
|
|
222
287
|
}
|
|
223
288
|
}
|
|
224
289
|
|
|
225
|
-
onResize() {
|
|
290
|
+
onResize(): void {
|
|
226
291
|
if (!this.table) {
|
|
227
292
|
return
|
|
228
293
|
}
|
|
@@ -230,7 +295,7 @@ export class ImageOverview {
|
|
|
230
295
|
}
|
|
231
296
|
|
|
232
297
|
/* Initialize the overview table */
|
|
233
|
-
initTable(ids) {
|
|
298
|
+
initTable(ids: string[]): void {
|
|
234
299
|
if (this.overviewTable) {
|
|
235
300
|
this.overviewTable.destroy()
|
|
236
301
|
this.overviewTable = null
|
|
@@ -238,10 +303,13 @@ export class ImageOverview {
|
|
|
238
303
|
this.table = null
|
|
239
304
|
this.dtBulk = null
|
|
240
305
|
|
|
241
|
-
const contentsEl = this.dom.querySelector(".fw-contents")
|
|
306
|
+
const contentsEl = this.dom.querySelector(".fw-contents") as HTMLElement | null
|
|
307
|
+
if (!contentsEl) {
|
|
308
|
+
return
|
|
309
|
+
}
|
|
242
310
|
contentsEl.innerHTML = ""
|
|
243
311
|
|
|
244
|
-
const hiddenCols = [0]
|
|
312
|
+
const hiddenCols: number[] = [0]
|
|
245
313
|
|
|
246
314
|
if (window.innerWidth < 500) {
|
|
247
315
|
hiddenCols.push(1)
|
|
@@ -272,11 +340,11 @@ export class ImageOverview {
|
|
|
272
340
|
sort: this.lastSort.dir
|
|
273
341
|
}
|
|
274
342
|
],
|
|
275
|
-
data: ids.map(id => this.createTableRow(id)),
|
|
343
|
+
data: ids.map(id => this.createTableRow(Number.parseInt(id))),
|
|
276
344
|
idColumn: 0,
|
|
277
345
|
checkboxColumn: 1,
|
|
278
346
|
bulkMenu: bulkMenuModel(),
|
|
279
|
-
bulkMenuPage: this,
|
|
347
|
+
bulkMenuPage: this as Record<string, unknown>,
|
|
280
348
|
searchable: true,
|
|
281
349
|
scrollY: `${Math.max(window.innerHeight - 360, 100)}px`,
|
|
282
350
|
tabIndex: 1,
|
|
@@ -292,7 +360,7 @@ export class ImageOverview {
|
|
|
292
360
|
gettext("Added"),
|
|
293
361
|
""
|
|
294
362
|
],
|
|
295
|
-
template: (options, _dom) =>
|
|
363
|
+
template: (options: {classes: Record<string, string>; scrollY: string; paging?: boolean}, _dom) =>
|
|
296
364
|
`<div class='${options.classes.container}'${options.scrollY.length ? ` style='height: ${options.scrollY}; overflow-Y: auto;'` : ""}></div>
|
|
297
365
|
<div class='${options.classes.bottom}'>
|
|
298
366
|
${
|
|
@@ -303,20 +371,23 @@ export class ImageOverview {
|
|
|
303
371
|
<nav class='${options.classes.pagination}'></nav>
|
|
304
372
|
</div>`,
|
|
305
373
|
rowRender: (row, tr, _index) => {
|
|
306
|
-
const id = row.cells[0].data
|
|
307
|
-
const inputNode = {
|
|
374
|
+
const id = row.cells[0].data as number
|
|
375
|
+
const inputNode: VirtualNode = {
|
|
308
376
|
nodeName: "input",
|
|
309
377
|
attributes: {
|
|
310
378
|
type: "checkbox",
|
|
311
379
|
class: "entry-select fw-check",
|
|
312
|
-
"data-id": id,
|
|
380
|
+
"data-id": String(id),
|
|
313
381
|
id: `doc-img-${id}`
|
|
314
382
|
}
|
|
315
383
|
}
|
|
316
384
|
if (row.cells[1].data) {
|
|
317
|
-
inputNode.attributes
|
|
385
|
+
inputNode.attributes!.checked = "checked"
|
|
318
386
|
}
|
|
319
|
-
|
|
387
|
+
const trNode = tr as {
|
|
388
|
+
childNodes: {childNodes: VirtualNode[]}[]
|
|
389
|
+
}
|
|
390
|
+
trNode.childNodes[0].childNodes = [
|
|
320
391
|
inputNode,
|
|
321
392
|
{
|
|
322
393
|
nodeName: "label",
|
|
@@ -330,39 +401,46 @@ export class ImageOverview {
|
|
|
330
401
|
if (this.getSelected().length > 0) {
|
|
331
402
|
return
|
|
332
403
|
}
|
|
333
|
-
|
|
404
|
+
if (!this.table) {
|
|
405
|
+
return
|
|
406
|
+
}
|
|
407
|
+
const rowIndex = this.table.data.data.findIndex(
|
|
408
|
+
dataRow =>
|
|
409
|
+
(dataRow as unknown as DataTableRow).cells[0].data ===
|
|
410
|
+
row.cells[0].data
|
|
411
|
+
)
|
|
334
412
|
const button = this.table.dom.querySelector(
|
|
335
413
|
`tr[data-index="${rowIndex}"] span.edit-image`
|
|
336
414
|
)
|
|
337
415
|
if (button) {
|
|
338
|
-
button.click()
|
|
416
|
+
;(button as HTMLElement).click()
|
|
339
417
|
}
|
|
340
418
|
},
|
|
341
419
|
onDelete: row => {
|
|
342
|
-
const imageId = row.cells[0].data
|
|
420
|
+
const imageId = row.cells[0].data as number
|
|
343
421
|
this.deleteImageDialog([imageId])
|
|
344
422
|
}
|
|
345
423
|
})
|
|
346
424
|
this.overviewTable.init()
|
|
347
|
-
this.table = this.overviewTable.table
|
|
348
|
-
this.table.id = "imagelist"
|
|
349
|
-
this.dtBulk = this.overviewTable.dtBulk
|
|
425
|
+
this.table = this.overviewTable.table!
|
|
426
|
+
;(this.table as unknown as {id: string}).id = "imagelist"
|
|
427
|
+
this.dtBulk = this.overviewTable.dtBulk || null
|
|
350
428
|
|
|
351
429
|
this.table.on("datatable.sort", (column, dir) => {
|
|
352
|
-
this.lastSort = {column, dir}
|
|
430
|
+
this.lastSort = {column: column as number, dir: dir as "asc" | "desc"}
|
|
353
431
|
})
|
|
354
432
|
|
|
355
433
|
this.table.dom.focus()
|
|
356
434
|
}
|
|
357
435
|
|
|
358
436
|
// get IDs of selected bib entries
|
|
359
|
-
getSelected() {
|
|
437
|
+
getSelected(): number[] {
|
|
360
438
|
return Array.from(
|
|
361
439
|
this.dom.querySelectorAll(".entry-select:checked:not(:disabled)")
|
|
362
|
-
).map(el => Number.parseInt(el.getAttribute("data-id")))
|
|
440
|
+
).map(el => Number.parseInt(el.getAttribute("data-id") || "0"))
|
|
363
441
|
}
|
|
364
442
|
|
|
365
|
-
bindEvents() {
|
|
443
|
+
bindEvents(): void {
|
|
366
444
|
this.dom.addEventListener("click", event =>
|
|
367
445
|
this.handleActivation(event)
|
|
368
446
|
)
|
|
@@ -371,33 +449,37 @@ export class ImageOverview {
|
|
|
371
449
|
)
|
|
372
450
|
}
|
|
373
451
|
|
|
374
|
-
handleActivation(event) {
|
|
452
|
+
handleActivation(event: Event): void {
|
|
375
453
|
if (!isActivationEvent(event)) {
|
|
376
454
|
return
|
|
377
455
|
}
|
|
378
|
-
const el = {}
|
|
456
|
+
const el: {target?: Element | null} = {}
|
|
379
457
|
switch (true) {
|
|
380
458
|
case findTarget(event, ".delete-image", el): {
|
|
381
|
-
const imageId = el.target
|
|
382
|
-
this.deleteImageDialog([imageId])
|
|
459
|
+
const imageId = (el.target as HTMLElement | null)?.dataset.id
|
|
460
|
+
this.deleteImageDialog([imageId || ""])
|
|
383
461
|
break
|
|
384
462
|
}
|
|
385
463
|
case findTarget(event, ".edit-image", el): {
|
|
386
|
-
const imageId = el.target
|
|
387
|
-
import("../edit_dialog/index.js").then(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
464
|
+
const imageId = (el.target as HTMLElement | null)?.dataset.id
|
|
465
|
+
import("../edit_dialog/index.js").then(
|
|
466
|
+
({ImageEditDialog}) => {
|
|
467
|
+
const dialog = new ImageEditDialog(
|
|
468
|
+
this.app.imageDB,
|
|
469
|
+
imageId ? Number.parseInt(imageId) : false,
|
|
470
|
+
this as unknown as ImageManagerPage
|
|
471
|
+
)
|
|
472
|
+
dialog.init().then(() => {
|
|
473
|
+
if (imageId) {
|
|
474
|
+
this.updateTable([Number.parseInt(imageId)])
|
|
475
|
+
}
|
|
476
|
+
})
|
|
477
|
+
}
|
|
478
|
+
)
|
|
397
479
|
break
|
|
398
480
|
}
|
|
399
481
|
case findTarget(event, ".fw-add-input", el): {
|
|
400
|
-
const itemEl = el.target
|
|
482
|
+
const itemEl = (el.target as HTMLElement | null)?.closest(".fw-list-input") as HTMLElement
|
|
401
483
|
if (!itemEl.nextElementSibling) {
|
|
402
484
|
itemEl.insertAdjacentHTML(
|
|
403
485
|
"afterend",
|
|
@@ -409,7 +491,7 @@ export class ImageOverview {
|
|
|
409
491
|
</tr>`
|
|
410
492
|
)
|
|
411
493
|
} else {
|
|
412
|
-
itemEl.parentElement
|
|
494
|
+
itemEl.parentElement!.removeChild(itemEl)
|
|
413
495
|
}
|
|
414
496
|
break
|
|
415
497
|
}
|
|
@@ -418,7 +500,7 @@ export class ImageOverview {
|
|
|
418
500
|
}
|
|
419
501
|
}
|
|
420
502
|
|
|
421
|
-
close() {
|
|
503
|
+
close(): void {
|
|
422
504
|
if (this.table) {
|
|
423
505
|
this.table.destroy()
|
|
424
506
|
this.table = null
|
|
@@ -429,7 +511,7 @@ export class ImageOverview {
|
|
|
429
511
|
}
|
|
430
512
|
if (this.menu) {
|
|
431
513
|
this.menu.destroy()
|
|
432
|
-
this.menu = null
|
|
514
|
+
this.menu = null as unknown as OverviewMenuView
|
|
433
515
|
}
|
|
434
516
|
}
|
|
435
517
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {gettext} from "fwtoolkit"
|
|
2
|
+
import type {ContentMenuInit} from "fwtoolkit/content_menu"
|
|
3
|
+
import type {OverviewMenuModel} from "fwtoolkit/overview_menu"
|
|
4
|
+
|
|
5
|
+
import type {ImageManagerPage} from "../types.js"
|
|
6
|
+
import type {ImageOverview} from "./index.js"
|
|
7
|
+
|
|
8
|
+
export const bulkMenuModel = (): ContentMenuInit => ({
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
title: gettext("Delete selected"),
|
|
12
|
+
tooltip: gettext("Delete selected images."),
|
|
13
|
+
action: (overview: unknown) => {
|
|
14
|
+
const ids = (overview as ImageOverview).getSelected()
|
|
15
|
+
if (ids.length) {
|
|
16
|
+
;(overview as ImageOverview).deleteImageDialog(ids)
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
disabled: (overview: unknown) =>
|
|
20
|
+
!(overview as ImageOverview).getSelected().length ||
|
|
21
|
+
(overview as ImageOverview).app.isOffline()
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const menuModel = (): OverviewMenuModel => ({
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: "dropdown",
|
|
30
|
+
id: "cat_selector",
|
|
31
|
+
keys: "Alt-c",
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
title: gettext("All categories"),
|
|
35
|
+
action: (_overview: unknown) => {
|
|
36
|
+
const trs = document.querySelectorAll(
|
|
37
|
+
"#imagelist > tbody > tr"
|
|
38
|
+
)
|
|
39
|
+
trs.forEach(tr => ((tr as HTMLElement).style.display = ""))
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
order: 1
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
title: gettext("Edit categories"),
|
|
48
|
+
keys: "Alt-e",
|
|
49
|
+
action: (overview: unknown) =>
|
|
50
|
+
(overview as ImageOverview).mod.categories!.editCategoryDialog(),
|
|
51
|
+
order: 2,
|
|
52
|
+
disabled: (overview: unknown) => (overview as ImageOverview).app.isOffline()
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
title: gettext("Upload new image"),
|
|
57
|
+
keys: "Alt-u",
|
|
58
|
+
action: (overview: unknown) => {
|
|
59
|
+
import("../edit_dialog/index.js").then(({ImageEditDialog}) => {
|
|
60
|
+
const imageUpload = new ImageEditDialog(
|
|
61
|
+
(overview as ImageOverview).app.imageDB,
|
|
62
|
+
false,
|
|
63
|
+
overview as ImageManagerPage
|
|
64
|
+
)
|
|
65
|
+
imageUpload.init().then(imageId => {
|
|
66
|
+
if (imageId) {
|
|
67
|
+
;(overview as ImageOverview).updateTable([imageId])
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
order: 3,
|
|
73
|
+
disabled: (overview: unknown) => (overview as ImageOverview).app.isOffline()
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: "search",
|
|
77
|
+
icon: "search",
|
|
78
|
+
title: gettext("Search images"),
|
|
79
|
+
keys: "Alt-s",
|
|
80
|
+
input: (overview: unknown, text: string) =>
|
|
81
|
+
(overview as ImageOverview).table!.search(text),
|
|
82
|
+
order: 4
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
})
|