@cairn214/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.
136 lines (135 loc) • 4.62 kB
JavaScript
"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const lodashEs = require("lodash-es");
const Quill = require("quill");
const image = require("./image.cjs.js");
const Options = require("./Options.cjs.js");
const CustomImageSpec = require("./specs/CustomImageSpec.cjs.js");
const dontMerge = (_destination, source) => source;
class BlotFormatter {
constructor(quill, options = {}) {
this.onClick = () => {
this.hide();
};
this.hideImageOverlay = (event) => {
var _a;
const target = event.target;
const isBlotFormatter = (_a = target == null ? void 0 : target.classList) == null ? void 0 : _a.contains("blot-formatter__overlay");
if (!isBlotFormatter) {
this.hide();
}
document.body.removeEventListener("click", this.hideImageOverlay);
};
this.quill = quill;
this.options = lodashEs.merge(Options.default, options, { arrayMerge: dontMerge });
this.currentSpec = null;
this.actions = [];
this.overlay = document.createElement("div");
this.overlay.classList.add(this.options.overlay.className);
if (this.options.overlay.style) {
Object.assign(this.overlay.style, this.options.overlay.style);
}
document.execCommand("enableObjectResizing", false, "false");
this.quill.root.addEventListener("click", this.onClick);
this.specs = this.options.specs.map((SpecClass) => new SpecClass(this));
this.specs.forEach((spec) => spec.init());
}
static register() {
Quill.register("formats/image", image.default, true);
Quill.register("formats/image-container", image.ImageContainerBlot, true);
Quill.register("modules/image-spec", CustomImageSpec.CustomImageSpec, true);
}
show(spec) {
this.currentSpec = spec;
this.currentSpec.setSelection();
this.setUserSelect("none");
this.quill.root.parentNode.appendChild(this.overlay);
this.repositionOverlay();
this.createActions(spec);
const imageDom = spec.getTargetElement();
const win = window;
const MutationObserver = win.MutationObserver || win.WebKitMutationObserver || win.MozMutationObserver;
const element = imageDom.parentNode;
this.observer = new MutationObserver((mutationList) => {
for (const mutation of mutationList) {
const target = mutation.target;
const image2 = target.querySelector("img");
if (image2) {
this.repositionOverlay();
}
}
});
this.observer.observe(element, {
attributes: true,
attributeFilter: ["class"],
attributeOldValue: true,
subtree: true
});
document.body.addEventListener("click", this.hideImageOverlay, true);
}
hide() {
if (!this.currentSpec) {
return;
}
const imgDom = this.currentSpec.getTargetElement();
if (imgDom) {
imgDom.classList.remove("current-select-img");
}
this.currentSpec.onHide();
this.currentSpec = null;
this.quill.root.parentNode.removeChild(this.overlay);
this.overlay.style.setProperty("display", "none");
this.setUserSelect("");
this.destroyActions();
}
update() {
this.repositionOverlay();
this.actions.forEach((action) => action.onUpdate());
}
createActions(spec) {
this.actions = spec.getActions().map((ActionClass) => {
const action = new ActionClass(this);
action.onCreate();
return action;
});
}
destroyActions() {
this.actions.forEach((action) => action.onDestroy());
this.actions = [];
}
repositionOverlay() {
if (!this.currentSpec) {
return;
}
const overlayTarget = this.currentSpec.getOverlayElement();
if (!overlayTarget) {
return;
}
const parent = this.quill.root.parentNode;
const specRect = overlayTarget.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
Object.assign(this.overlay.style, {
display: "block",
left: `${specRect.left - parentRect.left - 1 + parent.scrollLeft}px`,
top: `${specRect.top - parentRect.top + parent.scrollTop}px`,
width: `${specRect.width}px`,
height: `${specRect.height}px`
});
}
setUserSelect(value) {
const props = [
"userSelect",
"mozUserSelect",
"webkitUserSelect",
"msUserSelect"
];
props.forEach((prop) => {
this.quill.root.style.setProperty(prop, value);
if (document.documentElement) {
document.documentElement.style.setProperty(prop, value);
}
});
}
}
exports.default = BlotFormatter;
//# sourceMappingURL=BlotFormatter.cjs.js.map