Crystina
init
0a97af6
// Global variables
let allPapers = [];
let filteredPapers = [];
let searchKeywords = [];
let removeSearchKeywords = [];
let currentPage = 1;
let papersPerPage = 10;
let selectedYearMin = 1960;
let selectedYearMax = 2025;
let yearFilterActive = false;
let selectedConferences = [];
let conferenceFilterActive = false;
let conferencesData = {};
let includeNoAbstract = true;
let abstractFilterActive = false;
let includeNoAuthor = true;
let authorFilterActive = false;
let showOnlyStarred = false;
let starredFilterActive = false;
let starredPapers = []; // Array to store starred paper keys
// Multilingual keywords for filtering
const multilingualKeywords = [
'multilingual', 'crosslingual', 'multi lingual', 'cross lingual',
'multi-lingual', 'cross-lingual', 'low-resource language', 'low resource language',
'multi-language', 'multi language', 'cross-language', 'cross language',
'language transfer',
'code-switching', 'code switching', 'language adaptation',
'language pair', 'bilingual', 'trilingual', 'polyglot',
'translation', "nmt",
'transliteration',
'multilingual bert', 'xlm', 'mbert', 'xlm-roberta',
'language identification', 'language detection'
]
// Language names for filtering
const languageNames = [
'english', 'afrikaans', 'albanian', 'amharic', 'arabic', 'armenian', 'azerbaijani', 'basque', 'belarusian', 'bengali', 'bosnian', 'bulgarian', 'catalan', 'cebuano', 'chinese', 'croatian', 'czech', 'danish', 'dutch', 'esperanto', 'estonian', 'filipino', 'finnish', 'french', 'galician', 'georgian', 'german', 'greek', 'gujarati', 'haitian', 'hausa', 'hawaiian', 'hebrew', 'hindi', 'hmong', 'hungarian', 'icelandic', 'igbo', 'indonesian', 'irish', 'italian', 'japanese', 'javanese', 'kannada', 'kazakh', 'khmer', 'korean', 'kurdish', 'kyrgyz', 'lao', 'latin', 'latvian', 'lithuanian', 'luxembourgish', 'macedonian', 'malagasy', 'malay', 'malayalam', 'maltese', 'maori', 'marathi', 'mongolian', 'myanmar', 'nepali', 'norwegian', 'odia', 'pashto', 'persian', 'polish', 'portuguese', 'punjabi', 'romanian', 'russian', 'samoan', 'scots gaelic', 'serbian', 'sesotho', 'shona', 'sindhi', 'sinhala', 'slovak', 'slovenian', 'somali', 'spanish', 'sundanese', 'swahili', 'swedish', 'tagalog', 'tajik', 'tamil', 'telugu', 'thai', 'turkish', 'ukrainian', 'urdu', 'uzbek', 'vietnamese', 'welsh', 'xhosa', 'yiddish', 'yoruba', 'zulu',
// Additional language variations and names
'mandarin', 'cantonese', 'hindi', 'urdu', 'bengali', 'tamil', 'telugu', 'marathi', 'gujarati', 'kannada', 'malayalam', 'punjabi', 'odia', 'assamese', 'maithili', 'sanskrit', 'kashmiri', 'konkani', 'manipuri', 'nepali', 'sindhi', 'dogri', 'bodo', 'santali', 'khasi', 'mizo', 'garo', 'naga', 'tibetan', 'dzongkha', 'sikkimese', 'lepcha', 'limbu', 'tamang', 'gurung', 'magar', 'tharu', 'rajbanshi', 'bhojpuri', 'awadhi', 'chhattisgarhi', 'haryanvi', 'braj', 'bundeli', 'bagheli', 'chhattisgarhi', 'garhwali', 'kumaoni', 'jaunsari', 'kangri', 'mandeali', 'himachali', 'pahari', 'dogri', 'kashmiri', 'ladakhi', 'balti', 'shina', 'burushaski', 'khowar', 'wakhi', 'domaki', 'kohistani', 'torwali', 'palula', 'sawi', 'gawar-bati', 'kalasha', 'dameli', 'phalura', 'savi', 'kundal shahi', 'bateri', 'chilisso', 'gawro', 'kalkoti', 'kashmiri', 'kohistani', 'palula', 'sawi', 'shina', 'torwali', 'wakhi', 'yidgha', 'zangskari', 'balti', 'burushaski', 'domaki', 'khowar', 'shina', 'wakhi', 'domaki', 'kohistani', 'torwali', 'palula', 'sawi', 'gawar-bati', 'kalasha', 'dameli', 'phalura', 'savi', 'kundal shahi', 'bateri', 'chilisso', 'gawro', 'kalkoti', 'kashmiri', 'kohistani', 'palula', 'sawi', 'shina', 'torwali', 'wakhi', 'yidgha', 'zangskari',
'african', 'indian', 'indic', 'asian', "indigenous",
];
// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
});
async function initializeApp() {
try {
await Promise.all([
loadBibTeXFile(),
loadConferencesData()
]);
setupEventListeners();
populateConferenceSelect();
updateAbstractFilterInfo();
updateAuthorFilterInfo();
updateStarredFilterInfo();
updateSearchKeywordsDisplay();
updateRemoveKeywordsDisplay();
updateStarredCount(); // Initialize starred count
console.log('Initial filter states:', {
includeNoAbstract,
abstractFilterActive,
includeNoAuthor,
authorFilterActive
});
filterPapers();
} catch (error) {
console.error('Error initializing app:', error);
showError('Failed to load papers. Please refresh the page.');
}
}
async function loadBibTeXFile() {
const loadingIndicator = document.getElementById('loadingIndicator');
const papersList = document.getElementById('papersList');
try {
loadingIndicator.style.display = 'block';
papersList.style.display = 'none';
// Try to load the multilingual papers file first
let response = await fetch('data/multilingual_papers.bib');
// let response = await fetch('https://github.com/crystina-z/multilingual-paperbase/raw/refs/heads/master/data/multilingual_papers.bib');
if (response.ok) {
// Load from pre-filtered multilingual papers file
const bibText = await response.text();
allPapers = parseBibTeX(bibText);
console.log(`Loaded ${allPapers.length} multilingual papers from multilingual_papers.bib`);
} else {
// If multilingual file doesn't exist, report error and ask user to run python script
console.error('Multilingual papers file not found. Please run the python script to generate the file.');
throw new Error('Multilingual papers file not found. Please run the python script to generate the file.');
}
filteredPapers = [...allPapers];
updateResultCount();
loadingIndicator.style.display = 'none';
papersList.style.display = 'grid';
} catch (error) {
console.error('Error loading BibTeX file:', error);
loadingIndicator.style.display = 'none';
showError('Failed to load the BibTeX file. Please check if the file exists.');
}
}
async function loadConferencesData() {
try {
const response = await fetch('data/unique_conferences.json');
// const response = await fetch('https://github.com/crystina-z/multilingual-paperbase/raw/refs/heads/master/data/unique_conferences.json');
// const response = await fetch('https://github.com/crystina-z/multilingual-paperbase/data/unique_conferences.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
conferencesData = await response.json();
console.log('Available conference keys:', Object.keys(conferencesData));
} catch (error) {
console.error('Error loading conferences data:', error);
conferencesData = {};
}
}
function populateConferenceSelect() {
const conferenceSelect = document.getElementById('conferenceSelect');
if (!conferenceSelect || !conferencesData) return;
// Clear existing options
conferenceSelect.innerHTML = '';
// Sort conferences by count (descending), but put "Others (820 Venues)" at the bottom
const sortedConferences = Object.entries(conferencesData)
.sort((a, b) => {
// Put "Others (820 Venues)" at the bottom
if (a[0].includes('Others')) return 1;
if (b[0].includes('Others')) return -1;
// Sort by count descending
return b[1].count - a[1].count;
});
// Add options to select
sortedConferences.forEach(([conferenceName, conferenceData]) => {
const option = document.createElement('option');
option.value = conferenceName;
option.textContent = `${conferenceName} (${conferenceData.count})`;
conferenceSelect.appendChild(option);
});
// Initialize the display
updateConferenceCountDisplay();
updateSelectedConferencesDisplay();
}
function parseBibTeX(bibText) {
const papers = [];
const entries = bibText.split(/(?=@)/);
for (const entry of entries) {
if (!entry.trim()) continue;
try {
const paper = parseBibTeXEntry(entry);
if (paper && (paper.title || paper.abstract)) {
papers.push(paper);
}
} catch (error) {
console.warn('Error parsing entry:', error);
}
}
return papers;
}
function parseBibTeXEntry(entry) {
const paper = {};
// Extract entry type and key
const typeMatch = entry.match(/@(\w+)\{([^,]+)/);
if (typeMatch) {
paper.type = typeMatch[1];
paper.key = typeMatch[2];
}
// Extract fields
const fields = ['title', 'author', 'abstract', 'year', 'booktitle', 'journal', 'pages'];
for (const field of fields) {
const regex = new RegExp(`${field}\\s*=\\s*\\{([^}]*)\\}|${field}\\s*=\\s*"([^"]*)"`, 'gi');
const match = entry.match(regex);
if (match) {
let value = match[0].replace(new RegExp(`${field}\\s*=\\s*[{"']?|["}']?$`, 'gi'), '');
// Clean up LaTeX commands
value = cleanLatexCommands(value);
paper[field] = value.trim();
}
}
// Extract conference information
if (paper.booktitle) {
paper.conference = paper.booktitle;
} else if (paper.journal) {
paper.conference = paper.journal;
}
// Extract year from key if not found in fields
if (!paper.year && paper.key) {
const yearMatch = paper.key.match(/\d{4}/);
if (yearMatch) {
paper.year = yearMatch[0];
}
}
// Determine if paper is multilingual
paper.isMultilingual = isMultilingualPaper(paper);
paper.keywords = extractKeywords(paper);
return paper;
}
function cleanLatexCommands(text) {
if (!text) return '';
return text
.replace(/\\[a-zA-Z]+\{([^}]*)\}/g, '$1') // Remove LaTeX commands with braces
.replace(/\\[a-zA-Z]+/g, '') // Remove simple LaTeX commands
.replace(/\{\\?([^}]*)\}/g, '$1') // Remove braces
.replace(/\\"/g, '"') // Replace escaped quotes
.replace(/\\'/g, "'") // Replace escaped apostrophes
.replace(/\\&/g, '&') // Replace escaped ampersands
.replace(/\\%/g, '%') // Replace escaped percent signs
.replace(/\\_/g, '_') // Replace escaped underscores
.replace(/\\\$/g, '$') // Replace escaped dollar signs
.replace(/\s+/g, ' ') // Normalize whitespace
.trim();
}
function isMultilingualPaper(paper) {
const text = `${paper.title || ''} ${paper.abstract || ''}`.toLowerCase();
// Check for multilingual keywords
for (const keyword of multilingualKeywords) {
if (text.includes(keyword.toLowerCase())) {
return true;
}
}
// Check for language names
for (const language of languageNames) {
if (text.includes(language.toLowerCase())) {
return true;
}
}
return false;
}
function extractKeywords(paper) {
const keywords = [];
const text = `${paper.title || ''} ${paper.abstract || ''}`.toLowerCase();
// Extract multilingual keywords
for (const keyword of multilingualKeywords) {
if (text.includes(keyword.toLowerCase())) {
keywords.push(keyword);
}
}
// Extract language names
for (const language of languageNames) {
if (text.includes(language.toLowerCase())) {
keywords.push(language);
}
}
// Additional keyword extraction based on common patterns
const additionalPatterns = [
{ pattern: /(\d+)\s*languages?/gi, keyword: 'multiple languages' },
{ pattern: /(\d+)\s*lingual/gi, keyword: 'multiple lingual' },
{ pattern: /translation\s+model/gi, keyword: 'translation model' },
{ pattern: /cross\s*lingual/gi, keyword: 'cross-lingual' },
{ pattern: /multi\s*lingual/gi, keyword: 'multilingual' },
{ pattern: /zero\s*shot/gi, keyword: 'zero-shot' },
{ pattern: /few\s*shot/gi, keyword: 'few-shot' },
{ pattern: /code\s*switch/gi, keyword: 'code-switching' },
{ pattern: /language\s+transfer/gi, keyword: 'language transfer' },
{ pattern: /language\s+adaptation/gi, keyword: 'language adaptation' },
{ pattern: /language\s+identification/gi, keyword: 'language identification' },
{ pattern: /language\s+detection/gi, keyword: 'language detection' }
];
for (const { pattern, keyword } of additionalPatterns) {
if (pattern.test(text)) {
keywords.push(keyword);
}
}
// Remove duplicates and sort
return [...new Set(keywords)].sort();
}
function updateAuthorFilterInfo() {
const authorFilterInfo = document.getElementById('authorFilterInfo');
if (authorFilterInfo) {
if (authorFilterActive) {
authorFilterInfo.textContent = '(Showing only papers with author information)';
} else {
authorFilterInfo.textContent = '(Showing all papers)';
}
}
}
function updateStarredFilterInfo() {
const starredFilterInfo = document.getElementById('starredFilterInfo');
if (starredFilterInfo) {
if (starredFilterActive) {
starredFilterInfo.textContent = `(Showing only ${starredPapers.length} starred papers)`;
} else {
starredFilterInfo.textContent = '(Showing all papers)';
}
}
}
function setupEventListeners() {
// Search input
const searchInput = document.getElementById('searchInput');
const addSearchKeyword = document.getElementById('addSearchKeyword');
const clearSearch = document.getElementById('clearSearch');
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addSearchKeywordFromInput();
}
});
addSearchKeyword.addEventListener('click', addSearchKeywordFromInput);
clearSearch.addEventListener('click', clearAllSearchKeywords);
// Remove search input
const removeSearchInput = document.getElementById('removeSearchInput');
const addRemoveKeyword = document.getElementById('addRemoveKeyword');
const clearRemoveSearch = document.getElementById('clearRemoveSearch');
removeSearchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addRemoveKeywordFromInput();
}
});
addRemoveKeyword.addEventListener('click', addRemoveKeywordFromInput);
clearRemoveSearch.addEventListener('click', clearAllRemoveKeywords);
// Year filter
const yearInputMin = document.getElementById('yearInputMin');
const yearInputMax = document.getElementById('yearInputMax');
const yearRange = document.getElementById('yearRange');
const clearYearFilter = document.getElementById('clearYearFilter');
yearInputMin.addEventListener('input', debounce((e) => {
const value = parseInt(e.target.value) || 1960;
const maxValue = parseInt(yearInputMax.value) || 2025;
if (value >= 1960 && value <= 2025) {
if (value <= maxValue) {
selectedYearMin = value;
yearFilterActive = true;
updateYearRangeDisplay();
filterPapers();
} else {
// If min is greater than max, set max to min
selectedYearMin = value;
selectedYearMax = value;
yearInputMax.value = value;
yearFilterActive = true;
updateYearRangeDisplay();
filterPapers();
}
}
}, 300));
yearInputMax.addEventListener('input', debounce((e) => {
const value = parseInt(e.target.value) || 2025;
const minValue = parseInt(yearInputMin.value) || 1960;
if (value >= 1960 && value <= 2025) {
if (value >= minValue) {
selectedYearMax = value;
yearFilterActive = true;
updateYearRangeDisplay();
filterPapers();
} else {
// If max is less than min, set min to max
selectedYearMax = value;
selectedYearMin = value;
yearInputMin.value = value;
yearFilterActive = true;
updateYearRangeDisplay();
filterPapers();
}
}
}, 300));
clearYearFilter.addEventListener('click', () => {
yearInputMin.value = 1960;
yearInputMax.value = 2025;
selectedYearMin = 1960;
selectedYearMax = 2025;
yearFilterActive = false;
updateYearRangeDisplay();
filterPapers();
});
// Conference filter
const conferenceSelect = document.getElementById('conferenceSelect');
const clearConferenceFilter = document.getElementById('clearConferenceFilter');
conferenceSelect.addEventListener('change', () => {
const selectedOptions = Array.from(conferenceSelect.selectedOptions).map(option => option.value);
selectedConferences = selectedOptions;
conferenceFilterActive = selectedConferences.length > 0;
console.log('Selected conferences:', selectedConferences);
updateConferenceCountDisplay();
updateSelectedConferencesDisplay();
filterPapers();
});
clearConferenceFilter.addEventListener('click', () => {
conferenceSelect.selectedIndex = -1;
selectedConferences = [];
conferenceFilterActive = false;
updateConferenceCountDisplay();
updateSelectedConferencesDisplay();
filterPapers();
});
// Abstract filter
const includeNoAbstractCheckbox = document.getElementById('includeNoAbstract');
if (includeNoAbstractCheckbox) {
includeNoAbstractCheckbox.addEventListener('change', () => {
includeNoAbstract = includeNoAbstractCheckbox.checked;
abstractFilterActive = !includeNoAbstract; // When unchecked, we filter out papers without abstracts
console.log('Abstract filter changed:', { includeNoAbstract, abstractFilterActive });
updateAbstractFilterInfo();
filterPapers();
});
console.log('Abstract filter checkbox found and event listener added');
} else {
console.error('Abstract filter checkbox not found!');
}
// Author filter
const includeNoAuthorCheckbox = document.getElementById('includeNoAuthor');
if (includeNoAuthorCheckbox) {
includeNoAuthorCheckbox.addEventListener('change', () => {
includeNoAuthor = includeNoAuthorCheckbox.checked;
authorFilterActive = !includeNoAuthor; // When unchecked, we filter out papers without author info
console.log('Author filter changed:', { includeNoAuthor, authorFilterActive });
updateAuthorFilterInfo();
filterPapers();
});
console.log('Author filter checkbox found and event listener added');
} else {
console.error('Author filter checkbox not found!');
}
// Starred filter
const showOnlyStarredCheckbox = document.getElementById('showOnlyStarred');
if (showOnlyStarredCheckbox) {
showOnlyStarredCheckbox.addEventListener('change', () => {
showOnlyStarred = showOnlyStarredCheckbox.checked;
starredFilterActive = showOnlyStarred; // When checked, we filter to show only starred papers
console.log('Starred filter changed:', { showOnlyStarred, starredFilterActive });
updateStarredFilterInfo();
filterPapers();
});
console.log('Starred filter checkbox found and event listener added');
} else {
console.error('Starred filter checkbox not found!');
}
// Pagination controls
const prevPage = document.getElementById('prevPage');
const nextPage = document.getElementById('nextPage');
prevPage.addEventListener('click', () => {
if (currentPage > 1) {
currentPage--;
displayPapers();
}
});
nextPage.addEventListener('click', () => {
const totalPages = Math.ceil(filteredPapers.length / papersPerPage);
if (currentPage < totalPages) {
currentPage++;
displayPapers();
}
});
// Page input functionality
const pageInput = document.getElementById('pageInput');
const goToPageBtn = document.getElementById('goToPage');
pageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
goToPage();
}
});
goToPageBtn.addEventListener('click', goToPage);
// Modal
const modal = document.getElementById('paperModal');
window.addEventListener('click', (event) => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
// Export and save/load buttons
const saveStatus = document.getElementById('saveStatus');
const loadStatus = document.getElementById('loadStatus');
const exportBibTeX = document.getElementById('exportBibTeX');
const exportStarred = document.getElementById('exportStarred');
if (saveStatus) {
saveStatus.addEventListener('click', saveCurrentStatus);
}
if (loadStatus) {
loadStatus.addEventListener('click', loadStatusFromFile);
}
if (exportBibTeX) {
exportBibTeX.addEventListener('click', exportFilteredResults);
}
if (exportStarred) {
exportStarred.addEventListener('click', exportStarredPapers);
}
}
function addSearchKeywordFromInput() {
const searchInput = document.getElementById('searchInput');
const keyword = searchInput.value.trim();
if (keyword && !searchKeywords.includes(keyword.toLowerCase())) {
searchKeywords.push(keyword.toLowerCase());
searchInput.value = '';
updateSearchKeywordsDisplay();
filterPapers();
}
}
function removeSearchKeyword(keyword) {
searchKeywords = searchKeywords.filter(k => k !== keyword);
updateSearchKeywordsDisplay();
filterPapers();
}
function clearAllSearchKeywords() {
searchKeywords = [];
updateSearchKeywordsDisplay();
filterPapers();
}
function updateSearchKeywordsDisplay() {
const container = document.getElementById('searchKeywordsContainer');
const clearSearch = document.getElementById('clearSearch');
container.innerHTML = '';
searchKeywords.forEach(keyword => {
const tag = document.createElement('div');
tag.className = 'search-keyword-tag';
tag.innerHTML = `
<span>${keyword}</span>
<button class="remove-keyword" onclick="removeSearchKeyword('${keyword}')" title="Remove keyword">
<i class="fas fa-times"></i>
</button>
`;
container.appendChild(tag);
});
if (searchKeywords.length > 0) {
clearSearch.classList.add('visible');
} else {
clearSearch.classList.remove('visible');
}
}
function addRemoveKeywordFromInput() {
const removeSearchInput = document.getElementById('removeSearchInput');
const keyword = removeSearchInput.value.trim();
if (keyword && !removeSearchKeywords.includes(keyword.toLowerCase())) {
removeSearchKeywords.push(keyword.toLowerCase());
removeSearchInput.value = '';
updateRemoveKeywordsDisplay();
filterPapers();
}
}
function removeKeyword(keyword) {
removeSearchKeywords = removeSearchKeywords.filter(k => k !== keyword);
updateRemoveKeywordsDisplay();
filterPapers();
}
function clearAllRemoveKeywords() {
removeSearchKeywords = [];
updateRemoveKeywordsDisplay();
filterPapers();
}
function updateRemoveKeywordsDisplay() {
const container = document.getElementById('removeKeywordsContainer');
const clearRemoveSearch = document.getElementById('clearRemoveSearch');
container.innerHTML = '';
removeSearchKeywords.forEach(keyword => {
const tag = document.createElement('div');
tag.className = 'remove-keyword-tag';
tag.innerHTML = `
<span>${keyword}</span>
<button class="remove-keyword" onclick="removeKeyword('${keyword}')" title="Remove keyword">
<i class="fas fa-times"></i>
</button>
`;
container.appendChild(tag);
});
if (removeSearchKeywords.length > 0) {
clearRemoveSearch.classList.add('visible');
} else {
clearRemoveSearch.classList.remove('visible');
}
}
function updatePaginationInfo(start, end, total) {
const paginationInfo = document.getElementById('paginationInfo');
if (total === 0) {
paginationInfo.textContent = 'No papers found';
} else {
paginationInfo.textContent = `Showing ${start}-${end} of ${total} papers`;
}
}
function updatePaginationControls(totalPages) {
const prevPage = document.getElementById('prevPage');
const nextPage = document.getElementById('nextPage');
const pageNumbers = document.getElementById('pageNumbers');
// Update previous/next buttons
prevPage.disabled = currentPage <= 1;
nextPage.disabled = currentPage >= totalPages;
// Generate page numbers
pageNumbers.innerHTML = '';
if (totalPages <= 1) {
updatePageInput();
return;
}
const maxVisiblePages = 5;
let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
// Adjust start page if we're near the end
if (endPage - startPage + 1 < maxVisiblePages) {
startPage = Math.max(1, endPage - maxVisiblePages + 1);
}
// Add first page and ellipsis if needed
if (startPage > 1) {
addPageNumber(1);
if (startPage > 2) {
addEllipsis();
}
}
// Add visible page numbers
for (let i = startPage; i <= endPage; i++) {
addPageNumber(i);
}
// Add last page and ellipsis if needed
if (endPage < totalPages) {
if (endPage < totalPages - 1) {
addEllipsis();
}
addPageNumber(totalPages);
}
updatePageInput();
}
function addEllipsis() {
const pageNumbers = document.getElementById('pageNumbers');
const ellipsis = document.createElement('span');
ellipsis.className = 'page-ellipsis';
ellipsis.textContent = '...';
pageNumbers.appendChild(ellipsis);
}
function updatePageInput() {
const pageInput = document.getElementById('pageInput');
const goToPageBtn = document.getElementById('goToPage');
const totalPages = Math.ceil(filteredPapers.length / papersPerPage);
if (pageInput && goToPageBtn) {
pageInput.max = totalPages;
pageInput.value = currentPage;
goToPageBtn.disabled = currentPage < 1 || currentPage > totalPages;
}
}
function goToPage() {
const pageInput = document.getElementById('pageInput');
const totalPages = Math.ceil(filteredPapers.length / papersPerPage);
const inputValue = parseInt(pageInput.value);
if (inputValue && inputValue >= 1 && inputValue <= totalPages) {
currentPage = inputValue;
displayPapers();
} else {
// Reset input to current page if invalid
pageInput.value = currentPage;
showNotification('Please enter a valid page number between 1 and ' + totalPages, 'warning');
}
}
function addPageNumber(pageNum) {
const pageNumbers = document.getElementById('pageNumbers');
const pageBtn = document.createElement('button');
pageBtn.className = `page-number ${pageNum === currentPage ? 'active' : ''}`;
pageBtn.textContent = pageNum;
pageBtn.addEventListener('click', () => {
currentPage = pageNum;
displayPapers();
});
pageNumbers.appendChild(pageBtn);
}
function filterPapers() {
let filtered = [...allPapers];
console.log('Starting filterPapers with:', {
totalPapers: allPapers.length,
abstractFilterActive,
includeNoAbstract,
authorFilterActive,
includeNoAuthor
});
// Apply search filter
if (searchKeywords.length > 0) {
filtered = filtered.filter(paper => {
// Check if paper contains any of the search keywords in any field
const title = (paper.title || '').toLowerCase();
const author = (paper.author || '').toLowerCase();
const abstract = (paper.abstract || '').toLowerCase();
return searchKeywords.some(keyword =>
title.includes(keyword) || author.includes(keyword) || abstract.includes(keyword)
);
});
}
// Apply remove search filter (remove papers containing the specified keywords)
if (removeSearchKeywords.length > 0) {
const beforeCount = filtered.length;
filtered = filtered.filter(paper => {
// Check if paper contains any of the removal keywords in title or abstract only
const title = (paper.title || '').toLowerCase();
const abstract = (paper.abstract || '').toLowerCase();
return !removeSearchKeywords.some(keyword =>
title.includes(keyword) || abstract.includes(keyword)
);
});
const removedCount = beforeCount - filtered.length;
console.log(`Remove search filter: ${beforeCount} -> ${filtered.length} papers (removed ${removedCount} papers with keywords: ${removeSearchKeywords.join(', ')})`);
}
// Apply year filter
if (yearFilterActive) {
filtered = filtered.filter(paper => {
const paperYear = parseInt(paper.year) || 0;
return paperYear >= selectedYearMin && paperYear <= selectedYearMax;
});
}
// Apply conference filter
if (conferenceFilterActive) {
console.log('Applying conference filter for:', selectedConferences);
const beforeCount = filtered.length;
filtered = filtered.filter(paper => {
const paperConference = paper.conference || '';
const matches = selectedConferences.some(selectedConf => {
// Check if the paper's conference name contains the selected conference name
// This handles cases where the conference name might be a substring
const paperConfLower = paperConference.toLowerCase();
const selectedConfLower = selectedConf.toLowerCase();
// Check if the selected conference is a key in conferencesData
// and if the paper's conference is in the conferences list
if (conferencesData[selectedConf] && conferencesData[selectedConf].conferences) {
const confMatch = conferencesData[selectedConf].conferences.some(confName => {
const confNameLower = confName.toLowerCase();
const matches = (paperConfLower == confNameLower);
if (matches) {
console.log('Conference list match found for:', selectedConf, 'with conference name:', confName);
}
return matches;
});
return confMatch;
}
return false;
});
return matches;
});
console.log(`Conference filter: ${beforeCount} -> ${filtered.length} papers`);
}
// Apply abstract filter
if (abstractFilterActive) {
const beforeCount = filtered.length;
const papersWithAbstract = filtered.filter(paper => {
const hasAbstract = paper.abstract && paper.abstract.trim().length > 0;
return hasAbstract;
}).length;
const papersWithoutAbstract = beforeCount - papersWithAbstract;
filtered = filtered.filter(paper => {
const hasAbstract = paper.abstract && paper.abstract.trim().length > 0;
return hasAbstract;
});
console.log(`Abstract filter: ${beforeCount} -> ${filtered.length} papers (excluding ${papersWithoutAbstract} papers without abstracts)`);
} else {
const papersWithAbstract = filtered.filter(paper => {
const hasAbstract = paper.abstract && paper.abstract.trim().length > 0;
return hasAbstract;
}).length;
const papersWithoutAbstract = filtered.length - papersWithAbstract;
console.log(`Abstract filter inactive - showing all papers (${papersWithAbstract} with abstracts, ${papersWithoutAbstract} without abstracts)`);
}
// Apply author filter
if (authorFilterActive) {
const beforeCount = filtered.length;
const papersWithAuthor = filtered.filter(paper => {
const hasAuthor = paper.author && paper.author.trim().length > 0 && paper.author.toLowerCase() !== 'unknown authors';
return hasAuthor;
}).length;
const papersWithoutAuthor = beforeCount - papersWithAuthor;
filtered = filtered.filter(paper => {
const hasAuthor = paper.author && paper.author.trim().length > 0 && paper.author.toLowerCase() !== 'unknown authors';
return hasAuthor;
});
console.log(`Author filter: ${beforeCount} -> ${filtered.length} papers (excluding ${papersWithoutAuthor} papers without author info)`);
} else {
const papersWithAuthor = filtered.filter(paper => {
const hasAuthor = paper.author && paper.author.trim().length > 0 && paper.author.toLowerCase() !== 'unknown authors';
return hasAuthor;
}).length;
const papersWithoutAuthor = filtered.length - papersWithAuthor;
console.log(`Author filter inactive - showing all papers (${papersWithAuthor} with author info, ${papersWithoutAuthor} without author info)`);
}
// Apply starred filter
if (starredFilterActive) {
const beforeCount = filtered.length;
filtered = filtered.filter(paper => {
return starredPapers.includes(paper.key);
});
console.log(`Starred filter: ${beforeCount} -> ${filtered.length} papers (showing only starred papers)`);
} else {
console.log(`Starred filter inactive - showing all papers`);
}
// Sort papers: papers with abstracts and known conferences first, then papers with abstracts but unknown conferences, then papers without abstracts
filtered.sort((a, b) => {
const aHasAbstract = a.abstract && a.abstract.trim().length > 0;
const bHasAbstract = b.abstract && b.abstract.trim().length > 0;
// const aConferenceKey = getConferenceKey(a);
// const bConferenceKey = getConferenceKey(b);
// const aHasUnknownConference = aConferenceKey === 'Unknown';
// const bHasUnknownConference = bConferenceKey === 'Unknown';
if (aHasAbstract && !bHasAbstract) return -1;
if (!aHasAbstract && bHasAbstract) return 1;
// // First priority: papers with abstracts and known conferences
// if (aHasAbstract && !aHasUnknownConference && (!bHasAbstract || bHasUnknownConference)) return -1;
// if (bHasAbstract && !bHasUnknownConference && (!aHasAbstract || aHasUnknownConference)) return 1;
// // Second priority: papers with abstracts but unknown conferences
// if (aHasAbstract && aHasUnknownConference && (!bHasAbstract || (bHasAbstract && !bHasUnknownConference))) return -1;
// if (bHasAbstract && bHasUnknownConference && (!aHasAbstract || (aHasAbstract && !aHasUnknownConference))) return 1;
// // Third priority: papers without abstracts (unknown conferences come last)
// if (!aHasAbstract && !bHasAbstract) {
// if (aHasUnknownConference && !bHasUnknownConference) return 1;
// if (!aHasUnknownConference && bHasUnknownConference) return -1;
// }
return 0;
});
filteredPapers = filtered;
currentPage = 1; // Reset to first page when filtering
displayPapers();
}
function updateYearRangeDisplay() {
const yearRange = document.getElementById('yearRange');
if (yearFilterActive) {
if (selectedYearMin === 1960 && selectedYearMax === 2025) {
yearRange.textContent = 'All Years';
} else {
yearRange.textContent = `${selectedYearMin} - ${selectedYearMax}`;
}
} else {
yearRange.textContent = 'All Years';
}
}
function updateConferenceCountDisplay() {
const conferenceCount = document.getElementById('conferenceCount');
if (conferenceFilterActive) {
conferenceCount.textContent = `${selectedConferences.length} Conference${selectedConferences.length !== 1 ? 's' : ''} Selected`;
} else {
conferenceCount.textContent = 'All Conferences';
}
}
function updateAbstractFilterInfo() {
const abstractFilterInfo = document.getElementById('abstractFilterInfo');
if (abstractFilterActive) {
abstractFilterInfo.textContent = '(Showing only papers with abstracts)';
} else {
abstractFilterInfo.textContent = '(Showing all papers)';
}
}
function updateSelectedConferencesDisplay() {
const selectedConferencesDiv = document.getElementById('selectedConferences');
if (!selectedConferencesDiv) return;
selectedConferencesDiv.innerHTML = '';
selectedConferences.forEach(conference => {
const tag = document.createElement('div');
tag.className = 'conference-tag';
tag.innerHTML = `
${conference}
<button class="remove-tag" onclick="removeConference('${conference}')">
<i class="fas fa-times"></i>
</button>
`;
selectedConferencesDiv.appendChild(tag);
});
}
function removeConference(conference) {
const conferenceSelect = document.getElementById('conferenceSelect');
const option = Array.from(conferenceSelect.options).find(opt => opt.value === conference);
if (option) {
option.selected = false;
}
selectedConferences = selectedConferences.filter(c => c !== conference);
conferenceFilterActive = selectedConferences.length > 0;
updateConferenceCountDisplay();
updateSelectedConferencesDisplay();
filterPapers();
}
function displayPapers() {
const papersList = document.getElementById('papersList');
const noResults = document.getElementById('noResults');
if (filteredPapers.length === 0) {
papersList.style.display = 'none';
noResults.style.display = 'block';
updatePaginationInfo(0, 0, 0);
updatePaginationControls(0);
} else {
papersList.style.display = 'grid';
noResults.style.display = 'none';
// Calculate pagination
const totalPages = Math.ceil(filteredPapers.length / papersPerPage);
const startIndex = (currentPage - 1) * papersPerPage;
const endIndex = Math.min(startIndex + papersPerPage, filteredPapers.length);
const currentPagePapers = filteredPapers.slice(startIndex, endIndex);
papersList.innerHTML = currentPagePapers.map(paper => createPaperCard(paper)).join('');
// Add click listeners to paper cards
const paperCards = document.querySelectorAll('.paper-card');
paperCards.forEach((card, index) => {
card.addEventListener('click', () => {
showPaperModal(currentPagePapers[index]);
});
});
updatePaginationInfo(startIndex + 1, endIndex, filteredPapers.length);
updatePaginationControls(totalPages);
updatePageInput();
}
updateResultCount();
}
function getConferenceKey(paper) {
if (!paper.conference || !conferencesData) return 'Unknown';
const paperConference = paper.conference.toLowerCase();
console.log('Looking for conference key for:', paper.conference);
// Find the conference key that matches this paper
for (const [conferenceKey, conferenceData] of Object.entries(conferencesData)) {
// Check if the paper's conference is in the conferences list
if (conferenceData.conferences) {
for (const confName of conferenceData.conferences) {
// if (paperConference.includes(confName.toLowerCase())) {
if (paperConference.toLowerCase() == confName.toLowerCase()) {
console.log('Found match by conference name:', conferenceKey, 'for:', confName);
return conferenceKey;
}
}
}
}
// If no specific match found, check if it should be in "Others (820 Venues)"
// This handles cases where the paper's conference is not in any specific category
if (conferencesData["Others (820 Venues)"]) {
console.log('No specific match found, returning Others (820 Venues)');
return "Others (820 Venues)";
}
console.log('No match found, returning Unknown');
return 'Unknown';
}
function createPaperCard(paper) {
const title = paper.title || 'Untitled';
const authors = paper.author || 'Unknown authors';
const abstract = paper.abstract || 'No abstract available';
const year = paper.year || 'Unknown year';
const conferenceKey = getConferenceKey(paper);
const hasAbstract = paper.abstract && paper.abstract.trim().length > 0;
const hasAuthor = paper.author && paper.author.trim().length > 0 && paper.author.toLowerCase() !== 'unknown authors';
const isStarred = isPaperStarred(paper.key);
let cardClasses = 'paper-card';
if (!hasAbstract) cardClasses += ' no-abstract';
if (!hasAuthor) cardClasses += ' no-author';
return `
<div class="${cardClasses}">
<div class="paper-header">
<h3 class="paper-title">${title}</h3>
<button class="star-button ${isStarred ? 'starred' : ''}"
data-paper-key="${paper.key}"
onclick="toggleStar('${paper.key}', event)"
title="${isStarred ? 'Remove from starred' : 'Add to starred'}">
<i class="${isStarred ? 'fas' : 'far'} fa-star"></i>
</button>
</div>
<p class="paper-authors">${authors}</p>
<p class="paper-abstract">${abstract}</p>
<div class="paper-meta">
<span class="paper-year">${year}</span>
<span class="paper-conference">${conferenceKey}</span>
</div>
</div>
`;
}
function showPaperModal(paper) {
const modal = document.getElementById('paperModal');
const modalTitle = document.getElementById('modalTitle');
const modalAuthors = document.getElementById('modalAuthors');
const modalAbstract = document.getElementById('modalAbstract');
const modalYear = document.getElementById('modalYear');
const modalConference = document.getElementById('modalConference');
const modalKeywords = document.getElementById('modalKeywords');
const modalStarButton = document.getElementById('modalStarButton');
const modalFindPaperButton = document.getElementById('modalFindPaperButton');
modalTitle.textContent = paper.title || 'Untitled';
modalAuthors.textContent = paper.author || 'Unknown authors';
modalAbstract.textContent = paper.abstract || 'No abstract available';
modalYear.textContent = paper.year || 'Unknown year';
// Get conference information using the same logic as in createPaperCard
// const conferenceKey = getConferenceKey(paper);
if (!paper.conference || !conferencesData){
modalConference.textContent = 'Unknown conference';
} else {
modalConference.textContent = paper.conference || 'Unknown conference'
}
// const conferenceKey = paper.conference || 'Unknown conference';
// modalConference.textContent = paper.conference || 'Unknown conference';
modalKeywords.textContent = paper.keywords.length > 0 ? paper.keywords.join(', ') : 'No keywords';
// Update modal star button
if (modalStarButton) {
const isStarred = isPaperStarred(paper.key);
modalStarButton.className = `star-button ${isStarred ? 'starred' : ''}`;
modalStarButton.setAttribute('data-paper-key', paper.key);
modalStarButton.setAttribute('title', isStarred ? 'Remove from starred' : 'Add to starred');
modalStarButton.onclick = (event) => toggleStar(paper.key, event);
const icon = modalStarButton.querySelector('i');
if (icon) {
icon.className = `${isStarred ? 'fas' : 'far'} fa-star`;
}
}
// Set up Find Paper button
if (modalFindPaperButton) {
modalFindPaperButton.onclick = () => searchPaperOnGoogle(paper.title);
}
modal.style.display = 'block';
}
function searchPaperOnGoogle(paperTitle) {
if (!paperTitle || paperTitle === 'Untitled') {
return;
}
// Encode the paper title for URL
const encodedTitle = encodeURIComponent(paperTitle);
const googleSearchUrl = `https://www.google.com/search?q=${encodedTitle}`;
// Open Google search in a new tab
window.open(googleSearchUrl, '_blank');
}
function generateBibTeXContent(papers) {
let content = '';
for (const paper of papers) {
// Reconstruct the original BibTeX entry
content += `@${paper.type}{${paper.key},\n`;
if (paper.title) {
content += ` title = {${paper.title}},\n`;
}
if (paper.author) {
content += ` author = {${paper.author}},\n`;
}
if (paper.abstract) {
content += ` abstract = {${paper.abstract}},\n`;
}
if (paper.year) {
content += ` year = {${paper.year}},\n`;
}
if (paper.booktitle) {
content += ` booktitle = {${paper.booktitle}},\n`;
}
if (paper.journal) {
content += ` journal = {${paper.journal}},\n`;
}
if (paper.pages) {
content += ` pages = {${paper.pages}},\n`;
}
// Remove trailing comma and add closing brace
content = content.replace(/,\n$/, '\n');
content += '}\n\n';
}
return content;
}
function showNotification(message, type = 'success', duration = 10000) {
// Create notification element
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
let icon = 'fa-info-circle';
if (type === 'error') icon = 'fa-exclamation-triangle';
else if (type === 'warning') icon = 'fa-exclamation-circle';
else if (type === 'success') icon = 'fa-check-circle';
notification.innerHTML = `
<div class="notification-content">
<i class="fas ${icon}"></i>
<span>${message}</span>
<button class="notification-close" onclick="this.parentElement.parentElement.remove()">
<i class="fas fa-times"></i>
</button>
</div>
`;
// Add to page
document.body.appendChild(notification);
// Auto-remove after duration
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, duration);
}
function updateResultCount() {
const resultCount = document.getElementById('resultCount');
const removeResultCount = document.getElementById('removeResultCount');
const total = allPapers.length;
const filtered = filteredPapers.length;
if (searchKeywords.length === 0) {
resultCount.textContent = `Total: ${total} papers`;
} else {
resultCount.textContent = `Found ${filtered} of ${total} papers (${searchKeywords.length} keyword${searchKeywords.length !== 1 ? 's' : ''})`;
}
if (removeSearchKeywords.length === 0) {
removeResultCount.textContent = 'All papers included';
} else {
// Calculate how many papers were removed by the remove search
const papersAfterSearch = searchKeywords.length > 0 ?
allPapers.filter(paper => {
const title = (paper.title || '').toLowerCase();
const author = (paper.author || '').toLowerCase();
const abstract = (paper.abstract || '').toLowerCase();
return searchKeywords.some(keyword =>
title.includes(keyword) || author.includes(keyword) || abstract.includes(keyword)
);
}) :
allPapers;
const removedCount = papersAfterSearch.length - filtered;
removeResultCount.textContent = `Removed ${removedCount} papers (${removeSearchKeywords.length} keyword${removeSearchKeywords.length !== 1 ? 's' : ''})`;
}
}
function showError(message) {
const papersList = document.getElementById('papersList');
const loadingIndicator = document.getElementById('loadingIndicator');
loadingIndicator.style.display = 'none';
papersList.style.display = 'none';
papersList.innerHTML = `
<div class="no-results">
<i class="fas fa-exclamation-triangle"></i>
<h3>Error</h3>
<p>${message}</p>
</div>
`;
papersList.style.display = 'block';
}
function matchesSearchField(paper, query, field) {
const title = (paper.title || '').toLowerCase();
const author = (paper.author || '').toLowerCase();
const abstract = (paper.abstract || '').toLowerCase();
switch (field) {
case 'title':
return title.includes(query);
case 'author':
return author.includes(query);
case 'abstract':
return abstract.includes(query);
case 'title+author':
return title.includes(query) || author.includes(query);
case 'title+abstract':
return title.includes(query) || abstract.includes(query);
case 'author+abstract':
return author.includes(query) || abstract.includes(query);
case 'all':
default:
return title.includes(query) || author.includes(query) || abstract.includes(query);
}
}
// Utility function for debouncing
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Star functionality
function toggleStar(paperKey, event) {
event.stopPropagation(); // Prevent triggering the card click
const index = starredPapers.indexOf(paperKey);
if (index > -1) {
// Remove from starred
starredPapers.splice(index, 1);
showNotification('Paper removed from starred list', 'success', 1000);
} else {
// Add to starred
starredPapers.push(paperKey);
showNotification('Paper added to starred list', 'success', 1000);
}
// Update the star button appearance
updateStarButton(paperKey);
updateStarredCount();
updateStarredFilterInfo(); // Update filter info when starred papers change
}
function isPaperStarred(paperKey) {
return starredPapers.includes(paperKey);
}
function updateStarButton(paperKey) {
const starButtons = document.querySelectorAll(`[data-paper-key="${paperKey}"]`);
starButtons.forEach(button => {
const icon = button.querySelector('i');
if (isPaperStarred(paperKey)) {
button.classList.add('starred');
icon.className = 'fas fa-star';
} else {
button.classList.remove('starred');
icon.className = 'far fa-star';
}
});
}
function updateStarredCount() {
const exportStarred = document.getElementById('exportStarred');
if (exportStarred) {
// Clear the button content and rebuild it with the updated count
exportStarred.innerHTML = `
<i class="fas fa-star"></i>
Export Starred (${starredPapers.length})
`;
}
}
function exportStarredPapers() {
if (starredPapers.length === 0) {
showNotification('No starred papers to export', 'warning');
return;
}
// Get the actual paper objects for starred papers
const starredPaperObjects = allPapers.filter(paper => starredPapers.includes(paper.key));
const bibTeXContent = generateBibTeXContent(starredPaperObjects);
const blob = new Blob([bibTeXContent], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const now = new Date();
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '_');
a.download = `starred_papers_${starredPapers.length}_papers_${timestamp}.bib`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showNotification(`Exported ${starredPapers.length} starred papers to BibTeX file!`);
}
// Save current filtering status and document IDs to JSON file
function saveCurrentStatus() {
const status = {
timestamp: new Date().toISOString(),
filters: {
searchKeywords: searchKeywords,
removeSearchKeywords: removeSearchKeywords,
yearFilter: {
min: selectedYearMin,
max: selectedYearMax,
active: yearFilterActive
},
conferenceFilter: {
selectedConferences: selectedConferences,
active: conferenceFilterActive
},
abstractFilter: {
includeNoAbstract: includeNoAbstract,
active: abstractFilterActive
},
authorFilter: {
includeNoAuthor: includeNoAuthor,
active: authorFilterActive
},
starredFilter: {
showOnlyStarred: showOnlyStarred,
active: starredFilterActive
}
},
pagination: {
currentPage: currentPage,
papersPerPage: papersPerPage
},
results: {
totalPapers: allPapers.length,
filteredPapersCount: filteredPapers.length,
filteredPaperIds: filteredPapers.map(paper => paper.key)
},
starredPapers: starredPapers // Save starred papers list
};
const blob = new Blob([JSON.stringify(status, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const now = new Date();
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '_');
a.download = `multilingual_papers_filter_${timestamp}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showNotification('Filter status saved successfully!');
}
// Load filtering status from JSON file
function loadStatusFromFile() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
const status = JSON.parse(e.target.result);
applyLoadedStatus(status);
showNotification('Filter status loaded successfully!');
} catch (error) {
console.error('Error parsing status file:', error);
showNotification('Error: Invalid status file format', 'error');
}
};
reader.readAsText(file);
}
};
input.click();
}
// Apply loaded filtering status
function applyLoadedStatus(status) {
if (!status.filters) {
showNotification('Error: Invalid status file format', 'error');
return;
}
const filters = status.filters;
// Apply search keywords
searchKeywords = filters.searchKeywords || [];
removeSearchKeywords = filters.removeSearchKeywords || [];
// Apply year filter
if (filters.yearFilter) {
selectedYearMin = filters.yearFilter.min || 1960;
selectedYearMax = filters.yearFilter.max || 2025;
yearFilterActive = filters.yearFilter.active || false;
// Update UI
const yearInputMin = document.getElementById('yearInputMin');
const yearInputMax = document.getElementById('yearInputMax');
if (yearInputMin) yearInputMin.value = selectedYearMin;
if (yearInputMax) yearInputMax.value = selectedYearMax;
updateYearRangeDisplay();
}
// Apply conference filter
if (filters.conferenceFilter) {
selectedConferences = filters.conferenceFilter.selectedConferences || [];
conferenceFilterActive = filters.conferenceFilter.active || false;
// Update UI
const conferenceSelect = document.getElementById('conferenceSelect');
if (conferenceSelect) {
// Clear current selection
conferenceSelect.selectedIndex = -1;
// Select the loaded conferences
selectedConferences.forEach(conference => {
const option = Array.from(conferenceSelect.options).find(opt => opt.value === conference);
if (option) {
option.selected = true;
}
});
}
updateConferenceCountDisplay();
updateSelectedConferencesDisplay();
}
// Apply abstract filter
if (filters.abstractFilter) {
includeNoAbstract = filters.abstractFilter.includeNoAbstract !== undefined ?
filters.abstractFilter.includeNoAbstract : true;
abstractFilterActive = filters.abstractFilter.active || false;
// Update UI
const includeNoAbstractCheckbox = document.getElementById('includeNoAbstract');
if (includeNoAbstractCheckbox) {
includeNoAbstractCheckbox.checked = includeNoAbstract;
}
updateAbstractFilterInfo();
}
// Apply author filter
if (filters.authorFilter) {
includeNoAuthor = filters.authorFilter.includeNoAuthor !== undefined ?
filters.authorFilter.includeNoAuthor : true;
authorFilterActive = filters.authorFilter.active || false;
// Update UI
const includeNoAuthorCheckbox = document.getElementById('includeNoAuthor');
if (includeNoAuthorCheckbox) {
includeNoAuthorCheckbox.checked = includeNoAuthor;
}
updateAuthorFilterInfo();
}
// Apply starred filter
if (filters.starredFilter) {
showOnlyStarred = filters.starredFilter.showOnlyStarred !== undefined ?
filters.starredFilter.showOnlyStarred : false;
starredFilterActive = filters.starredFilter.active || false;
// Update UI
const showOnlyStarredCheckbox = document.getElementById('showOnlyStarred');
if (showOnlyStarredCheckbox) {
showOnlyStarredCheckbox.checked = showOnlyStarred;
}
updateStarredFilterInfo();
}
// Apply pagination
if (status.pagination) {
currentPage = status.pagination.currentPage || 1;
papersPerPage = status.pagination.papersPerPage || 10;
}
// Apply starred papers
if (status.starredPapers) {
starredPapers = status.starredPapers || [];
}
// Update displays
updateSearchKeywordsDisplay();
updateRemoveKeywordsDisplay();
updateStarredCount(); // Update starred count display
// Re-apply filters
filterPapers();
console.log('Applied loaded status:', status);
}
// Export current filtered results to BibTeX
function exportFilteredResults() {
if (filteredPapers.length === 0) {
showNotification('No papers to export', 'warning');
return;
}
const bibTeXContent = generateBibTeXContent(filteredPapers);
const blob = new Blob([bibTeXContent], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const now = new Date();
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '_');
a.download = `multilingual_papers_filtered_${filteredPapers.length}_papers_${timestamp}.bib`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showNotification(`Exported ${filteredPapers.length} papers to BibTeX file!`);
}