UNPKG

quill-uploader

Version:

Quill custom Uploader, supports images, videos, and attachments, with customizable loading indicators.

163 lines (144 loc) 4.32 kB
import Quill from 'quill' import 'quill/dist/quill.snow.css' import CustomUploader from '../src/index' import attachmentIcon from 'quill/assets/icons/attachment.svg?raw' // replace iframe video to native video tag import Video from 'quill-formats-video' // import { randomString } from '../src/util.js' Quill.register(Video, true) Quill.register('modules/customUploader', CustomUploader) const Icons = Quill.import('ui/icons') Icons.attachment = attachmentIcon // support blob protocol for demo Video.PROTOCOL_WHITELIST.push('blob') const Link = Quill.import('formats/link') Link.PROTOCOL_WHITELIST.push('blob') const Image = Quill.import('formats/image') Image.sanitize = url => url const demoEditor = new Quill('#editor', { theme: 'snow', modules: { toolbar: { container: [ ['bold', 'italic', 'underline', 'strike', { align: [] }, { color: [] }], [{ list: 'ordered' }, { list: 'bullet' }], ['link', 'image', 'video', 'attachment'] ], handlers: { // 必须有值才能绑定事件 attachment: true } }, uploader: { // call customUploader handler (range, files) { return this.quill.customUploader?.uploadFiles(range, files) } }, customUploader: { // handle files key, thumb /* handler: async (files) => { const fileList = [] for (let i = 0; i < files.length; i++) { const f = files[i] // f.key = await calcHash(f) f.key = randomString() fileList.push(f) } return fileList }, */ // Wait for all files to be uploaded // upload: uploadAllSettled, // Callback after each file upload upload: uploadCallback } } }) // callback event demoEditor.on(CustomUploader.Events.start, files => { console.warn('upload-start', files) }) demoEditor.on(CustomUploader.Events.done, results => { console.warn('upload-done', results) }) // wait for all files async function uploadAllSettled (_range, files) { const results = await Promise.allSettled(files.map((f, i) => waitUpload(f, i))) return results.map(item => { if (item.status === 'fulfilled') { return getFileResult(item.value) } else { return { key: item.file?.key, error: item.reason.message } } }) } // each file callback async function uploadCallback (_range, files, callback) { await Promise.allSettled(files.map(async (f, i) => { try { const res = await waitUpload(f, i) callback(null, getFileResult(res)) } catch (e) { callback(e, f) } })) } function waitUpload (file, i) { return new Promise((resolve, reject) => { const t = (i + 1) * 1000 /* const type = file.type.split('/')[0] // reject attachment if (!['image', 'video'].includes(type)) { setTimeout(() => { const error = new Error('test error') error.file = file reject(error) }, t) return } */ // resolve // const t = (Math.random() * 5 + 2) * 1000 file.url = URL.createObjectURL(file) setTimeout(() => resolve(file), t) }) } // result to customUploader function getFileResult (file) { return { type: file.type, name: file.name, key: file.key, url: file.url } } // demo const $result = document.querySelector('#result') $result.value = `Quill V${Quill.version}` document.querySelector('.btn-html').addEventListener('click', function () { $result.value = demoEditor.getSemanticHTML() }) document.querySelector('.btn-content').addEventListener('click', function () { const result = demoEditor.getContents() $result.value = JSON.stringify(result) }) document.querySelector('.btn-text').addEventListener('click', function () { $result.value = demoEditor.getText() }) document.querySelector('.btn-undo').addEventListener('click', function () { demoEditor.history.undo() }) document.querySelector('.btn-redo').addEventListener('click', function () { demoEditor.history.redo() }) document.querySelector('.btn-insert').addEventListener('click', function () { demoEditor.customUploader.insertToEditor({ key: String(Math.random()), type: 'text/plain', name: String(Math.random()), url: `http://test.com/${Math.random()}` }) }) window.editor = demoEditor