|
@@ -0,0 +1,281 @@
|
|
|
|
+import { insertTagToEditor } from "./utils";
|
|
|
|
+// import { randomCode } from "../../utils/utils";
|
|
|
|
+
|
|
|
|
+let _this = null;
|
|
|
|
+
|
|
|
|
+export function dataUrlToBlob(base64Buf) {
|
|
|
|
+ console.log(base64Buf);
|
|
|
|
+ const bufs = base64Buf.split(".");
|
|
|
|
+ const mime = bufs[0].match(/:(.*?);/)[1];
|
|
|
|
+ const bstr = window.atob(bufs[1]);
|
|
|
|
+ const len = bstr.length;
|
|
|
|
+ const u8arr = new Uint8Array(len);
|
|
|
|
+ for (let i = 0; i < len; i++) {
|
|
|
|
+ u8arr[i] = bstr.charCodeAt(i);
|
|
|
|
+ }
|
|
|
|
+ return new Blob([u8arr], { type: mime });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function fileToBase64(file) {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ const reader = new FileReader();
|
|
|
|
+ reader.readAsDataURL(file);
|
|
|
|
+ reader.onload = () => resolve(reader.result);
|
|
|
|
+ reader.onerror = (error) => reject(error);
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getDataUrlFromImageUrl(url) {
|
|
|
|
+ const img = new Image();
|
|
|
|
+ img.setAttribute("crossorigin", "anonymous");
|
|
|
|
+ img.src = url;
|
|
|
|
+
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ const canvas = document.createElement("canvas");
|
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
|
+ canvas.width = img.width;
|
|
|
|
+ canvas.height = img.height;
|
|
|
|
+ // console.dir(img);
|
|
|
|
+ img.onload = function () {
|
|
|
|
+ ctx.drawImage(img, 0, 0);
|
|
|
|
+ resolve(canvas.toDataURL("image/png"));
|
|
|
|
+ };
|
|
|
|
+ img.onerror = function (err) {
|
|
|
|
+ reject(err);
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function dataItemGetAsString(dataTransferItem) {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ try {
|
|
|
|
+ dataTransferItem.getAsString((s) => {
|
|
|
|
+ resolve(s);
|
|
|
|
+ });
|
|
|
|
+ } catch (error) {
|
|
|
|
+ reject(error);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// function checkHtmlIsFromOffice(htmlDom) {
|
|
|
|
+// const meta = htmlDom.querySelector("meta[name='Originator']");
|
|
|
|
+// return meta && meta.getAttribute("content").includes("Microsoft Word");
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+function checkDomIsBlock(dom) {
|
|
|
|
+ if (dom.nodeType === Node.ELEMENT_NODE) {
|
|
|
|
+ const disPlay = window.getComputedStyle(dom).display;
|
|
|
|
+ if (disPlay) {
|
|
|
|
+ return disPlay === "block";
|
|
|
|
+ } else {
|
|
|
|
+ const blockDomNames = [
|
|
|
|
+ "div",
|
|
|
|
+ "p",
|
|
|
|
+ "h1",
|
|
|
|
+ "h2",
|
|
|
|
+ "h3",
|
|
|
|
+ "h4",
|
|
|
|
+ "h5",
|
|
|
|
+ "h6",
|
|
|
|
+ "ul",
|
|
|
|
+ "ol",
|
|
|
|
+ "table",
|
|
|
|
+ "tr",
|
|
|
|
+ ];
|
|
|
|
+ return blockDomNames.includes(dom.tagName.toLowerCase());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function checkDomHasTextContent(content) {
|
|
|
|
+ let cont = content.replace(/\n/g, "");
|
|
|
|
+ return !!cont;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function checkDomIsUnvalid(dom) {
|
|
|
|
+ const unvalidFunc = [
|
|
|
|
+ (node) =>
|
|
|
|
+ node.tagName &&
|
|
|
|
+ ["meta", "link", "script", "style", "title"].includes(
|
|
|
|
+ node.tagName.toLowerCase()
|
|
|
|
+ ),
|
|
|
|
+ (node) => node.nodeType === Node.COMMENT_NODE,
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ return unvalidFunc.some((unfunc) => unfunc(dom));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getHtmlValidDom(htmlDom, checkBlock) {
|
|
|
|
+ let doms = [];
|
|
|
|
+ let curBlockDoms = [];
|
|
|
|
+
|
|
|
|
+ const findDom = (nodeList) => {
|
|
|
|
+ nodeList.forEach((node) => {
|
|
|
|
+ if (checkDomIsUnvalid(node)) return;
|
|
|
|
+
|
|
|
|
+ if (checkBlock && checkDomIsBlock(node) && curBlockDoms.length) {
|
|
|
|
+ doms.push(curBlockDoms);
|
|
|
|
+ curBlockDoms = [];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (node.childNodes.length) {
|
|
|
|
+ findDom(node.childNodes);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (
|
|
|
|
+ (node.tagName && node.tagName.toLowerCase() === "img") ||
|
|
|
|
+ (node.nodeType === Node.TEXT_NODE &&
|
|
|
|
+ checkDomHasTextContent(node.textContent))
|
|
|
|
+ ) {
|
|
|
|
+ curBlockDoms.push(node);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ findDom(htmlDom.childNodes);
|
|
|
|
+
|
|
|
|
+ if (curBlockDoms.length) {
|
|
|
|
+ doms.push(curBlockDoms);
|
|
|
|
+ curBlockDoms = [];
|
|
|
|
+ }
|
|
|
|
+ console.log(doms);
|
|
|
|
+ return doms;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// function getOfficeHtmlValidDom(htmlDom) {
|
|
|
|
+// let doms = [];
|
|
|
|
+// htmlDom.querySelectorAll("p").forEach((pDom) => {
|
|
|
|
+// const elems = getHtmlValidDom(pDom, false);
|
|
|
|
+// if (elems.length) doms.push(...elems);
|
|
|
|
+// });
|
|
|
|
+// return doms;
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+async function pasteHtmlItem(htmlItem) {
|
|
|
|
+ const cont = await dataItemGetAsString(htmlItem).catch((e) => {
|
|
|
|
+ console.log(e);
|
|
|
|
+ });
|
|
|
|
+ if (!cont) return;
|
|
|
|
+
|
|
|
|
+ const divDom = document.createElement("div");
|
|
|
|
+ divDom.innerHTML = cont;
|
|
|
|
+ console.log(divDom);
|
|
|
|
+
|
|
|
|
+ const groups = getHtmlValidDom(divDom, true);
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < groups.length; i++) {
|
|
|
|
+ for (let j = 0; j < groups[i].length; j++) {
|
|
|
|
+ const element = groups[i][j];
|
|
|
|
+ if (element.tagName && element.tagName.toLowerCase() === "img") {
|
|
|
|
+ await pasteImageDom(element);
|
|
|
|
+ } else {
|
|
|
|
+ document.execCommand("insertText", false, element.textContent);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ document.execCommand("insertParagraph");
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function pasteImageDom(imgDom) {
|
|
|
|
+ console.log(imgDom);
|
|
|
|
+ const src = imgDom.getAttribute("src");
|
|
|
|
+ if (!src) return;
|
|
|
|
+ let attributes = {};
|
|
|
|
+ if (imgDom.getAttribute("width"))
|
|
|
|
+ attributes.width = imgDom.getAttribute("width");
|
|
|
|
+ if (imgDom.getAttribute("height"))
|
|
|
|
+ attributes.height = imgDom.getAttribute("height");
|
|
|
|
+
|
|
|
|
+ if (src.includes("base64")) {
|
|
|
|
+ insertTagToEditor(null, "IMG", src, attributes);
|
|
|
|
+ } else if (
|
|
|
|
+ src.includes("http://") ||
|
|
|
|
+ src.includes("https://") ||
|
|
|
|
+ src.includes("file:///")
|
|
|
|
+ ) {
|
|
|
|
+ const dataUrl = await getDataUrlFromImageUrl(src).catch(() => {});
|
|
|
|
+ // console.log(dataUrl);
|
|
|
|
+ if (!dataUrl) return;
|
|
|
|
+ insertTagToEditor(null, "IMG", dataUrl, attributes);
|
|
|
|
+ } else {
|
|
|
|
+ console.log("unknown image url");
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function pasteImage(file, attributes) {
|
|
|
|
+ if (file.size > _this.maxImageSize) {
|
|
|
|
+ _this.$message(`单张图片超过限制,最大为 ${_this.maxImageSize / 1024} KB.`);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 默认转base64;
|
|
|
|
+ const srcBase64 = await fileToBase64(file);
|
|
|
|
+ insertTagToEditor(null, "IMG", srcBase64, attributes);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function pasteText(textItem) {
|
|
|
|
+ const cont = await dataItemGetAsString(textItem).catch((e) => {
|
|
|
|
+ console.log(e);
|
|
|
|
+ });
|
|
|
|
+ if (!cont) return;
|
|
|
|
+
|
|
|
|
+ document.execCommand("insertText", false, cont);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function filterItem(dataItems, filterFunc) {
|
|
|
|
+ let data = [];
|
|
|
|
+ for (let index = 0; index < dataItems.length; index++) {
|
|
|
|
+ if (filterFunc(dataItems[index])) data.push(dataItems[index]);
|
|
|
|
+ }
|
|
|
|
+ return data;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export async function pasteHandle(event) {
|
|
|
|
+ _this = this;
|
|
|
|
+ // 禁止默认粘贴
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ const clipboard = event.clipboardData;
|
|
|
|
+
|
|
|
|
+ const htmlItems = filterItem(
|
|
|
|
+ clipboard.items,
|
|
|
|
+ (item) => item.kind == "string" && item.type.match("^text/html")
|
|
|
|
+ );
|
|
|
|
+ if (htmlItems.length) {
|
|
|
|
+ console.log("... paste: html ");
|
|
|
|
+ for (let index = 0; index < htmlItems.length; index++) {
|
|
|
|
+ await pasteHtmlItem(htmlItems[index]);
|
|
|
|
+ }
|
|
|
|
+ // _this.$refs.editor.dispatchEvent(new Event("input"));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const fileItems = filterItem(
|
|
|
|
+ clipboard.items,
|
|
|
|
+ (item) => item.kind == "file" && item.type.match("^image/")
|
|
|
|
+ );
|
|
|
|
+ if (fileItems.length) {
|
|
|
|
+ console.log("... paste: file ");
|
|
|
|
+ for (let index = 0; index < fileItems.length; index++) {
|
|
|
|
+ const file = fileItems[index].getAsFile();
|
|
|
|
+ await pasteImage(file);
|
|
|
|
+ }
|
|
|
|
+ // _this.$refs.editor.dispatchEvent(new Event("input"));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (var i = 0; i < clipboard.items.length; i++) {
|
|
|
|
+ const clipboardItem = clipboard.items[i];
|
|
|
|
+ if (
|
|
|
|
+ clipboardItem.kind == "string" &&
|
|
|
|
+ clipboardItem.type.match("^text/plain")
|
|
|
|
+ ) {
|
|
|
|
+ console.log("... paste: text ");
|
|
|
|
+ await pasteText(clipboardItem);
|
|
|
|
+ } else {
|
|
|
|
+ console.log("... paste: other ");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // _this.$refs.editor.dispatchEvent(new Event("input"));
|
|
|
|
+}
|