Răsfoiți Sursa

:sparkles: https://github.com/Vanessa219/vditor/issues/1791

Vanessa 6 luni în urmă
părinte
comite
7369e0cf50

+ 2 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ### 升级
 
 * 3.10
+  * 添加 options.upload.cancel
   * 添加 options.unSelect
 * 3.9
   * 添加 insertEmptyBlock
@@ -25,6 +26,7 @@
 
 ### v3.11.0 / 2025-04
 
+* [添加 `options.upload.cancel` 回调](https://github.com/Vanessa219/vditor/issues/1791) `引入特性`
 * [修复代码行号对不齐](https://github.com/Vanessa219/vditor/issues/1786) `修复缺陷`
 * [mermaid 升级至 11.6.0](https://github.com/Vanessa219/vditor/issues/1140) `开发重构`
 * [初始化后立即 `destroy` 不再进行 `after` 的回调](https://github.com/Vanessa219/vditor/issues/1790) `改进功能`

+ 1 - 0
README.md

@@ -481,6 +481,7 @@ if (xhr.status === 200) {
 | handler(files: File[]) => string \| null \| Promise<string> \| Promise<null> | 自定义上传,当发生错误时返回错误信息 | - |
 | format(files: File[], responseText: string): string | 对服务端返回的数据进行转换,以满足内置的数据结构 | - |
 | file(files: File[]): File[] \| Promise<File[]> | 将上传的文件处理后再返回 | - |
+| cancel(files: File[]): void | 取消正在上传的文件 | - |
 | setHeaders(): { [key: string]: string } | 上传前使用返回值设置头 | - |
 | extraData: { [key: string]: string \| Blob } | 为 FormData 添加额外的参数 | - |
 | multiple | 上传文件是否为多个 | true |

+ 1 - 0
README_en_US.md

@@ -434,6 +434,7 @@ xhr.send(JSON.stringify({url: src})); // src is the address of the image outside
 | handler(files: File[]) => string \| null \| Promise<string> \| Promise<null> | Custom upload, return error message when an error occurs | - |
 | format | Transform the data returned by the server to meet the built-in data structure (files: File[], responseText: string): string | - |
 | file(files: File[]): File[] \| Promise<File[]> | Process the uploaded file before return. | - |
+| cancel(files: File[]): void | Cancel uploading a file. | - |
 | setHeaders | Use the return value to set the header before uploading (): { [key: string]: string } | - |
 | extraData | Append data to FormData { [key: string]: string | Blob } | - |
 | multiple | Allow multiple file uploads | true |

+ 1 - 0
src/js/i18n/en_US.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': 'Alternate text',
   'bold': 'Bold',
   'both': 'editor & preview',
+  'cancelUpload': 'Cancel upload',
   'check': 'Task List',
   'close': 'Close',
   'code': 'Code Block',

+ 1 - 0
src/js/i18n/fr_FR.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': 'Texte de remplacement',
   'bold': 'Gras',
   'both': 'éditeur & prévisualisation',
+  'cancelUpload': 'Annuler le téléchargement',
   'check': 'Liste de tâches',
   'close': 'Fermer',
   'code': 'Bloc de code',

+ 1 - 0
src/js/i18n/ja_JP.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': 'イメージタグ',
   'bold': '太く',
   'both': 'エディター & プレビュー',
+  'cancelUpload': 'アップロードをキャンセル',
   'check': 'チェックリスト',
   'close': '閉じる',
   'code': 'コードブロック挿入',

+ 1 - 0
src/js/i18n/ko_KR.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': '이미지 태그',
   'bold': '굵게',
   'both': '에디터 & 미리보기',
+  'cancelUpload': '업로드 취소',
   'check': '체크박스',
   'close': '닫기',
   'code': '코드블럭삽입',

+ 1 - 0
src/js/i18n/pt_BR.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': 'Texto alternativo',
   'bold': 'Negrito',
   'both': 'Editor e visualização',
+  'cancelUpload': 'Cancelar envio',
   'check': 'Lista de tarefas',
   'close': 'Fechar',
   'code': 'Bloco de código',

+ 1 - 0
src/js/i18n/ru_RU.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': 'Альтернативный текст',
   'bold': 'Полужирный текст',
   'both': 'Редактор с предпросмотром',
+  'cancelUpload': 'Отменить загрузку',
   'check': 'Список задач',
   'close': 'Закрыть',
   'code': 'Блок кода',

+ 1 - 0
src/js/i18n/sv_SE.js

@@ -5,6 +5,7 @@
   'alternateText': 'Alternativ text',
   'bold': 'Fet',
   'both': 'editera & granska',
+  'cancelUpload': 'Avbryt uppladdning',
   'check': 'Att göra lista',
   'close': 'Stäng',
   'code': 'Kodblock',

+ 1 - 0
src/js/i18n/zh_CN.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': '替代文本',
   'bold': '粗体',
   'both': '编辑 & 预览',
+  'cancelUpload': '取消上传',
   'check': '任务列表',
   'close': '关闭',
   'code': '代码块',

+ 1 - 0
src/js/i18n/zh_TW.js

@@ -5,6 +5,7 @@ window.VditorI18n = {
   'alternateText': '替代文字',
   'bold': '粗體',
   'both': '編輯 & 預覽',
+  'cancelUpload': '取消上傳',
   'check': '任務列表',
   'close': '關閉',
   'code': '代碼塊',

+ 13 - 2
src/ts/upload/index.ts

@@ -16,7 +16,7 @@ class Upload {
 
 const validateFile = (vditor: IVditor, files: File[]) => {
     vditor.tip.hide();
-    const uploadFileList = [];
+    const uploadFileList: File[] = [];
     let errorTip = "";
     let uploadingStr = "";
     const lang: keyof II18n | "" = vditor.options.lang;
@@ -63,12 +63,23 @@ const validateFile = (vditor: IVditor, files: File[]) => {
 
         if (validate) {
             uploadFileList.push(file);
-            uploadingStr += `<li>${filename} ${window.VditorI18n.uploading}</li>`;
+            uploadingStr += `<li>${filename} ${window.VditorI18n.uploading} <a class="vditorCancelUpload" href="javascript:void(0)">${window.VditorI18n.cancelUpload}</a></li>`;
         }
     }
 
     vditor.tip.show(`<ul>${errorTip}${uploadingStr}</ul>`);
 
+    if (vditor.options.upload.cancel) {
+        const vditorCancelUploadElement = vditor.tip.element.querySelector(".vditorCancelUpload");
+        if (vditorCancelUploadElement) {
+            vditorCancelUploadElement.addEventListener("click", () => {
+                vditor.options.upload.cancel(uploadFileList);
+                vditor.tip.hide();
+                vditor.upload.isUploading = false;
+            });
+        }
+    }
+
     return uploadFileList;
 };
 

+ 8 - 3
types/index.d.ts

@@ -362,8 +362,10 @@ interface IUpload {
     max?: number;
     /** 剪切板中包含图片地址时,使用此 url 重新上传 */
     linkToImgUrl?: string;
+
     /** 剪切板中包含图片地址时,使用此方法进行自定义 */
     renderLinkDest?(vditor: IVditor, node: ILuteNode, entering: boolean): [string, number];
+
     /** CORS 上传验证,头为 X-Upload-Token */
     token?: string;
     /** 文件上传类型,同 [input accept](https://www.w3schools.com/tags/att_input_accept.asp) */
@@ -406,6 +408,9 @@ interface IUpload {
     /** 将上传的文件处理后再返回  */
     file?(files: File[]): File[] | Promise<File[]>;
 
+    /** 取消正在上传的文件  */
+    cancel?(files: File[]): void;
+
     /** 图片地址上传后的回调  */
     linkToImgCallback?(responseText: string): void;
 }
@@ -516,7 +521,7 @@ interface IPreview {
     theme?: IPreviewTheme;
     /** @link https://ld246.com/article/1549638745630#options-preview-actions  */
     actions?: Array<IPreviewAction | IPreviewActionCustom>;
-    render?: IPreviewRender
+    render?: IPreviewRender;
 
     /** 预览回调 */
     parse?(element: HTMLElement): void;
@@ -528,7 +533,7 @@ interface IPreview {
 interface IPreviewRender {
     media?: {
         enable?: boolean;
-    }
+    };
 }
 
 type IPreviewAction = "desktop" | "tablet" | "mobile" | "mp-wechat" | "zhihu";
@@ -564,7 +569,7 @@ interface IPreviewOptions {
     renderers?: ILuteRender;
     theme?: IPreviewTheme;
     icon?: "ant" | "material" | undefined;
-    render?: IPreviewRender
+    render?: IPreviewRender;
 
     transform?(html: string): string;