Files
2025-07-02 14:13:16 +09:00

348 lines
13 KiB
JavaScript

function removeElementsTemporarily(selectors, callback) {
const elements = document.querySelectorAll(selectors);
const originalStyles = [];
elements.forEach(el => {
originalStyles.push(el.style.display);
el.style.display = "none";
});
return callback().finally(() => {
elements.forEach((el, index) => {
el.style.display = originalStyles[index];
});
});
}
function addMarginToCanvas(canvas, marginSize = 50) {
const newCanvas = document.createElement("canvas");
const ctx = newCanvas.getContext("2d");
newCanvas.width = canvas.width + marginSize * 2;
newCanvas.height = canvas.height + marginSize * 2;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, newCanvas.width, newCanvas.height);
ctx.drawImage(canvas, marginSize, marginSize);
return newCanvas;
}
function captureEditor() {
return new Promise((resolve, reject) => {
const editor = document.getElementById("editor");
if (!editor) {
console.error("Error: `#editor` 요소를 찾을 수 없음");
return reject("Missing `#editor` element");
}
const resizableElements = document.querySelectorAll(".resizable");
// `.selected` 클래스 제거
resizableElements.forEach(resizable => resizable.classList.remove("selected"));
return html2canvas(editor, {
useCORS: true,
scale: window.devicePixelRatio * 3,
allowTaint: true,
backgroundColor: null
}).then(editorCanvas => {
// `.resizable`이 하나도 없으면 `#editor`만 저장
if (resizableElements.length === 0) {
resolve(editorCanvas);
return;
}
// `.resizable`이 있을 경우 개별적으로 필터 적용
const newCanvas = document.createElement("canvas");
const ctx = newCanvas.getContext("2d");
newCanvas.width = editorCanvas.width;
newCanvas.height = editorCanvas.height;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, newCanvas.width, newCanvas.height);
ctx.drawImage(editorCanvas, 0, 0);
const imagePromises = [];
resizableElements.forEach(resizable => {
const img = resizable.querySelector("img");
if (!img) return;
const imgObj = new Image();
imgObj.crossOrigin = "anonymous";
imgObj.src = img.src;
const imgStyle = getComputedStyle(img);
const resizableRect = resizable.getBoundingClientRect();
const editorRect = editor.getBoundingClientRect();
const imgLeft = resizableRect.left - editorRect.left;
const imgTop = resizableRect.top - editorRect.top;
const resizableWidth = resizable.offsetWidth;
const resizableHeight = resizable.offsetHeight;
const borderRadius = parseFloat(imgStyle.borderRadius) * 3;
const borderWidth = parseFloat(imgStyle.borderWidth) * 3;
const borderColor = imgStyle.borderColor;
const boxShadow = imgStyle.boxShadow.match(/(-?\d+px)/g);
const shadowOffsetX = boxShadow ? parseFloat(boxShadow[0]) * 3 : 0;
const shadowOffsetY = boxShadow ? parseFloat(boxShadow[1]) * 3 : 0;
const shadowBlur = boxShadow ? parseFloat(boxShadow[2]) * 3 : 0;
const shadowColor = imgStyle.boxShadow.match(/rgba?\([\d,.\s]+\)/);
const promise = new Promise((imgResolve) => {
imgObj.onload = function () {
ctx.save();
if (shadowColor) {
ctx.shadowColor = shadowColor[0];
ctx.shadowBlur = shadowBlur;
ctx.shadowOffsetX = shadowOffsetX;
ctx.shadowOffsetY = shadowOffsetY;
}
ctx.filter = imgStyle.filter;
ctx.globalAlpha = imgStyle.opacity;
const imgRatio = imgObj.width / imgObj.height;
const canvasRatio = resizableWidth / resizableHeight;
let sx, sy, sWidth, sHeight;
if (imgRatio > canvasRatio) {
sHeight = imgObj.height;
sWidth = sHeight * canvasRatio;
sx = (imgObj.width - sWidth) / 2;
sy = 0;
} else {
sWidth = imgObj.width;
sHeight = sWidth / canvasRatio;
sx = 0;
sy = (imgObj.height - sHeight) / 2;
}
ctx.beginPath();
ctx.roundRect(imgLeft * 3, imgTop * 3, resizableWidth * 3, resizableHeight * 3, borderRadius);
ctx.closePath();
ctx.clip();
ctx.drawImage(imgObj, sx, sy, sWidth, sHeight, imgLeft * 3, imgTop * 3, resizableWidth * 3, resizableHeight * 3);
if (borderWidth > 0) {
ctx.strokeStyle = borderColor;
ctx.lineWidth = borderWidth;
ctx.stroke();
}
ctx.restore();
imgResolve();
};
imgObj.onerror = function () {
console.error("Error: 이미지 로드 실패");
imgResolve();
};
});
imagePromises.push(promise);
});
Promise.all(imagePromises).then(() => {
resolve(newCanvas);
});
}).catch(error => {
console.error("html2canvas 캡처 오류:", error);
reject(error);
});
});
}
/* 고도화 후 오픈예정
document.getElementById("save-pdf-btn").addEventListener("click", function () {
removeElementsTemporarily(".resize-handle, .delete-preview, .rb-video-container", () => {
return captureEditor().then(canvas => {
const finalCanvas = addMarginToCanvas(canvas, 50);
const imgData = finalCanvas.toDataURL("image/png");
const {
jsPDF
} = window.jspdf;
const pdf = new jsPDF("p", "mm", "a4");
const pdfWidth = pdf.internal.pageSize.getWidth(); // A4 너비 (mm)
const pdfHeight = pdf.internal.pageSize.getHeight(); // A4 높이 (mm)
const canvasWidth = finalCanvas.width;
const canvasHeight = finalCanvas.height;
// PDF에 맞는 비율 계산
const scaleFactor = pdfWidth / canvasWidth;
const imgHeight = canvasHeight * scaleFactor;
let positionY = 0;
while (positionY < imgHeight) {
pdf.addImage(imgData, "PNG", 0, -positionY, pdfWidth, imgHeight, "FAST");
positionY += pdfHeight; // 한 페이지 크기만큼 이동
if (positionY < imgHeight) {
pdf.addPage();
}
}
pdf.save("editor.pdf");
});
});
});
document.getElementById("save-image-btn").addEventListener("click", function () {
removeElementsTemporarily(".resize-handle, .delete-preview, .rb-video-container", () => {
return captureEditor().then(canvas => {
const finalCanvas = addMarginToCanvas(canvas, 50);
const link = document.createElement("a");
link.download = "editor.png";
link.href = finalCanvas.toDataURL("image/png");
link.click();
});
});
});
document.getElementById("save-print-btn").addEventListener("click", function () {
removeElementsTemporarily(".resize-handle, .delete-preview, .rb-video-container", () => {
return captureEditor().then(canvas => {
const finalCanvas = addMarginToCanvas(canvas, 50);
const imageData = finalCanvas.toDataURL("image/png");
const printWindow = window.open("", "_blank");
printWindow.document.write(`
<html>
<head>
<title>인쇄</title>
<style>
@media print {
body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; }
img { display: block; width: 100%; height: auto; page-break-after: always; }
}
</style>
</head>
<body>
<img src="${imageData}" onload="window.print(); setTimeout(() => { window.close(); }, 500);">
</body>
</html>
`);
printWindow.document.close();
});
});
});
*/
window.addEventListener("message", function (event) {
if (event.data.type === "rbeditor-submit") {
const editorContent = document.getElementById("editor").innerHTML;
const iframe = window.frameElement;
const editorId = iframe.getAttribute("data-editor-id");
window.parent.postMessage({
type: "rbeditor-content",
content: editorContent,
editorId: editorId
}, "*");
}
if (event.data.type === "rbeditor-set-content") {
const editorId = event.data.editorId; // 부모 창에서 전달받은 editorId
let content = event.data.content;
if (content) {
// 1. 엔티티를 디코딩하여 원래 HTML로 변환
const tempDiv = document.createElement("div");
tempDiv.innerHTML = content; // 자동 디코딩 수행
// 2. 에디터에 변환된 HTML 삽입
const editor = document.getElementById("editor");
if (editor) {
editor.innerHTML = tempDiv.textContent || tempDiv.innerText;
} else {
//console.error(`Editor with ID ${editorId} not found`);
}
}
}
/* 자동저장 전송 */
if (event.data.type === "rbeditor-insert-content") {
const content = event.data.content;
// HTML 엔티티 디코딩 (태그 및 스타일 유지)
const tempDiv = document.createElement("div");
tempDiv.innerHTML = content;
const decodedContent = tempDiv.innerHTML;
// 강제로 `#regular-mode-btn` 클릭 효과 실행
function triggerRegularMode() {
var regularModeBtn = document.getElementById("regular-mode-btn");
if (regularModeBtn) {
//console.log("#regular-mode-btn 클릭 트리거 실행");
regularModeBtn.click(); // 클릭 효과 발생
} else {
//console.error("#regular-mode-btn을 찾을 수 없습니다.");
}
}
// RB 에디터에 내용 삽입
function insertContent() {
var editor = document.getElementById("editor");
if (!editor) {
console.error("에디터를 찾을 수 없습니다.");
return;
}
editor.innerHTML = decodedContent; // 기존 내용 교체
editor.focus(); // 포커스 유지
//console.log("에디터 내용이 정상적으로 업데이트됨");
}
// `#regular-mode-btn` 클릭 효과 실행 후 내용 삽입
triggerRegularMode();
setTimeout(insertContent, 100); // 클릭 효과 후 약간의 지연 적용
}
if (event.data.type === "rbeditor-get-content") {
//console.log("autosave 요청 수신"); // 로그 추가
const editorContent = document.getElementById("editor").innerHTML;
// 부모 창으로 에디터 내용 전송
event.source.postMessage({
type: "rbeditor-content",
content: editorContent
}, "*");
}
});
/* 고도화 후 오픈예정
document.getElementById("btn_rb_autosave").addEventListener("click", function () {
//console.log("아이프레임에서 부모 창으로 autosave-trigger 요청 전송");
// 부모 창으로 자동 저장 실행 요청
window.parent.postMessage({
type: "autosave-trigger"
}, "*");
});
document.getElementById("btn_tb_autosave_popup").addEventListener("click", function () {
//console.log("아이프레임에서 부모 창으로 autosave 요청 전송");
// 부모 창으로 메시지 전송
window.parent.postMessage({
type: "trigger-autosave-popup"
}, "*");
});
*/