diff --git a/packages/ui-default/components/editor/index.ts b/packages/ui-default/components/editor/index.ts index 8267d958..651b51bb 100644 --- a/packages/ui-default/components/editor/index.ts +++ b/packages/ui-default/components/editor/index.ts @@ -1,6 +1,9 @@ import _ from 'lodash'; import Notification from 'vj/components/notification'; import DOMAttachedObject from 'vj/components/DOMAttachedObject'; +import { nanoid } from 'nanoid'; +import i18n from 'vj/utils/i18n'; +import request from 'vj/utils/request'; export const config = { toolbar: [ @@ -158,6 +161,8 @@ export default class Editor extends DOMAttachedObject { } async initVditor() { + const pagename = document.documentElement.getAttribute('data-page'); + const isProblemEdit = pagename === 'problem_edit'; const { default: Vditor } = await import('vditor'); const { $dom } = this; const hasFocus = $dom.is(':focus') || $dom.hasClass('autofocus'); @@ -167,7 +172,52 @@ export default class Editor extends DOMAttachedObject { const { onChange } = this.options; await new Promise((resolve) => { this.vditor = new Vditor(ele, { - ...config, + upload: { + multiple: false, + handler: (files) => { + let wrapper = ['', '']; + let ext: string; + const matches = files[0].type.match(/^image\/(png|jpg|jpeg|gif)$/i); + if (matches) { + wrapper = ['![image](', ')']; + [, ext] = matches; + } else if (files[0].type === 'application/x-zip-compressed') { + wrapper = ['[file](', ')']; + ext = 'zip'; + } + if (!ext) return i18n('No Supported file type.'); + const filename = `${nanoid()}.${ext}`; + const data = new FormData(); + data.append('filename', filename); + data.append('file', files[0]); + data.append('operation', 'upload_file'); + if (isProblemEdit) data.append('type', 'additional_file'); + let progress = 0; + request.postFile(isProblemEdit ? './files' : '/file', data, { + xhr: () => { + const xhr = new XMLHttpRequest(); + xhr.upload.addEventListener('loadstart', () => this.vditor.vditor.tip.show(i18n('Uploading...'), 0)); + xhr.upload.addEventListener('progress', (e) => { + if (!e.lengthComputable) return; + const percentComplete = Math.round((e.loaded / e.total) * 100); + if (percentComplete === progress) return; + progress = percentComplete; + this.vditor.vditor.tip.show(`${i18n('Uploading...')} ${percentComplete}%`, 0); + }, false); + return xhr; + }, + }) + .then(() => { + this.vditor.insertValue(`${wrapper.join(`file://${filename}`)} `); + this.vditor.vditor.tip.hide(); + }) + .catch((e: { message: string; }) => { + console.error(e); + return `${i18n('Upload Failed')}: ${e.message}`; + }); + return null; + }, + }, ...this.options, after: () => { const pos = $(ele).find('button[data-mode="sv"]').get(); diff --git a/packages/ui-default/pages/problem_edit.page.js b/packages/ui-default/pages/problem_edit.page.js index b60ca9cf..ec97f392 100644 --- a/packages/ui-default/pages/problem_edit.page.js +++ b/packages/ui-default/pages/problem_edit.page.js @@ -173,7 +173,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => { setInterval(() => { $('img').each(function () { if (this.src.startsWith('file://')) { - this.setAttribute('src', this.src.replace('file://', './file/').replace(/\/$/, '')); + $(this).attr('src', $(this).attr('src').replace('file://', (pagename === 'problem_create' ? `/file/${UserContext._id}/` : './file/'))); } }); }, 500); @@ -189,50 +189,6 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => { if (!isObject) content = JSON.stringify(content); } catch (e) { } if (!isObject) content = { [activeTab]: content }; - const upload = { - accept: 'image/*,.mp3, .wav, .zip', - url: './files', - extraData: { - type: 'additional_file', - operation: 'upload_file', - }, - multiple: false, - fieldName: 'file', - setHeaders() { - return { accept: 'application/json' }; - }, - format(files, resp) { - const res = JSON.parse(resp); - if (res.error) { - return JSON.stringify({ - msg: res.error.message, - code: -1, - data: { - errFiles: [files[0].name], - succMap: {}, - }, - }); - } - return JSON.stringify({ - msg: '', - code: 0, - data: { - errFiles: [], - succMap: { - [files[0].name]: `file://${files[0].name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5.)]/g, '') - .replace(/[?\\/:|<>*[\]()$%{}@~]/g, '') - .replace(/\s/g, '')}`, - }, - }, - }); - }, - filename(name) { - return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5.)]/g, '') - .replace(/[?\\/:|<>*[\]()$%{}@~]/g, '') - .replace(/\s/g, ''); - }, - validate: () => (pagename === 'problem_create' ? i18n('Cannot upload file before problem is created.') : true), - }; function getContent(lang) { let c = ''; if (content[lang]) c = content[lang]; @@ -255,7 +211,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => { if (!Object.keys(content).length) $field.text(''); else $field.text(JSON.stringify(content)); } - const editor = Editor.getOrConstruct($main, { upload, onChange }); + const editor = Editor.getOrConstruct($main, { onChange }); $('[data-lang]').on('click', (ev) => { $('[data-lang]').removeClass('tab--active'); $(ev.currentTarget).addClass('tab--active');