various fixes

This commit is contained in:
2026-09-24 08:28:43 -07:00
parent 92883d63f5
commit 720ffca099
7 changed files with 119 additions and 6 deletions

View File

@@ -24,6 +24,8 @@ browser.runtime.onMessage.addListener((msg, sender) => {
return saveNote(msg);
case 'upload_attachment':
return uploadAttachment(msg);
case 'capture_full_page':
return captureFullPage(msg);
default:
return Promise.reject(new Error('Unknown message kind'));
}
@@ -93,6 +95,60 @@ async function uploadAttachment(msg) {
return res.json();
}
const MAX_SLICES = 60;
function sleep(ms) {
return new Promise(function (resolve) { setTimeout(resolve, ms); });
}
function loadImage(dataUrl) {
return new Promise(function (resolve, reject) {
const img = new Image();
img.onload = function () { resolve(img); };
img.onerror = function () { reject(new Error('Could not decode screenshot slice')); };
img.src = dataUrl;
});
}
async function captureFullPage(msg) {
const tabId = msg.tabId;
const windowId = msg.windowId;
if (tabId == null) throw new Error('No active tab');
const dims = await browser.tabs.sendMessage(tabId, { kind: 'get_viewport' });
const vw = dims.viewportWidth || 1;
const vh = dims.viewportHeight || 1;
const ph = dims.pageHeight || vh;
const dpr = dims.devicePixelRatio || 1;
const sliceCount = Math.min(MAX_SLICES, Math.ceil(ph / vh));
if (Math.ceil(ph / vh) > MAX_SLICES) {
throw new Error('Page too tall to capture (' + Math.ceil(ph / vh) + ' viewports)');
}
const parts = [];
for (let i = 0; i < sliceCount; i++) {
const y = Math.max(0, Math.min(i * vh, ph - vh));
await browser.tabs.sendMessage(tabId, { kind: 'scroll_to', y: y });
await sleep(250);
const dataUrl = await browser.tabs.captureVisibleTab(windowId, { format: 'png' });
parts.push({ dataUrl: dataUrl, y: y });
}
await browser.tabs.sendMessage(tabId, { kind: 'scroll_to', y: dims.scrollY || 0 }).catch(() => {});
const canvas = document.createElement('canvas');
canvas.width = Math.round(vw * dpr);
canvas.height = Math.round(ph * dpr);
const ctx = canvas.getContext('2d');
for (const p of parts) {
const img = await loadImage(p.dataUrl);
ctx.drawImage(img, 0, Math.round(p.y * dpr));
}
return { dataUrl: canvas.toDataURL('image/png') };
}
function dataUrlToBlob(dataUrl) {
const [meta, b64] = dataUrl.split(',');
const mime = (meta.match(/data:(.*?);/) || [])[1] || 'image/png';

View File

@@ -23,7 +23,9 @@
// ── Extension→Page messaging (capture context for the popup) ──────────────
browser.runtime.onMessage.addListener(function (msg) {
if (msg && msg.kind === 'get_context') {
if (!msg || typeof msg.kind !== 'string') return Promise.resolve(undefined);
if (msg.kind === 'get_context') {
var selection = '';
try { selection = window.getSelection().toString().trim(); } catch (e) {}
return Promise.resolve({
@@ -32,6 +34,26 @@
url: window.location.href || '',
});
}
if (msg.kind === 'get_viewport') {
var ph = Math.max(
document.documentElement ? document.documentElement.scrollHeight : 0,
document.body ? document.body.scrollHeight : 0
);
return Promise.resolve({
viewportWidth: window.innerWidth || document.documentElement.clientWidth || 0,
viewportHeight: window.innerHeight || document.documentElement.clientHeight || 0,
pageHeight: ph,
devicePixelRatio: window.devicePixelRatio || 1,
scrollY: window.scrollY || window.pageYOffset || 0,
});
}
if (msg.kind === 'scroll_to') {
window.scrollTo(0, msg.y);
return Promise.resolve({ y: window.scrollY || window.pageYOffset || 0 });
}
return Promise.resolve(undefined);
});
})();

View File

@@ -11,7 +11,7 @@
</div>
<textarea id="note" placeholder="Type a note…" spellcheck="false"></textarea>
<div class="actions">
<button id="capture-page" title="Insert page title + link" type="button">⤴ Page</button>
<button id="capture-page" title="Insert page title + link and attach a full-page screenshot" type="button">⤴ Page</button>
<div class="spacer"></div>
<button id="save" class="primary" type="button">Save</button>
</div>

View File

@@ -68,16 +68,23 @@
noteEl.value = v + link + '\n';
captureBtn.disabled = true;
showStatus('Capturing full page…', true);
try {
const dataUrl = await browser.tabs.captureVisibleTab({ format: 'png' });
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (!tabs.length || tabs[0].id == null) { showStatus('No active tab ', false); return; }
const shot = await browser.runtime.sendMessage({
kind: 'capture_full_page',
tabId: tabs[0].id,
windowId: tabs[0].windowId,
});
const r = await browser.runtime.sendMessage({
kind: 'upload_attachment',
dataUrl: dataUrl,
dataUrl: shot.dataUrl,
filename: 'page.png',
username: userEl.value,
});
noteEl.value += '![Screenshot](' + r.url + ')\n';
showStatus('Screenshot attached', true);
showStatus('Full-page screenshot attached', true);
} catch (e) {
showStatus('Screenshot failed: ' + e.message, false);
} finally {