@ebl-vue/editor-full 1.0.12 → 1.1.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.
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +860 -445
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/components/Editor/Editor.vue +47 -12
- package/src/i18n/zh-cn.ts +6 -1
- package/src/icons/index.ts +15 -0
- package/src/installer.ts +4 -3
- package/src/plugins/alert/index.ts +19 -27
- package/src/plugins/block-alignment/index.ts +4 -3
- package/src/plugins/code/index.ts +3 -2
- package/src/plugins/color-picker/index.ts +3 -11
- package/src/plugins/delimiter/index.ts +5 -6
- package/src/plugins/header/H1.ts +1 -1
- package/src/plugins/header/H2.ts +1 -1
- package/src/plugins/header/H3.ts +1 -1
- package/src/plugins/header/H4.ts +1 -2
- package/src/plugins/header/H5.ts +1 -3
- package/src/plugins/header/H6.ts +1 -3
- package/src/plugins/imageResizeCrop/ImageTune.ts +900 -0
- package/src/plugins/imageResizeCrop/index.css +234 -0
- package/src/plugins/imageResizeCrop/index.ts +5 -0
- package/src/plugins/imageResizeCrop/types.d.ts +23 -0
- package/src/plugins/imageTool/index.css +145 -0
- package/src/plugins/imageTool/index.ts +538 -0
- package/src/plugins/imageTool/types/codexteam__ajax.d.ts +89 -0
- package/src/plugins/imageTool/types/types.ts +236 -0
- package/src/plugins/imageTool/ui.ts +313 -0
- package/src/plugins/imageTool/uploader.ts +268 -0
- package/src/plugins/imageTool/utils/dom.ts +24 -0
- package/src/plugins/imageTool/utils/index.ts +73 -0
- package/src/plugins/imageTool/utils/isPromise.ts +10 -0
- package/src/plugins/indent/index.ts +5 -7
- package/src/plugins/inline-code/index.ts +2 -5
- package/src/plugins/list/ListRenderer/ChecklistRenderer.ts +1 -4
- package/src/plugins/list/index.ts +20 -37
- package/src/plugins/list/types/OlCounterType.ts +1 -1
- package/src/plugins/marker/index.ts +28 -16
- package/src/plugins/paragraph/index.ts +3 -2
- package/src/plugins/quote/index.ts +1 -4
- package/src/plugins/table/plugin.ts +1 -1
- package/src/plugins/table/table.ts +40 -38
- package/src/plugins/table/toolbox.ts +5 -4
- package/src/plugins/table/utils/dom.ts +15 -14
- package/src/plugins/table/utils/popover.ts +28 -15
- package/src/plugins/underline/index.ts +2 -4
- package/src/plugins/undo/index.ts +48 -33
- package/src/plugins/undo/observer.ts +3 -3
- package/src/utils/AxiosService.ts +87 -0
- package/types/index.d.ts +6 -0
- package/vite.config.ts +3 -1
- package/src/plugins/list/styles/icons/index.ts +0 -10
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
|
|
2
|
+
import isPromise from './utils/isPromise';
|
|
3
|
+
import type { IUploadResponseFormat, UploadOptions } from './types/types';
|
|
4
|
+
import type { UploadResponseFormat, ImageConfig } from './types/types';
|
|
5
|
+
import axios, { AxiosInstance } from "axios";
|
|
6
|
+
import { selectFiles } from './utils/index';
|
|
7
|
+
/**
|
|
8
|
+
* Params interface for Uploader constructor
|
|
9
|
+
*/
|
|
10
|
+
interface UploaderParams {
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for the uploader
|
|
13
|
+
*/
|
|
14
|
+
config: ImageConfig;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Handles the upload response.
|
|
18
|
+
* @param {UploadResponseFormat} response - Response format expected from the backend on file uploading.
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
21
|
+
onUpload: (response: UploadResponseFormat) => void;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param error : error type
|
|
26
|
+
* @returns void
|
|
27
|
+
*/
|
|
28
|
+
onError: (error: string) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Module for file uploading. Handle 3 scenarios:
|
|
33
|
+
* 1. Select file from device and upload
|
|
34
|
+
* 2. Upload by pasting URL
|
|
35
|
+
* 3. Upload by pasting file from Clipboard or by Drag'n'Drop
|
|
36
|
+
*/
|
|
37
|
+
export default class Uploader {
|
|
38
|
+
private config: ImageConfig;
|
|
39
|
+
private onUpload: (response: UploadResponseFormat) => void;
|
|
40
|
+
private onError: (error: string) => void;
|
|
41
|
+
/**
|
|
42
|
+
* @param params - uploader module params
|
|
43
|
+
* @param params.config - image tool config
|
|
44
|
+
* @param params.onUpload - one callback for all uploading (file, url, d-n-d, pasting)
|
|
45
|
+
* @param params.onError - callback for uploading errors
|
|
46
|
+
*/
|
|
47
|
+
constructor({ config, onUpload, onError }: UploaderParams) {
|
|
48
|
+
this.config = config;
|
|
49
|
+
this.onUpload = onUpload;
|
|
50
|
+
this.onError = onError;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Handle clicks on the upload file button
|
|
55
|
+
* Fires ajax.transport()
|
|
56
|
+
* @param onPreview - callback fired when preview is ready
|
|
57
|
+
*/
|
|
58
|
+
public async uploadSelectedFile({ onPreview, noSelectedFile }: UploadOptions) {
|
|
59
|
+
|
|
60
|
+
const preparePreview = function (file: File): void {
|
|
61
|
+
const reader = new FileReader();
|
|
62
|
+
|
|
63
|
+
reader.readAsDataURL(file);
|
|
64
|
+
reader.onload = (e) => {
|
|
65
|
+
onPreview((e.target as FileReader).result as string);
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Custom uploading
|
|
71
|
+
* or default uploading
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
let cdn: string = "";
|
|
75
|
+
let objectKey: string = "";
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
//选获取上传文件的地址
|
|
80
|
+
const files = await selectFiles({ accept: this.config.types ?? 'image/*' });
|
|
81
|
+
|
|
82
|
+
if (files && files.length > 0) {
|
|
83
|
+
preparePreview(files[0]);
|
|
84
|
+
} else {
|
|
85
|
+
noSelectedFile();
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
const file = files[0];
|
|
89
|
+
const fileTypes = this.config.types.split(",");
|
|
90
|
+
let suffixIndex = file.name.lastIndexOf(".");
|
|
91
|
+
let suffix = file.name.slice(suffixIndex);
|
|
92
|
+
|
|
93
|
+
if (!fileTypes.includes(suffix.toLowerCase())) {
|
|
94
|
+
this.onError("文件类型不支持");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let headers: Record<string, string> = {};
|
|
99
|
+
if (this.config.userStore) {
|
|
100
|
+
const token = this.config.userStore.token;
|
|
101
|
+
const tokenName = this.config.userStore.tokenName;
|
|
102
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
103
|
+
if (token && tokenName) {
|
|
104
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
108
|
+
timeout: 1800000,
|
|
109
|
+
headers: headers,
|
|
110
|
+
});
|
|
111
|
+
headers["Content-Type"] = "application/json";
|
|
112
|
+
|
|
113
|
+
const uploadBodyRes = await axiosInstance.post(this.config.endpoints.byFile!, {
|
|
114
|
+
"fileName": file.name,
|
|
115
|
+
"contentType": file.type
|
|
116
|
+
})
|
|
117
|
+
if (uploadBodyRes.status !== 200) {
|
|
118
|
+
this.onError(uploadBodyRes.statusText);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const uploadRes = uploadBodyRes.data;
|
|
122
|
+
if (!uploadRes.success) {
|
|
123
|
+
this.onError(uploadRes.message!);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
console.log(uploadRes);
|
|
127
|
+
cdn = uploadRes.data.cdn;
|
|
128
|
+
objectKey = uploadRes.data.objectKey;
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
headers["Content-Type"] = file.type;
|
|
132
|
+
|
|
133
|
+
let upload = axiosInstance.put(uploadRes.data.presignedUrl, file);
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
upload.then((response) => {
|
|
139
|
+
if (response.status === 200) {
|
|
140
|
+
response = {
|
|
141
|
+
success: 1,
|
|
142
|
+
file: { url: cdn + objectKey }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
this.onUpload(response);
|
|
146
|
+
}).catch((error: string) => {
|
|
147
|
+
this.onError(error);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Handle clicks on the upload file button
|
|
153
|
+
* Fires ajax.post()
|
|
154
|
+
* @param url - image source url
|
|
155
|
+
*/
|
|
156
|
+
public uploadByUrl(url: string): void {
|
|
157
|
+
let upload;
|
|
158
|
+
let headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
159
|
+
if (this.config.userStore) {
|
|
160
|
+
const token = this.config.userStore.token;
|
|
161
|
+
const tokenName = this.config.userStore.tokenName;
|
|
162
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
163
|
+
if (token && tokenName) {
|
|
164
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
168
|
+
timeout: 1800000,
|
|
169
|
+
headers: headers,
|
|
170
|
+
});
|
|
171
|
+
upload = axiosInstance.post(this.config.endpoints.byUrl!, {
|
|
172
|
+
"url": url,
|
|
173
|
+
"accept": ".jpg,.jpeg,.gif,.png,.webp"
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
upload.then((response) => {
|
|
180
|
+
|
|
181
|
+
if(response.status !== 200||response.data.success===false){
|
|
182
|
+
this.onError(response.data.message!);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let cdn = response.data.data.cdn;
|
|
187
|
+
let objectKey = response.data.data.objectKey;
|
|
188
|
+
|
|
189
|
+
let res = {
|
|
190
|
+
success: 1,
|
|
191
|
+
file: { url: cdn + objectKey }
|
|
192
|
+
};
|
|
193
|
+
this.onUpload(res);
|
|
194
|
+
}).catch((error: string) => {
|
|
195
|
+
this.onError(error);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Handle clicks on the upload file button
|
|
202
|
+
* Fires ajax.post()
|
|
203
|
+
* @param file - file pasted by drag-n-drop
|
|
204
|
+
* @param onPreview - file pasted by drag-n-drop
|
|
205
|
+
*/
|
|
206
|
+
public async uploadByFile(file: Blob, { onPreview }: UploadOptions) {
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
const fileTypes = this.config.types.split(",");
|
|
210
|
+
|
|
211
|
+
let suffixIndex = file.name.lastIndexOf(".");
|
|
212
|
+
let suffix = file.name.slice(suffixIndex);
|
|
213
|
+
|
|
214
|
+
if (!fileTypes.includes(suffix.toLowerCase())) {
|
|
215
|
+
this.onError("文件类型不支持");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
let headers: Record<string, string> = {};
|
|
222
|
+
if (this.config.userStore) {
|
|
223
|
+
const token = this.config.userStore.token;
|
|
224
|
+
const tokenName = this.config.userStore.tokenName;
|
|
225
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
226
|
+
if (token && tokenName) {
|
|
227
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
231
|
+
timeout: 1800000,
|
|
232
|
+
headers: headers,
|
|
233
|
+
});
|
|
234
|
+
headers["Content-Type"] = "application/json";
|
|
235
|
+
|
|
236
|
+
const uploadBodyRes = await axiosInstance.post(this.config.endpoints.byFile!, {
|
|
237
|
+
"fileName": file.name,
|
|
238
|
+
"contentType": file.type
|
|
239
|
+
})
|
|
240
|
+
if (uploadBodyRes.status !== 200) {
|
|
241
|
+
this.onError(uploadBodyRes.statusText);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const uploadRes = uploadBodyRes.data;
|
|
245
|
+
if (!uploadRes.success) {
|
|
246
|
+
this.onError(uploadRes.message!);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
console.log(uploadRes);
|
|
250
|
+
let cdn = uploadRes.data.cdn;
|
|
251
|
+
let objectKey = uploadRes.data.objectKey;
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
headers["Content-Type"] = file.type;
|
|
255
|
+
let upload = axiosInstance.put(uploadRes.data.presignedUrl, file);
|
|
256
|
+
upload.then((response) => {
|
|
257
|
+
if (response.status === 200) {
|
|
258
|
+
response = {
|
|
259
|
+
success: 1,
|
|
260
|
+
file: { url: cdn + objectKey }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
this.onUpload(response);
|
|
264
|
+
}).catch((error: string) => {
|
|
265
|
+
this.onError(error);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper for making Elements with attributes
|
|
3
|
+
* @param tagName - new Element tag name
|
|
4
|
+
* @param classNames - list or name of CSS class
|
|
5
|
+
* @param attributes - any attributes
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function make(tagName: string, classNames: string[] | string | null = null, attributes: { [key: string]: string | boolean } = {}): HTMLElement {
|
|
9
|
+
const el = document.createElement(tagName);
|
|
10
|
+
|
|
11
|
+
if (Array.isArray(classNames)) {
|
|
12
|
+
el.classList.add(...classNames);
|
|
13
|
+
} else if (classNames !== null) {
|
|
14
|
+
el.classList.add(classNames);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const attrName in attributes) {
|
|
18
|
+
if (attributes.hasOwnProperty(attrName)) {
|
|
19
|
+
(el as unknown as { [key: string]: string | boolean })[attrName] = attributes[attrName];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return el;
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
interface IConfig {
|
|
2
|
+
multiple?: boolean;
|
|
3
|
+
accept?: string;
|
|
4
|
+
}
|
|
5
|
+
export function selectFiles(config = {} as IConfig): Promise<File[]> {
|
|
6
|
+
let fileCancle = true;
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
/**
|
|
9
|
+
* Create a new INPUT element
|
|
10
|
+
* @type {HTMLElement}
|
|
11
|
+
*/
|
|
12
|
+
let inputElement = document.createElement('INPUT');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Set a 'FILE' type for this input element
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
inputElement.type = 'file';
|
|
19
|
+
|
|
20
|
+
if (config.multiple) {
|
|
21
|
+
inputElement.setAttribute('multiple', 'multiple');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (config.accept) {
|
|
25
|
+
inputElement.setAttribute('accept', config.accept);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Do not show element
|
|
30
|
+
*/
|
|
31
|
+
inputElement.style.display = 'none';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Append element to the body
|
|
35
|
+
* Fix using module on mobile devices
|
|
36
|
+
*/
|
|
37
|
+
document.body.appendChild(inputElement);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add onchange listener for «choose file» pop-up
|
|
41
|
+
*/
|
|
42
|
+
inputElement.addEventListener('change', event => {
|
|
43
|
+
console.log("选中文件")
|
|
44
|
+
fileCancle = false;
|
|
45
|
+
/**
|
|
46
|
+
* Get files from input field
|
|
47
|
+
*/
|
|
48
|
+
const files = event.target.files;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return ready to be uploaded files array
|
|
52
|
+
*/
|
|
53
|
+
resolve(files);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Remove element from a DOM
|
|
57
|
+
*/
|
|
58
|
+
document.body.removeChild(inputElement);
|
|
59
|
+
}, false);
|
|
60
|
+
window.addEventListener("focus", () => {
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
if (fileCancle) {
|
|
63
|
+
console.log("取消选择文件")
|
|
64
|
+
resolve([]);
|
|
65
|
+
}
|
|
66
|
+
}, 1000)
|
|
67
|
+
},{once: true})
|
|
68
|
+
/**
|
|
69
|
+
* Fire click event on «input file» field
|
|
70
|
+
*/
|
|
71
|
+
inputElement.click();
|
|
72
|
+
});
|
|
73
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { UploadResponseFormat } from '../types/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if passed object is a Promise
|
|
5
|
+
* @param object - object to check
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export default function isPromise(object: Promise<UploadResponseFormat>): object is Promise<UploadResponseFormat> {
|
|
9
|
+
return object !== undefined && typeof object.then === 'function';
|
|
10
|
+
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import type { BlockTune, API, BlockAPI, BlockAddedEvent,ToolConfig } from '@ebl-vue/editorjs/types'
|
|
2
2
|
|
|
3
3
|
import type { MenuConfig } from '@ebl-vue/editorjs/types/tools'
|
|
4
|
-
|
|
4
|
+
import { IconIndentLeft,IconIndentRight } from '../../icons';
|
|
5
5
|
|
|
6
6
|
import './index.css'
|
|
7
7
|
|
|
8
|
-
const IconChevronLeft = `<svg t="1763708081701" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2604" width="24" height="24"><path d="M469.3330000000001 725.333H896V640H469.3330000000001v85.333zM128 512l170.667 170.667V341.3330000000001L128 512z m0 384h768v-85.333H128V896z m0-768v85.333h768V128H128z m341.333 256H896v-85.333H469.3330000000001V384z m0 170.667H896v-85.334H469.3330000000001v85.334z" p-id="2605" fill="#000000"></path></svg>`;
|
|
9
8
|
|
|
10
|
-
const IconChevronRight = `<svg t="1763708124227" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2788" width="24" height="24"><path d="M128 896h768v-85.333H128V896z m0-554.667v341.334L298.667 512 128 341.333z m341.333 384H896V640H469.333v85.333zM128 128v85.333h768V128H128z m341.333 256H896v-85.333H469.333V384z m0 170.667H896v-85.334H469.333v85.334z" p-id="2789" fill="#000000"></path></svg>`;
|
|
11
9
|
|
|
12
10
|
interface ConstructorArgs {
|
|
13
11
|
data: IndentData;
|
|
@@ -196,7 +194,7 @@ export default class IndentTune implements BlockTune {
|
|
|
196
194
|
//@ts-ignore
|
|
197
195
|
item.title = this.rightText;
|
|
198
196
|
},
|
|
199
|
-
icon:
|
|
197
|
+
icon: IconIndentRight,
|
|
200
198
|
name: rightElementName,
|
|
201
199
|
},
|
|
202
200
|
{
|
|
@@ -209,7 +207,7 @@ export default class IndentTune implements BlockTune {
|
|
|
209
207
|
//@ts-ignore
|
|
210
208
|
item.title = this.leftText;
|
|
211
209
|
},
|
|
212
|
-
icon:
|
|
210
|
+
icon: IconIndentLeft,
|
|
213
211
|
name: leftElementName,
|
|
214
212
|
},
|
|
215
213
|
]
|
|
@@ -217,9 +215,9 @@ export default class IndentTune implements BlockTune {
|
|
|
217
215
|
|
|
218
216
|
const html = /*html*/ `
|
|
219
217
|
<div class="${this.CSS.popoverItem} ${this.CSS.customPopoverItem}" data-item-name='indent' version=${this.config.version}>
|
|
220
|
-
<button type="button" class="${this.CSS.popoverItemIcon}" data-${this.TuneNames.indentLeft}>${
|
|
218
|
+
<button type="button" class="${this.CSS.popoverItemIcon}" data-${this.TuneNames.indentLeft}>${IconIndentLeft}</button>
|
|
221
219
|
<span class="${this.CSS.popoverItemTitle}">${this.api.sanitizer.clean(this.api.i18n.t('Indent'), {})}</span>
|
|
222
|
-
<button type="button" class="${this.CSS.popoverItemIcon}" data-${this.TuneNames.indentRight} style="margin-left:10px;">${
|
|
220
|
+
<button type="button" class="${this.CSS.popoverItemIcon}" data-${this.TuneNames.indentRight} style="margin-left:10px;">${IconIndentRight}</button>
|
|
223
221
|
</div>
|
|
224
222
|
`
|
|
225
223
|
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
* Build styles
|
|
3
3
|
*/
|
|
4
4
|
import './index.css';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<path d="M15 8L19 12L15 16" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
-
</svg>
|
|
9
|
-
`;
|
|
5
|
+
import {IconBrackets} from '../../icons';
|
|
6
|
+
|
|
10
7
|
import { API, InlineTool, InlineToolConstructorOptions, SanitizerConfig } from "@editorjs/editorjs";
|
|
11
8
|
|
|
12
9
|
interface IconClasses {
|
|
@@ -4,10 +4,7 @@ import { isEmpty, make } from '@editorjs/dom';
|
|
|
4
4
|
import { DefaultListCssClasses } from './ListRenderer';
|
|
5
5
|
import type { ListCssClasses, ListRendererInterface } from './ListRenderer';
|
|
6
6
|
import { CssPrefix } from '../styles/CssPrefix';
|
|
7
|
-
|
|
8
|
-
<path d="M7 12L10.4884 15.8372C10.5677 15.9245 10.705 15.9245 10.7844 15.8372L17 9" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
9
|
-
</svg>
|
|
10
|
-
`;
|
|
7
|
+
import { IconCheck } from "../../../icons";
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
10
|
* Interface that represents all list used only in unordered list rendering
|
|
@@ -1,46 +1,28 @@
|
|
|
1
1
|
import type { API, BlockAPI, PasteConfig, ToolboxConfig } from '@ebl-vue/editorjs';
|
|
2
2
|
import type {
|
|
3
3
|
BlockToolConstructorOptions,
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
ToolConfig
|
|
6
6
|
} from '@editorjs/editorjs/types/tools';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
import type { ListConfig, ListData, ListDataStyle, ListItem, OldListData } from './types/ListParams';
|
|
10
10
|
import ListTabulator from './ListTabulator';
|
|
11
11
|
import { CheckListRenderer, OrderedListRenderer, UnorderedListRenderer } from './ListRenderer';
|
|
12
12
|
import type { ListRenderer } from './types/ListRenderer';
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<line x1="9" y1="17" x2="19" y2="17" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
20
|
-
<path d="M5.00001 17H4.99002" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
21
|
-
<path d="M5.00001 12H4.99002" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
22
|
-
<path d="M5.00001 7H4.99002" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
23
|
-
</svg>
|
|
24
|
-
`;
|
|
25
|
-
const IconListNumbered = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
26
|
-
<line x1="12" y1="7" x2="19" y2="7" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
27
|
-
<line x1="12" y1="12" x2="19" y2="12" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
28
|
-
<line x1="12" y1="17" x2="19" y2="17" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
29
|
-
<path d="M7.79999 14L7.79999 7.2135C7.79999 7.12872 7.7011 7.0824 7.63597 7.13668L4.79999 9.5" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
30
|
-
</svg>
|
|
31
|
-
`;
|
|
32
|
-
const IconChecklist = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
33
|
-
<path d="M9.2 12L11.0586 13.8586C11.1367 13.9367 11.2633 13.9367 11.3414 13.8586L14.7 10.5" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
|
34
|
-
<rect x="5" y="5" width="14" height="14" rx="4" stroke="black" stroke-width="2"/>
|
|
35
|
-
</svg>
|
|
36
|
-
`;
|
|
13
|
+
|
|
14
|
+
import { type OlCounterType, OlCounterTypesMap } from './types/OlCounterType';
|
|
15
|
+
|
|
16
|
+
import { IconListBulleted, IconListNumbered, IconChecklist } from "../../icons";
|
|
17
|
+
|
|
18
|
+
|
|
37
19
|
|
|
38
20
|
/**
|
|
39
21
|
* Build styles
|
|
40
22
|
*/
|
|
41
23
|
import './styles/list.css';
|
|
42
24
|
import './styles/input.css';
|
|
43
|
-
|
|
25
|
+
|
|
44
26
|
import normalizeData from './utils/normalizeData';
|
|
45
27
|
import type { PasteEvent } from './types';
|
|
46
28
|
import type { OrderedListItemMeta } from './types/ItemMeta';
|
|
@@ -54,6 +36,7 @@ export type ListParams = BlockToolConstructorOptions<ListData | OldListData, Lis
|
|
|
54
36
|
* Default class of the component used in editor
|
|
55
37
|
*/
|
|
56
38
|
export default class EditorjsList {
|
|
39
|
+
defaultCounterTypes: OlCounterType[];
|
|
57
40
|
/**
|
|
58
41
|
* Notify core that read-only mode is supported
|
|
59
42
|
*/
|
|
@@ -196,7 +179,7 @@ export default class EditorjsList {
|
|
|
196
179
|
/**
|
|
197
180
|
* Default Counter type of the ordered list
|
|
198
181
|
*/
|
|
199
|
-
private defaultCounterTypes: OlCounterType[];
|
|
182
|
+
//private defaultCounterTypes: OlCounterType[];
|
|
200
183
|
|
|
201
184
|
/**
|
|
202
185
|
* Tool's data
|
|
@@ -438,21 +421,21 @@ export default class EditorjsList {
|
|
|
438
421
|
* Changes ordered list counterType property value
|
|
439
422
|
* @param counterType - new value of the counterType value
|
|
440
423
|
*/
|
|
441
|
-
private changeCounters(counterType: OlCounterType): void {
|
|
442
|
-
|
|
424
|
+
// private changeCounters(counterType: OlCounterType): void {
|
|
425
|
+
// this.list?.changeCounters(counterType);
|
|
443
426
|
|
|
444
|
-
|
|
445
|
-
}
|
|
427
|
+
// (this.data.meta as OrderedListItemMeta).counterType = counterType;
|
|
428
|
+
// }
|
|
446
429
|
|
|
447
430
|
/**
|
|
448
431
|
* Changes ordered list start property value
|
|
449
432
|
* @param index - new value of the start property
|
|
450
|
-
|
|
451
|
-
private changeStartWith(index: number): void {
|
|
452
|
-
|
|
433
|
+
// */
|
|
434
|
+
// private changeStartWith(index: number): void {
|
|
435
|
+
// this.list?.changeStartWith(index);
|
|
453
436
|
|
|
454
|
-
|
|
455
|
-
}
|
|
437
|
+
// (this.data.meta as OrderedListItemMeta).start = index;
|
|
438
|
+
// }
|
|
456
439
|
|
|
457
440
|
/**
|
|
458
441
|
* This method allows changing tabulator respectfully to passed style
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IconNumber, IconLowerRoman, IconUpperRoman, IconLowerAlpha, IconUpperAlpha } from '
|
|
1
|
+
import { IconNumber, IconLowerRoman, IconUpperRoman, IconLowerAlpha, IconUpperAlpha } from '../../../icons';
|
|
2
2
|
|
|
3
3
|
export type OlCounterType = 'numeric' | 'upper-roman' | 'lower-roman' | 'upper-alpha' | 'lower-alpha';
|
|
4
4
|
|
|
@@ -2,15 +2,23 @@
|
|
|
2
2
|
* Build styles
|
|
3
3
|
*/
|
|
4
4
|
import './index.css';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import type { API } from '@ebl-vue/editorjs';
|
|
6
|
+
import { IconMarker } from '../../icons';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Marker Tool for the Editor.js
|
|
10
10
|
*
|
|
11
11
|
* Allows to wrap inline fragment and style it somehow.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
export default class Marker {
|
|
14
|
+
private api: API;
|
|
15
|
+
private button: HTMLElement | null;
|
|
16
|
+
private tag: string;
|
|
17
|
+
private iconClasses: {base: string; active: string};
|
|
18
|
+
|
|
19
|
+
static get toolboxIcon() {
|
|
20
|
+
return IconMarker;
|
|
21
|
+
}
|
|
14
22
|
/**
|
|
15
23
|
* Class name for term-tag
|
|
16
24
|
*
|
|
@@ -23,7 +31,7 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
23
31
|
/**
|
|
24
32
|
* @param {{api: object}} - Editor.js API
|
|
25
33
|
*/
|
|
26
|
-
constructor({api}) {
|
|
34
|
+
constructor({api}: {api: any}) {
|
|
27
35
|
this.api = api;
|
|
28
36
|
|
|
29
37
|
/**
|
|
@@ -65,7 +73,8 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
65
73
|
*/
|
|
66
74
|
render() {
|
|
67
75
|
this.button = document.createElement('button');
|
|
68
|
-
this.button.type = 'button';
|
|
76
|
+
//this.button.type = 'button';
|
|
77
|
+
this.button.setAttribute("type", "button");
|
|
69
78
|
this.button.classList.add(this.iconClasses.base);
|
|
70
79
|
this.button.innerHTML = this.toolboxIcon;
|
|
71
80
|
|
|
@@ -77,7 +86,7 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
77
86
|
*
|
|
78
87
|
* @param {Range} range - selected fragment
|
|
79
88
|
*/
|
|
80
|
-
surround(range) {
|
|
89
|
+
surround(range:Range) {
|
|
81
90
|
if (!range) {
|
|
82
91
|
return;
|
|
83
92
|
}
|
|
@@ -99,7 +108,7 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
99
108
|
*
|
|
100
109
|
* @param {Range} range - selected fragment
|
|
101
110
|
*/
|
|
102
|
-
wrap(range) {
|
|
111
|
+
wrap(range:Range) {
|
|
103
112
|
/**
|
|
104
113
|
* Create a wrapper for highlighting
|
|
105
114
|
*/
|
|
@@ -127,32 +136,35 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
127
136
|
*
|
|
128
137
|
* @param {HTMLElement} termWrapper - term wrapper tag
|
|
129
138
|
*/
|
|
130
|
-
unwrap(termWrapper) {
|
|
139
|
+
unwrap(termWrapper: HTMLElement) {
|
|
131
140
|
/**
|
|
132
141
|
* Expand selection to all term-tag
|
|
133
142
|
*/
|
|
134
143
|
this.api.selection.expandToTag(termWrapper);
|
|
135
144
|
|
|
136
145
|
let sel = window.getSelection();
|
|
137
|
-
let range = sel
|
|
146
|
+
let range = sel?.getRangeAt(0);
|
|
138
147
|
|
|
139
|
-
let unwrappedContent = range
|
|
148
|
+
let unwrappedContent = range?.extractContents();
|
|
140
149
|
|
|
141
150
|
/**
|
|
142
151
|
* Remove empty term-tag
|
|
143
152
|
*/
|
|
144
|
-
termWrapper
|
|
153
|
+
termWrapper?.parentNode?.removeChild(termWrapper);
|
|
145
154
|
|
|
146
155
|
/**
|
|
147
156
|
* Insert extracted content
|
|
148
157
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
158
|
+
if (unwrappedContent) {
|
|
159
|
+
range?.insertNode(unwrappedContent);
|
|
160
|
+
}
|
|
151
161
|
/**
|
|
152
162
|
* Restore selection
|
|
153
163
|
*/
|
|
154
|
-
sel
|
|
155
|
-
|
|
164
|
+
sel?.removeAllRanges();
|
|
165
|
+
if (range) {
|
|
166
|
+
sel?.addRange(range);
|
|
167
|
+
}
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
/**
|
|
@@ -161,7 +173,7 @@ const IconMarker = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
|
161
173
|
checkState() {
|
|
162
174
|
const termTag = this.api.selection.findParentTag(this.tag, Marker.CSS);
|
|
163
175
|
|
|
164
|
-
this.button
|
|
176
|
+
this.button?.classList.toggle(this.iconClasses.active, !!termTag);
|
|
165
177
|
}
|
|
166
178
|
|
|
167
179
|
/**
|