@fiduswriter/image-manager 0.1.13 → 0.1.14

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 (48) hide show
  1. package/dist/copyright_dialog/index.d.ts.map +1 -1
  2. package/dist/copyright_dialog/index.js +19 -20
  3. package/dist/copyright_dialog/index.js.map +1 -1
  4. package/dist/copyright_dialog/templates.d.ts +2 -2
  5. package/dist/copyright_dialog/templates.d.ts.map +1 -1
  6. package/dist/copyright_dialog/templates.js +3 -3
  7. package/dist/copyright_dialog/templates.js.map +1 -1
  8. package/dist/database.d.ts.map +1 -1
  9. package/dist/database.js +7 -8
  10. package/dist/database.js.map +1 -1
  11. package/dist/edit_dialog/index.d.ts.map +1 -1
  12. package/dist/edit_dialog/index.js +25 -23
  13. package/dist/edit_dialog/index.js.map +1 -1
  14. package/dist/edit_dialog/model.d.ts.map +1 -1
  15. package/dist/edit_dialog/model.js +14 -18
  16. package/dist/edit_dialog/model.js.map +1 -1
  17. package/dist/edit_dialog/templates.d.ts.map +1 -1
  18. package/dist/edit_dialog/templates.js.map +1 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/overview/categories.d.ts.map +1 -1
  23. package/dist/overview/categories.js +17 -20
  24. package/dist/overview/categories.js.map +1 -1
  25. package/dist/overview/index.d.ts.map +1 -1
  26. package/dist/overview/index.js +3 -2
  27. package/dist/overview/index.js.map +1 -1
  28. package/dist/overview/menu.d.ts.map +1 -1
  29. package/dist/overview/menu.js +13 -15
  30. package/dist/overview/menu.js.map +1 -1
  31. package/dist/selection_dialog/index.d.ts.map +1 -1
  32. package/dist/selection_dialog/index.js +22 -26
  33. package/dist/selection_dialog/index.js.map +1 -1
  34. package/dist/types.d.ts +10 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/package.json +8 -4
  37. package/src/copyright_dialog/index.ts +177 -186
  38. package/src/copyright_dialog/templates.ts +26 -19
  39. package/src/database.ts +61 -68
  40. package/src/edit_dialog/index.ts +261 -251
  41. package/src/edit_dialog/model.ts +220 -220
  42. package/src/edit_dialog/templates.ts +22 -22
  43. package/src/index.ts +5 -4
  44. package/src/overview/categories.ts +106 -116
  45. package/src/overview/index.ts +2 -2
  46. package/src/overview/menu.ts +77 -77
  47. package/src/selection_dialog/index.ts +197 -207
  48. package/src/types.ts +79 -65
@@ -1,233 +1,233 @@
1
- import Cropper from "cropperjs"
1
+ import Cropper from "cropperjs";
2
2
 
3
- import {gettext} from "fwtoolkit"
4
- import type {ContentMenuInit} from "fwtoolkit/content_menu"
5
- import type {Dialog as FwDialog} from "fwtoolkit/dialog"
3
+ import { gettext } from "fwtoolkit";
4
+ import type { ContentMenuInit } from "fwtoolkit/content_menu";
5
+ import type { Dialog as FwDialog } from "fwtoolkit/dialog";
6
6
 
7
- import {CopyrightDialog} from "../copyright_dialog/index.js"
8
- import type {ImageEditDialog} from "./index.js"
7
+ import { CopyrightDialog } from "../copyright_dialog/index.js";
8
+ import type { ImageEditDialog } from "./index.js";
9
9
 
10
- let mediaPreviewerImg: HTMLImageElement | false = false
10
+ let mediaPreviewerImg: HTMLImageElement | false = false;
11
11
 
12
12
  export const imageEditModel = (): ContentMenuInit => ({
13
- content: [
14
- {
15
- title: gettext("Rotate Left"),
16
- type: "action",
17
- tooltip: gettext("Rotate-left"),
18
- order: 0,
19
- action: (dialog: unknown) => {
20
- const d = dialog as ImageEditDialog
21
- const mediaPreviewer = d.mediaPreviewer as
22
- | (HTMLElement & {
23
- currentStyle?: CSSStyleDeclaration
24
- })
25
- | undefined
26
- if (!mediaPreviewer) {
27
- return
28
- }
29
- const mediaPreviewerStyle =
30
- mediaPreviewer.currentStyle ||
31
- window.getComputedStyle(
32
- mediaPreviewer,
33
- false as unknown as string | null
34
- )
35
- rotateBase64Image(
36
- mediaPreviewerStyle.backgroundImage
37
- .slice(4, -1)
38
- .replace(/"/g, ""),
39
- d.mediaInput!.type,
40
- "left"
41
- ).then(response =>
42
- d.mediaPreviewer!.setAttribute(
43
- "style",
44
- `background-image: url(${response});`
45
- )
46
- )
47
- if (d.rotation === 0) {
48
- d.rotation = 270
49
- } else {
50
- d.rotation -= 90
51
- }
52
- },
53
- disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
54
- icon: "redo fa-rotate-180"
55
- },
56
- {
57
- title: gettext("Rotate Right"),
58
- type: "action",
59
- tooltip: gettext("Rotate-right"),
60
- order: 1,
61
- action: (dialog: unknown) => {
62
- const d = dialog as ImageEditDialog
63
- const mediaPreviewer = d.mediaPreviewer as
64
- | (HTMLElement & {
65
- currentStyle?: CSSStyleDeclaration
66
- })
67
- | undefined
68
- if (!mediaPreviewer) {
69
- return
70
- }
71
- const mediaPreviewerStyle =
72
- mediaPreviewer.currentStyle ||
73
- window.getComputedStyle(
74
- mediaPreviewer,
75
- false as unknown as string | null
76
- )
77
- rotateBase64Image(
78
- mediaPreviewerStyle.backgroundImage
79
- .slice(4, -1)
80
- .replace(/"/g, ""),
81
- d.mediaInput!.type,
82
- "right"
83
- ).then(response =>
84
- d.mediaPreviewer!.setAttribute(
85
- "style",
86
- `background-image: url(${response});`
87
- )
88
- )
89
- if (d.rotation === 270) {
90
- d.rotation = 0
91
- } else {
92
- d.rotation += 90
93
- }
94
- },
95
- disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
96
- icon: "undo"
97
- },
98
- {
99
- title: gettext("Crop"),
100
- type: "action",
101
- tooltip: gettext("Crop image"),
102
- order: 2,
103
- action: (dialog: unknown) => {
104
- const d = dialog as ImageEditDialog
105
- const mediaPreviewer = d.mediaPreviewer as
106
- | (HTMLElement & {
107
- currentStyle?: CSSStyleDeclaration
108
- })
109
- | undefined
110
- if (!mediaPreviewer) {
111
- return
112
- }
113
- const mediaPreviewerStyle =
114
- mediaPreviewer.currentStyle ||
115
- window.getComputedStyle(
116
- mediaPreviewer,
117
- false as unknown as string | null
118
- )
119
- //const base64data = mediaPreviewerStyle.backgroundImage.slice(4, -1).replace(/"/g, "")
120
- mediaPreviewerImg = document.createElement("img")
121
- //img.src = `url(${base64data})`
122
- mediaPreviewerImg.src = mediaPreviewerStyle.backgroundImage
123
- .slice(4, -1)
124
- .replace(/"/g, "")
125
- d.mediaPreviewer!.parentElement!.replaceChild(
126
- mediaPreviewerImg,
127
- d.mediaPreviewer!
128
- )
129
- const cropper = new Cropper(mediaPreviewerImg, {
130
- viewMode: 1,
131
- responsive: true
132
- })
133
- toggleCropMode(true, d, cropper)
134
- },
135
- disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
136
- icon: "crop"
137
- },
138
- {
139
- title: gettext("Set Copyright"),
140
- type: "action",
141
- tooltip: gettext("Specify copyright information"),
142
- order: 3,
143
- action: (dialog: unknown) => {
144
- const d = dialog as ImageEditDialog
145
- const crDialog = new CopyrightDialog(d.copyright)
146
- crDialog.init().then(copyright => {
147
- if (copyright) {
148
- d.copyright = copyright
149
- }
150
- })
151
- }
13
+ content: [
14
+ {
15
+ title: gettext("Rotate Left"),
16
+ type: "action",
17
+ tooltip: gettext("Rotate-left"),
18
+ order: 0,
19
+ action: (dialog: unknown) => {
20
+ const d = dialog as ImageEditDialog;
21
+ const mediaPreviewer = d.mediaPreviewer as
22
+ | (HTMLElement & {
23
+ currentStyle?: CSSStyleDeclaration;
24
+ })
25
+ | undefined;
26
+ if (!mediaPreviewer) {
27
+ return;
28
+ }
29
+ const mediaPreviewerStyle =
30
+ mediaPreviewer.currentStyle ||
31
+ window.getComputedStyle(
32
+ mediaPreviewer,
33
+ false as unknown as string | null,
34
+ );
35
+ rotateBase64Image(
36
+ mediaPreviewerStyle.backgroundImage.slice(4, -1).replace(/"/g, ""),
37
+ d.mediaInput!.type,
38
+ "left",
39
+ ).then((response) =>
40
+ d.mediaPreviewer!.setAttribute(
41
+ "style",
42
+ `background-image: url(${response});`,
43
+ ),
44
+ );
45
+ if (d.rotation === 0) {
46
+ d.rotation = 270;
47
+ } else {
48
+ d.rotation -= 90;
49
+ }
50
+ },
51
+ disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
52
+ icon: "redo fa-rotate-180",
53
+ },
54
+ {
55
+ title: gettext("Rotate Right"),
56
+ type: "action",
57
+ tooltip: gettext("Rotate-right"),
58
+ order: 1,
59
+ action: (dialog: unknown) => {
60
+ const d = dialog as ImageEditDialog;
61
+ const mediaPreviewer = d.mediaPreviewer as
62
+ | (HTMLElement & {
63
+ currentStyle?: CSSStyleDeclaration;
64
+ })
65
+ | undefined;
66
+ if (!mediaPreviewer) {
67
+ return;
68
+ }
69
+ const mediaPreviewerStyle =
70
+ mediaPreviewer.currentStyle ||
71
+ window.getComputedStyle(
72
+ mediaPreviewer,
73
+ false as unknown as string | null,
74
+ );
75
+ rotateBase64Image(
76
+ mediaPreviewerStyle.backgroundImage.slice(4, -1).replace(/"/g, ""),
77
+ d.mediaInput!.type,
78
+ "right",
79
+ ).then((response) =>
80
+ d.mediaPreviewer!.setAttribute(
81
+ "style",
82
+ `background-image: url(${response});`,
83
+ ),
84
+ );
85
+ if (d.rotation === 270) {
86
+ d.rotation = 0;
87
+ } else {
88
+ d.rotation += 90;
152
89
  }
153
- ]
154
- })
90
+ },
91
+ disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
92
+ icon: "undo",
93
+ },
94
+ {
95
+ title: gettext("Crop"),
96
+ type: "action",
97
+ tooltip: gettext("Crop image"),
98
+ order: 2,
99
+ action: (dialog: unknown) => {
100
+ const d = dialog as ImageEditDialog;
101
+ const mediaPreviewer = d.mediaPreviewer as
102
+ | (HTMLElement & {
103
+ currentStyle?: CSSStyleDeclaration;
104
+ })
105
+ | undefined;
106
+ if (!mediaPreviewer) {
107
+ return;
108
+ }
109
+ const mediaPreviewerStyle =
110
+ mediaPreviewer.currentStyle ||
111
+ window.getComputedStyle(
112
+ mediaPreviewer,
113
+ false as unknown as string | null,
114
+ );
115
+ //const base64data = mediaPreviewerStyle.backgroundImage.slice(4, -1).replace(/"/g, "")
116
+ mediaPreviewerImg = document.createElement("img");
117
+ //img.src = `url(${base64data})`
118
+ mediaPreviewerImg.src = mediaPreviewerStyle.backgroundImage
119
+ .slice(4, -1)
120
+ .replace(/"/g, "");
121
+ d.mediaPreviewer!.parentElement!.replaceChild(
122
+ mediaPreviewerImg,
123
+ d.mediaPreviewer!,
124
+ );
125
+ const cropper = new Cropper(mediaPreviewerImg, {
126
+ viewMode: 1,
127
+ responsive: true,
128
+ });
129
+ toggleCropMode(true, d, cropper);
130
+ },
131
+ disabled: (dialog: unknown) => !!(dialog as ImageEditDialog).imageId,
132
+ icon: "crop",
133
+ },
134
+ {
135
+ title: gettext("Set Copyright"),
136
+ type: "action",
137
+ tooltip: gettext("Specify copyright information"),
138
+ order: 3,
139
+ action: (dialog: unknown) => {
140
+ const d = dialog as ImageEditDialog;
141
+ const crDialog = new CopyrightDialog(d.copyright);
142
+ crDialog.init().then((copyright) => {
143
+ if (copyright) {
144
+ d.copyright = copyright;
145
+ }
146
+ });
147
+ },
148
+ },
149
+ ],
150
+ });
155
151
 
156
- let oldButtons: FwDialog["buttons"] | false = false
152
+ let oldButtons: FwDialog["buttons"] | false = false;
157
153
 
158
- const toggleCropMode = (val: boolean, dialog: ImageEditDialog, cropper: Cropper) => {
159
- if (!dialog.dialog) {
160
- return
154
+ const toggleCropMode = (
155
+ val: boolean,
156
+ dialog: ImageEditDialog,
157
+ cropper: Cropper,
158
+ ) => {
159
+ if (!dialog.dialog) {
160
+ return;
161
+ }
162
+ const dialogEl = dialog.dialog;
163
+ if (val && !oldButtons) {
164
+ dialog.mediaPreviewerDiv!.classList.add("crop-mode");
165
+ oldButtons = dialogEl.buttons;
166
+ dialogEl.setButtons([
167
+ {
168
+ text: gettext("Crop"),
169
+ click: () => {
170
+ dialog.mediaPreviewer!.setAttribute(
171
+ "style",
172
+ `background-image: url(${cropper
173
+ .getCroppedCanvas()
174
+ .toDataURL(dialog.mediaInput!.type)});`,
175
+ );
176
+ dialog.cropped = true;
177
+ cropper.destroy();
178
+ toggleCropMode(false, dialog, cropper);
179
+ },
180
+ classes: "fw-dark",
181
+ },
182
+ {
183
+ type: "cancel",
184
+ classes: "fw-orange",
185
+ click: () => {
186
+ cropper.destroy();
187
+ toggleCropMode(false, dialog, cropper);
188
+ },
189
+ },
190
+ ]);
191
+ } else {
192
+ dialog.mediaPreviewerDiv!.classList.remove("crop-mode");
193
+ if (mediaPreviewerImg) {
194
+ mediaPreviewerImg.parentElement!.replaceChild(
195
+ dialog.mediaPreviewer!,
196
+ mediaPreviewerImg,
197
+ );
198
+ mediaPreviewerImg = false;
161
199
  }
162
- const dialogEl = dialog.dialog
163
- if (val && !oldButtons) {
164
- dialog.mediaPreviewerDiv!.classList.add("crop-mode")
165
- oldButtons = dialogEl.buttons
166
- dialogEl.setButtons([
167
- {
168
- text: gettext("Crop"),
169
- click: () => {
170
- dialog.mediaPreviewer!.setAttribute(
171
- "style",
172
- `background-image: url(${cropper
173
- .getCroppedCanvas()
174
- .toDataURL(dialog.mediaInput!.type)});`
175
- )
176
- dialog.cropped = true
177
- cropper.destroy()
178
- toggleCropMode(false, dialog, cropper)
179
- },
180
- classes: "fw-dark"
181
- },
182
- {
183
- type: "cancel",
184
- classes: "fw-orange",
185
- click: () => {
186
- cropper.destroy()
187
- toggleCropMode(false, dialog, cropper)
188
- }
189
- }
190
- ])
191
- } else {
192
- dialog.mediaPreviewerDiv!.classList.remove("crop-mode")
193
- if (mediaPreviewerImg) {
194
- mediaPreviewerImg.parentElement!.replaceChild(
195
- dialog.mediaPreviewer!,
196
- mediaPreviewerImg
197
- )
198
- mediaPreviewerImg = false
199
- }
200
- if (oldButtons) {
201
- dialogEl.buttons = oldButtons
202
- oldButtons = false
203
- }
200
+ if (oldButtons) {
201
+ dialogEl.buttons = oldButtons;
202
+ oldButtons = false;
204
203
  }
205
- dialogEl.refreshButtons()
206
- dialogEl.centerDialog()
207
- }
204
+ }
205
+ dialogEl.refreshButtons();
206
+ dialogEl.centerDialog();
207
+ };
208
208
 
209
209
  const rotateBase64Image = (
210
- base64data: string,
211
- type: string,
212
- direction: "left" | "right"
210
+ base64data: string,
211
+ type: string,
212
+ direction: "left" | "right",
213
213
  ): Promise<string> => {
214
- return new Promise(resolve => {
215
- const canvas = document.createElement("canvas")
216
- const ctx = canvas.getContext("2d")!
217
- const image = new Image()
218
- image.src = base64data
219
- image.onload = () => {
220
- canvas.height = image.width
221
- canvas.width = image.height
222
- if (direction == "left") {
223
- ctx.rotate((90 * Math.PI) / 180)
224
- ctx.translate(0, -canvas.width)
225
- } else {
226
- ctx.rotate((-90 * Math.PI) / 180)
227
- ctx.translate(-canvas.height, 0)
228
- }
229
- ctx.drawImage(image, 0, 0)
230
- resolve(canvas.toDataURL(type))
231
- }
232
- })
233
- }
214
+ return new Promise((resolve) => {
215
+ const canvas = document.createElement("canvas");
216
+ const ctx = canvas.getContext("2d")!;
217
+ const image = new Image();
218
+ image.src = base64data;
219
+ image.onload = () => {
220
+ canvas.height = image.width;
221
+ canvas.width = image.height;
222
+ if (direction == "left") {
223
+ ctx.rotate((90 * Math.PI) / 180);
224
+ ctx.translate(0, -canvas.width);
225
+ } else {
226
+ ctx.rotate((-90 * Math.PI) / 180);
227
+ ctx.translate(-canvas.height, 0);
228
+ }
229
+ ctx.drawImage(image, 0, 0);
230
+ resolve(canvas.toDataURL(type));
231
+ };
232
+ });
233
+ };
@@ -1,38 +1,38 @@
1
- import {escapeText, gettext} from "fwtoolkit"
1
+ import { escapeText, gettext } from "fwtoolkit";
2
2
 
3
- import type {Image, ImageCategory} from "../types.js"
3
+ import type { Image, ImageCategory } from "../types.js";
4
4
 
5
5
  interface ImageEditCategoryTemplateData {
6
- cats: ImageCategory[]
6
+ cats: ImageCategory[];
7
7
  }
8
8
 
9
9
  interface ImageEditTemplateData {
10
- image: Image | false
11
- cats: ImageCategory[]
10
+ image: Image | false;
11
+ cats: ImageCategory[];
12
12
  }
13
13
 
14
14
  /* A template for the image category selection of the image selection dialog. */
15
- const imageEditCategoryTemplate = ({cats}: ImageEditCategoryTemplateData) => {
16
- if (!cats.length) {
17
- return ""
18
- }
19
- return `<div class="fw-media-category">
15
+ const imageEditCategoryTemplate = ({ cats }: ImageEditCategoryTemplateData) => {
16
+ if (!cats.length) {
17
+ return "";
18
+ }
19
+ return `<div class="fw-media-category">
20
20
  <div>${gettext("Select categories")}</div>
21
21
  <div id="image-edit-categories"></div>
22
- </div>`
23
- }
22
+ </div>`;
23
+ };
24
24
 
25
25
  /* A template for the form for the image upload dialog. */
26
- export const imageEditTemplate = ({image, cats}: ImageEditTemplateData) =>
27
- `<div>
26
+ export const imageEditTemplate = ({ image, cats }: ImageEditTemplateData) =>
27
+ `<div>
28
28
  <input name="title" class="fw-media-title" type="text"
29
29
  placeholder="${gettext("Insert a title")}" value="${
30
- image ? escapeText(image.title) : ""
30
+ image ? escapeText(image.title) : ""
31
31
  }" />
32
32
  ${
33
- image
34
- ? ""
35
- : `<button type="button" class="fw-media-select-button fw-button fw-light">
33
+ image
34
+ ? ""
35
+ : `<button type="button" class="fw-media-select-button fw-button fw-light">
36
36
  ${gettext("Select a file")}
37
37
  </button>
38
38
  <input name="image" type="file" class="fw-media-file-input">`
@@ -44,9 +44,9 @@ export const imageEditTemplate = ({image, cats}: ImageEditTemplateData) =>
44
44
  </button>
45
45
  <div>
46
46
  ${
47
- image && image.image
48
- ? `<div class="img" style="background-image: url(${image.image});"></div>`
49
- : ""
47
+ image && image.image
48
+ ? `<div class="img" style="background-image: url(${image.image});"></div>`
49
+ : ""
50
50
  }
51
51
  </div></div>
52
- ${imageEditCategoryTemplate({cats})}`
52
+ ${imageEditCategoryTemplate({ cats })}`;
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
- export {ImageDB} from "./database.js"
2
- export {ImageOverview} from "./overview/index.js"
3
- export {ImageEditDialog} from "./edit_dialog/index.js"
4
- export {ImageSelectionDialog} from "./selection_dialog/index.js"
1
+ export { ImageDB } from "./database.js";
2
+ export { ImageOverview } from "./overview/index.js";
3
+ export { ImageEditDialog } from "./edit_dialog/index.js";
4
+ export { ImageSelectionDialog } from "./selection_dialog/index.js";
5
+ export type { ImageApi } from "./types.js";