글작성 미리보기시 이미지 호출로인한 페이지 리로드 이슈 개선, css적용하여 이미지지 div넘어가는 이슈 개선
All checks were successful
Build And Test / build-and-push (push) Successful in 4m22s

This commit is contained in:
2025-04-09 23:53:14 +09:00
parent 06d6010c19
commit 422c1a6341
10 changed files with 290 additions and 138 deletions

View File

@ -19,6 +19,7 @@
<div class="col-md-12">
{{ form.contents }}
</div>
<!-- 버튼 -->
<div class="d-flex justify-content-end mt-4">
<button type="submit" class="btn btn-primary me-2">Create Notice</button>
@ -26,17 +27,18 @@
</div>
</form>
</div>
<div class="col-md-6">
<div id="preview" class="border p-3 bg-light h-100 overflow-auto"></div>
</div>
</div>
<!-- 마크다운 파서 및 스크립-->
<!-- 마크다운 파서 및 하이라이-->
<script src="https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>
// 마크다운 파서 초기화
const md = window.markdownit({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
@ -46,49 +48,34 @@
.value;
} catch (__) {}
}
return ''; // 기본 HTML 이스케이프 처리
return '';
}
});
// content 필드와 미리보기 연결
const textarea = document.getElementById("markdown-editor");
const textarea = document.getElementById("markdown-editor"); // form.contents에서 id="markdown-editor" 꼭 설정돼 있어야 함
const preview = document.getElementById("preview");
// 미리보기 업데이트 함수
async function updatePreview() {
let presignedUrlMap = new Map(); // object_name => presigned_url 저장
// 미리보기 렌더링 (fetch 없이 빠르게)
function updatePreview() {
const markdownContent = textarea.value;
const lines = markdownContent.split("\n");
const previewLines = [...lines];
for (let i = 0; i < lines.length; i++) {
const match = lines[i].match(/!\[Image\]\((.+)\)/);
for (let i = 0; i < previewLines.length; i++) {
const match = previewLines[i].match(/!\[Image\]\((.+)\)/);
if (match) {
const objectName = match[1];
try {
// Presigned URL 가져오기
const response = await fetch("/obs_minio/get_presigned_url/", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({object_name: objectName})
});
if (response.ok) {
const data = await response.json();
const presignedUrl = data.presigned_url;
lines[i] = `![Image](${presignedUrl})`; // Presigned URL로 업데이트
}
} catch (error) {
console.error("Error fetching presigned URL:", error);
if (presignedUrlMap.has(objectName)) {
const presignedUrl = presignedUrlMap.get(objectName);
previewLines[i] = `![Image](${presignedUrl})`;
}
}
}
// 마크다운 렌더링 및 미리보기 업데이트
const renderedContent = md.render(lines.join("\n"));
preview.innerHTML = renderedContent;
preview.innerHTML = md.render(previewLines.join("\n"));
// Highlight.js로 코드 블록 강조
document
.querySelectorAll("#preview pre code")
.forEach((block) => {
@ -96,10 +83,7 @@
});
}
// 실시간 미리보기 업데이트
textarea.addEventListener("input", updatePreview);
// Ctrl+V로 이미지 붙여넣기 처리
// 이미지 붙여넣기 처리
textarea.addEventListener("paste", async function (event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
@ -113,7 +97,6 @@
formData.append("image", file);
try {
// 이미지 업로드 API 호출
const response = await fetch("/obs_minio/upload/", {
method: "POST",
body: formData
@ -121,17 +104,39 @@
if (response.ok) {
const data = await response.json();
const fullImageUrl = data.url; // 전체 URL
const fullImageUrl = data.url;
const objectName = fullImageUrl
.split("/")
.slice(-2)
.join("/");
// 마크다운 에디터에 이미지 삽입
// textarea에 object_name 삽입
const markdownImage = `![Image](${objectName})\n`;
textarea.value += markdownImage;
const cursorPos = textarea.selectionStart;
const textBefore = textarea
.value
.substring(0, cursorPos);
const textAfter = textarea
.value
.substring(cursorPos);
textarea.value = textBefore + markdownImage + textAfter;
textarea.focus();
// presigned URL 받아서 map에 저장
const presignedResponse = await fetch("/obs_minio/get_presigned_url/", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({object_name: objectName})
});
if (presignedResponse.ok) {
const presignedData = await presignedResponse.json();
presignedUrlMap.set(objectName, presignedData.presigned_url);
}
// 미리보기 업데이트
updatePreview();
} else {
alert("Image upload failed. Please try again.");
@ -143,6 +148,15 @@
}
}
});
// 입력할 때는 부드럽게 미리보기만 갱신
textarea.addEventListener("input", function () {
updatePreview();
});
document.addEventListener("DOMContentLoaded", function () {
updatePreview();
});
</script>
</div>
{% endblock %}