Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', () => { | |
| const papersGrid = document.getElementById('papersGrid'); | |
| const searchInput = document.getElementById('searchInput'); | |
| const dateFrom = document.getElementById('dateFrom'); | |
| const dateTo = document.getElementById('dateTo'); | |
| const searchBtn = document.getElementById('searchBtn'); | |
| const loader = document.getElementById('loader'); | |
| const noResults = document.getElementById('noResults'); | |
| const resultCount = document.getElementById('resultCount'); | |
| // Default query for AI papers | |
| const DEFAULT_QUERY = 'cat:cs.AI OR cat:cs.LG OR cat:cs.CL'; | |
| // Initial Fetch | |
| fetchPapers(DEFAULT_QUERY); | |
| // Event Listeners | |
| searchBtn.addEventListener('click', () => { | |
| const query = searchInput.value.trim(); | |
| fetchPapers(query ? `all:${query}` : DEFAULT_QUERY); | |
| }); | |
| searchInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| searchBtn.click(); | |
| } | |
| }); | |
| // Date Filter Listener (Client-side filter on loaded data) | |
| // For simplicity in this demo, we re-fetch or filter if data is present. | |
| // Here we'll re-trigger the search logic to apply filters if data exists, | |
| // but for a robust app, we'd store the 'allPapers' array. | |
| let allPapersData = []; | |
| dateFrom.addEventListener('change', applyClientFilters); | |
| dateTo.addEventListener('change', applyClientFilters); | |
| async function fetchPapers(searchQuery) { | |
| showLoader(true); | |
| noResults.classList.add('hidden'); | |
| papersGrid.innerHTML = ''; | |
| try { | |
| // ArXiv API endpoint | |
| const baseUrl = 'http://export.arxiv.org/api/query?'; | |
| const params = new URLSearchParams({ | |
| search_query: searchQuery, | |
| start: 0, | |
| max_results: 50, // Fetch a good amount to filter by date | |
| sortBy: 'submittedDate', | |
| sortOrder: 'descending' | |
| }); | |
| const response = await fetch(baseUrl + params.toString()); | |
| if (!response.ok) throw new Error('Network response was not ok'); | |
| const xmlText = await response.text(); | |
| const papers = parseArxivXml(xmlText); | |
| allPapersData = papers; | |
| applyClientFilters(); // Apply any existing date filters immediately | |
| } catch (error) { | |
| console.error('Error fetching papers:', error); | |
| resultCount.textContent = 'Error fetching data'; | |
| noResults.classList.remove('hidden'); | |
| showLoader(false); | |
| } | |
| } | |
| function parseArxivXml(xmlString) { | |
| const parser = new DOMParser(); | |
| const xmlDoc = parser.parseFromString(xmlString, "text/xml"); | |
| const entries = xmlDoc.getElementsByTagName("entry"); | |
| const papers = []; | |
| for (let i = 0; i < entries.length; i++) { | |
| const entry = entries[i]; | |
| // Title | |
| const title = entry.getElementsByTagName("title")[0].textContent; | |
| // Summary (Abstract) - Remove newlines and trim | |
| const summary = entry.getElementsByTagName("summary")[0].textContent.replace(/\s+/g, ' ').trim(); | |
| // Published Date | |
| const published = entry.getElementsByTagName("published")[0].textContent; | |
| // Authors | |
| const authors = []; | |
| const authorNodes = entry.getElementsByTagName("author"); | |
| for (let j = 0; j < authorNodes.length; j++) { | |
| authors.push(authorNodes[j].getElementsByTagName("name")[0].textContent); | |
| } | |
| // Link (PDF) | |
| const links = entry.getElementsByTagName("link"); | |
| let pdfLink = ""; | |
| for(let k=0; k<links.length; k++) { | |
| if(links[k].getAttribute("type") === "application/pdf") { | |
| pdfLink = links[k].getAttribute("href"); | |
| break; | |
| } | |
| } | |
| // Arxiv ID Link | |
| const idLink = entry.getElementsByTagName("id")[0].textContent; | |
| papers.push({ | |
| title, | |
| summary, | |
| published, | |
| authors, | |
| pdfLink, | |
| idLink | |
| }); | |
| } | |
| return papers; | |
| } | |
| function applyClientFilters() { | |
| papersGrid.innerHTML = ''; | |
| const fromVal = dateFrom.value ? new Date(dateFrom.value) : null; | |
| const toVal = dateTo.value ? new Date(dateTo.value) : null; | |
| // Set time to end of day for 'to' filter to be inclusive | |
| if (toVal) toVal.setHours(23, 59, 59, 999); | |
| const filteredPapers = allPapersData.filter(paper => { | |
| const paperDate = new Date(paper.published); | |
| let isValid = true; | |
| if (fromVal && paperDate < fromVal) isValid = false; | |
| if (toVal && paperDate > toVal) isValid = false; | |
| return isValid; | |
| }); | |
| displayPapers(filteredPapers); | |
| } | |
| function displayPapers(papers) { | |
| showLoader(false); | |
| resultCount.textContent = `Found ${papers.length} papers`; | |
| if (papers.length === 0) { | |
| noResults.classList.remove('hidden'); | |
| return; | |
| } | |
| papers.forEach(paper => { | |
| // Create Web Component | |
| const card = document.createElement('paper-card'); | |
| // Pass data to component | |
| card.setAttribute('title', paper.title); | |
| card.setAttribute('summary', paper.summary); | |
| card.setAttribute('authors', paper.authors.join(', ')); | |
| card.setAttribute('date', new Date(paper.published).toLocaleDateString()); | |
| card.setAttribute('pdf-link', paper.pdfLink); | |
| card.setAttribute('abs-link', paper.idLink); | |
| papersGrid.appendChild(card); | |
| }); | |
| } | |
| function showLoader(show) { | |
| if (show) { | |
| loader.classList.remove('hidden'); | |
| papersGrid.classList.add('hidden'); | |
| resultCount.textContent = 'Searching...'; | |
| } else { | |
| loader.classList.add('hidden'); | |
| papersGrid.classList.remove('hidden'); | |
| } | |
| } | |
| }); |