Files
snotes/browser-extension/popup.js
2026-09-23 21:18:30 -07:00

166 lines
5.0 KiB
JavaScript

(function () {
'use strict';
var serverUrl = '';
var noteId = null;
var lastBody = '';
var autosaveTimer = null;
var noteEl = document.getElementById('note');
var userEl = document.getElementById('user');
var saveBtn = document.getElementById('save');
var captureBtn = document.getElementById('capture-page');
var statusEl = document.getElementById('status');
var userOptsBtn = document.getElementById('open-options');
function showStatus(msg, ok) {
statusEl.textContent = msg;
statusEl.className = 'status ' + (ok ? 'ok' : 'err');
if (ok) setTimeout(function () { if (statusEl.textContent === msg) statusEl.textContent = ''; }, 3000);
}
function currentBody() { return noteEl.value; }
async function loadUsers() {
try {
const r = await browser.runtime.sendMessage({ kind: 'list_users' });
const users = (r && r.users) || [];
const saved = await browser.storage.sync.get('username').then(x => x.username);
userEl.innerHTML = '';
for (const u of users) {
const opt = document.createElement('option');
opt.value = u.name;
opt.textContent = u.name;
userEl.appendChild(opt);
}
if (saved && [...userEl.options].some(o => o.value === saved)) {
userEl.value = saved;
}
} catch (e) {
showStatus('Cannot load users: ' + e.message, false);
}
}
async function captureContext() {
try {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
if (!tabs.length || tabs[0].id == null) return;
const ctx = await browser.tabs.sendMessage(tabs[0].id, { kind: 'get_context' });
if (ctx && ctx.selection && !noteEl.value) {
noteEl.value = ctx.selection;
}
if (ctx) {
noteEl.dataset.pageTitle = ctx.title || '';
noteEl.dataset.pageUrl = ctx.url || '';
}
} catch (e) {
// no selection / content script unavailable on this page — ignore
}
}
async function capturePage() {
var title = noteEl.dataset.pageTitle || '';
var url = noteEl.dataset.pageUrl || '';
if (!title && !url) { showStatus('No page to capture', false); return; }
var link = '[' + (title || url) + '](' + (url || '') + ')';
var v = noteEl.value;
if (v && !/\n$/.test(v)) v += '\n';
noteEl.value = v + link + '\n';
captureBtn.disabled = true;
try {
const dataUrl = await browser.tabs.captureVisibleTab({ format: 'png' });
const r = await browser.runtime.sendMessage({
kind: 'upload_attachment',
dataUrl: dataUrl,
filename: 'page.png',
username: userEl.value,
});
noteEl.value += '![Screenshot](' + r.url + ')\n';
showStatus('Screenshot attached', true);
} catch (e) {
showStatus('Screenshot failed: ' + e.message, false);
} finally {
captureBtn.disabled = false;
}
noteEl.focus();
scheduleAutosave();
}
async function save() {
var body = currentBody();
if (!body.trim()) { showStatus('Nothing to save', false); return; }
if (body === lastBody && noteId) return;
saveBtn.disabled = true;
try {
const note = await browser.runtime.sendMessage({
kind: 'save_note',
id: noteId,
body: body,
username: userEl.value,
});
noteId = note.id;
lastBody = body;
var tags = (note.tags || []).map(function (t) { return '#' + t; }).join(' ');
showStatus('Saved' + (tags ? ' · ' + tags : ''), true);
} catch (e) {
showStatus('Error: ' + e.message, false);
} finally {
saveBtn.disabled = false;
}
}
function scheduleAutosave() {
if (autosaveTimer) clearTimeout(autosaveTimer);
autosaveTimer = setTimeout(function () {
autosaveTimer = null;
save();
}, 8000);
}
noteEl.addEventListener('input', scheduleAutosave);
userEl.addEventListener('change', function () {
browser.storage.sync.set({ username: userEl.value });
});
document.getElementById('logo').addEventListener('click', function () {
browser.storage.sync.get('serverUrl').then(function (r) {
var url = (r.serverUrl || '').replace(/\/+$/, '');
if (url) browser.tabs.create({ url: url });
});
});
saveBtn.addEventListener('click', function () {
if (autosaveTimer) { clearTimeout(autosaveTimer); autosaveTimer = null; }
save();
});
captureBtn.addEventListener('click', function () {
if (autosaveTimer) { clearTimeout(autosaveTimer); autosaveTimer = null; }
capturePage();
});
userOptsBtn.addEventListener('click', function (e) {
e.preventDefault();
browser.runtime.openOptionsPage();
});
function updateIndicator() {
var el = document.getElementById('server-indicator');
var display = serverUrl ? serverUrl.replace(/^https?:\/\//, '') : 'Set server URL…';
el.textContent = display;
el.title = serverUrl || '';
}
browser.storage.sync.get('serverUrl').then(function (r) {
serverUrl = (r.serverUrl || '').replace(/\/+$/, '');
updateIndicator();
loadUsers();
});
captureContext();
noteEl.focus();
})();