const DEFAULT_SERVER = "https://everclone.vloser.us"; const DEFAULT_KEY = "evc_master_vloser_key_2026"; let currentMode = 'article'; let activeTab = null; document.addEventListener('DOMContentLoaded', async () => { const stored = await chrome.storage.local.get(['serverUrl', 'apiKey', 'lastNotebook']); const serverUrl = (stored.serverUrl || DEFAULT_SERVER).replace(/\/$/, ''); const apiKey = stored.apiKey || DEFAULT_KEY; document.getElementById('serverUrl').value = serverUrl; document.getElementById('apiKey').value = apiKey; if (!apiKey || apiKey === '') { document.getElementById('settingsPanel').style.display = 'block'; } document.getElementById('toggleSettings').addEventListener('click', () => { const p = document.getElementById('settingsPanel'); p.style.display = p.style.display === 'block' ? 'none' : 'block'; }); document.getElementById('saveSettingsBtn').addEventListener('click', async () => { const s = document.getElementById('serverUrl').value.trim().replace(/\/$/, ''); const k = document.getElementById('apiKey').value.trim(); await chrome.storage.local.set({ serverUrl: s, apiKey: k }); document.getElementById('settingsPanel').style.display = 'none'; loadNotebooks(s, k); }); document.querySelectorAll('.mode-btn').forEach((btn) => { btn.addEventListener('click', () => { document.querySelectorAll('.mode-btn').forEach((b) => b.classList.remove('active')); btn.classList.add('active'); currentMode = btn.getAttribute('data-mode'); }); }); const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); activeTab = tab; if (tab && tab.title) { document.getElementById('noteTitle').value = tab.title; } await loadNotebooks(serverUrl, apiKey, stored.lastNotebook); document.getElementById('clipBtn').addEventListener('click', handleClip); }); async function loadNotebooks(serverUrl, apiKey, preferredNb) { if (!serverUrl || !apiKey) return; try { const res = await fetch(`${serverUrl}/api/hooks/note?action=notebooks`, { headers: { Authorization: `Bearer ${apiKey}` }, }); if (!res.ok) return; const data = await res.json(); if (Array.isArray(data.notebooks) && data.notebooks.length > 0) { const sel = document.getElementById('notebookSelect'); sel.innerHTML = ''; data.notebooks.forEach((nb) => { const opt = document.createElement('option'); opt.value = nb.name; opt.textContent = nb.name; if (preferredNb ? nb.name === preferredNb : nb.name === 'Web Clips' || nb.isDefault) { opt.selected = true; } sel.appendChild(opt); }); } } catch { // keep default options } } async function handleClip() { const btn = document.getElementById('clipBtn'); const statusBox = document.getElementById('statusBox'); statusBox.className = 'status'; btn.disabled = true; btn.textContent = 'Clipping & saving graphics...'; try { const serverUrl = document.getElementById('serverUrl').value.trim().replace(/\/$/, ''); const apiKey = document.getElementById('apiKey').value.trim(); const title = document.getElementById('noteTitle').value.trim(); const notebook = document.getElementById('notebookSelect').value; const tags = document.getElementById('noteTags').value.split(',').map((t) => t.trim()).filter(Boolean); const comment = document.getElementById('noteComment').value.trim(); await chrome.storage.local.set({ serverUrl, apiKey, lastNotebook: notebook }); let captured = { pageHtml: '', selectionHtml: '', url: activeTab?.url || '' }; if (activeTab?.id && currentMode !== 'bookmark') { const results = await chrome.scripting.executeScript({ target: { tabId: activeTab.id }, func: () => { // Clone document and resolve lazy-loaded images & relative URLs inside the live tab const clone = document.documentElement.cloneNode(true); clone.querySelectorAll('script, style, noscript, iframe').forEach((el) => el.remove()); clone.querySelectorAll('img').forEach((img) => { const best = img.getAttribute('data-img-url') || img.getAttribute('data-src') || img.getAttribute('data-lazy-src') || img.getAttribute('data-original') || img.currentSrc || img.src; if (best) { try { img.setAttribute('src', new URL(best, location.href).href); } catch {} } }); let selHtml = ''; const sel = window.getSelection(); if (sel && sel.rangeCount > 0 && !sel.isCollapsed) { const container = document.createElement('div'); for (let i = 0; i < sel.rangeCount; i++) { container.appendChild(sel.getRangeAt(i).cloneContents()); } container.querySelectorAll('img').forEach((img) => { if (img.src) img.setAttribute('src', img.src); }); selHtml = container.innerHTML; } return { pageHtml: '' + clone.innerHTML + '', bodyHtml: clone.querySelector('body')?.innerHTML || '', selectionHtml: selHtml, url: location.href, }; }, }); if (results && results[0] && results[0].result) { captured = results[0].result; } } const payload = { title, url: captured.url || activeTab?.url || '', notebook, tags, comment, clipMode: currentMode, }; if (currentMode === 'article') { payload.pageHtml = captured.pageHtml; } else if (currentMode === 'selection') { payload.html = captured.selectionHtml || '

No text selected on page.

'; } else if (currentMode === 'full') { payload.html = captured.bodyHtml || captured.pageHtml; } else if (currentMode === 'bookmark') { payload.html = `

Bookmarked: ${payload.url}

`; } const res = await fetch(`${serverUrl}/api/hooks/note`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify(payload), }); const data = await res.json(); if (!res.ok) { throw new Error(data.error || `HTTP ${res.status}`); } statusBox.className = 'status ok'; statusBox.innerHTML = `✓ Saved to ${notebook}! Open Note`; btn.textContent = 'Clipped!'; } catch (err) { statusBox.className = 'status err'; statusBox.textContent = 'Error: ' + (err.message || String(err)); btn.disabled = false; btn.textContent = 'Save Clip to Everclone'; } }