Files
everclone/brave-extension/popup.js
T

184 lines
6.8 KiB
JavaScript

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 === '<YOUR_API_KEY>') {
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: '<!DOCTYPE html><html>' + clone.innerHTML + '</html>',
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 || '<p>No text selected on page.</p>';
} else if (currentMode === 'full') {
payload.html = captured.bodyHtml || captured.pageHtml;
} else if (currentMode === 'bookmark') {
payload.html = `<p>Bookmarked: <a href="${payload.url}" target="_blank">${payload.url}</a></p>`;
}
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 <strong>${notebook}</strong>! <a href="${serverUrl}/?noteId=${data.noteId}" target="_blank" style="color:#fff;text-decoration:underline;margin-left:6px;">Open Note</a>`;
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';
}
}