// Global application state let currentResults = []; let currentMode = 'single'; // Initialization document.addEventListener('DOMContentLoaded', function() { initializeApp(); }); function initializeApp() { setupTabHandlers(); setupKeyboardHandlers(); updateHeaderStats('Ready'); } // Tab management function setupTabHandlers() { document.querySelectorAll('.tab-button').forEach(button => { button.addEventListener('click', function() { const mode = this.dataset.mode; switchMode(mode); }); }); } function switchMode(mode) { currentMode = mode; // Update tabs document.querySelectorAll('.tab-button').forEach(btn => { btn.classList.remove('active'); }); document.querySelector(`[data-mode="${mode}"]`).classList.add('active'); // Update forms document.querySelectorAll('.search-form').forEach(form => { form.classList.remove('active'); }); document.getElementById(`${mode}-form`).classList.add('active'); // Reset results hideResults(); } // Keyboard shortcuts management function setupKeyboardHandlers() { document.getElementById('doc-id').addEventListener('keypress', function(e) { if (e.key === 'Enter') searchSingle(); }); document.getElementById('keywords').addEventListener('keypress', function(e) { if (e.key === 'Enter') searchKeyword(); }); document.getElementById('bm25-keywords').addEventListener('keypress', function(e) { if (e.key === 'Enter') searchBM25(); }); } // Search functions async function searchSingle() { const docId = document.getElementById('doc-id').value.trim(); if (!docId) { showError('Please enter a document ID'); return; } showLoading(); updateHeaderStats('Searching...'); try { const response = await fetch(`/find/single`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ doc_id: docId }) }); const data = await response.json(); if (response.ok) { displaySingleResult(data); updateHeaderStats(`Found in ${data.search_time.toFixed(3)}s`); } else { showError(data.detail); updateHeaderStats('Error'); } } catch (error) { showError('Error connecting to server'); updateHeaderStats('Error'); console.error('Error:', error); } finally { hideLoading(); } } async function searchBatch() { const batchText = document.getElementById('batch-ids').value.trim(); if (!batchText) { showError('Please enter at least one document ID'); return; } const docIds = batchText.split('\n') .map(id => id.trim()) .filter(id => id !== ''); if (docIds.length === 0) { showError('Please enter at least one valid document ID'); return; } showLoading(); updateHeaderStats('Searching...'); try { const response = await fetch(`/find/batch`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ doc_ids: docIds }) }); const data = await response.json(); if (response.ok) { displayBatchResults(data); updateHeaderStats(`${Object.keys(data.results).length} found, ${data.missing.length} missing - ${data.search_time.toFixed(3)}s`); } else { showError(data.detail); updateHeaderStats('Error'); } } catch (error) { showError('Error connecting to server'); updateHeaderStats('Error'); console.error('Error:', error); } finally { hideLoading(); } } async function searchKeyword() { const keywords = document.getElementById('keywords').value.trim(); const searchMode = document.getElementById('search-mode-filter').value; if (!keywords && searchMode === 'deep') { showError('Please enter at least one keyword in deep search mode'); return; } showLoading(); updateHeaderStats('Searching...'); try { const body = { keywords: keywords, search_mode: searchMode, case_sensitive: document.getElementById('case-sensitive-filter').checked, source: document.getElementById('source-filter').value, mode: document.getElementById('mode-filter').value }; const specType = document.getElementById('spec-type-filter').value; if (specType) { body.spec_type = specType; } const response = await fetch(`/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body) }); const data = await response.json(); if (response.ok) { displaySearchResults(data); updateHeaderStats(`${data.results.length} result(s) - ${data.search_time.toFixed(3)}s`); } else { showError(data.detail); updateHeaderStats('Error'); } } catch (error) { showError('Error connecting to server'); updateHeaderStats('Error'); console.error('Error:', error); } finally { hideLoading(); } } async function searchBM25() { const keywords = document.getElementById('bm25-keywords').value.trim(); if (!keywords) { showError('Please enter a search query'); return; } showLoading(); updateHeaderStats('Searching...'); try { const body = { keywords: keywords, source: document.getElementById('bm25-source-filter').value, threshold: parseInt(document.getElementById('threshold').value) || 60 }; const specType = document.getElementById('bm25-spec-type-filter').value; if (specType) { body.spec_type = specType; } const response = await fetch(`/search/bm25`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body) }); const data = await response.json(); if (response.ok) { displaySearchResults(data); updateHeaderStats(`${data.results.length} result(s) - ${data.search_time.toFixed(3)}s`); } else { showError(data.detail); updateHeaderStats('Error'); } } catch (error) { showError('Error connecting to server'); updateHeaderStats('Error'); console.error('Error:', error); } finally { hideLoading(); } } // Results display functions function displaySingleResult(data) { const resultsContent = document.getElementById('results-content'); resultsContent.innerHTML = `
${data.doc_id}
Found
${data.version ? `
Version: ${data.version}
` : ''} ${data.scope ? `
Scope: ${data.scope}
` : ''}
`; showResults(); } function displayBatchResults(data) { const resultsContent = document.getElementById('results-content'); let html = ''; // Found results Object.entries(data.results).forEach(([docId, url]) => { html += `
${docId}
Found
URL: ${url}
`; }); // Missing documents data.missing.forEach(docId => { html += `
${docId}
Not Found
Document not found or not indexed
`; }); resultsContent.innerHTML = html; showResults(); } function displaySearchResults(data) { const resultsContent = document.getElementById('results-content'); currentResults = data.results; let html = ''; data.results.forEach((spec, index) => { const hasContent = spec.contains && Object.keys(spec.contains).length > 0; html += `
${spec.id}
${spec.type || 'Specification'}
Title: ${spec.title}
${spec.version ? `
Version: ${spec.version}
` : ''} ${spec.working_group ? `
Working Group: ${spec.working_group}
` : ''} ${spec.type ? `
Type: ${spec.type}
` : ''} ${spec.scope ? `
Scope: ${spec.scope}
` : ''} ${hasContent ? `` : ''}
`; }); resultsContent.innerHTML = html; showResults(); } // Content display functions function viewContent(index) { const spec = currentResults[index]; if (!spec.contains) return; document.getElementById('content-title').textContent = `${spec.id} - ${spec.title}`; const contentSections = document.getElementById('content-sections'); let html = ''; Object.entries(spec.contains).forEach(([sectionTitle, content]) => { html += `

${sectionTitle}

${content}

`; }); contentSections.innerHTML = html; showContentPage(); } function closeContentPage() { hideContentPage(); } function copyAllContent() { const sections = document.querySelectorAll('.content-section p'); const allText = Array.from(sections).map(p => p.textContent).join('\n\n'); copyText(allText); } function copyText(text) { navigator.clipboard.writeText(text).then(() => { showSuccess('Text copied to clipboard'); }).catch(() => { showError('Error copying text'); }); } // Interface utilities function showLoading() { document.getElementById('loading-container').style.display = 'flex'; hideResults(); hideError(); } function hideLoading() { document.getElementById('loading-container').style.display = 'none'; } function showResults() { document.getElementById('results-container').style.display = 'block'; hideError(); } function hideResults() { document.getElementById('results-container').style.display = 'none'; } function showContentPage() { document.getElementById('content-page').classList.add('active'); } function hideContentPage() { document.getElementById('content-page').classList.remove('active'); } function showError(message) { hideError(); const errorDiv = document.createElement('div'); errorDiv.className = 'error-message'; errorDiv.textContent = message; document.querySelector('.search-container').appendChild(errorDiv); setTimeout(() => { hideError(); }, 5000); } function showSuccess(message) { hideError(); const successDiv = document.createElement('div'); successDiv.className = 'success-message'; successDiv.textContent = message; document.querySelector('.search-container').appendChild(successDiv); setTimeout(() => { hideError(); }, 3000); } function hideError() { const existingMessages = document.querySelectorAll('.error-message, .success-message'); existingMessages.forEach(msg => msg.remove()); } function updateHeaderStats(text) { document.getElementById('header-stats').innerHTML = `${text}`; }