feat: enhanced API and interface
This commit is contained in:
177
static/script.js
177
static/script.js
@@ -2,48 +2,157 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const dateElement = document.getElementById('current-date');
|
||||
const eventsList = document.getElementById('events-list');
|
||||
const timeCommentElement = document.getElementById('time-comment');
|
||||
const today = new Date();
|
||||
const prevBtn = document.getElementById('prev-btn');
|
||||
const nextBtn = document.getElementById('next-btn');
|
||||
|
||||
// Date display
|
||||
const options = { year: 'numeric', month: 'long', day: 'numeric' };
|
||||
dateElement.textContent = today.toLocaleDateString('zh-TW', options);
|
||||
|
||||
// Query to API
|
||||
fetch('/api/query')
|
||||
.then(response => response.json())
|
||||
.then(events => {
|
||||
eventsList.innerHTML = '';
|
||||
const dialog = document.getElementById('date-dialog');
|
||||
const datePickerInput = document.getElementById('date-picker-input');
|
||||
const cancelDateBtn = document.getElementById('cancel-date-btn');
|
||||
const confirmDateBtn = document.getElementById('confirm-date-btn');
|
||||
|
||||
if (events == null || events.length == 0 || events.length == undefined) {
|
||||
eventsList.innerHTML = '<p>今天沒有已記載的重大事件。</p>';
|
||||
timeCommentElement.classList.add('hide');
|
||||
return;
|
||||
}
|
||||
|
||||
events.forEach(event => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'event-card';
|
||||
let currentDate;
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const yearParam = urlParams.get("year");
|
||||
const monthParam = urlParams.get("month");
|
||||
const dayParam = urlParams.get("day");
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'event-title';
|
||||
title.textContent = event.title;
|
||||
|
||||
const year = document.createElement('span');
|
||||
year.className = 'event-year';
|
||||
year.textContent = `(${event.year} 年)`;
|
||||
if (yearParam && monthParam && dayParam) {
|
||||
currentDate = new Date(parseInt(yearParam), parseInt(monthParam) - 1, parseInt(dayParam));
|
||||
} else {
|
||||
currentDate = new Date();
|
||||
}
|
||||
|
||||
const description = document.createElement('p');
|
||||
description.textContent = event.description;
|
||||
|
||||
title.appendChild(year);
|
||||
card.appendChild(title);
|
||||
card.appendChild(description);
|
||||
eventsList.appendChild(card);
|
||||
timeCommentElement.classList.remove('hide');
|
||||
fetchAndRender(currentDate);
|
||||
|
||||
function fetchAndRender(date) {
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
const newUrl = `?year=${year}&month=${month}&day=${day}`;
|
||||
window.history.pushState({ path: newUrl }, '', newUrl);
|
||||
|
||||
|
||||
const options = { year: 'numeric', month: 'long', day: 'numeric' };
|
||||
dateElement.textContent = date.toLocaleDateString('zh-TW', options);
|
||||
|
||||
|
||||
eventsList.innerHTML = '<p>正在載入歷史事件...</p>';
|
||||
timeCommentElement.classList.add('hide');
|
||||
|
||||
|
||||
const requestURL = `/api/query?year=${year}&month=${month}&day=${day}`;
|
||||
|
||||
fetch(requestURL)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error("Network response was not ok");
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
renderEvents(data.events);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch error:', error);
|
||||
eventsList.innerHTML = '<p style="color: red;">載入歷史事件失敗。請檢查 API 連線。</p>';
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch error:', error);
|
||||
eventsList.innerHTML = '<p style="color: red;">載入歷史事件失敗。請檢查 API。</p>';
|
||||
}
|
||||
|
||||
function renderEvents(events) {
|
||||
eventsList.innerHTML = '';
|
||||
|
||||
if (!events || events.length === 0) {
|
||||
eventsList.innerHTML = '<p>這一天沒有已記載的重大事件。</p>';
|
||||
timeCommentElement.classList.add('hide');
|
||||
return;
|
||||
}
|
||||
|
||||
events.forEach(event => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'event-card';
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'event-title';
|
||||
title.textContent = event.title;
|
||||
|
||||
const yearSpan = document.createElement('span');
|
||||
yearSpan.className = 'event-year';
|
||||
yearSpan.textContent = `(${event.year} 年)`;
|
||||
|
||||
const description = document.createElement('p');
|
||||
description.textContent = event.description;
|
||||
|
||||
title.appendChild(yearSpan);
|
||||
card.appendChild(title);
|
||||
card.appendChild(description);
|
||||
eventsList.appendChild(card);
|
||||
});
|
||||
|
||||
timeCommentElement.classList.remove('hide');
|
||||
}
|
||||
|
||||
dateElement.addEventListener("wheel", (event) => {
|
||||
if (event.deltaY > 0) {
|
||||
nextBtn.click();
|
||||
} else if (event.deltaY < 0) {
|
||||
prevBtn.click();
|
||||
}
|
||||
})
|
||||
|
||||
prevBtn.addEventListener('click', () => {
|
||||
currentDate.setDate(currentDate.getDate() - 1);
|
||||
fetchAndRender(currentDate);
|
||||
});
|
||||
|
||||
nextBtn.addEventListener('click', () => {
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
fetchAndRender(currentDate);
|
||||
});
|
||||
|
||||
|
||||
dateElement.addEventListener('click', () => {
|
||||
|
||||
const yyyy = currentDate.getFullYear();
|
||||
const mm = String(currentDate.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(currentDate.getDate()).padStart(2, '0');
|
||||
|
||||
datePickerInput.value = `${yyyy}-${mm}-${dd}`;
|
||||
dialog.showModal();
|
||||
});
|
||||
|
||||
|
||||
cancelDateBtn.addEventListener('click', () => {
|
||||
dialog.close();
|
||||
});
|
||||
|
||||
confirmDateBtn.addEventListener('click', () => {
|
||||
const selectedValue = datePickerInput.value;
|
||||
if (selectedValue) {
|
||||
const [y, m, d] = selectedValue.split('-').map(Number);
|
||||
currentDate = new Date(y, m - 1, d);
|
||||
fetchAndRender(currentDate);
|
||||
}
|
||||
dialog.close();
|
||||
});
|
||||
|
||||
|
||||
dialog.addEventListener('click', (event) => {
|
||||
const rect = dialog.getBoundingClientRect();
|
||||
const isInDialog = (rect.top <= event.clientY && event.clientY <= rect.top + rect.height &&
|
||||
rect.left <= event.clientX && event.clientX <= rect.left + rect.width);
|
||||
if (!isInDialog) {
|
||||
dialog.close();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.addEventListener("keypress", (event) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
confirmDateBtn.click();
|
||||
}
|
||||
})
|
||||
});
|
||||
Reference in New Issue
Block a user