// Main JavaScript for SpeciScan document.addEventListener('DOMContentLoaded', function() { // DOM Elements const uploadForm = document.getElementById('upload-form'); const nameForm = document.getElementById('name-form'); const fileInput = document.getElementById('file-input'); const fileName = document.getElementById('file-name'); const uploadZone = document.getElementById('upload-zone'); const resultsContainer = document.getElementById('results'); const loadingOverlay = document.getElementById('loading-overlay'); // Handle drag and drop for file upload uploadZone.addEventListener('dragover', function(e) { e.preventDefault(); uploadZone.classList.add('dragover'); }); uploadZone.addEventListener('dragleave', function() { uploadZone.classList.remove('dragover'); }); uploadZone.addEventListener('drop', function(e) { e.preventDefault(); uploadZone.classList.remove('dragover'); if (e.dataTransfer.files.length) { fileInput.files = e.dataTransfer.files; updateFileName(); } }); // Update file name display when file is selected fileInput.addEventListener('change', updateFileName); function updateFileName() { if (fileInput.files.length > 0) { fileName.textContent = fileInput.files[0].name; uploadZone.classList.add('has-file'); } else { fileName.textContent = ''; uploadZone.classList.remove('has-file'); } } // Handle image upload form submission uploadForm.addEventListener('submit', function(e) { e.preventDefault(); if (fileInput.files.length === 0) { alert('Please select an image file.'); return; } const formData = new FormData(); formData.append('file', fileInput.files[0]); // Show loading overlay loadingOverlay.classList.add('active'); // Submit form data to server fetch('/upload_image', { method: 'POST', body: formData }) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { // Hide loading overlay loadingOverlay.classList.remove('active'); // Display results displayResults(data); }) .catch(error => { // Hide loading overlay loadingOverlay.classList.remove('active'); console.error('Error:', error); alert('Error: ' + error.message); }); }); // Handle species name form submission nameForm.addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(nameForm); // Show loading overlay loadingOverlay.classList.add('active'); // Submit form data to server fetch('/search_by_name', { method: 'POST', body: formData }) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { // Hide loading overlay loadingOverlay.classList.remove('active'); // Display results displayResults(data); }) .catch(error => { // Hide loading overlay loadingOverlay.classList.remove('active'); console.error('Error:', error); alert('Error: ' + error.message); }); }); // Handle suggestion chips const suggestionChips = document.querySelectorAll('.chip'); const speciesNameInput = nameForm.querySelector('input[name="species_name"]'); suggestionChips.forEach(chip => { chip.addEventListener('click', function() { const speciesName = this.getAttribute('data-species'); speciesNameInput.value = speciesName; nameForm.dispatchEvent(new Event('submit')); }); }); // Function to display results function displayResults(data) { // Scroll to results resultsContainer.scrollIntoView({ behavior: 'smooth' }); // Check if we have valid data if (data.error) { resultsContainer.innerHTML = `

Error

${data.error}

`; resultsContainer.classList.add('active'); return; } // Extract data const speciesData = data.species_data; const images = data.images; // Check if species data contains an error if (speciesData.error) { // If we have some basic information despite the error, display it with a notice if (speciesData.title) { let errorHtml = `

${speciesData.error}

`; // Build the complete HTML for limited results const resultsHtml = `
${speciesData.title}

${speciesData.title}

${speciesData.title}

${errorHtml}

${speciesData.description || 'No description available.'}

`; // Update the results container and make it visible resultsContainer.innerHTML = resultsHtml; resultsContainer.classList.add('active'); return; } resultsContainer.innerHTML = `

Error

${speciesData.error}

`; resultsContainer.classList.add('active'); return; } // Build the classification table let classificationHtml = ''; const classification = speciesData.classification; for (const [rank, taxon] of Object.entries(classification)) { if (taxon !== 'Unknown') { classificationHtml += ` ${capitalizeFirstLetter(rank)} ${taxon} `; } } // Build fun facts HTML let funFactsHtml = ''; if (speciesData.fun_facts && speciesData.fun_facts.length > 0) { speciesData.fun_facts.forEach(fact => { funFactsHtml += `
  • ${fact}
  • `; }); } else { funFactsHtml = '
  • No fun facts available.
  • '; } // Build image gallery HTML let galleryHtml = ''; if (images && images.length > 0) { images.forEach(image => { // Skip images with errors if (image.error) return; galleryHtml += ` `; }); } else { galleryHtml = '

    No images available.

    '; } // Get the main image from the first gallery image or use a placeholder const mainImageUrl = images && images.length > 0 && !images[0].error ? images[0].url : 'https://via.placeholder.com/300x250?text=No+Image+Available'; // Build the complete HTML for results const resultsHtml = `
    ${speciesData.title}

    ${speciesData.title}

    ${speciesData.title}

    ${speciesData.description || 'No description available.'}

    Classification

    ${classificationHtml}

    Habitat

    ${speciesData.habitat || 'Habitat information not available.'}

    Fun Facts

    ${speciesData.data_sources ? `

    Data sources: ${speciesData.data_sources.join(', ')}

    ` : ''} `; // Update the results container and make it visible resultsContainer.innerHTML = resultsHtml; resultsContainer.classList.add('active'); } // Helper function to capitalize the first letter of a string function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } });