const statusEl = document.getElementById('status'); const form = document.getElementById('link-form'); const titleInput = document.getElementById('title'); const urlInput = document.getElementById('url'); const commentInput = document.getElementById('comment'); const openSettingsButton = document.getElementById('open-settings'); const existingTags = document.getElementById('existing-tags'); const newTagsInput = document.getElementById('new-tags'); function setStatus(message, isError = false) { statusEl.textContent = message; statusEl.classList.remove('hidden'); statusEl.classList.toggle('error', isError); statusEl.classList.toggle('success', !isError); } async function getSettings() { const result = await browser.storage.local.get([ 'backendUrl', 'accessToken', 'tokenExpiresAt', ]); return result; } async function loadExistingTags() { const settings = await getSettings(); if (!settings.backendUrl || !settings.accessToken) { existingTags.textContent = 'Sign in to select existing tags.'; return; } const response = await fetch(`${settings.backendUrl}/api/tags`, { headers: {'Authorization': `Bearer ${settings.accessToken}`}, }); if (!response.ok) { existingTags.textContent = 'Could not load existing tags.'; return; } const tags = await response.json(); existingTags.replaceChildren(...tags.map((tag) => { const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = tag; label.append(checkbox, document.createTextNode(` ${tag}`)); return label; })); } function getTags() { const selected = [...existingTags.querySelectorAll('input:checked')].map((input) => input.value); const newTags = newTagsInput.value.split(',').map((tag) => tag.trim()).filter((tag) => tag.startsWith('#')); return [...new Set([...selected, ...newTags])].slice(0, 10); } function removeKnownTrackingParams(urlString) { try { const url = new URL(urlString); const known = new Set([ 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_id', 'utm_name', 'gclid', 'fbclid', 'dclid', 'msclkid' ]); for (const key of known) { url.searchParams.delete(key); } return url.toString(); } catch (error) { return urlString; } } async function populateCurrentTab() { const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); if (!tab) return; titleInput.value = tab.title || ''; urlInput.value = tab.url || ''; } async function handleSubmit(event) { event.preventDefault(); setStatus('Submitting...', false); const settings = await getSettings(); const token = settings.accessToken; const backendUrl = settings.backendUrl; if (!token || !backendUrl) { setStatus('Please configure the backend URL and log in first.', true); browser.runtime.openOptionsPage(); return; } try { const response = await fetch(`${backendUrl}/api/links`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ title: titleInput.value, url: removeKnownTrackingParams(urlInput.value), comment: commentInput.value, timestamp: new Date().toISOString(), tags: getTags(), }) }); if (response.status === 401) { setStatus('Session expired. Re-authenticate in settings.', true); browser.runtime.openOptionsPage(); return; } if (!response.ok) { throw new Error('Submission failed'); } setStatus('Link saved successfully'); } catch (error) { setStatus('Submission failed. Check your backend connection.', true); } } openSettingsButton.addEventListener('click', () => browser.runtime.openOptionsPage()); form.addEventListener('submit', handleSubmit); populateCurrentTab(); loadExistingTags();