anime-backlog-list/js/main.js
2025-01-07 12:23:54 +05:00

541 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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';
}
});
});