feat(project): 홈 카드/내 업무 패널 업무 항목에도 우클릭 메뉴(완료 포함) 추가
지금까지 홈 카드 안 업무 행·"내 업무" 패널 행은 자체 우클릭 메뉴가 없어서 이벤트가 부모 프로젝트 카드로 버블링돼 엉뚱하게 프로젝트 메뉴가 뜨던 문제를 같이 고침(stopPropagation 누락). 열기(프로젝트 페이지로 이동)/업무 추가/ 수정(팝업 편집)/완료토글/삭제 5항목을 공용 함수(homeTaskContextItems)로 묶어 두 곳(카드 안 업무 행, 내 업무 패널)에서 그대로 재사용.
This commit is contained in:
+53
-17
@@ -362,6 +362,56 @@
|
||||
if (prog) prog.remove();
|
||||
}
|
||||
}
|
||||
// 업무 우클릭 메뉴 — 홈 카드 안 업무 행·"내 업무" 패널 행 공용(둘 다 같은
|
||||
// .pj-task-popup-link 를 씀). 열기=프로젝트 페이지로 실제 이동, 수정=이
|
||||
// 자리에서 팝업 편집 — 서로 다른 동작이라 항목을 나눴다. 카드 자체의
|
||||
// 우클릭 메뉴와 겹치지 않도록 stopPropagation 필수(안 하면 이벤트가
|
||||
// 버블링돼 카드 메뉴가 나중에 열려 덮어써 버린다).
|
||||
function homeTaskContextItems(t) {
|
||||
return [
|
||||
{ label: "열기", onClick: function () { location.href = "/project/p/" + t.project_id + "?task=" + t.id; } },
|
||||
{ label: "업무 추가", onClick: function () { if (openNewTaskModalRef) openNewTaskModalRef(t.project_id, t.project_name); } },
|
||||
{ label: "수정", onClick: function () { if (openHomeTaskModalRef) openHomeTaskModalRef(t); } },
|
||||
{
|
||||
label: t.completed_at ? "완료 취소" : "완료로 표시",
|
||||
onClick: async function () {
|
||||
try {
|
||||
const res = await api("PUT", "/project/api/tasks/" + t.id, { completed: !t.completed_at });
|
||||
upsertHomeTaskRow(res.task);
|
||||
} catch (e) { showToast("처리 실패: " + e.message, "error"); }
|
||||
},
|
||||
},
|
||||
null,
|
||||
{
|
||||
label: "삭제", danger: true,
|
||||
onClick: async function () {
|
||||
if (!confirm("이 업무를 삭제할까요?")) return;
|
||||
try {
|
||||
await api("DELETE", "/project/api/tasks/" + t.id);
|
||||
removeHomeTaskRow(t.id, t.project_id);
|
||||
} catch (e) { showToast("삭제 실패: " + e.message, "error"); }
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
// .pj-task-popup-link 하나에 클릭(팝업 열기)+우클릭(메뉴) 배선 — 최초
|
||||
// 로드된 행과 optimistic 하게 새로 그려진 행(upsertHomeTaskRow/
|
||||
// syncMyTaskPanel) 모두 이 함수 하나로 통일.
|
||||
function wireHomeTaskPopupLink(a, taskOverride) {
|
||||
a.addEventListener("click", function (e) {
|
||||
const task = taskOverride || homeTasks[a.dataset.taskId];
|
||||
if (!task) return; // 정보 없으면 기존 링크 이동으로 폴백
|
||||
e.preventDefault();
|
||||
if (openHomeTaskModalRef) openHomeTaskModalRef(task);
|
||||
});
|
||||
a.addEventListener("contextmenu", function (e) {
|
||||
const task = taskOverride || homeTasks[a.dataset.taskId];
|
||||
if (!task) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showContextMenu(e.clientX, e.clientY, homeTaskContextItems(task));
|
||||
});
|
||||
}
|
||||
function upsertHomeTaskRow(t) {
|
||||
const card = document.querySelector('.pj-project-card[data-id="' + t.project_id + '"]');
|
||||
if (!card) { syncMyTaskPanel(t); return; }
|
||||
@@ -377,10 +427,7 @@
|
||||
const wrap = document.createElement("div");
|
||||
wrap.innerHTML = homeTaskRowHtml(t);
|
||||
const newLi = wrap.firstElementChild;
|
||||
newLi.querySelector(".pj-task-popup-link").addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
if (openHomeTaskModalRef) openHomeTaskModalRef(t);
|
||||
});
|
||||
wireHomeTaskPopupLink(newLi.querySelector(".pj-task-popup-link"), t);
|
||||
const badge = newLi.querySelector(".pj-cmt-badge");
|
||||
if (badge) {
|
||||
badge.addEventListener("click", function (e) { e.preventDefault(); e.stopPropagation(); });
|
||||
@@ -444,10 +491,7 @@
|
||||
const wrap = document.createElement("div");
|
||||
wrap.innerHTML = html;
|
||||
const newLi = wrap.firstElementChild;
|
||||
newLi.querySelector(".pj-task-popup-link").addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
if (openHomeTaskModalRef) openHomeTaskModalRef(t);
|
||||
});
|
||||
wireHomeTaskPopupLink(newLi.querySelector(".pj-task-popup-link"), t);
|
||||
if (existingLi) existingLi.replaceWith(newLi); else group.appendChild(newLi);
|
||||
}
|
||||
|
||||
@@ -880,15 +924,7 @@
|
||||
catch (e) { showToast("삭제 실패: " + e.message, "error"); }
|
||||
});
|
||||
|
||||
document.querySelectorAll(".pj-task-popup-link").forEach(function (a) {
|
||||
a.addEventListener("click", function (e) {
|
||||
const tid = a.dataset.taskId;
|
||||
const task = homeTasks[tid];
|
||||
if (!task) return; // 정보 없으면 기존 링크 이동으로 폴백
|
||||
e.preventDefault();
|
||||
openHomeTaskModal(task);
|
||||
});
|
||||
});
|
||||
document.querySelectorAll(".pj-task-popup-link").forEach(function (a) { wireHomeTaskPopupLink(a); });
|
||||
}
|
||||
|
||||
// ── 댓글 말풍선(카드/내 업무) — 더블클릭 시 댓글만 보는 채팅형 팝업 ──
|
||||
|
||||
Reference in New Issue
Block a user