diff --git a/bundled-addons/screenshot/addon.json b/bundled-addons/screenshot/addon.json index b2eeb70..7b12a98 100644 --- a/bundled-addons/screenshot/addon.json +++ b/bundled-addons/screenshot/addon.json @@ -1,7 +1,7 @@ { "id": "screenshot", "name": "Screenshot", - "version": "0.2.3", + "version": "0.2.4", "description": "Capture the current tab — visible viewport, entire scrollable page, or a rectangle you draw. Pick a mode from a toolbar dropdown; the capture opens in a full-tab editor (crop, annotate, redact, save).", "author": "Silent Mode", "icon": "📸", diff --git a/bundled-addons/screenshot/editor.js b/bundled-addons/screenshot/editor.js index 54aad05..fd48a37 100644 --- a/bundled-addons/screenshot/editor.js +++ b/bundled-addons/screenshot/editor.js @@ -112,10 +112,38 @@ function loadImage(url) { } async function init() { - if (!srcUrl) { toast("Missing ?src=", true); return; } + // Preferred source: a pending capture handed to us through addon storage + // (the toolbar-menu capture path). A file:// src won't load — Chromium + // treats the editor at file:///…/addons/screenshot/editor.html as a + // different origin from the scratch PNG at file:///…/addons-data/…, + // so quietly errors. Storage-based delivery sidesteps the origin + // entirely. + let dataUrl = null; + let toolFromPending = ""; + let pendingName = baseName; + try { + if (window.silentmode?.storage) { + const pending = await window.silentmode.storage.get("__pending", null); + if (pending && pending.dataUrl) { + dataUrl = pending.dataUrl; + toolFromPending = pending.tool || ""; + if (pending.name) { pendingName = pending.name; nameEl.textContent = pending.name; document.title = pending.name + " — editor"; } + // Clear so a later editor open (e.g. "recent captures") doesn't + // accidentally reload the same capture. + await window.silentmode.storage.set("__pending", null); + } + } + } catch (e) { console.warn("editor: storage read failed:", e); } + // Fallback path — retained so the "openRecent" flow (which currently + // still passes ?src=file://) keeps working after we teach it to use + // storage too. + if (!dataUrl) { + if (!srcUrl) { toast("No capture to edit", true); return; } + dataUrl = srcUrl; + } let img; - try { img = await loadImage(srcUrl); } - catch (e) { toast(e.message, true); return; } + try { img = await loadImage(dataUrl); } + catch (e) { toast("Couldn't load capture: " + e.message, true); return; } sizeCanvases(img.naturalWidth, img.naturalHeight); cctx.drawImage(img, 0, 0); undo = []; @@ -123,7 +151,8 @@ async function init() { pushSnapshot(); // baseline so the very first edit is undoable updateUndoButtons(); fitBoard(); - if (initialTool) setTool(initialTool); + const t = initialTool || toolFromPending; + if (t) setTool(t); } // Scale the stage to fit within the board when the image is bigger than diff --git a/bundled-addons/screenshot/index.js b/bundled-addons/screenshot/index.js index c9c7d1e..22512a1 100644 --- a/bundled-addons/screenshot/index.js +++ b/bundled-addons/screenshot/index.js @@ -83,11 +83,20 @@ module.exports = { recent.unshift({ id: name, name, path: written.path, url: fileUrl(written.path), bytes: written.bytes, at: Date.now(), mode: id }); recent = pruneRecent(recent); api.storage.set("recent", recent); + // Hand the raw data URL to the editor tab through addon storage. We + // used to pass `?src=file://…` and let the editor load the scratch + // file, but Chromium's file:// origin policy blocks from + // cross-directory file loads: editor.html lives under + // /addons/screenshot/ and scratch PNGs land under + // /addons-data/screenshot-scratch/, which is a sibling of + // the addon dir, and the load quietly fails — the editor initializes + // but the image never draws, so every subsequent tool (draw, save, + // discard) operates on a still-empty canvas. Storage isn't + // origin-scoped, so the editor can pull the data URL out and paint + // it locally. + api.storage.set("__pending", { name, dataUrl: cap.dataUrl, tool: id === "region" ? "crop" : "", at: Date.now() }); api.log(`captured ${id} → ${name} (${written.bytes} bytes)`); - // Region mode = land in the crop tool immediately so the user can trim - // further if the freehand rect was rough. - const tool = id === "region" ? "crop" : ""; - api.openTab("editor.html", { query: { src: fileUrl(written.path), name, tool } }); + api.openTab("editor.html", { query: { name } }); return { ok: true, name }; });