feat(cafe24): HTML 편집기 Shift+Delete 줄 삭제

커서가 있는 줄(선택이 있으면 그 줄들)을 통째로 지운다. 윈도우 기본 동작인
"잘라내기"를 대신한다.

- 줄바꿈까지 함께 지워 빈 줄이 남지 않게 한다. 마지막 줄이면 대신 앞의
  줄바꿈을 지운다(문서 끝에 빈 줄이 생기지 않게).
- 커서는 지운 자리로 올라온 줄의 같은 칸에 둔다(칸이 모자라면 줄 끝).
- 빈 문자열은 insertText 가 브라우저에 따라 무시되므로 applyEdit 이
  execCommand("delete") 로 갈라진다. Ctrl+Z 는 그대로 동작한다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 22:22:17 +09:00
parent 024653dc8e
commit a58fa7b83b
2 changed files with 34 additions and 3 deletions
@@ -78,7 +78,7 @@
<input type="hidden" name="list_query" value="{{ list_query }}" /> <input type="hidden" name="list_query" value="{{ list_query }}" />
<div class="cf24-editor-bar"> <div class="cf24-editor-bar">
<span class="cf24-muted">상세설명 HTML · {{ desc.description | length }}자 · PC/모바일 공통 · Ctrl+/ 주석 · Alt+↑↓ 줄 이동</span> <span class="cf24-muted">상세설명 HTML · {{ desc.description | length }}자 · PC/모바일 공통 · Ctrl+/ 주석 · Alt+↑↓ 줄 이동 · Shift+Del 줄 삭제</span>
<span class="cf24-editor-bar-right"> <span class="cf24-editor-bar-right">
<input class="cf24-memo" type="text" name="memo" maxlength="200" <input class="cf24-memo" type="text" name="memo" maxlength="200"
placeholder="변경 메모 (버전 이력에 남습니다)" /> placeholder="변경 메모 (버전 이력에 남습니다)" />
@@ -100,7 +100,7 @@
<pre class="cf24-code-hl" id="cf24-hl-pc" aria-hidden="true"></pre> <pre class="cf24-code-hl" id="cf24-hl-pc" aria-hidden="true"></pre>
<textarea id="cf24-html-pc" class="cf24-code-input" name="html" wrap="off" <textarea id="cf24-html-pc" class="cf24-code-input" name="html" wrap="off"
spellcheck="false" autocapitalize="off" autocorrect="off" spellcheck="false" autocapitalize="off" autocorrect="off"
title="Tab 들여쓰기 · Ctrl+/ 주석 토글 · Alt+↑/↓ 줄 이동 · Alt+Shift+↑/↓ 줄 복사 (선택이 없으면 커서가 있는 줄)">{{ html_pc }}</textarea> title="Tab 들여쓰기 · Ctrl+/ 주석 토글 · Alt+↑/↓ 줄 이동 · Alt+Shift+↑/↓ 줄 복사 · Shift+Delete 줄 삭제 (선택이 없으면 커서가 있는 줄)">{{ html_pc }}</textarea>
</div> </div>
</div> </div>
</form> </form>
@@ -209,7 +209,12 @@
ta.selectionStart = from; ta.selectionStart = from;
ta.selectionEnd = to; ta.selectionEnd = to;
var inserted = false; var inserted = false;
try { inserted = document.execCommand("insertText", false, text); } catch (err) { inserted = false; } try {
// 빈 문자열은 insertText 가 브라우저에 따라 무시된다 — 삭제는 delete 로.
inserted = text === ""
? document.execCommand("delete")
: document.execCommand("insertText", false, text);
} catch (err) { inserted = false; }
if (!inserted) ta.value = value.slice(0, from) + text + value.slice(to); if (!inserted) ta.value = value.slice(0, from) + text + value.slice(to);
ta.selectionStart = selStart; ta.selectionStart = selStart;
ta.selectionEnd = selEnd; ta.selectionEnd = selEnd;
@@ -288,6 +293,25 @@
applyEdit(r.from, r.to, text, r.start + shift, r.end + shift); applyEdit(r.from, r.to, text, r.start + shift, r.end + shift);
} }
/* Shift+Delete — 커서가 있는 줄(선택이 있으면 그 줄들)을 통째로 지운다.
줄바꿈까지 같이 지워야 빈 줄이 남지 않는다. 마지막 줄이면 대신 앞의
줄바꿈을 지운다(문서 끝에 빈 줄이 생기지 않게). */
function deleteLines() {
var r = lineRange();
var from = r.from, to = r.to;
if (to < r.value.length) to += 1;
else if (from > 0) from -= 1;
if (from === to) return; // 빈 문서 — 지울 것이 없다
var rest = r.value.slice(0, from) + r.value.slice(to);
// 커서는 지운 자리로 올라온 줄의 같은 칸에 둔다(칸이 모자라면 줄 끝).
var lineFrom = rest.lastIndexOf("\n", from - 1) + 1;
var lineTo = rest.indexOf("\n", lineFrom);
if (lineTo === -1) lineTo = rest.length;
var col = Math.min(Math.max(0, r.start - r.from), lineTo - lineFrom);
applyEdit(from, to, "", lineFrom + col, lineFrom + col);
}
ta.addEventListener("scroll", sync); ta.addEventListener("scroll", sync);
ta.addEventListener("input", function () { dirty = true; refresh(); }); ta.addEventListener("input", function () { dirty = true; refresh(); });
ta.addEventListener("keydown", function (e) { ta.addEventListener("keydown", function (e) {
@@ -307,6 +331,13 @@
else moveLines(isDown); else moveLines(isDown);
return; return;
} }
// Shift+Delete — 줄 삭제. (윈도우 기본 동작인 "잘라내기"를 대신한다)
if (e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey &&
(e.key === "Delete" || e.code === "Delete")) {
e.preventDefault();
deleteLines();
return;
}
// Tab 은 포커스 이동이 아니라 들여쓰기로 쓴다. // Tab 은 포커스 이동이 아니라 들여쓰기로 쓴다.
if (e.key !== "Tab") return; if (e.key !== "Tab") return;
e.preventDefault(); e.preventDefault();