"Keyboard shortcut 은 power user 용. Popup 은 discovery 용. Right-click menu 는 그 사이 모두 — 텍스트 선택했는데 어떻게 저장할지 잘 모르는 user — 용. Lesson 3 가 ClipDeck 을 시끄럽지 안 게 obvious 하게 만드는 menu 추가."
API shape
chrome.contextMenus 가 작고 완전히 SW-side. 세 호출이 거의 모든 거 cover:
create({ id, title, contexts, parentId? })— menu item 추가. Id 반환 (Chrome 이 auto-generate 하게 할 때 유용).update(id, { title?, enabled?, visible? })— 기존 item 을 재생성 없이 변경.remove(id)— item 삭제.removeAll()— 전체 wipe (install / startup 시 재생성 전에 유용).
Plus click event: chrome.contextMenus.onClicked.addListener((info, tab) => ...). info 가 click 기술 (어느 menu id, 현재 선택 텍스트, page URL); tab 은 click 일어난 tab.
Context — Menu 가 나타나는 곳
contexts 배열이 item 이 menu 에 있을 때 결정:
page— 어떤 page background 든 right-click (가장 permissive).selection— user 가 highlight 된 텍스트에서 right-click 할 때만. "Save selection to ClipDeck" 에 완벽.link— anchor 태그에서만.image—<img>요소에서만.video,audio— 그 media 요소에서.editable— input field / textarea 에서만.frame— iframe 안에서 specifically.action— user 가 extension 의 toolbar icon 에서 right-click 할 때 (Chrome 88+).
contexts: ['selection'] 가진 item 은 user 가 실제로 뭔가 select 할 때까지 hidden 유지. ClipDeck 이 useful 한 거 안 할 수 있는 page 에 menu noise 없음.
Install-time 패턴
Context menu 가 Chrome 에 저장되지만 매 install / startup 마다 재생성해야 함. Idiomatic 패턴:
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.removeAll(() => {
chrome.contextMenus.create({
id: 'clipdeck-save-selection',
title: 'Save "%s" to ClipDeck',
contexts: ['selection'],
});
});
});
Title 의 %s 가 Chrome 이 실제 선택 텍스트 (truncate 된) 로 교체. User 가 generic label 대신 "Save 'service workers idle-evict' to ClipDeck" 봄 — 즉시 읽힘.
Click 처리
onClicked handler 가 SW 에서 돔. 관련 field populate 된 info object 받음:
info.menuItemId— 어느 item click. 항상 먼저 확인; 한 listener 가 여러 item 처리 가능.info.selectionText— 선택 텍스트 (selectioncontext 용). ~1024 자까지.info.pageUrl— click 일어난 page.info.linkUrl—linkcontext 의 destination URL.info.srcUrl—image/video/audio의 media URL.info.frameUrl— click 이 iframe 안이었을 때.
ClipDeck save flow 에 SW 가 info.selectionText, info.pageUrl, tab.title 에서 직접 clip 생성 가능 — content script 에 메시지 필요 없음, context menu 가 이미 다 줬으니까.
Nested menu 와 parent id
Item 을 submenu 아래 그룹화하려면 parent item 먼저 생성 (onclick 없이, title 만) 하고 그 id 를 child 의 parentId 로 전달:
- Parent:
{ id: 'clipdeck-root', title: 'ClipDeck', contexts: ['selection'] } - Child A:
{ id: 'cd-save', parentId: 'clipdeck-root', title: 'Save selection', contexts: ['selection'] } - Child B:
{ id: 'cd-save-tagged', parentId: 'clipdeck-root', title: 'Save with tag…', contexts: ['selection'] }
Submenu 는 2–3 개 넘는 관련 action 있을 때 도움. 하나만 있으면 flat top-level item 이 더 명확.
contexts 배열이 useful 안 한 데서 menu 조용. Title 의 %s 가 user 한테 뭘 저장할지 보여 줘.