@ebl-vue/editor-full 1.0.11 → 1.0.13

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 (47) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.mjs +733 -440
  3. package/dist/index.mjs.map +1 -1
  4. package/package.json +3 -1
  5. package/src/components/Editor/Editor.vue +34 -10
  6. package/src/i18n/zh-cn.ts +6 -1
  7. package/src/icons/index.ts +15 -0
  8. package/src/installer.ts +4 -3
  9. package/src/plugins/alert/index.ts +19 -27
  10. package/src/plugins/block-alignment/index.ts +4 -3
  11. package/src/plugins/code/index.ts +3 -2
  12. package/src/plugins/color-picker/index.ts +3 -11
  13. package/src/plugins/delimiter/index.ts +5 -6
  14. package/src/plugins/header/H1.ts +1 -1
  15. package/src/plugins/header/H2.ts +1 -1
  16. package/src/plugins/header/H3.ts +1 -1
  17. package/src/plugins/header/H4.ts +1 -2
  18. package/src/plugins/header/H5.ts +1 -3
  19. package/src/plugins/header/H6.ts +1 -3
  20. package/src/plugins/imageTool/index.css +145 -0
  21. package/src/plugins/imageTool/index.ts +519 -0
  22. package/src/plugins/imageTool/types/codexteam__ajax.d.ts +89 -0
  23. package/src/plugins/imageTool/types/types.ts +234 -0
  24. package/src/plugins/imageTool/ui.ts +312 -0
  25. package/src/plugins/imageTool/uploader.ts +234 -0
  26. package/src/plugins/imageTool/utils/dom.ts +24 -0
  27. package/src/plugins/imageTool/utils/isPromise.ts +10 -0
  28. package/src/plugins/indent/index.ts +5 -7
  29. package/src/plugins/inline-code/index.ts +2 -5
  30. package/src/plugins/list/ListRenderer/ChecklistRenderer.ts +1 -4
  31. package/src/plugins/list/index.ts +20 -37
  32. package/src/plugins/list/types/OlCounterType.ts +1 -1
  33. package/src/plugins/marker/index.ts +28 -16
  34. package/src/plugins/paragraph/index.ts +3 -2
  35. package/src/plugins/quote/index.ts +1 -4
  36. package/src/plugins/table/plugin.ts +1 -1
  37. package/src/plugins/table/table.ts +40 -38
  38. package/src/plugins/table/toolbox.ts +5 -4
  39. package/src/plugins/table/utils/dom.ts +15 -14
  40. package/src/plugins/table/utils/popover.ts +28 -15
  41. package/src/plugins/underline/index.ts +2 -4
  42. package/src/plugins/undo/index.ts +48 -33
  43. package/src/plugins/undo/observer.ts +3 -3
  44. package/src/style.css +6 -0
  45. package/types/index.d.ts +5 -0
  46. package/vite.config.ts +3 -1
  47. package/src/plugins/list/styles/icons/index.ts +0 -10
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Module declaration for '@codexteam/ajax'.
3
+ */
4
+ declare module '@codexteam/ajax' {
5
+ /**
6
+ * Options for configuring an Ajax request.
7
+ */
8
+ export interface AjaxOptions {
9
+ /**
10
+ * The URL to which the request is sent.
11
+ */
12
+ url?: string;
13
+ /**
14
+ * The data to send with the request.
15
+ */
16
+ data?: object;
17
+ /**
18
+ * The MIME type of the request.
19
+ */
20
+ accept?: string;
21
+ /**
22
+ * The headers to send with the request.
23
+ */
24
+ headers?: object;
25
+ /**
26
+ * A function to call before the request is sent, with the files to be sent.
27
+ */
28
+ beforeSend?: (files: File[]) => void;
29
+ /**
30
+ * The name of the field in the form data to which the file should be assigned.
31
+ */
32
+ fieldName?: string;
33
+ /**
34
+ * The type of the request (e.g., 'POST', 'GET').
35
+ */
36
+ type?: string;
37
+ }
38
+
39
+ /**
40
+ * Parameter type of selectFiles function in AjaxOptions interface
41
+ */
42
+ export type AjaxFileOptionsParam = {
43
+ /**
44
+ * the accepted file types.
45
+ */
46
+ accept: string;
47
+ };
48
+
49
+ /**
50
+ * Represents the response from an Ajax request.
51
+ * @template T - The type of the response body.
52
+ */
53
+ export interface AjaxResponse<T = object> {
54
+ /** The body of the response. */
55
+ body: T;
56
+ }
57
+
58
+ /**
59
+ * Prompts the user to select files and returns a promise that resolves with the selected files.
60
+ * @param options - Options for file selection.
61
+ * @param options.accept - The accepted file types.
62
+ * @returns A promise that resolves with the selected files.
63
+ */
64
+ export function selectFiles(options: AjaxFileOptionsParam): Promise<File[]>;
65
+
66
+ /**
67
+ * Sends an Ajax request with the specified options.
68
+ * @param options - Options for the Ajax request.
69
+ * @returns A promise that resolves with the Ajax response.
70
+ */
71
+ export function transport(options: AjaxOptions): Promise<AjaxResponse>;
72
+
73
+ /**
74
+ * Sends a POST request with the specified options.
75
+ * @param options - Options for the POST request.
76
+ * @returns A promise that resolves with the Ajax response.
77
+ */
78
+ export function post(options: AjaxOptions): Promise<AjaxResponse>;
79
+
80
+ /**
81
+ * Represents common content types.
82
+ */
83
+ export const contentType: {
84
+ /**
85
+ * The MIME type for JSON content.
86
+ */
87
+ JSON: string;
88
+ };
89
+ }
@@ -0,0 +1,234 @@
1
+ import type { HTMLPasteEventDetail } from '@editorjs/editorjs';
2
+
3
+ /**
4
+ * Represents options for uploading, including a function to handle previewing.
5
+ */
6
+ export interface UploadOptions {
7
+ /**
8
+ * Callback function to be called when the preview is ready.
9
+ * @param src - The source of the preview as a string.
10
+ * @returns void
11
+ */
12
+ onPreview: (src: string) => void;
13
+ }
14
+
15
+ /**
16
+ * User configuration of Image block tunes. Allows to add custom tunes through the config
17
+ */
18
+ export interface ActionConfig {
19
+ /**
20
+ * The name of the tune.
21
+ */
22
+ name: string;
23
+
24
+ /**
25
+ * The icon for the tune. Should be an SVG string.
26
+ */
27
+ icon: string;
28
+
29
+ /**
30
+ * The title of the tune. This will be displayed in the UI.
31
+ */
32
+ title: string;
33
+
34
+ /**
35
+ * An optional flag indicating whether the tune is a toggle (true) or not (false).
36
+ */
37
+ toggle?: boolean;
38
+
39
+ /**
40
+ * An optional action function to be executed when the tune is activated.
41
+ */
42
+ action?: Function;
43
+ };
44
+
45
+ /**
46
+ * UploadResponseFormat interface representing the response format expected from the backend on file uploading.
47
+ */
48
+ export interface UploadResponseFormat<AdditionalFileData = {}> {
49
+ status?: number;
50
+ /**
51
+ * success - 1 for successful uploading, 0 for failure
52
+ */
53
+ success: number;
54
+
55
+ /**
56
+ * Object with file data.
57
+ * 'url' is required,
58
+ * also can contain any additional data that will be saved and passed back
59
+ */
60
+ file: {
61
+ /**
62
+ * The URL of the uploaded image.
63
+ */
64
+ url: string;
65
+ } & AdditionalFileData;
66
+ }
67
+ export interface IUploadResponseFormat<> {
68
+
69
+ success: boolean;
70
+ data?: any,
71
+ message?: string;
72
+ }
73
+ /**
74
+ * ImageToolData type representing the input and output data format for the image tool, including optional custome actions.
75
+ */
76
+ export type ImageToolData<Actions = {}, AdditionalFileData = {}> = {
77
+ /**
78
+ * Caption for the image.
79
+ */
80
+ caption: string;
81
+
82
+ /**
83
+ * Flag indicating whether the image has a border.
84
+ */
85
+ withBorder: boolean;
86
+
87
+ /**
88
+ * Flag indicating whether the image has a background.
89
+ */
90
+ withBackground: boolean;
91
+
92
+ /**
93
+ * Flag indicating whether the image is stretched.
94
+ */
95
+ stretched: boolean;
96
+
97
+ /**
98
+ * Object containing the URL of the image file.
99
+ * Also can contain any additional data.
100
+ */
101
+ file: {
102
+ /**
103
+ * The URL of the image.
104
+ */
105
+ url: string;
106
+ } & AdditionalFileData;
107
+ } & (Actions extends Record<string, boolean> ? Actions : {});
108
+
109
+ /**
110
+ * @description Allows to enable or disable features.
111
+ */
112
+ export type FeaturesConfig = {
113
+ /**
114
+ * Flag to enable/disable tune - background.
115
+ */
116
+ background?: boolean;
117
+ /**
118
+ * Flag to enable/disable tune - border.
119
+ */
120
+ border?: boolean;
121
+ /**
122
+ * Flag to enable/disable caption.
123
+ * Can be set to 'optional' to allow users to toggle via block tunes.
124
+ */
125
+ caption?: boolean | 'optional';
126
+ /**
127
+ * Flag to enable/disable tune - stretched
128
+ */
129
+ stretch?: boolean;
130
+ };
131
+
132
+ /**
133
+ *
134
+ * @description Config supported by Tool
135
+ */
136
+ export interface ImageConfig {
137
+ /**
138
+ * Endpoints for upload, whether using file or URL.
139
+ */
140
+ endpoints: {
141
+
142
+ /**
143
+ * Endpoint for file upload.
144
+ */
145
+ byFile?: string;
146
+
147
+ /**
148
+ * Endpoints for URL upload.
149
+ */
150
+ byUrl?: string;
151
+ };
152
+
153
+ /**
154
+ * Field name for the uploaded image.
155
+ */
156
+ field?: string;
157
+
158
+ /**
159
+ * Allowed mime-types for the uploaded image.
160
+ */
161
+ types?: string;
162
+
163
+ /**
164
+ * Placeholder text for the caption field.
165
+ */
166
+ captionPlaceholder?: string;
167
+
168
+ /**
169
+ * Additional data to send with requests.
170
+ */
171
+ additionalRequestData?: object;
172
+
173
+ /**
174
+ * Additional headers to send with requests.
175
+ */
176
+ additionalRequestHeaders?: object;
177
+
178
+ /**
179
+ * Custom content for the select file button.
180
+ */
181
+ buttonContent?: string;
182
+
183
+ /**
184
+ * Optional custom uploader.
185
+ */
186
+ uploader?: {
187
+
188
+ /**
189
+ * Method to upload an image by file.
190
+ */
191
+ uploadByFile?: (file: Blob) => Promise<UploadResponseFormat>;
192
+
193
+ /**
194
+ * Method to upload an image by URL.
195
+ */
196
+ uploadByUrl?: (url: string) => Promise<UploadResponseFormat>;
197
+ };
198
+
199
+ /**
200
+ * Additional actions for the tool.
201
+ */
202
+ actions?: ActionConfig[];
203
+
204
+ /**
205
+ * Tunes to be enabled.
206
+ */
207
+ features?: FeaturesConfig;
208
+ }
209
+
210
+ /**
211
+ * Interface representing the details of a paste event for HTML elements.
212
+ * Extends the `HTMLPasteEventDetail` interface to include additional data properties.
213
+ */
214
+ export interface HTMLPasteEventDetailExtended extends HTMLPasteEventDetail {
215
+ /**
216
+ * The data property containing the source of the image and HTML element details.
217
+ */
218
+ data: {
219
+ /**
220
+ * The source URL of the pasted image.
221
+ */
222
+ src: string;
223
+ } & HTMLElement;
224
+ }
225
+
226
+ /**
227
+ * Parameter type of Image setter function in ImageTool
228
+ */
229
+ export type ImageSetterParam = {
230
+ /**
231
+ * url path of the image
232
+ */
233
+ url: string;
234
+ };
@@ -0,0 +1,312 @@
1
+ import { IconPicture } from '@codexteam/icons';
2
+ import { make } from './utils/dom';
3
+ import type { API } from '@editorjs/editorjs';
4
+ import type { ImageConfig } from './types/types';
5
+
6
+ /**
7
+ * Enumeration representing the different states of the UI.
8
+ */
9
+ export enum UiState {
10
+ /**
11
+ * The UI is in an empty state, with no image loaded or being selected.
12
+ */
13
+ Empty = 'empty',
14
+
15
+ /**
16
+ * The UI is in an uploading state, indicating an image is currently being uploaded.
17
+ */
18
+ Uploading = 'uploading',
19
+
20
+ /**
21
+ * The UI is in a filled state, with an image successfully loaded.
22
+ */
23
+ Filled = 'filled'
24
+ };
25
+
26
+ /**
27
+ * Nodes interface representing various elements in the UI.
28
+ */
29
+ interface Nodes {
30
+ /**
31
+ * Wrapper element in the UI.
32
+ */
33
+ wrapper: HTMLElement;
34
+
35
+ /**
36
+ * Container for the image element in the UI.
37
+ */
38
+ imageContainer: HTMLElement;
39
+
40
+ /**
41
+ * Button for selecting files.
42
+ */
43
+ fileButton: HTMLElement;
44
+
45
+ /**
46
+ * Represents the image element in the UI, if one is present; otherwise, it's undefined.
47
+ */
48
+ imageEl?: HTMLElement;
49
+
50
+ /**
51
+ * Preloader element for the image.
52
+ */
53
+ imagePreloader: HTMLElement;
54
+
55
+ /**
56
+ * Caption element for the image.
57
+ */
58
+ caption: HTMLElement;
59
+ }
60
+
61
+ /**
62
+ * ConstructorParams interface representing parameters for the Ui class constructor.
63
+ */
64
+ interface ConstructorParams {
65
+ /**
66
+ * Editor.js API.
67
+ */
68
+ api: API;
69
+ /**
70
+ * Configuration for the image.
71
+ */
72
+ config: ImageConfig;
73
+ /**
74
+ * Callback function for selecting a file.
75
+ */
76
+ onSelectFile: () => void;
77
+ /**
78
+ * Flag indicating if the UI is in read-only mode.
79
+ */
80
+ readOnly: boolean;
81
+ }
82
+
83
+ /**
84
+ * Class for working with UI:
85
+ * - rendering base structure
86
+ * - show/hide preview
87
+ * - apply tune view
88
+ */
89
+ export default class Ui {
90
+ /**
91
+ * Nodes representing various elements in the UI.
92
+ */
93
+ public nodes: Nodes;
94
+
95
+ /**
96
+ * API instance for Editor.js.
97
+ */
98
+ private api: API;
99
+
100
+ /**
101
+ * Configuration for the image tool.
102
+ */
103
+ private config: ImageConfig;
104
+
105
+ /**
106
+ * Callback function for selecting a file.
107
+ */
108
+ private onSelectFile: () => void;
109
+
110
+ /**
111
+ * Flag indicating if the UI is in read-only mode.
112
+ */
113
+ private readOnly: boolean;
114
+
115
+ /**
116
+ * @param ui - image tool Ui module
117
+ * @param ui.api - Editor.js API
118
+ * @param ui.config - user config
119
+ * @param ui.onSelectFile - callback for clicks on Select file button
120
+ * @param ui.readOnly - read-only mode flag
121
+ */
122
+ constructor({ api, config, onSelectFile, readOnly }: ConstructorParams) {
123
+ this.api = api;
124
+ this.config = config;
125
+ this.onSelectFile = onSelectFile;
126
+
127
+ this.readOnly = readOnly;
128
+ this.nodes = {
129
+ wrapper: make('div', [this.CSS.baseClass, this.CSS.wrapper]),
130
+ imageContainer: make('div', [this.CSS.imageContainer]),
131
+ fileButton: this.createFileButton(),
132
+ imageEl: undefined,
133
+ imagePreloader: make('div', this.CSS.imagePreloader),
134
+ caption: make('div', [this.CSS.input, this.CSS.caption], {
135
+ contentEditable: !this.readOnly,
136
+ }),
137
+ };
138
+
139
+ /**
140
+ * Create base structure
141
+ * <wrapper>
142
+ * <image-container>
143
+ * <image-preloader />
144
+ * </image-container>
145
+ * <caption />
146
+ * <select-file-button />
147
+ * </wrapper>
148
+ */
149
+ this.nodes.caption.dataset.placeholder = this.config.captionPlaceholder;
150
+ this.nodes.imageContainer.appendChild(this.nodes.imagePreloader);
151
+ this.nodes.wrapper.appendChild(this.nodes.imageContainer);
152
+ this.nodes.wrapper.appendChild(this.nodes.caption);
153
+ this.nodes.wrapper.appendChild(this.nodes.fileButton);
154
+ }
155
+
156
+ /**
157
+ * Apply visual representation of activated tune
158
+ * @param tuneName - one of available tunes {@link Tunes.tunes}
159
+ * @param status - true for enable, false for disable
160
+ */
161
+ public applyTune(tuneName: string, status: boolean): void {
162
+ this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${tuneName}`, status);
163
+ }
164
+
165
+ /**
166
+ * Renders tool UI
167
+ */
168
+ public render(): HTMLElement {
169
+ this.toggleStatus(UiState.Empty);
170
+
171
+ return this.nodes.wrapper;
172
+ }
173
+
174
+ /**
175
+ * Shows uploading preloader
176
+ * @param src - preview source
177
+ */
178
+ public showPreloader(src: string): void {
179
+ this.nodes.imagePreloader.style.backgroundImage = `url(${src})`;
180
+
181
+ this.toggleStatus(UiState.Uploading);
182
+ }
183
+
184
+ /**
185
+ * Hide uploading preloader
186
+ */
187
+ public hidePreloader(): void {
188
+ this.nodes.imagePreloader.style.backgroundImage = '';
189
+ this.toggleStatus(UiState.Empty);
190
+ }
191
+
192
+ /**
193
+ * Shows an image
194
+ * @param url - image source
195
+ */
196
+ public fillImage(url: string): void {
197
+ /**
198
+ * Check for a source extension to compose element correctly: video tag for mp4, img — for others
199
+ */
200
+ const tag = /\.mp4$/.test(url) ? 'VIDEO' : 'IMG';
201
+
202
+ const attributes: { [key: string]: string | boolean } = {
203
+ src: url,
204
+ };
205
+
206
+ /**
207
+ * We use eventName variable because IMG and VIDEO tags have different event to be called on source load
208
+ * - IMG: load
209
+ * - VIDEO: loadeddata
210
+ */
211
+ let eventName = 'load';
212
+
213
+ /**
214
+ * Update attributes and eventName if source is a mp4 video
215
+ */
216
+ if (tag === 'VIDEO') {
217
+ /**
218
+ * Add attributes for playing muted mp4 as a gif
219
+ */
220
+ attributes.autoplay = true;
221
+ attributes.loop = true;
222
+ attributes.muted = true;
223
+ attributes.playsinline = true;
224
+
225
+ /**
226
+ * Change event to be listened
227
+ */
228
+ eventName = 'loadeddata';
229
+ }
230
+
231
+ /**
232
+ * Compose tag with defined attributes
233
+ */
234
+ this.nodes.imageEl = make(tag, this.CSS.imageEl, attributes);
235
+
236
+ /**
237
+ * Add load event listener
238
+ */
239
+ this.nodes.imageEl.addEventListener(eventName, () => {
240
+ this.toggleStatus(UiState.Filled);
241
+
242
+ /**
243
+ * Preloader does not exists on first rendering with presaved data
244
+ */
245
+ if (this.nodes.imagePreloader !== undefined) {
246
+ this.nodes.imagePreloader.style.backgroundImage = '';
247
+ }
248
+ });
249
+
250
+ this.nodes.imageContainer.appendChild(this.nodes.imageEl);
251
+ }
252
+
253
+ /**
254
+ * Shows caption input
255
+ * @param text - caption content text
256
+ */
257
+ public fillCaption(text: string): void {
258
+ if (this.nodes.caption !== undefined) {
259
+ this.nodes.caption.innerHTML = text;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Changes UI status
265
+ * @param status - see {@link Ui.status} constants
266
+ */
267
+ public toggleStatus(status: UiState): void {
268
+ for (const statusType in UiState) {
269
+ if (Object.prototype.hasOwnProperty.call(UiState, statusType)) {
270
+ const state = UiState[statusType as keyof typeof UiState];
271
+
272
+ this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${state}`, state === status);
273
+ }
274
+ }
275
+ }
276
+
277
+ /**
278
+ * CSS classes
279
+ */
280
+ private get CSS(): Record<string, string> {
281
+ return {
282
+ baseClass: this.api.styles.block,
283
+ loading: this.api.styles.loader,
284
+ input: this.api.styles.input,
285
+ button: this.api.styles.button,
286
+
287
+ /**
288
+ * Tool's classes
289
+ */
290
+ wrapper: 'image-tool',
291
+ imageContainer: 'image-tool__image',
292
+ imagePreloader: 'image-tool__image-preloader',
293
+ imageEl: 'image-tool__image-picture',
294
+ caption: 'image-tool__caption',
295
+ };
296
+ };
297
+
298
+ /**
299
+ * Creates upload-file button
300
+ */
301
+ private createFileButton(): HTMLElement {
302
+ const button = make('div', [this.CSS.button]);
303
+
304
+ button.innerHTML = this.config.buttonContent ?? `${IconPicture} ${this.api.i18n.t('Select an Image')}`;
305
+
306
+ button.addEventListener('click', () => {
307
+ this.onSelectFile();
308
+ });
309
+
310
+ return button;
311
+ }
312
+ }