diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html
index 432bb47..da75de5 100644
--- a/app/modules/project/templates/project/inbox.html
+++ b/app/modules/project/templates/project/inbox.html
@@ -45,5 +45,5 @@
{% endif %}
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html
index fbf9fe9..0205590 100644
--- a/app/modules/project/templates/project/index.html
+++ b/app/modules/project/templates/project/index.html
@@ -392,5 +392,5 @@
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html
index f89ff45..10e568d 100644
--- a/app/modules/project/templates/project/project.html
+++ b/app/modules/project/templates/project/project.html
@@ -405,5 +405,5 @@
-
+
{% endblock %}
diff --git a/app/static/project.js b/app/static/project.js
index 31ea712..4994800 100644
--- a/app/static/project.js
+++ b/app/static/project.js
@@ -211,6 +211,12 @@
const descEditor = initDescEditor();
const subtaskBlock = initSubtaskBlock();
const linksBlock = initLinksBlock();
+ if (descEditor) {
+ descEditor.setOnImageRemoved(function () {
+ const tid = el("pj-t-id").value;
+ if (tid) loadHomeAttachments(tid);
+ });
+ }
// 닫을 때(배경 클릭·Esc·취소 버튼) 수정한 내용이 있으면 저장할지 물어본다.
let homeTaskSnapshot = null;
@@ -1631,6 +1637,12 @@
const descEditor = initDescEditor();
const subtaskBlock = initSubtaskBlock();
const linksBlock = initLinksBlock();
+ if (descEditor) {
+ descEditor.setOnImageRemoved(function () {
+ const tid = el("pj-t-id").value;
+ if (tid) loadAttachments(tid);
+ });
+ }
// 닫을 때(배경 클릭·Esc·취소 버튼) 수정한 내용이 있으면 저장할지 물어본다.
// 하위업무/첨부/댓글/연결은 각자 즉시 저장돼서 여기서 추적할 필요 없다 —
@@ -2139,6 +2151,22 @@
const imgDelBtn = imgTools.querySelector(".pj-img-del");
const imgHandle = imgTools.querySelector(".pj-img-handle");
let selectedImg = null;
+ let onImageRemoved = null;
+
+ // 설명란 이미지는 첨부파일 업로드로 들어간 실제 첨부 레코드다 — 에디터에서
+ // 지우면 첨부파일 목록에도 안 남게 서버 첨부도 같이 삭제한다.
+ async function deleteSelectedImage() {
+ if (!selectedImg) return;
+ const img = selectedImg;
+ const m = (img.getAttribute("src") || "").match(/\/attachments\/(\d+)\/inline/);
+ img.remove();
+ selectImg(null);
+ if (!m) return;
+ try {
+ await api("DELETE", "/project/api/attachments/" + m[1]);
+ } catch (_) { /* 이미 지워졌을 수 있음 — 에디터에서는 이미 빠졌으니 조용히 무시 */ }
+ if (onImageRemoved) onImageRemoved();
+ }
function positionImgTools() {
if (!selectedImg || !selectedImg.isConnected) { selectedImg = null; imgTools.hidden = true; return; }
@@ -2161,10 +2189,7 @@
document.addEventListener("click", function (e) {
if (selectedImg && !wrap.contains(e.target)) selectImg(null);
});
- imgDelBtn.addEventListener("click", function () {
- if (selectedImg) selectedImg.remove();
- selectImg(null);
- });
+ imgDelBtn.addEventListener("click", function () { deleteSelectedImage(); });
let dragging = false, dragStartX = 0, dragStartW = 0;
imgHandle.addEventListener("mousedown", function (e) {
if (!selectedImg) return;
@@ -2190,8 +2215,7 @@
const active = document.activeElement;
if (active && ["INPUT", "TEXTAREA", "SELECT"].indexOf(active.tagName) >= 0) return;
e.preventDefault();
- selectedImg.remove();
- selectImg(null);
+ deleteSelectedImage();
});
// 업로드 버튼 클릭 → 파일 선택창이 뜨는 동안 contenteditable의 선택 범위가
@@ -2322,6 +2346,7 @@
setHtml: function (html) { selectImg(null); lastRange = null; box.innerHTML = html || ""; },
getHtml: function () { return box.innerHTML; },
isUploading: function () { return pendingUploads > 0; },
+ setOnImageRemoved: function (fn) { onImageRemoved = fn; },
};
}