3GPPDocFinder / static /script.js
om4r932's picture
Remove "Get document content" button
2b49e80
raw
history blame
15.1 kB
// 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 singleInput = document.querySelector('.single-input');
const batchInput = document.querySelector('.batch-input');
const keywordSearchInput = document.querySelector(".keyword-input");
const docIdInput = document.getElementById('doc-id');
const batchIdsInput = document.getElementById('batch-ids');
const keywordInput = document.getElementById("keywords");
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 searchBtn = document.getElementById('search-btn');
const batchSearchBtn = document.getElementById('batch-search-btn');
const keywordSearchBtn = document.getElementById("keyword-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');
singleInput.style.display = 'block';
batchInput.style.display = 'none';
keywordSearchInput.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');
batchInput.style.display = 'block';
keywordSearchInput.style.display = "none";
singleInput.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");
singleInput.style.display = "none";
batchInput.style.display = "none";
keywordSearchInput.style.display = "block";
})
document.getElementById('toggleFilters').onclick = function() {
var target = document.getElementById('filtersForm');
target.style.display = (target.style.display === 'none' || target.style.display === '') ? 'flex' : 'none';
};
keywordSearchBtn.addEventListener("click", async ()=>{
const keywords = keywordInput.value.trim();
if (!keywords) {
showError("Please enter at least one keyword");
return;
}
showLoader();
hideError();
try{
let body = {
keywords,
"case_sensitive": caseSensitiveFilter.checked,
"mode": modeFilter.value
};
if (releaseFilter.value != ""){body.release = releaseFilter.value}
if (workingGroupFilter.value != ""){body["working_group"] = workingGroupFilter.value}
if (specTypeFilter.value != ""){body["spec_type"] = specTypeFilter.value}
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);
} 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();
}
})
// 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 {
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 ? `<p>Scope : ${data.scope}</p>` : ""
resultItem.innerHTML = `
<div class="result-header">
<div class="result-id">${data.doc_id}</div>
<div class="result-status status-found">Found</div>
</div>
<div class="result-url">
<a href="${data.url}" target="_blank">${data.url}</a>
${scopeItem}
</div>
`;
resultsList.appendChild(resultItem);
resultsStats.textContent = `Found in ${data.search_time.toFixed(2)} seconds`;
resultsContainer.style.display = 'block';
}
// Display single not found result
function displaySingleNotFound(docId, message) {
resultsList.innerHTML = '';
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
<div class="result-header">
<div class="result-id">${docId}</div>
<div class="result-status status-not-found">Not Found</div>
</div>
<div>${message}</div>
`;
resultsList.appendChild(resultItem);
resultsStats.textContent = 'Document not found';
resultsContainer.style.display = 'block';
}
function displayKeywordResults(data) {
resultsList.innerHTML = '';
data.results.forEach(spec => {
const resultItem = document.createElement("div");
resultItem.className = "result-item";
resultItem.innerHTML = `
<div class="result-header">
<div class="result-id">${spec.id}</div>
<div class="result-status status-found">Found</div>
</div>
<div class="result-url">
<p>Title: ${spec.title}</p>
<p>Type: ${spec.type}</p>
<p>Release: ${spec.release}</p>
<p>Version: ${spec.version}</p>
<p>WG: ${spec.working_group}</p>
<p>URL: <a target="_blank" href="${spec.url}">${spec.url}</a></p>
<p>Scope: ${spec.scope}</p>
</div>
<div class="result-actions">
<button class="get-section-btn btn" data-spec-id="${spec.id}">Get section</button>
</div>
`;
// Ajouter le bouton au DOM
resultsList.appendChild(resultItem);
// Récupérer le bouton nouvellement créé
const button1 = resultItem.querySelector('.get-section-btn');
// Stocker l'objet directement sur l'élément DOM
button1._sections = spec.contains;
});
document.querySelectorAll('.get-section-btn').forEach(button => {
button.addEventListener('click', function() {
let specId = this.getAttribute("data-spec-id");
let sections = this._sections;
openSectionPopup(specId, sections);
});
});
resultsStats.textContent = `Found ${data.results.length} in ${data.search_time.toFixed(2)} seconds`
resultsContainer.style.display = 'block';
}
function openSectionPopup(specId, sections) {
popupTitle.textContent = `Sections of specification ${specId}`;
popupTextareas.innerHTML = '';
Object.entries(sections).forEach(([section, content], index) => {
const container = document.createElement("div");
container.className = "textarea-container";
const textarea = document.createElement("textarea");
textarea.id = `section-${index}`;
textarea.value = `${section}\n\n${content}`
textarea.readOnly = true;
const copyBtn = document.createElement('button');
copyBtn.className = 'copy-btn';
copyBtn.textContent = 'Copy';
copyBtn.onclick = () => copyTextarea(`section-${index}`);
container.appendChild(textarea);
container.appendChild(copyBtn);
popupTextareas.appendChild(container);
});
sectionPopup.style.display = 'block';
document.body.style.overflow = 'hidden';
}
function copyTextarea(id) {
const textarea = document.getElementById(id);
textarea.select();
document.execCommand("copy");
// Effet visuel pour confirmer la copie
const btn = textarea.nextElementSibling;
const originalText = btn.textContent;
btn.textContent = 'Copied !';
btn.style.backgroundColor = '#34a853';
btn.style.color = 'white';
setTimeout(() => {
btn.textContent = originalText;
btn.style.backgroundColor = '';
btn.style.color = '';
}, 1500);
}
// Fonction pour copier tout le contenu
copyAllBtn.addEventListener('click', () => {
const textareas = popupTextareas.querySelectorAll('textarea');
let allContent = '';
textareas.forEach((textarea, index) => {
allContent += textarea.value;
if (index < textareas.length - 1) {
allContent += '\n\n---\n\n';
}
});
// Créer un textarea temporaire pour copier le contenu
const tempTextarea = document.createElement('textarea');
tempTextarea.value = allContent;
document.body.appendChild(tempTextarea);
tempTextarea.select();
document.execCommand('copy');
document.body.removeChild(tempTextarea);
// Effet visuel pour confirmer la copie
const originalText = copyAllBtn.textContent;
copyAllBtn.textContent = 'Copied all !';
setTimeout(() => {
copyAllBtn.textContent = originalText;
}, 1500);
});
// Fermer la popup
closePopupBtn.addEventListener('click', () => {
sectionPopup.style.display = 'none';
document.body.style.overflow = ''; // Rétablir le défilement du body
});
// Fermer la popup en cliquant à l'extérieur
window.addEventListener('click', (event) => {
if (event.target === sectionPopup) {
sectionPopup.style.display = 'none';
document.body.style.overflow = '';
}
});
// Display batch results
function displayBatchResults(data) {
resultsList.innerHTML = '';
// Found documents
Object.entries(data.results).forEach(([docId, url]) => {
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
<div class="result-header">
<div class="result-id">${docId}</div>
<div class="result-status status-found">Found</div>
</div>
<div class="result-url">
<a href="${url}" target="_blank">${url}</a>
</div>
`;
resultsList.appendChild(resultItem);
});
// Not found documents
data.missing.forEach(docId => {
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
<div class="result-header">
<div class="result-id">${docId}</div>
<div class="result-status status-not-found">Not Found</div>
</div>
`;
resultsList.appendChild(resultItem);
});
const foundCount = Object.keys(data.results).length;
const totalCount = foundCount + data.missing.length;
resultsStats.textContent = `Found ${foundCount} of ${totalCount} documents in ${data.search_time.toFixed(2)} seconds`;
resultsContainer.style.display = 'block';
}
// Show loader
function showLoader() {
loader.style.display = 'block';
}
// Hide loader
function hideLoader() {
loader.style.display = 'none';
}
// Show error message
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
}
// Hide error message
function hideError() {
errorMessage.style.display = 'none';
}
// Enter key event for single search
docIdInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
searchBtn.click();
}
});
keywordInput.addEventListener('keypress', (event)=>{
if (event.key === "Enter"){
keywordSearchBtn.click();
}
})