@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.
242 lines (241 loc) • 7.22 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
class ImagePreviewModal {
constructor() {
__publicField(this, "modal", null);
__publicField(this, "overlay", null);
__publicField(this, "previewImage", null);
__publicField(this, "scaleTooltip", null);
__publicField(this, "closeBtn", null);
__publicField(this, "currentScale", 1);
__publicField(this, "minScale", 0.5);
__publicField(this, "maxScale", 3);
__publicField(this, "scaleStep", 0.1);
__publicField(this, "tooltipHideTimer", null);
/**
* 处理鼠标滚轮事件 - 缩放图片
*/
__publicField(this, "onMouseWheel", (event) => {
if (!this.modal || this.modal.style.display === "none") {
return;
}
event.preventDefault();
const delta = event.deltaY > 0 ? -this.scaleStep : this.scaleStep;
this.setScale(this.currentScale + delta);
this.showScaleTooltip();
});
this.initModal();
}
initModal() {
this.overlay = document.createElement("div");
this.overlay.className = "image-preview-overlay";
this.overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: none;
z-index: 9999;
cursor: pointer;
`;
this.modal = document.createElement("div");
this.modal.className = "image-preview-modal";
this.modal.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: transparent;
display: none;
z-index: 10000;
max-width: 90vw;
max-height: 90vh;
cursor: auto;
`;
this.previewImage = document.createElement("img");
this.previewImage.className = "image-preview-img";
this.previewImage.style.cssText = `
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: transform 0.2s ease-out;
cursor: grab;
`;
this.closeBtn = document.createElement("button");
this.closeBtn.className = "tiny-editor-image-preview-close";
this.closeBtn.innerHTML = "×";
this.closeBtn.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
width: 40px;
height: 40px;
border: none;
background-color: transparent;
color: white;
font-size: 32px;
cursor: pointer;
z-index: 10001;
line-height: 1;
padding: 0;
`;
this.closeBtn.addEventListener("click", () => this.hide());
this.modal.appendChild(this.previewImage);
document.body.appendChild(this.closeBtn);
this.scaleTooltip = document.createElement("div");
this.scaleTooltip.className = "image-preview-scale-tooltip";
this.scaleTooltip.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 12px 20px;
border-radius: 6px;
font-size: 14px;
z-index: 10002;
display: none;
pointer-events: none;
white-space: nowrap;
font-weight: 500;
`;
document.body.appendChild(this.scaleTooltip);
this.overlay.addEventListener("click", () => this.hide());
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
this.hide();
}
});
document.addEventListener("wheel", (e) => this.onMouseWheel(e), { passive: false });
this.modal.addEventListener("click", (e) => {
e.stopPropagation();
});
document.body.appendChild(this.overlay);
document.body.appendChild(this.modal);
}
/**
* 设置缩放比例
*/
setScale(scale) {
this.currentScale = Math.max(this.minScale, Math.min(scale, this.maxScale));
if (this.previewImage) {
this.previewImage.style.transform = `scale(${this.currentScale})`;
}
}
/**
* 显示缩放百分比提示
*/
showScaleTooltip() {
if (!this.scaleTooltip) {
return;
}
if (this.tooltipHideTimer !== null) {
clearTimeout(this.tooltipHideTimer);
}
const percentage = Math.round(this.currentScale * 100);
this.scaleTooltip.textContent = `${percentage}%`;
this.scaleTooltip.style.display = "block";
this.tooltipHideTimer = window.setTimeout(() => {
if (this.scaleTooltip) {
this.scaleTooltip.style.display = "none";
}
this.tooltipHideTimer = null;
}, 1500);
}
/**
* 隐藏缩放提示
*/
hideScaleTooltip() {
if (this.tooltipHideTimer !== null) {
clearTimeout(this.tooltipHideTimer);
this.tooltipHideTimer = null;
}
if (this.scaleTooltip) {
this.scaleTooltip.style.display = "none";
}
}
/**
* 重置缩放比例
*/
resetScale() {
this.currentScale = 1;
if (this.previewImage) {
this.previewImage.style.transform = "scale(1)";
}
this.hideScaleTooltip();
}
/**
* 显示预览
* @param imageUrl 图片URL
*/
show(imageUrl) {
if (!this.previewImage || !this.modal || !this.overlay) {
return;
}
this.resetScale();
this.previewImage.src = imageUrl;
this.modal.style.display = "flex";
this.modal.style.alignItems = "center";
this.modal.style.justifyContent = "center";
this.overlay.style.display = "block";
if (this.closeBtn) {
this.closeBtn.style.display = "block";
}
document.body.style.overflow = "hidden";
}
/**
* 隐藏预览
*/
hide() {
if (this.modal && this.overlay) {
this.modal.style.display = "none";
this.overlay.style.display = "none";
document.body.style.overflow = "";
this.resetScale();
if (this.closeBtn) {
this.closeBtn.style.display = "none";
}
}
}
/**
* 销毁预览模态框
*/
destroy() {
this.hideScaleTooltip();
if (this.overlay && this.overlay.parentNode) {
this.overlay.parentNode.removeChild(this.overlay);
}
if (this.modal && this.modal.parentNode) {
this.modal.parentNode.removeChild(this.modal);
}
if (this.closeBtn && this.closeBtn.parentNode) {
this.closeBtn.parentNode.removeChild(this.closeBtn);
}
if (this.scaleTooltip && this.scaleTooltip.parentNode) {
this.scaleTooltip.parentNode.removeChild(this.scaleTooltip);
}
this.modal = null;
this.overlay = null;
this.previewImage = null;
this.closeBtn = null;
this.scaleTooltip = null;
}
}
let globalPreviewModal = null;
function getImagePreviewModal() {
if (!globalPreviewModal) {
globalPreviewModal = new ImagePreviewModal();
}
return globalPreviewModal;
}
exports.ImagePreviewModal = ImagePreviewModal;
exports.getImagePreviewModal = getImagePreviewModal;
//# sourceMappingURL=preview-modal.cjs.js.map