Skip to content

Commit

Permalink
feat: 增加上传文件格式限制,优化上传文件回调逻辑,增加视频封面功能 #328
Browse files Browse the repository at this point in the history
  • Loading branch information
sunsonliu committed Oct 18, 2022
1 parent ebb8881 commit dbf8788
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 41 deletions.
22 changes: 21 additions & 1 deletion src/Cherry.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ const callbacks = {
*/
urlProcessor: (url, srcType) => url,
fileUpload(file, callback) {
callback('images/demo-dog.png');
if (/video/i.test(file.type)) {
callback('images/demo-dog.png', {
name: `${file.name.replace(/\.[^.]+$/, '')}`,
poster: 'images/demo-dog.png?poster=true',
isBorder: true,
isShadow: true,
isRadius: true,
});
} else {
callback('images/demo-dog.png', { name: `${file.name.replace(/\.[^.]+$/, '')}`, isShadow: true });
}
},
afterChange: (text, html) => {},
afterInit: (text, html) => {},
Expand Down Expand Up @@ -228,6 +238,16 @@ const defaultConfig = {
float: ['h1', 'h2', 'h3', '|', 'checklist', 'quote', 'quickTable', 'code'], // array or false
},
fileUpload: callbacks.fileUpload,
/**
* 上传文件的时候用来指定文件类型
*/
fileTypeLimitMap: {
video: 'video/*',
audio: 'audio/*',
image: 'image/*',
word: '.doc,.docx',
pdf: '.pdf',
},
callback: {
afterChange: callbacks.afterChange,
afterInit: callbacks.afterInit,
Expand Down
23 changes: 18 additions & 5 deletions src/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import pasteHelper from '@/utils/pasteHelper';
import { addEvent } from './utils/event';
import Logger from '@/Logger';
import Event from '@/Event';
import { handelParams } from '@/utils/file';

/**
* @typedef {import('~types/editor').EditorConfiguration} EditorConfiguration
Expand Down Expand Up @@ -292,16 +293,28 @@ export default class Editor {
if (fileType === '' || /^text/i.test(fileType)) {
continue;
}
const defaultName = (file.name && file.name.replace(/\.[^.]+$/, '')) || 'enter description here';
const defaultIsImage = /^image/i.test(file.type);
this.options.fileUpload(file, (url, name = defaultName, isImage = defaultIsImage) => {
this.options.fileUpload(file, (url, params) => {
if (typeof url !== 'string') {
return;
}
// 拖拽上传文件时,强制改成没有文字选择区的状态
codemirror.setSelection(codemirror.getCursor());
let insertValue = isImage ? `![${name}](${url})` : `[${name}](${url})`;
insertValue = needBr ? `\n${insertValue}` : insertValue;
const name = params.name ? params.name : file.name;
let type = '';
let poster = '';
if (/video/i.test(file.type)) {
type = '!video';
poster = params.poster ? `{poster=${params.poster}}` : '';
}
if (/audio/i.test(file.type)) {
type = '!audio';
}
if (/image/i.test(file.type)) {
type = '!';
}
const style = type ? handelParams(params) : '';
type = needBr ? `\n${type}` : type;
const insertValue = `${type}[${name}${style}](${url})${poster}`;
// 当批量上传文件时,每个被插入的文件中间需要加个换行,但单个上传文件的时候不需要加换行
needBr = true;
codemirror.replaceSelection(insertValue);
Expand Down
1 change: 0 additions & 1 deletion src/toolbars/MenuBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export default class MenuBase {
* @param {*} $cherry
*/
constructor($cherry) {
/** @type {boolean} 是否浮动菜单*/
this.$cherry = $cherry;
this.bubbleMenu = false;
this.subMenu = null; // 子菜单实例
Expand Down
12 changes: 7 additions & 5 deletions src/toolbars/hooks/Audio.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/
import MenuBase from '@/toolbars/MenuBase';
import { handleUpload } from '@/utils/file';
import { handleUpload, handelParams } from '@/utils/file';
/**
* 插入音频
*/
Expand All @@ -32,17 +32,19 @@ export default class Audio extends MenuBase {
onClick(selection, shortKey = '') {
if (this.hasCacheOnce()) {
// @ts-ignore
const { name, url } = this.getAndCleanCacheOnce();
const { name, url, params } = this.getAndCleanCacheOnce();
const begin = '!audio[';
const end = `](${url})`;
this.registerAfterClickCb(() => {
this.setLessSelection(begin, end);
});
return `${begin}${name}${end}`;
const finalName = params.name ? params.name : name;
return `${begin}${finalName}${handelParams(params)}${end}`;
}
const accept = this.$cherry.options?.fileTypeLimitMap?.audio ?? '*';
// 插入图片,调用上传文件逻辑
handleUpload(this.editor, 'audio', (name, url) => {
this.setCacheOnce({ name, url });
handleUpload(this.editor, 'audio', accept, (name, url, params) => {
this.setCacheOnce({ name, url, params });
this.fire(null);
});
this.updateMarkdown = false;
Expand Down
12 changes: 7 additions & 5 deletions src/toolbars/hooks/Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/
import MenuBase from '@/toolbars/MenuBase';
import { handleUpload } from '@/utils/file';
import { handleUpload, handelParams } from '@/utils/file';
/**
* 插入图片
*/
Expand All @@ -32,17 +32,19 @@ export default class Image extends MenuBase {
onClick(selection, shortKey = '') {
if (this.hasCacheOnce()) {
// @ts-ignore
const { name, url } = this.getAndCleanCacheOnce();
const { name, url, params } = this.getAndCleanCacheOnce();
const begin = '![';
const end = `](${url})`;
this.registerAfterClickCb(() => {
this.setLessSelection(begin, end);
});
return `${begin}${name}${end}`;
const finalName = params.name ? params.name : name;
return `${begin}${finalName}${handelParams(params)}${end}`;
}
const accept = this.$cherry.options?.fileTypeLimitMap?.image ?? '*';
// 插入图片,调用上传文件逻辑
handleUpload(this.editor, 'image', (name, url) => {
this.setCacheOnce({ name, url });
handleUpload(this.editor, 'image', accept, (name, url, params) => {
this.setCacheOnce({ name, url, params });
this.fire(null);
});
this.updateMarkdown = false;
Expand Down
10 changes: 6 additions & 4 deletions src/toolbars/hooks/Pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ export default class Pdf extends MenuBase {
onClick(selection, shortKey = '') {
if (this.hasCacheOnce()) {
// @ts-ignore
const { name, url } = this.getAndCleanCacheOnce();
const { name, url, params } = this.getAndCleanCacheOnce();
const begin = '[';
const end = `](${url})`;
this.registerAfterClickCb(() => {
this.setLessSelection(begin, end);
});
return `${begin}${name}${end}`;
const finalName = params.name ? params.name : name;
return `${begin}${finalName}${end}`;
}
const accept = this.$cherry.options?.fileTypeLimitMap?.pdf ?? '*';
// 插入图片,调用上传文件逻辑
handleUpload(this.editor, 'pdf', (name, url) => {
this.setCacheOnce({ name, url });
handleUpload(this.editor, 'pdf', accept, (name, url, params) => {
this.setCacheOnce({ name, url, params });
this.fire(null);
});
this.updateMarkdown = false;
Expand Down
14 changes: 8 additions & 6 deletions src/toolbars/hooks/Video.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/
import MenuBase from '@/toolbars/MenuBase';
import { handleUpload } from '@/utils/file';
import { handleUpload, handelParams } from '@/utils/file';
/**
* 插入视频
*/
Expand All @@ -32,17 +32,19 @@ export default class Video extends MenuBase {
onClick(selection, shortKey = '') {
if (this.hasCacheOnce()) {
// @ts-ignore
const { name, url } = this.getAndCleanCacheOnce();
const { name, url, params } = this.getAndCleanCacheOnce();
const begin = '!video[';
const end = `](${url})`;
const end = params.poster ? `](${url}){poster=${params.poster}}` : `](${url})`;
this.registerAfterClickCb(() => {
this.setLessSelection(begin, end);
});
return `${begin}${name}${end}`;
const finalName = params.name ? params.name : name;
return `${begin}${finalName}${handelParams(params)}${end}`;
}
const accept = this.$cherry.options?.fileTypeLimitMap?.video ?? '*';
// 插入图片,调用上传文件逻辑
handleUpload(this.editor, 'video', (name, url) => {
this.setCacheOnce({ name, url });
handleUpload(this.editor, 'video', accept, (name, url, params) => {
this.setCacheOnce({ name, url, params });
this.fire(null);
});
this.updateMarkdown = false;
Expand Down
10 changes: 6 additions & 4 deletions src/toolbars/hooks/Word.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ export default class Word extends MenuBase {
onClick(selection, shortKey = '') {
if (this.hasCacheOnce()) {
// @ts-ignore
const { name, url } = this.getAndCleanCacheOnce();
const { name, url, params } = this.getAndCleanCacheOnce();
const begin = '[';
const end = `](${url})`;
this.registerAfterClickCb(() => {
this.setLessSelection(begin, end);
});
return `${begin}${name}${end}`;
const finalName = params.name ? params.name : name;
return `${begin}${finalName}${end}`;
}
const accept = this.$cherry.options?.fileTypeLimitMap?.word ?? '*';
// 插入图片,调用上传文件逻辑
handleUpload(this.editor, 'word', (name, url) => {
this.setCacheOnce({ name, url });
handleUpload(this.editor, 'word', accept, (name, url, params) => {
this.setCacheOnce({ name, url, params });
this.fire(null);
});
this.updateMarkdown = false;
Expand Down
49 changes: 40 additions & 9 deletions src/utils/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,27 @@
* 上传文件的逻辑,如果有callback,则不再走默认的替换文本的逻辑,而是调用callback
* @param {string} type 上传文件的类型
*/
export function handleUpload(editor, type = 'image', callback = null) {
export function handleUpload(editor, type = 'image', accept = '*', callback = null) {
// type为上传文件类型 image|video|audio|pdf|word
const input = document.createElement('input');
input.type = 'file';
input.id = 'fileUpload';
input.value = '';
input.style.display = 'none';
input.accept = accept;
// document.body.appendChild(input);
input.addEventListener('change', (event) => {
// @ts-ignore
const [file] = event.target.files;
// 文件上传后的回调函数可以由调用方自己实现
editor.options.fileUpload(file, (url) => {
editor.options.fileUpload(file, (url, params = {}) => {
// 文件上传的默认回调行数,调用方可以完全不使用该函数
if (typeof url !== 'string' || !url) {
return;
}
if (callback) {
return callback(file.name, url, params);
}
let code = '';
if (type === 'image') {
// 如果是图片,则返回固定的图片markdown源码
Expand All @@ -49,14 +53,41 @@ export function handleUpload(editor, type = 'image', callback = null) {
// 默认返回超链接
code = `[${file.name}](${url})`;
}
if (callback) {
callback(file.name, url);
} else {
// 替换选中区域
// @ts-ignore
editor.editor.doc.replaceSelection(code);
}
// 替换选中区域
// @ts-ignore
editor.editor.doc.replaceSelection(code);
});
});
input.click();
}

/**
* 解析params参数
* @param params?.isBorder 是否有边框样式(图片场景下生效)
* @param params?.isShadow 是否有阴影样式(图片场景下生效)
* @param params?.isRadius 是否有圆角样式(图片场景下生效)
* @param params?.width 设置宽度,可以是像素、也可以是百分比(图片、视频场景下生效)
* @param params?.height 设置高度,可以是像素、也可以是百分比(图片、视频场景下生效)
*/
export function handelParams(params) {
const ret = [];
if (params.isBorder) {
ret.push('#B');
}
if (params.isShadow) {
ret.push('#S');
}
if (params.isRadius) {
ret.push('#R');
}
if (params.width) {
ret.push(`#${params.width}`);
}
if (params.height) {
if (!params.width) {
ret.push('#auto');
}
ret.push(`#${params.height}`);
}
return ret.join(' ');
}
21 changes: 20 additions & 1 deletion types/cherry.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ export interface CherryOptions {
toolbars: CherryToolbarOptions;
/** 文件上传回调 */
fileUpload: CherryFileUploadHandler;
/** 上传文件的时候用来指定文件类型 */
fileTypeLimitMap: {
video: string,
audio: string,
image: string,
word: string,
pdf: string,
};
callback: {
/** 编辑器内容改变并完成渲染后触发 */
afterChange: CherryLifecycle;
Expand Down Expand Up @@ -216,5 +224,16 @@ export interface CherryFileUploadHandler {
* @param file 用户上传的文件对象
* @param callback 回调函数,接收最终的文件url
*/
(file: File, callback: (url: string) => void): void;
(file: File,
/**
* @param params.name 回填的alt信息
* @param params.poster 封面图片地址(视频的场景下生效)
* @param params.isBorder 是否有边框样式(图片场景下生效)
* @param params.isShadow 是否有阴影样式(图片场景下生效)
* @param params.isRadius 是否有圆角样式(图片场景下生效)
* @param params.width 设置宽度,可以是像素、也可以是百分比(图片、视频场景下生效)
* @param params.height 设置高度,可以是像素、也可以是百分比(图片、视频场景下生效)
*/
callback: (url: string, params?: {name?: string, poster?: string, isBorder?: boolean, isShadow?: boolean, isRadius?: boolean; width?: string, height?: string}
) => void): void;
}

0 comments on commit dbf8788

Please sign in to comment.