anime-backlog-list/js/main.js

541 lines
20 KiB
JavaScript
Raw Normal View History

2025-01-07 12:23:54 +05:00
let currentYear;
//Adding new element in the array creates new tab
const years = ['pre-2009', '2009', '2010', '2011', '2012', '2013', '2014', '2015',
'2016','2017','2018','2019','2020','2021','2022','2023', '2024', 're-watch', 'manga'];
function loadYearTabs() {
const yearTabs = document.getElementById('year-tabs');
// Populate the tabs
years.forEach(year => {
const li = document.createElement('li');
li.textContent = year;
li.classList.add('tab');
li.dataset.year = year; // Set data-year attribute for each tab
// Add a click event listener to each tab
li.addEventListener('click', () => {
loadYearContent(year);
});
yearTabs.appendChild(li);
// Now check if all entries are completed for this year
fetch(`php/check_completed_year.php?year=${encodeURIComponent(year)}`)
.then(response => response.json())
.then(data => {
if (data.all_completed) {
// Strike through the tab if all are completed
li.style.textDecoration = 'line-through';
}
})
.catch(error => console.error('Error checking completed status:', error));
});
// Load the last active tab or default to 'pre-2009'
const activeYear = localStorage.getItem('activeYear') || 'pre-2009';
loadYearContent(activeYear);
}
function loadYearContent(year) {
currentYear = year;
// Save the current year in localStorage for persistence
localStorage.setItem('activeYear', year);
// Highlight the active tab
const tabs = document.querySelectorAll('#year-tabs .tab');
tabs.forEach(tab => {
// Add or remove the active class based on the tab's data-year
if (tab.dataset.year === year) {
tab.classList.add('active');
} else {
tab.classList.remove('active');
}
});
// Fetch and display content for the selected year
fetch(`php/fetch_data.php?year=${encodeURIComponent(year)}`)
.then(response => response.text())
.then(html => {
document.getElementById('content').innerHTML = html;
setupFormSubmission();
setupEditButtons();
setupDeleteButtons();
setupSuggestButton();
setupSetCompleteButtons();
setupSetCurrentlyWatchingButtons();
})
.catch(error => console.error('Error loading content:', error));
}
function setupFormSubmission() {
const form = document.getElementById('add-form');
function handleFormSubmit(event) {
event.preventDefault();
const formData = new FormData(form);
fetch('php/add_record.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
// Если сервер вернул ошибку (например, 403)
return response.json().then(errorData => {
if (response.status === 403) {
alert(errorData.message || 'Access denied: You are not authorized to perform this action.');
}
throw new Error(errorData.message || 'An error occurred.');
});
}
return response.text();
})
.then(() => {
// Если запись добавлена успешно
loadYearContent(currentYear);
})
.catch(error => {
console.error('Error:', error);
});
}
form.addEventListener('submit', handleFormSubmit);
form.addEventListener('keydown', event => {
if (event.ctrlKey && event.key === 'Enter') {
event.preventDefault();
handleFormSubmit(event);
}
});
}
function setupEditButtons() {
const editButtons = document.querySelectorAll('.edit-button');
editButtons.forEach(button => {
button.addEventListener('click', () => {
const recordId = button.dataset.id;
openEditModal(recordId);
});
});
}
function setupDeleteButtons() {
const deleteButtons = document.querySelectorAll('.delete-button');
deleteButtons.forEach(button => {
button.addEventListener('click', () => {
const recordId = button.dataset.id;
if (confirm('Are you sure you want to delete this record?')) {
fetch(`php/delete_record.php?id=${recordId}`, {
method: 'DELETE' // Используем метод DELETE для удаления
})
.then(response => {
if (!response.ok) {
// Если сервер вернул ошибку (например, 403)
return response.json().then(errorData => {
if (response.status === 403) {
alert(errorData.message || 'Access denied: You are not authorized to delete this record.');
}
throw new Error(errorData.message || 'An error occurred while deleting the record.');
});
}
return response.text();
})
.then(() => {
// Если удаление прошло успешно
loadYearContent(currentYear);
})
.catch(error => {
console.error('Error:', error);
});
}
});
});
}
function openEditModal(id) {
// Fetch record data
fetch(`php/fetch_record.php?id=${id}`)
.then(response => response.json())
.then(data => {
const modal = document.getElementById('edit-modal');
const form = document.getElementById('edit-form');
form.innerHTML = generateEditForm(data);
modal.style.display = 'block';
setupEditFormSubmission();
});
}
function setupModal() {
const modal = document.getElementById('edit-modal');
const closeModal = document.getElementById('close-modal');
closeModal.addEventListener('click', () => modal.style.display = 'none');
window.addEventListener('keydown', event => {
if (event.key === 'Escape') {
modal.style.display = 'none';
}
});
// Close modal when clicking outside the modal content
modal.addEventListener('click', event => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
}
function mapLabelToYear(label) {
if (label === 'pre-2009') return -1;
if (label === 're-watch') return -2;
return parseInt(label, 10);
}
function setupEditFormSubmission() {
const form = document.getElementById('edit-form');
function handleEditFormSubmit(event) {
event.preventDefault();
const yearLabelSelect = form.querySelector('#year_label');
const numericYearInput = form.querySelector('#year_numeric');
const selectedLabel = yearLabelSelect.value;
// Use the mapLabelToYear function
numericYearInput.value = mapLabelToYear(selectedLabel);
const formData = new FormData(form);
fetch('php/edit_record.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
return response.json().then(errorData => {
if (response.status === 403) {
alert(errorData.message || 'Access denied: You are not authorized to edit this record.');
}
throw new Error(errorData.message || 'An error occurred while editing the record.');
});
}
return response.text();
})
.then(() => {
const modal = document.getElementById('edit-modal');
modal.style.display = 'none';
loadYearContent(currentYear);
})
.catch(error => {
console.error('Error:', error);
});
}
form.addEventListener('submit', handleEditFormSubmit);
form.addEventListener('keydown', event => {
if (event.ctrlKey && event.key === 'Enter') {
event.preventDefault();
handleEditFormSubmit(event);
}
});
}
function generateEditForm(data) {
function mapYearToLabel(yearValue) {
if (yearValue == -1) return 'pre-2009';
if (yearValue == -2) return 're-watch';
if (yearValue == -3) return 'manga';
return yearValue.toString();
}
const selectedYearLabel = mapYearToLabel(data.year);
return `
<h3>Edit Record</h3>
<input type="hidden" name="id" value="${data.id}">
<input type="hidden" name="year" id="year_numeric" value="${data.year}">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" name="name" id="name" class="form-control" value="${data.name || ''}" required>
</div>
<!-- Wrap season, year, and type fields in a single container -->
<div class="form-row">
<div class="form-group">
<label for="season">Season:</label>
<select name="season" id="season" class="form-control">
${['winter', 'spring', 'summer', 'fall', 'omake'].map(season => `
<option value="${season}" ${data.season === season ? 'selected' : ''}>
${season.charAt(0).toUpperCase() + season.slice(1)}
</option>
`).join('')}
</select>
</div>
<div class="form-group">
<label for="year_label">Year:</label>
<select name="year_label" id="year_label" class="form-control">
${years.map(y => `
<option value="${y}" ${y === selectedYearLabel ? 'selected' : ''}>${y}</option>
`).join('')}
</select>
</div>
<div class="form-group">
<label for="type">Type:</label>
<select name="type" id="type" class="form-control">
${['tv', 'special', 'short', 'ova', 'movie', 'other'].map(type => `
<option value="${type}" ${data.type === type ? 'selected' : ''}>${type}</option>
`).join('')}
</select>
</div>
</div>
<div class="form-group">
<label for="comment">Comment:</label>
<input type="text" name="comment" id="comment" class="form-control" value="${data.comment || ''}">
</div>
<div class="form-group">
<label for="date_completed">Date Completed:</label>
<input type="date" name="date_completed" id="date_completed" class="form-control" value="${data.date_completed || ''}">
</div>
<div class="form-group">
<label for="url">URL:</label>
<input type="url" name="url" id="url" class="form-control" value="${data.url || ''}">
</div>
<div class="form-group form-check">
<input type="checkbox" name="is_completed" id="is_completed" class="form-check-input" ${parseInt(data.is_completed) ? 'checked' : ''}>
<label for="is_completed" class="form-check-label">Is Completed</label>
</div>
<div class="form-group form-check">
<input type="checkbox" name="currently_watching" id="currently_watching" class="form-check-input" ${parseInt(data.currently_watching) ? 'checked' : ''}>
<label for="currently_watching" class="form-check-label">Currently Watching</label>
</div>
<button type="submit" class="btn btn-primary">Save Changes</button>
`;
}
function setupSuggestButton() {
const suggestButton = document.getElementById('suggest-button');
if (suggestButton) {
suggestButton.addEventListener('click', () => {
makeSuggestion();
});
}
}
function makeSuggestion() {
// Clear any previous suggestions
const previousSuggestion = document.getElementById('suggestion-display');
if (previousSuggestion) {
previousSuggestion.remove();
}
// Get all table rows that are not completed
const rows = Array.from(document.querySelectorAll('table tbody tr')).filter(row => {
return !row.classList.contains('completed');
});
// Exclude header rows and ensure there are at least two entries
if (rows.length < 1) {
alert('Not enough uncompleted entries to make a suggestion.');
return;
}
// Randomly select two different rows
const indices = [];
while (indices.length < 1) {
const index = Math.floor(Math.random() * rows.length);
if (!indices.includes(index)) {
indices.push(index);
}
}
const selectedRows = [rows[indices[0]]];
// Get the names of the selected records
const names = selectedRows.map(row => row.getAttribute('data-name'));
// Display the names at the top of the content
const content = document.getElementById('content');
const suggestionDisplayDiv = document.createElement('div');
suggestionDisplayDiv.id = 'suggestion-display';
suggestionDisplayDiv.innerHTML = `<p>${names.join('<br> ')}</p>`;
content.insertBefore(suggestionDisplayDiv, content.querySelector('button')); // Insert before the add form
}
function setupStickyTabs() {
const tabsContainer = document.querySelector('.tabs-container');
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle('is-sticky', e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(tabsContainer);
}
function setupSetCompleteButtons() {
const setCompleteButtons = document.querySelectorAll('.set-complete-button');
setCompleteButtons.forEach(button => {
button.addEventListener('click', () => {
const recordId = button.dataset.id;
const formData = new FormData();
formData.append('id', recordId);
fetch('php/set_complete.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
return response.json().then(errorData => {
if (response.status === 403) {
alert(errorData.message || 'Access denied: You are not authorized to perform this action.');
}
throw new Error(errorData.message || 'An error occurred while setting the record as complete.');
});
}
return response.json();
})
.then(() => {
// Reload the table to reflect the changes
loadYearContent(currentYear);
})
.catch(error => {
console.error('Error:', error);
});
});
});
}
function setupSetCurrentlyWatchingButtons() {
const setCurrentlyWatchingButtons = document.querySelectorAll('.set-currently-watching-button');
setCurrentlyWatchingButtons.forEach(button => {
button.addEventListener('click', () => {
const recordId = button.dataset.id;
const formData = new FormData();
formData.append('id', recordId);
fetch('php/set_currently_watching.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
return response.json().then(errorData => {
if (response.status === 403) {
alert(errorData.message || 'Access denied: You are not authorized to perform this action.');
}
throw new Error(errorData.message || 'An error occurred while setting the record as currently watching.');
});
}
return response.json();
})
.then(() => {
// Reload the table to reflect the changes
loadYearContent(currentYear);
})
.catch(error => {
console.error('Error:', error);
});
});
});
}
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM fully loaded and parsed');
loadYearTabs();
setupModal();
var imageCache = {};
var currentHoverTarget = null;
function showImageTooltip(event, imageUrl) {
var tooltip = document.getElementById('image-tooltip');
if (!tooltip) {
tooltip = document.createElement('div');
tooltip.id = 'image-tooltip';
tooltip.style.position = 'absolute';
tooltip.style.border = '1px solid #ccc';
tooltip.style.background = '#fff';
tooltip.style.padding = '5px';
tooltip.style.zIndex = 1000;
tooltip.style.maxWidth = '200px';
tooltip.style.maxHeight = '300px';
tooltip.style.overflow = 'hidden';
tooltip.style.display = 'none';
document.body.appendChild(tooltip);
}
tooltip.innerHTML = '<img src="' + imageUrl + '" style="max-width: 100%; max-height: 100%;">';
tooltip.style.left = (event.pageX + 15) + 'px';
tooltip.style.top = (event.pageY + 15) + 'px';
tooltip.style.display = 'block';
}
function hideImageTooltip() {
var tooltip = document.getElementById('image-tooltip');
if (tooltip) {
tooltip.style.display = 'none';
}
}
// Добавляем обработчики событий на родительский элемент
var contentDiv = document.getElementById('content');
contentDiv.addEventListener('mouseover', function (event) {
var target = event.target;
// Проверяем, является ли целевой элемент ссылкой с атрибутом data-url
if (target.tagName.toLowerCase() === 'a' && target.hasAttribute('data-url')) {
var url = target.getAttribute('data-url');
currentHoverTarget = target; // Set the current hover target
if (imageCache[url]) {
showImageTooltip(event, imageCache[url]);
} else {
var xhr = new XMLHttpRequest();
xhr.open('GET', './php/get_image.php?url=' + encodeURIComponent(url), true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
if (response.image_url) {
imageCache[url] = response.image_url;
if (currentHoverTarget === target) {
showImageTooltip(event, response.image_url);
}
} else if (response.error) {
console.error(response.error);
}
}
};
xhr.send();
}
}
});
contentDiv.addEventListener('mouseout', function (event) {
var target = event.target;
if (target.tagName.toLowerCase() === 'a' && target.hasAttribute('data-url')) {
hideImageTooltip();
if (currentHoverTarget === target) {
currentHoverTarget = null; // Clear the current hover target
}
}
});
contentDiv.addEventListener('mousemove', function (event) {
var tooltip = document.getElementById('image-tooltip');
if (tooltip && tooltip.style.display === 'block') {
tooltip.style.left = (event.pageX + 15) + 'px';
tooltip.style.top = (event.pageY + 15) + 'px';
}
});
});