fix(theseus/screenshot): 0.2.4 — deliver capture via addon storage, not a cross-origin file://
Blank editor + broken buttons root cause: index.js was writing the capture to <userData>/addons-data/screenshot-scratch/<name>.png and passing "?src=file://<that path>" to editor.html. The editor lives at file:///<userData>/addons/screenshot/editor.html — different directory tree under file://. Chromium's file:// origin policy treats those as different origins and quietly refuses the <img> load, so init()'s loadImage() rejects, the canvas never gets an image, and every tool after that operates on a still-empty 300×150 default canvas — the tools appear to work but produce no visible output because the base image never landed. The sidebar version we replaced set `previewImg.src = dataUrl` (a base64 data URL) directly, which has no origin and just worked; the tab version regressed by adding the file hop. Fix keeps the scratch file for the recent-captures ring but hands the raw capture through the add-on's per-add-on kv store (`__pending` key). Same store, same origin scoping, no cross-directory read: index.js writes via api.storage.set from main; editor.js reads via window.silentmode.storage.get through the tab preload (packaged since 0.3.27). Fallback path retained for "openRecent" callers still passing ?src=… — those will need their own fix in a follow-up. Bumped to 0.2.4 and signed for the OTA endpoint — first real independent add-on ship: no Theseus release needed to fix this, 0.3.27 installs pick up 0.2.4 via the boot-time signed-update poll.
This commit is contained in:
parent
1d0e25c4e0
commit
2e42783dfe
3 changed files with 47 additions and 9 deletions
|
|
@ -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": "📸",
|
||||
|
|
|
|||
|
|
@ -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 <img> 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
|
||||
|
|
|
|||
|
|
@ -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 <img> from
|
||||
// cross-directory file loads: editor.html lives under
|
||||
// <userData>/addons/screenshot/ and scratch PNGs land under
|
||||
// <userData>/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 };
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue