The Copy URL extension was intermittently failing to copy anything, and
its notification looked oversized with no icon. Several distinct problems:
- The MV3 service worker was pinned to stale cached code. Chromium caches
the worker script for a --load-extension command-line extension and does
NOT re-register it when the file changes in place — not on restart, not on
a manifest version bump, not even after a clean shutdown. So updated code
never took effect: the old worker kept calling chrome.scripting.executeScript,
which throws once the scripting permission is gone, and the copy silently
failed. Renaming the worker to a versioned filename (background-2.js) is a
new script URL, which forces a fresh registration for everyone — new
installs and existing installs alike. Rename it again on any future worker
change (see the note at the top of background-2.js).
- Clipboard writes now go through an offscreen document (MV3's sanctioned
path) using a textarea + execCommand('copy'), replacing executeScript +
navigator.clipboard. This works on chrome:// pages and needs no scripting
permission. execCommand is used deliberately: navigator.clipboard.writeText
rejects in an unfocused offscreen document.
- Add a toolbar action (chrome.action.onClicked) so the extension is
clickable, not keyboard-only — it was greyed out in the extensions menu
with nothing to invoke.
- Slim the "URL copied" notification: lead the summary with a glyph so the
omarchy notification shell collapses it to a single-line toast with an
icon, instead of an oversized card with a blank icon slot.
- Guard the Quattro shortcut-repair migration: it edits Chromium Preferences
to move the Alt+Shift+L binding to the new extension id, but a running
browser rewrites Preferences on exit and reverts the edit. Prompt (via gum)
to close the browser first, only when a browser is running and there is
actually a stale binding to repair.
66 lines
2.1 KiB
JavaScript
66 lines
2.1 KiB
JavaScript
// NOTE: this file is intentionally version-numbered (background-2.js). Chromium
|
|
// caches the service worker for a command-line --load-extension and does NOT
|
|
// re-register it when the script changes in place, so an updated worker never
|
|
// takes effect on existing installs. Changing the filename is a new script URL,
|
|
// which forces a fresh registration. If you change this worker's code, rename it
|
|
// (background-3.js, ...) and update manifest.json's background.service_worker.
|
|
|
|
let creatingOffscreenDocument;
|
|
|
|
async function ensureOffscreenDocument() {
|
|
if (await chrome.offscreen.hasDocument()) return;
|
|
|
|
if (!creatingOffscreenDocument) {
|
|
creatingOffscreenDocument = chrome.offscreen.createDocument({
|
|
url: 'offscreen.html',
|
|
reasons: ['CLIPBOARD'],
|
|
justification: 'Copy the active tab URL to the clipboard'
|
|
}).finally(() => {
|
|
creatingOffscreenDocument = undefined;
|
|
});
|
|
}
|
|
|
|
await creatingOffscreenDocument;
|
|
}
|
|
|
|
async function copyUrl(url) {
|
|
if (!url) return;
|
|
|
|
try {
|
|
await ensureOffscreenDocument();
|
|
const copied = await chrome.runtime.sendMessage({
|
|
target: 'offscreen',
|
|
type: 'copy-url',
|
|
url
|
|
});
|
|
|
|
if (!copied) return;
|
|
|
|
// The omarchy notification shell renders a chromium toast slim (no icon
|
|
// slot) when the summary begins with a glyph followed by 2+ spaces and the
|
|
// body is empty. iconUrl is a required field, so keep a 1x1 transparent png.
|
|
chrome.notifications.create({
|
|
type: 'basic',
|
|
iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR4nGNgAAIAAAUAAXpeqz8AAAAASUVORK5CYII=',
|
|
title: ' URL copied to clipboard',
|
|
message: ''
|
|
});
|
|
} catch (error) {
|
|
console.error('[copy-url] failed:', error);
|
|
}
|
|
}
|
|
|
|
// Keyboard shortcut (Alt+Shift+L).
|
|
chrome.commands.onCommand.addListener((command) => {
|
|
if (command !== 'copy-url') return;
|
|
|
|
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
|
copyUrl(tabs[0] && tabs[0].url);
|
|
});
|
|
});
|
|
|
|
// Clicking the extension's toolbar icon.
|
|
chrome.action.onClicked.addListener((tab) => {
|
|
copyUrl(tab && tab.url);
|
|
});
|