quickSnote

This commit is contained in:
2026-09-23 13:36:24 -07:00
parent 35c71a1e6d
commit 04a40840d1
14 changed files with 844 additions and 1 deletions

125
browser-extension/popup.js Normal file
View File

@@ -0,0 +1,125 @@
(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) || [];
userEl.innerHTML = '';
for (const u of users) {
const opt = document.createElement('option');
opt.value = u.name;
opt.textContent = u.name;
userEl.appendChild(opt);
}
} 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
}
}
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';
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);
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();
});
browser.storage.sync.get('serverUrl').then(function (r) {
serverUrl = (r.serverUrl || '').replace(/\/+$/, '');
if (!serverUrl) showStatus('Set the server URL in Options', false);
});
loadUsers();
captureContext();
noteEl.focus();
})();