/** * corpus-save.js — Shared "Save to corpus" handler. * * Two trigger paths: * * 1. Tool pages — buttons with class="js-save-corpus": * data-content-id="" * data-tool="" * data-suggested-title="" (optional) * * 2. Dashboard chat — page code calls: * dialog.dataset.pendingContent = "..."; * dialog.dataset.pendingTool = "dashboard-chat"; (optional) * dialog.showModal(); * Title and tags are populated by the caller before showModal(). * * Endpoint resolution: if window.DBN_DASHBOARD is present (dashboard pages), * POST to /api/dashboard/save-from-tool.php; otherwise fall back to the * legacy /api/save-to-corpus.php so existing tools keep working. */ (function () { 'use strict'; const dlg = document.getElementById('save-corpus-dialog'); const form = document.getElementById('save-corpus-form'); const titleIn = document.getElementById('save-corpus-title'); const tagsIn = document.getElementById('save-corpus-tags'); const cancelBtn = document.getElementById('save-corpus-cancel'); if (!dlg || !form) return; cancelBtn?.addEventListener('click', () => dlg.close()); let _pendingBtn = null; function endpoint() { return window.DBN_DASHBOARD ? '/api/dashboard/save-from-tool.php' : '/api/save-to-corpus.php'; } function bodyFor(kind, payload) { if (window.DBN_DASHBOARD) { return JSON.stringify({ title: payload.title, content: payload.content, source_tool: payload.tool || 'dashboard-save', tags: payload.tags, kind, }); } return JSON.stringify({ title: payload.title, content: payload.content, source_tool: payload.tool || '', tags: payload.tags, }); } // ── Path 1: legacy tool buttons (.js-save-corpus) ───────────────────── document.addEventListener('click', (e) => { const btn = e.target.closest('.js-save-corpus'); if (!btn) return; const contentId = btn.dataset.contentId; const el = contentId ? document.getElementById(contentId) : null; const content = (el ? (el.value ?? el.textContent) : '').trim(); if (!content || content.length < 30) { btn.textContent = 'Nothing to save'; setTimeout(() => { btn.textContent = 'Save to corpus'; }, 2000); return; } _pendingBtn = btn; dlg.dataset.pendingContent = content; dlg.dataset.pendingTool = btn.dataset.tool || ''; dlg.dataset.pendingKind = 'tool_output'; titleIn.value = btn.dataset.suggestedTitle || ''; tagsIn.value = ''; dlg.showModal(); titleIn.focus(); titleIn.select(); }); // ── Submit dialog (both paths) ──────────────────────────────────────── form.addEventListener('submit', async (e) => { e.preventDefault(); dlg.close(); const btn = _pendingBtn; const content = dlg.dataset.pendingContent || ''; const tool = dlg.dataset.pendingTool || ''; const kind = dlg.dataset.pendingKind || 'tool_output'; const title = titleIn.value.trim(); const tags = tagsIn.value.trim(); if (!title || !content) return; if (btn) { btn.disabled = true; btn.textContent = 'Saving…'; } try { const resp = await fetch(endpoint(), { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: bodyFor(kind, { title, content, tool, tags }), }); const data = await resp.json().catch(() => ({})); if (resp.ok && data.ok) { if (btn) { btn.textContent = '✓ Saved to corpus'; btn.classList.add('js-save-corpus--saved'); } else { // Path 2 (no button): show a fleeting toast showToast('Lagret i korpus — ' + (data.chunks || 0) + ' passasjer'); } } else { const msg = (data.error && data.error.message) || data.error || ('Error ' + resp.status); if (btn) { btn.textContent = 'Save failed'; btn.disabled = false; btn.title = msg; } else { showToast('Lagring feilet: ' + msg, true); } console.error('[corpus-save] Save failed:', msg); } } catch (err) { if (btn) { btn.textContent = 'Network error'; btn.disabled = false; } else { showToast('Nettverksfeil', true); } console.error('[corpus-save] Network error:', err); } _pendingBtn = null; delete dlg.dataset.pendingContent; delete dlg.dataset.pendingTool; delete dlg.dataset.pendingKind; }); function showToast(msg, isError) { const t = document.createElement('div'); t.textContent = msg; t.style.cssText = 'position:fixed;bottom:1.5rem;left:50%;transform:translateX(-50%);' + 'padding:0.65rem 1rem;border-radius:10px;font:inherit;font-size:0.9rem;' + 'z-index:99999;color:#fff;background:' + (isError ? '#ba0c2f' : '#00205b') + ';' + 'box-shadow:0 8px 24px rgba(0,0,0,0.25);'; document.body.appendChild(t); setTimeout(() => t.remove(), 3500); } }());