@opentiny/vue-renderless
Version:
An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.
701 lines (700 loc) • 26 kB
JavaScript
import "../chunk-G2ADBYYC.js";
import { extend } from "@opentiny/utils";
import { isNull } from "@opentiny/utils";
import { xss } from "@opentiny/utils";
import { set } from "../chart-core/deps/utils";
import { on, off } from "@opentiny/utils";
import { PopupManager } from "@opentiny/utils";
const init = ({
api,
emit,
props,
service,
state,
FluentEditor,
UploaderDfls,
defaultOptions,
vm,
useBreakpoint,
simpleToolbar
}) => () => {
var _a;
UploaderDfls.enableMultiUpload = { file: true, image: true };
UploaderDfls.handler = api.uploaderDflsHandler;
UploaderDfls.imagePasteFailCallback = props.imagePasteFailCallback;
defaultOptions.modules.toolbar.handlers = api.handlers();
state.innerOptions = extend(true, {}, defaultOptions, props.globalOptions, props.options);
if (props.imageUpload) {
state.innerOptions.imageUpload = props.imageUpload;
} else {
state.innerOptions.uploadOption.imageUploadToServer = false;
}
if (props.fileUpload) {
state.innerOptions.fileUpload = extend(
true,
{},
{ httpRequest: service && service.network.request },
props.fileUpload,
{ url: xss.filterUrl(state.fileUploadUrl) }
);
}
api.setToolbarTips();
const { current } = useBreakpoint();
if (current.value === "default") {
state.innerOptions.modules.toolbar = simpleToolbar;
}
(_a = props.beforeEditorInit) == null ? void 0 : _a.call(props, FluentEditor);
const quill = new FluentEditor(vm.$refs.editor, state.innerOptions);
quill.emitter.on("file-change", api.fileOperationToSev);
state.quill = Object.freeze(quill);
setTimeout(api.setToolbarTitle);
let insertTableButton = vm.$el.querySelector(".ql-better-table");
const tableModule = state.quill.getModule("better-table");
insertTableButton && (insertTableButton.onclick = (event, row = 3, col = 3) => {
tableModule.insertTable(row, col);
});
let fullscreenButton = vm.$el.querySelector(".ql-fullscreen");
fullscreenButton && (fullscreenButton.onclick = api.keyDownHandler);
state.quill.enable(false);
state.quill.on("selection-change", api.selectionChange);
state.quill.on("text-change", api.textChange);
if (state.content) {
if (props.dataType) {
state.quill.setContents(api.stringToJson(state.content));
} else {
let temp = xss.filterHtml(state.content);
state.quill.clipboard.dangerouslyPasteHTML(temp);
}
api.textChange();
}
if (!props.disabled) {
state.quill.enable(true);
}
api.handleComposition();
emit("ready", state.quill);
};
const checkTableISEndElement = (element) => {
if (element.children.length > 1) {
return checkTableISEndElement(element.children[element.children.length - 1]);
} else {
return element.children[0] instanceof HTMLTableElement;
}
};
const isSvg = (str) => {
return str.trim().startsWith("<svg");
};
const setIcons = ({ api, vm, iconOption, FluentEditor, keys = [] }) => {
var _a;
for (const key in iconOption) {
if (Object.hasOwnProperty.call(iconOption, key)) {
const option = iconOption[key];
if (typeof option === "object") {
setIcons({ api, vm, iconOption: option, FluentEditor, keys: [...keys, key] });
} else {
const outerHtml = isSvg(option) ? option : api.getOuterHTML((_a = vm.$refs[option]) == null ? void 0 : _a[0]);
if (option && outerHtml) {
const k = keys.length ? [...keys, key].join(".") : key;
set(FluentEditor.imports["ui/icons"], k.replace(/default/, ""), outerHtml);
}
}
}
}
};
const setToolbarTips = ({ api, vm, FluentEditor, iconOption }) => () => {
setIcons({ api, vm, iconOption, FluentEditor });
};
const getOuterHTML = () => (el) => el && el.outerHTML;
const keyDownHandler = ({ state }) => (e) => {
if (e.keyCode) {
if (e.keyCode === 27 && state.isFullscreen) {
state.isFullscreen = !state.isFullscreen;
}
} else {
state.isFullscreen = !state.isFullscreen;
}
};
const addFullscreenchange = ({ api }) => () => {
on(document, "keydown", api.keyDownHandler);
};
const removeFullscreenchange = ({ api }) => () => {
off(document, "keydown", api.keyDownHandler);
api.keyDownHandler = null;
};
const handleComposition = ({ state, api }) => () => {
on(state.quill.root, "compositionstart", api.handleCompositionstart);
on(state.quill.root, "compositionend", api.handleCompositionend);
};
const removeHandleComposition = ({ state, api }) => () => {
off(state.quill.root, "compositionstart", api.handleCompositionstart);
off(state.quill.root, "compositionend", api.handleCompositionend);
};
const handleCompositionstart = ({ state }) => () => {
state.quill.root.classList.remove("ql-blank");
};
const handleCompositionend = ({ state }) => (event) => {
if (state.quill.editor.isBlank()) {
if (state.quill.getLength() > 0 && event.data.length > 0) {
let data = event.data;
state.quill.setContents([{ insert: data }]);
state.quill.setSelection(data.length);
state.quill.root.classList.remove("ql-blank");
} else {
state.quill.root.classList.add("ql-blank");
}
} else {
let data = state.quill.container.innerHTML;
let range = state.quill.getSelection(true);
const [mentionItem, offset] = state.quill.getLeaf(range.index);
if (mentionItem.statics.blotName === "break") {
state.quill.clipboard.dangerouslyPasteHTML(data);
state.quill.setSelection(range.index + event.data.length);
} else {
let pattern = /[\u4E00-\u9FA5\uF900-\uFA2D]/;
let flag;
if (pattern.test(event.data)) {
flag = true;
}
if (flag) {
state.quill.setSelection(range.index);
} else {
if (offset !== 0) {
state.quill.setSelection(range.index);
} else {
if (event.data.length > 1) {
state.quill.setSelection(range.index + 1);
} else {
state.quill.setSelection(range.index);
}
}
}
}
state.quill.root.classList.remove("ql-blank");
}
};
const undoHandler = ({ state }) => () => {
const betterTableModule = state.quill.getModule("better-table");
if (betterTableModule && betterTableModule.table) {
betterTableModule.hideTableTools();
}
state.quill.history.undo();
};
const redoHandler = ({ state }) => () => {
const betterTableModule = state.quill.getModule("better-table");
if (betterTableModule && betterTableModule.table) {
betterTableModule.hideTableTools();
}
state.quill.history.redo();
};
const lineheightHandler = ({ state, FluentEditor }) => (value) => {
state.quill.format("lineheight", value, FluentEditor.sources.USER);
};
const fileHandler = ({ api, state }) => () => {
const option = state.quill.options.uploadOption;
const accept = option && option.fileAccept;
api.inputFileHandler("file", accept);
};
const imageHandler = ({ api, state }) => () => {
const option = state.quill.options.uploadOption;
const accept = option && option.imageAccept;
api.inputFileHandler("image", accept);
};
const inputFileHandler = ({ state, UploaderDfls }) => (type, accept) => {
const defaultMIMETypes = state.quill.uploader.options[type].join(", ");
const mimeTypes = accept || defaultMIMETypes;
const betterToolbar = state.quill.getModule("toolbar");
let fileInput = betterToolbar.container.querySelector(`input.ql-${type}[type=file]`);
if (isNull(fileInput)) {
fileInput = document.createElement("input");
fileInput.classList.add(`ql-${type}`);
fileInput.setAttribute("type", "file");
fileInput.setAttribute("accept", mimeTypes);
if (UploaderDfls.enableMultiUpload.file && type === "file" || UploaderDfls.enableMultiUpload.image && type === "image") {
fileInput.setAttribute("multiple", "");
}
fileInput.onchange = () => {
const range = state.quill.getSelection(true);
state.quill.uploader.upload(range, fileInput.files, type === "file");
fileInput.value = "";
};
betterToolbar.container.appendChild(fileInput);
}
fileInput.click();
};
const uploaderDflsHandler = ({ api, modules }) => (range, files, fileFlags, rejectFlags) => {
const fileArr = [];
const imgArr = [];
files.forEach((file, index) => fileFlags[index] ? fileArr.push(file) : imgArr.push(file));
if (modules.file && (fileArr.length || rejectFlags.file)) {
api.handleUploadFile(range, fileArr, rejectFlags.file);
}
if (imgArr.length || rejectFlags.image) {
api.handleUploadImage(range, { file: imgArr[0], files: imgArr }, rejectFlags.image);
}
};
const handleUploadFile = ({ api, UploaderDfls }) => (range, files, hasRejectedFile) => {
const fileEnableMultiUpload = UploaderDfls.enableMultiUpload === true || UploaderDfls.enableMultiUpload.file;
api.fileOperationToSev({
operation: "upload",
data: fileEnableMultiUpload ? { files } : { file: files[0] },
hasRejectedFile,
callback: (res) => {
if (!res) {
return;
}
if (fileEnableMultiUpload && Array.isArray(res)) {
res.forEach((value, index) => api.insertFileToEditor(range, files[index], value));
} else {
api.insertFileToEditor(range, files[0], res);
}
}
});
};
const getOption = (url, headers, method, fd, callbackOK, callbackKO, callback) => {
url = xss.filterUrl(url);
return {
url,
headers,
method,
data: fd,
onSuccess(res) {
res = res.data;
let resData = {};
for (let key in res) {
resData = res[key];
break;
}
callbackOK(res, ({ name, url: url2 }) => {
callback({
data: {
id: resData.attachmentId,
size: resData.fileSize,
title: name,
src: url2
}
});
});
},
onError(error) {
callbackKO(error);
}
};
};
const getOnloadOfFileOperToSev = ({ xmlhr, callbackOK, callback, callbackKO }) => () => {
if (xmlhr.status === 200) {
let res = JSON.parse(xmlhr.responseText);
let resData = {};
for (let key in res) {
resData = res[key];
break;
}
callbackOK(res, ({ name, url }) => {
callback({ data: { id: resData.attachmentId, size: resData.fileSize, title: name, src: url } });
});
} else {
callbackKO({ code: xmlhr.status, type: xmlhr.statusText, body: xmlhr.responseText });
}
};
const fileOperationToSev = ({ state }) => (event) => {
const { operation, hasRejectedFile, callback } = event;
const { files, fileDownloadUrl } = event.data;
switch (operation) {
case "upload": {
if (hasRejectedFile || !files || !files.length) {
return;
}
const options = state.innerOptions.fileUpload;
let { url, method = "POST", name = "file", headers = {} } = options;
let { success: callbackOK, fail: callbackKO } = options;
url = xss.filterUrl(url);
if (!url) {
return;
}
let fd = new FormData();
fd.append(name, files[0], files[0].name);
options.csrf && fd.append(options.csrf.token, options.csrf.hash);
if (options.httpRequest) {
let reqOptions = getOption(url, headers, method, fd, callbackOK, callbackKO, callback);
let req = options.httpRequest(reqOptions);
req && req.then && req.then(reqOptions.onSuccess, reqOptions.onError);
} else {
let xmlhr = new XMLHttpRequest();
xmlhr.withCredentials = options.withCredentials !== false;
xmlhr.open(method, url, true);
for (let index in headers) {
xmlhr.setRequestHeader(index, headers[index]);
}
xmlhr.onload = getOnloadOfFileOperToSev({ xmlhr, callbackOK, callback, callbackKO });
xmlhr.send(fd);
}
break;
}
case "download":
window.open(xss.filterUrl(fileDownloadUrl)).opener = null;
break;
default: {
break;
}
}
};
const handleUploadImage = ({ state, api, FluentEditor, Delta, UploaderDfls }) => (range, { file, files }, hasRejectedImage) => {
if (state.quill.options.uploadOption.imageUploadToServer) {
const index = state.promisesData.length;
const imageEnableMultiUpload = UploaderDfls.enableMultiUpload.image;
const result = {
file,
data: { files: [file] },
hasRejectedImage,
callback: (res) => {
if (!res) {
return;
}
state.cbNum += 1;
state.promisesData[index].range = range;
state.promisesData[index].imgUrlData = res;
if (state.cbNum === state.promises.length) {
Promise.all(state.promises).then((arr) => {
arr.forEach((data, index2) => {
const { imageEnableMultiUpload: imageEnableMultiUpload2, imgUrlData, range: range2 } = state.promisesData[index2];
if (imgUrlData) {
if (imageEnableMultiUpload2 && Array.isArray(imgUrlData)) {
imgUrlData.forEach(function(value) {
return api.insertImageToEditor(range2, value);
});
} else {
api.insertImageToEditor(range2, imgUrlData);
}
}
});
state.promises = [];
state.promisesData = [];
state.cbNum = 0;
});
}
}
};
if (imageEnableMultiUpload) {
result.data = { files };
}
state.promisesData.push({
imageEnableMultiUpload
});
state.promises.push(api.uploadImageToSev(result));
} else {
const promises = files.map((fileItem) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result);
};
reader.readAsDataURL(fileItem);
});
});
Promise.all(promises).then((images) => {
const update = images.reduce((delta, image) => {
return delta.insert({ image });
}, new Delta().retain(range.index).delete(range.length));
state.quill.updateContents(update, FluentEditor.sources.USER);
state.quill.setSelection(range.index + images.length, FluentEditor.sources.SILENT);
});
}
};
const insertFileToEditor = ({ state, FluentEditor, Delta }) => (range, file, { data }) => {
const oldContent = new Delta().retain(range.index).delete(range.length);
const videoFlag = state.quill.options.uploadOption && state.quill.options.uploadOption.isVideoPlay && /^video\/[-\w.]+$/.test(file.type);
const insertObj = videoFlag ? { video: data } : { file: data };
const currentContent = new Delta([{ insert: insertObj }]);
const newContent = oldContent.concat(currentContent);
state.quill.updateContents(newContent, FluentEditor.sources.USER);
};
const insertImageToEditor = ({ state, FluentEditor, Delta }) => (range, { data }) => {
const { imageId, imageUrl } = data;
const oldContent = new Delta().retain(range.index).delete(range.length);
const currentContent = new Delta([
{
insert: { image: xss.filterUrl(imageUrl) },
attributes: { "image-id": imageId }
}
]);
const newContent = oldContent.concat(currentContent);
state.quill.updateContents(newContent, FluentEditor.sources.USER);
};
const uploadImageToSev = ({ state }) => (event) => {
const { file, hasRejectedImage, callback } = event;
const { files } = event.data;
if (hasRejectedImage) {
return;
}
if (!files || !files.length) {
return;
}
const options = state.innerOptions.imageUpload;
let { url, method = "POST", name = "image", headers = {} } = options;
let { success: callbackOK, fail: callbackKO } = options;
url = xss.filterUrl(url);
if (!url) {
return;
}
let { fd = new FormData(), xhr = new XMLHttpRequest() } = {};
fd.append(name, file, file.name);
options.csrf && fd.append(options.csrf.token, options.csrf.hash);
xhr.withCredentials = options.withCredentials !== false;
xhr.open(method, url, true);
for (let index in headers) {
xhr.setRequestHeader(index, headers[index]);
}
xhr.onload = () => {
if (xhr.status === 200) {
let { res = JSON.parse(xhr.responseText), resData = {} } = {};
for (let key in res) {
resData = res[key];
break;
}
callbackOK(res, (imageUrl) => {
callback({ data: { imageId: resData.attachmentId, imageUrl } });
});
} else {
callbackKO({ code: xhr.status, type: xhr.statusText, body: xhr.responseText });
}
};
xhr.send(fd);
};
const handlers = ({ api }) => () => {
return {
undo: api.undoHandler,
redo: api.redoHandler,
lineheight: api.lineheightHandler,
file: api.fileHandler,
image: api.imageHandler,
inputFile: api.inputFileHandler
};
};
const getFileUploadUrl = ({ service }) => () => {
return service ? service.common.getFileUploadUrl() : Promise.resolve("");
};
const selectionChange = ({ state, emit }) => (range) => {
if (!range) {
emit("blur", state.quill);
} else {
emit("focus", state.quill);
}
};
const stringToJson = () => (str) => {
let contents = "";
try {
contents = JSON.parse(str);
} catch (e) {
contents = {};
}
return contents;
};
const initContent = ({ state, props, api, nextTick }) => () => {
if (state.quill) {
const flag = state.quill.selection.hasFocus();
if (state.content && state.content !== state.innerContent) {
state.innerContent = state.content;
if (props.dataType) {
state.quill.setContents(api.stringToJson(state.content));
} else {
state.quill.clipboard.dangerouslyPasteHTML(xss.filterHtml(state.content));
}
} else if (!state.content) {
state.quill.setText("");
}
nextTick(() => {
if (!props.disabled) {
state.quill.enable(true);
}
flag ? state.quill.selection.focus() : state.quill.blur();
});
}
};
const textChange = ({ emit, vm, state, props }) => () => {
let contents = "";
const quill = state.quill;
const text = state.quill.getText();
if (props.dataType || props.dataUpgrade) {
contents = JSON.stringify(state.quill.getContents());
if (contents === '{"ops":[{"insert":"\\n"}]}') {
contents = "";
}
} else {
contents = xss.filterHtml(vm.$refs.editor.children[0].innerHTML);
if (contents === "<p><br></p>" || contents === "<p><img></p>") {
contents = "";
}
}
state.innerContent = contents;
emit("update:modelValue", contents);
emit("change", { contents, text, quill });
};
const mounted = ({ api, props, state }) => () => {
if (props.fileUpload && !props.fileUpload.url) {
api.getFileUploadUrl().then((url) => {
url = xss.filterUrl(url);
state.fileUploadUrl = url;
api.init();
});
} else {
api.init();
}
api.addFullscreenchange();
};
const beforeUnmount = ({ state, api, vm }) => () => {
const toolbar = state.quill.getModule("toolbar");
state.quill.uploader.options && (state.quill.uploader.options.handler = null);
state.quill.uploader.options && (state.quill.uploader.options.imagePasteFailCallback = null);
toolbar.options && (toolbar.options.handlers = null);
toolbar.handlers = null;
state.quill.emitter.off("file-change", api.fileOperationToSev);
if (state.quill.options.imageUpload) {
state.quill.options.imageUpload.fail = null;
state.quill.options.imageUpload.success = null;
}
if (state.quill.options.fileUpload) {
state.quill.options.fileUpload.fail = null;
state.quill.options.fileUpload.success = null;
}
const fileInput = toolbar.container.querySelector(`input.ql-file[type=file]`);
const imageInput = toolbar.container.querySelector(`input.ql-image[type=file]`);
let insertTableButton = vm.$el.querySelector(".ql-better-table");
let fullscreenButton = vm.$el.querySelector(".ql-fullscreen");
fileInput && (fileInput.onchange = null);
imageInput && (imageInput.onchange = null);
insertTableButton && (insertTableButton.onclick = null);
fullscreenButton && (fullscreenButton.onclick = null);
api.removeFullscreenchange();
api.removeHandleComposition();
state.quill.off("selection-change", api.selectionChange);
state.quill.off("text-change", api.textChange);
state.quill = null;
delete state.quill;
};
const computePreviewOptions = ({ props, state, constants, api }) => () => {
if (props.picPreview && state.previewImgUrl) {
let previewOptions = typeof props.picPreview === "boolean" ? constants.PIC_PREVIEW_OPTIONS : props.picPreview;
previewOptions = extend(true, {}, previewOptions, {
urlList: [state.previewImgUrl]
});
let onClose = previewOptions.onClose;
if (typeof onClose !== "function") {
previewOptions.onClose = () => {
api.doPreview();
};
} else {
previewOptions.onClose = (...args) => {
onClose(...args);
api.doPreview();
};
}
return previewOptions;
}
return {};
};
const doPreview = ({ props, state, nextTick }) => (elem) => {
state.showPreview = false;
state.previewImgUrl = elem && elem.nodeType ? elem.dataset.image || elem.src : "";
state.previewImgUrl = /^data:image\/.{2,8};base64,\//.test(state.previewImgUrl) ? state.previewImgUrl : xss.filterUrl(state.previewImgUrl);
if (props.picPreview && state.previewImgUrl) {
nextTick(() => {
state.showPreview = true;
});
}
};
const handleDblclick = ({ props, api }) => (e) => {
if (props.picPreview && e && e.type === "dblclick" && [...e.target.classList].includes("blot-formatter__overlay") && e.target.dataset.image) {
api.doPreview(e.target);
}
};
const getToolbarTitle = (t) => {
return [
{ selector: ".ql-undo", title: t("ui.fluentEditor.undo") },
{ selector: ".ql-redo", title: t("ui.fluentEditor.redo") },
{ selector: ".ql-clean", title: t("ui.richText.clean") },
{ selector: ".ql-font", title: t("ui.richText.font") },
{ selector: ".ql-size", title: t("ui.richText.size") },
{ selector: ".ql-lineheight", title: t("ui.fluentEditor.lineheight") },
{ selector: ".ql-header.ql-picker", title: t("ui.richText.pickerLabel") },
{ selector: '.ql-header .ql-picker-item[data-value="1"]', title: t("ui.richText.headerPicker1") },
{ selector: '.ql-header .ql-picker-item[data-value="2"]', title: t("ui.richText.headerPicker2") },
{ selector: '.ql-header .ql-picker-item[data-value="3"]', title: t("ui.richText.headerPicker3") },
{ selector: '.ql-header .ql-picker-item[data-value="4"]', title: t("ui.richText.headerPicker4") },
{ selector: '.ql-header .ql-picker-item[data-value="5"]', title: t("ui.richText.headerPicker5") },
{ selector: '.ql-header .ql-picker-item[data-value="6"]', title: t("ui.richText.headerPicker6") },
{ selector: ".ql-header .ql-picker-item:not([data-value])", title: t("ui.richText.normal") },
{ selector: ".ql-bold", title: t("ui.richText.bold") },
{ selector: ".ql-italic", title: t("ui.richText.italic") },
{ selector: ".ql-underline", title: t("ui.richText.underline") },
{ selector: ".ql-strike", title: t("ui.richText.strike") },
{ selector: ".ql-blockquote", title: t("ui.richText.blockquote") },
{ selector: ".ql-code-block", title: t("ui.richText.codeBlock") },
{ selector: '.ql-header[value="1"]', title: t("ui.richText.header1") },
{ selector: '.ql-header[value="2"]', title: t("ui.richText.header2") },
{ selector: '.ql-list[value="ordered"]', title: t("ui.richText.listOrdered") },
{ selector: '.ql-list[value="bullet"]', title: t("ui.richText.listBullet") },
{ selector: '.ql-script[value="sub"]', title: t("ui.richText.subScript") },
{ selector: '.ql-script[value="super"]', title: t("ui.richText.superScript") },
{ selector: '.ql-indent[value="-1"]', title: t("ui.richText.indent1") },
{ selector: '.ql-indent[value="+1"]', title: t("ui.richText.indent2") },
{ selector: '.ql-direction[value="rtl"]', title: t("ui.richText.directionRTL") },
{ selector: ".ql-color", title: t("ui.richText.color") },
{ selector: ".ql-background", title: t("ui.richText.background") },
{ selector: ".ql-align", title: t("ui.richText.align") },
{ selector: ".ql-align .ql-picker-item", title: t("ui.richText.alignPicker1") },
{ selector: '.ql-align .ql-picker-item[data-value="center"]', title: t("ui.richText.alignPicker2") },
{ selector: '.ql-align .ql-picker-item[data-value="right"]', title: t("ui.richText.alignPicker3") },
{ selector: ".ql-link", title: t("ui.richText.link") },
{ selector: ".ql-image", title: t("ui.richText.image") },
{ selector: ".ql-video", title: t("ui.richText.video") },
{ selector: ".ql-file", title: t("ui.richText.file") },
{ selector: ".ql-better-table", title: t("ui.richText.betterTable") },
{ selector: ".ql-fullscreen", title: t("ui.richText.fullscreen") }
];
};
const setToolbarTitle = ({ state, t }) => () => {
const tips = getToolbarTitle(t);
const container = state.quill.container.parentNode;
for (let i = 0, l = tips.length; i < l; i++) {
const targetDom = container.querySelector(`.ql-formats ${tips[i].selector}`);
targetDom && targetDom.setAttribute("title", tips[i].title);
}
};
const computeZIndex = ({ constants, props }) => () => props.zIndex === constants.EDITOR_FULLSCREEN_OPTIONS || props.zIndex < 1 ? PopupManager.nextZIndex() : props.zIndex;
export {
addFullscreenchange,
beforeUnmount,
checkTableISEndElement,
computePreviewOptions,
computeZIndex,
doPreview,
fileHandler,
fileOperationToSev,
getFileUploadUrl,
getOuterHTML,
handleComposition,
handleCompositionend,
handleCompositionstart,
handleDblclick,
handleUploadFile,
handleUploadImage,
handlers,
imageHandler,
init,
initContent,
inputFileHandler,
insertFileToEditor,
insertImageToEditor,
keyDownHandler,
lineheightHandler,
mounted,
redoHandler,
removeFullscreenchange,
removeHandleComposition,
selectionChange,
setToolbarTips,
setToolbarTitle,
stringToJson,
textChange,
undoHandler,
uploadImageToSev,
uploaderDflsHandler
};