- 새 ui_template_native_menu.ts — 주소 /^[bm]\d/ · 글 입력 칸(input · textarea · contenteditable · 읽기 전용 포함) 제외 · preventDefault 만(우리 메뉴 그대로) - main.ts 공용 진입 한 줄 · cad_host.ts iframe load 때 같은 함수 - 「브라우저 메뉴 그대로 둔다」 주석 셋 바로잡음(B04 지도 · B05 배수 · 3D) - 시험 test_common_native_menu.py (PLAN 39-9a) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
36 lines
1.8 KiB
TypeScript
36 lines
1.8 KiB
TypeScript
/* =============================================================================
|
|
* ui_template_native_menu.ts
|
|
* 브라우저 기본 오른쪽 클릭 메뉴 막기 — 공용 진입(`A00_Common/main.ts`) · CAD iframe(`cad_host.ts`)이 부름.
|
|
*
|
|
* 창 캡처 단계에서 `preventDefault` 만 함 — 이벤트는 멈추지 않으므로 우리 메뉴 듣기는 그대로 돎.
|
|
* 글 입력 칸(input · textarea · contenteditable · 읽기 전용 포함)은 브라우저 메뉴를 살림(붙여넣기 · 맞춤법).
|
|
* ⚠ `instanceof` 안 씀 — iframe 문서의 요소는 다른 realm 이라 `instanceof HTMLElement` 가 거짓.
|
|
* ========================================================================== */
|
|
|
|
/** 막을 주소 — B · M 영역(`b01-…` · `m02-…`) · A 영역은 그대로 */
|
|
export const NATIVE_MENU_ROUTE = /^[bm]\d/;
|
|
|
|
/** 글을 쓰는 input 종류 — checkbox · range · button 등은 빠짐 */
|
|
const TEXT_INPUT_TYPES = new Set(["text", "search", "number", "email", "url", "tel", "password"]);
|
|
|
|
/** 오른쪽 클릭 자리가 글 입력 칸인지 */
|
|
export function isTextEditable(target: EventTarget | null): boolean {
|
|
const node = target as { tagName?: unknown; isContentEditable?: boolean; type?: string } | null;
|
|
if (!node || typeof node.tagName !== "string") return false;
|
|
if (node.isContentEditable) return true;
|
|
const tag = node.tagName.toUpperCase();
|
|
if (tag === "TEXTAREA") return true;
|
|
return tag === "INPUT" && TEXT_INPUT_TYPES.has((node.type || "text").toLowerCase());
|
|
}
|
|
|
|
/** `win` 의 기본 메뉴를 막음 — `isOn()` 이 거짓이면(예: A 영역 주소) 그대로 둠 */
|
|
export function blockNativeMenu(win: Window, isOn: () => boolean): void {
|
|
win.addEventListener(
|
|
"contextmenu",
|
|
(event) => {
|
|
if (isOn() && !isTextEditable(event.target)) event.preventDefault();
|
|
},
|
|
true,
|
|
);
|
|
}
|