// DOM elements const dynamicDesc = document.getElementById("dynamicDesc"); const dynamicTitle = document.getElementById("dynamicTitle"); const singleModeBtn = document.getElementById('single-mode-btn'); const batchModeBtn = document.getElementById('batch-mode-btn'); const keywordModeBtn = document.getElementById("keyword-mode-btn"); const expModeBtn = document.getElementById("exp-mode-btn"); const singleInputField = document.querySelector('.single-input'); const batchInputField = document.querySelector('.batch-input'); const keywordInputField = document.querySelector(".keyword-input"); const expKeywordInputField = document.querySelector(".experimental-input"); const docIdInput = document.getElementById('doc-id'); const batchIdsInput = document.getElementById('batch-ids'); const keywordInput = document.getElementById("keywords"); const expKeywordInput = document.getElementById("exp-keywords") const thresholdInput = document.getElementById("threshold"); const releaseFilter = document.querySelector("input[name=release]") const modeFilter = document.querySelector("select[name=mode]") const specTypeFilter = document.querySelector("select[name=spec_type]") const workingGroupFilter = document.querySelector("select[name=working_group]") const caseSensitiveFilter = document.querySelector("input[name=case_sensitive]") const searchMode = document.querySelector("select[name=search_mode]") const releaseFilter2 = document.querySelector("input[name=release2]") const specTypeFilter2 = document.querySelector("select[name=spec_type2]") const workingGroupFilter2 = document.querySelector("select[name=working_group2]") const searchBtn = document.getElementById('search-btn'); const batchSearchBtn = document.getElementById('batch-search-btn'); const keywordSearchBtn = document.getElementById("keyword-search-btn"); const expKeywordSearchBtn = document.getElementById("exp-search-btn"); const loader = document.getElementById('loader'); const resultsContainer = document.getElementById('results-container'); const resultsList = document.getElementById('results-list'); const resultsStats = document.getElementById('results-stats'); const errorMessage = document.getElementById('error-message'); const sectionPopup = document.getElementById('sectionPopup'); const popupTitle = document.getElementById('popupTitle'); const popupTextareas = document.getElementById('popupTextareas'); const copyAllBtn = document.getElementById('copyAllBtn'); const closePopupBtn = document.querySelector('.close-popup'); // Search mode toggle singleModeBtn.addEventListener('click', () => { dynamicTitle.textContent = "Find 3GPP Documents"; dynamicDesc.textContent = "Enter a TSG document ID / specification ID (e.g., S1-123456, C2-987654 or 31.102) to locate the document in the 3GPP FTP server."; singleModeBtn.classList.add('active'); keywordModeBtn.classList.remove("active"); batchModeBtn.classList.remove('active'); expModeBtn.classList.remove('active'); singleInputField.style.display = 'block'; batchInputField.style.display = 'none'; keywordInputField.style.display = "none"; expKeywordInputField.style.display = "none"; }); batchModeBtn.addEventListener('click', () => { dynamicTitle.textContent = "Find multiple 3GPP Documents"; dynamicDesc.textContent = "Enter a list of TSG document ID / specification ID (e.g., S1-123456, C2-987654 or 31.102) to locate all of the specified documents in the 3GPP FTP server."; batchModeBtn.classList.add('active'); keywordModeBtn.classList.remove("active"); singleModeBtn.classList.remove('active'); expModeBtn.classList.remove('active'); batchInputField.style.display = 'block'; keywordInputField.style.display = "none"; singleInputField.style.display = 'none'; expKeywordInputField.style.display = "none"; }); keywordModeBtn.addEventListener('click', () => { dynamicTitle.textContent = "Search 3GPP specifications"; dynamicDesc.textContent = "With keywords and filters, find all of 3GPP's specifications that matches your needs (with keywords, specification number, release or even working group (C1, S5, SP, CP: always the first letter of the group followed by the workgroup number)"; keywordModeBtn.classList.add("active"); singleModeBtn.classList.remove('active'); batchModeBtn.classList.remove("active"); expModeBtn.classList.remove('active'); singleInputField.style.display = "none"; batchInputField.style.display = "none"; expKeywordInputField.style.display = "none"; keywordInputField.style.display = "block"; }) expModeBtn.addEventListener('click', () => { dynamicTitle.textContent = "[EXPERIMENTAL] Search 3GPP specifications"; dynamicDesc.textContent = "With keywords and filters, find all of 3GPP's specifications that matches your needs (with keywords, specification number, release or even working group (C1, S5, SP, CP: always the first letter of the group followed by the workgroup number)"; keywordModeBtn.classList.remove("active"); singleModeBtn.classList.remove('active'); batchModeBtn.classList.remove("active"); expModeBtn.classList.add('active'); singleInputField.style.display = "none"; batchInputField.style.display = "none"; expKeywordInputField.style.display = "block"; keywordInputField.style.display = "none"; }) document.getElementById('toggleFilters').onclick = function() { var target = document.getElementById('filtersForm'); target.style.display = (target.style.display === 'none' || target.style.display === '') ? 'flex' : 'none'; }; document.getElementById('toggleFilters2').onclick = function() { var target = document.getElementById('filtersForm2'); target.style.display = (target.style.display === 'none' || target.style.display === '') ? 'flex' : 'none'; }; expKeywordSearchBtn.addEventListener("click", async ()=>{ let keywords = expKeywordInput.value.trim(); let release = releaseFilter2.value.trim(); let wg = workingGroupFilter2.value.trim(); let specType = specTypeFilter2.value.trim(); let threshold = thresholdInput.value.trim(); if (!keywords){ showError("Please enter at least one keyword"); return; } showLoader(); hideError(); try{ let body = { keywords, threshold }; if (release != ""){body["release"] = release} if (wg != ""){body["working_group"] = wg} if (specType != ""){body["spec_type"] = specType} const response = await fetch("/search-spec/experimental", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const data = await response.json(); if (response.ok){ displayKeywordResults(data, ""); } else if (response.status == 404) { showError('No specification has been found'); } else { showError(`Error processing keyword request: ${data.detail}`) } } catch (error) { showError('Error connecting to the server. Please check if the API is running.'); console.error('Error:', error); } finally { hideLoader(); } }) keywordSearchBtn.addEventListener("click", async ()=>{ let keywords = keywordInput.value.trim(); let release = releaseFilter.value; let wg = workingGroupFilter.value; let specType = specTypeFilter.value; let search = searchMode.value; let checked = caseSensitiveFilter.checked; let mode = modeFilter.value; if (!keywords && searchMode == "deep") { showError("Please enter at least one keyword in deep search mode"); return; } showLoader(); hideError(); try{ let body = { keywords, "search_mode": search, "case_sensitive": checked, "mode": mode }; if (release != ""){body.release = release} if (wg != ""){body["working_group"] = wg} if (specType != ""){body["spec_type"] = specType} const response = await fetch("/search-spec", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const data = await response.json(); if (response.ok){ displayKeywordResults(data, search); } else if (response.status == 404) { showError('No specification has been found'); } else { showError(`Error processing keyword request: ${data.detail}`) } } catch (error) { showError('Error connecting to the server. Please check if the API is running.'); console.error('Error:', error); } finally { hideLoader(); } }) // Single document search searchBtn.addEventListener('click', async () => { const docId = docIdInput.value.trim(); if (!docId) { showError('Please enter a document ID'); return; } showLoader(); hideError(); try { const response = await fetch(`/find`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ doc_id: docId, release: null }) }); const data = await response.json(); if (response.ok) { displaySingleResult(data); } else { displaySingleNotFound(docId, data.detail); } } catch (error) { showError('Error connecting to the server. Please check if the API is running.'); console.error('Error:', error); } finally { hideLoader(); } }); // Batch document search batchSearchBtn.addEventListener('click', async () => { const batchText = batchIdsInput.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; } showLoader(); hideError(); try { const response = await fetch(`/batch`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ doc_ids: docIds }) }); const data = await response.json(); if (response.ok) { displayBatchResults(data); } else if (response.status == 404) { showError('No document has been found'); } else { showError('Error processing batch request') } } catch (error) { showError('Error connecting to the server. Please check if the API is running.'); console.error('Error:', error); } finally { hideLoader(); } }); // Display single result function displaySingleResult(data) { resultsList.innerHTML = ''; const resultItem = document.createElement('div'); resultItem.className = 'result-item'; let scopeItem = data.scope ? `
Scope : ${data.scope}
` : "" resultItem.innerHTML = `Title: ${spec.title}
Type: ${spec.type}
Release: ${spec.release}
Version: ${spec.version}
WG: ${spec.working_group}
URL: ${spec.url}
Scope: ${spec.scope}
${content.replace(/\n/g, '
')}