@opentiny/fluent-editor
Version:
A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.
185 lines (184 loc) • 6.77 kB
JavaScript
import Quill from "quill";
import { imgToBase64 } from "../utils/image.es.js";
import { lockScroll } from "../utils/scroll-lock.es.js";
const Delta = Quill.import("delta");
function resolveOptions(options) {
return Object.assign({
// @ts-ignore
Html2Canvas: window.Html2Canvas,
useCORS: true,
scale: 1,
foreignObjectRendering: true,
beforeCreateImage: void 0,
beforeCreateCanvas: void 0
}, options);
}
function init() {
const maskExits = document.querySelectorAll(".ql-screenshot-mask");
if (maskExits) {
maskExits.forEach((item) => item && item.remove());
}
const wrapper = document.createElement("div");
wrapper.classList.add("ql-screenshot-wrapper");
const mask = document.createElement("div");
mask.className = "ql-screenshot-mask";
const cutter = document.createElement("div");
cutter.className = "ql-screenshot-cutter";
const coordinate = document.createElement("p");
coordinate.className = "ql-screenshot-coordinate";
cutter.appendChild(coordinate);
wrapper.appendChild(mask);
wrapper.appendChild(cutter);
document.body.appendChild(wrapper);
return { wrapper, mask, cutter, coordinate };
}
function findParentFixed(dom) {
if (dom.tagName === "BODY") return false;
if (["fixed", "sticky"].includes(dom.parentElement.style.position)) return true;
return findParentFixed(dom.parentElement);
}
async function renderImage(Html2Canvas, html2canvasOptions, rect, options) {
if (options && options.beforeCreateCanvas) {
await options.beforeCreateCanvas();
}
const canvas = await Html2Canvas(document.body, {
...html2canvasOptions,
onclone: async (doc, el) => {
const fixedDom = Array.from(doc.querySelectorAll('*[style*="position: fixed"]'));
const stickyDom = Array.from(doc.querySelectorAll('*[style*="position: sticky"]'));
const fixedDomList = /* @__PURE__ */ new Set([...fixedDom, ...stickyDom]);
for (const dom of fixedDomList) {
if (findParentFixed(dom)) continue;
let x = 0;
let y = 0;
if (dom.style.top !== "auto") {
y = window.scrollY;
}
if (dom.style.left !== "auto") {
x = window.scrollX;
}
if (x !== 0 || y !== 0) {
dom.style.transform = `translate(${x}px, ${y}px)`;
}
}
const imgs = doc.querySelectorAll("img");
const promises = Array.from(imgs).map(async (img) => {
img.src = await imgToBase64(img.src);
});
await Promise.all(promises);
html2canvasOptions.onclone && await html2canvasOptions.onclone(doc, el);
}
});
let cropCanvas = document.createElement("canvas");
cropCanvas.width = rect.width;
cropCanvas.height = rect.height;
const cropCanvasCtx = cropCanvas.getContext("2d");
cropCanvasCtx.drawImage(
canvas,
rect.x + window.scrollX,
rect.y + window.scrollY,
rect.width,
rect.height,
0,
0,
rect.width,
rect.height
);
if (options && options.beforeCreateImage) {
cropCanvas = await options.beforeCreateImage(cropCanvas);
}
return typeof cropCanvas === "string" ? cropCanvas : cropCanvas.toDataURL();
}
function Screenshot() {
this.quill.options.screenshot = resolveOptions(this.quill.options.screenshot);
const options = this.quill.options.screenshot;
const { Html2Canvas, beforeCreateImage, beforeCreateCanvas, ...html2CanvasOptions } = options;
if (!Html2Canvas) {
throw new Error("ScreenShot module requires html2canvas. Please include the library on the page before FluentEditor.");
}
const range = this.quill.getSelection();
const { wrapper, mask, cutter, coordinate } = init();
const status = {
leftClickLockFlag: false,
start: void 0
};
const cleanLock = lockScroll();
const removeContextmenu = (event) => {
event.preventDefault();
wrapper.remove();
cleanLock();
document.removeEventListener("contextmenu", removeContextmenu);
};
const afterShotCtrl = async (event) => {
document.removeEventListener("mousedown", toggleRect);
const cutterRect = cutter.getBoundingClientRect();
const target = event.target;
wrapper.remove();
cleanLock();
if (target && target.className === "ql-screenshot-confirm") {
const image = await renderImage(Html2Canvas, html2CanvasOptions, cutterRect, { beforeCreateCanvas, beforeCreateImage });
const delta = new Delta().retain(range.index).delete(range.length).insert({ image });
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(range.index + 1, Quill.sources.SILENT);
}
status.start = void 0;
};
const drawRect = (event) => {
const startX = status.start.x;
const startY = status.start.y;
const endX = event.clientX;
const endY = event.clientY;
const width = Math.abs(endX - startX);
const height = Math.abs(endY - startY);
const top = startY < endY ? startY : endY;
const left = startX < endX ? startX : endX;
const bottom = window.innerHeight - height - top;
const right = window.innerWidth - width - left;
const maskPath = `
linear-gradient(to top, #fff, #fff) top / 100% ${top}px,
linear-gradient(to bottom, #fff, #fff) bottom /100% ${bottom}px,
linear-gradient(to left, #fff, #fff) left / ${left}px 100%,
linear-gradient(to right, #fff, #fff) right / ${right}px 100%
`;
Object.assign(cutter.style, {
width: `${width}px`,
height: `${height}px`,
left: `${left}px`,
top: `${top}px`
});
Object.assign(mask.style, {
"mask": maskPath,
"-webkit-mask-repeat": "no-repeat"
});
coordinate.textContent = `${width}, ${height}`;
};
const toggleRect = (event) => {
if (event.button === 2) {
document.removeEventListener("mousemove", drawRect);
document.removeEventListener("mousedown", toggleRect);
document.addEventListener("contextmenu", removeContextmenu);
return;
}
if (!status.leftClickLockFlag) {
if (status.start) {
document.removeEventListener("mousemove", drawRect);
const doneBtn = document.createElement("div");
doneBtn.innerHTML = `<div class="ql-screenshot-confirm"></div><div class="ql-screenshot-cancel"></div>`;
doneBtn.className = "ql-screenshot-done";
doneBtn.addEventListener("click", afterShotCtrl);
coordinate.remove();
cutter.appendChild(doneBtn);
status.leftClickLockFlag = true;
} else {
status.start = { x: event.clientX, y: event.clientY };
document.addEventListener("mousemove", drawRect);
}
}
};
document.addEventListener("mousedown", toggleRect);
}
Screenshot.toolName = "screenshot";
export {
Screenshot
};
//# sourceMappingURL=screenshot.es.js.map