No timers configured.
';
return;
}
sct_timers.forEach(timer => {
const formattedDate = new Date(timer.date).toLocaleString('en-US', {
dateStyle: 'short',
timeStyle: 'short'
});
const item = document.createElement('div');
item.className = 'sct-list-item';
item.innerHTML = `
${sct_escapeHTML(timer.name)}
${formattedDate}
`;
sct_manageList.appendChild(item);
});
}
/**
* Handles the save/update of a timer
*/
window.sct_saveTimer = function(event) {
event.preventDefault();
if (!sct_eventName || !sct_eventDate || !sct_timerId) return;
const id = sct_timerId.value;
const name = sct_eventName.value;
const date = sct_eventDate.value;
if (!name || !date) return;
if (id) {
// Editing existing timer
const timer = sct_timers.find(t => t.id == id);
if (timer) {
timer.name = name;
timer.date = date;
}
} else {
// Adding new timer
const newTimer = {
id: Date.now(),
name: name,
date: date
};
sct_timers.push(newTimer);
}
sct_clearForm();
sct_renderDashboard();
sct_renderManageList();
}
/**
* Clears the "Add/Edit" form
*/
window.sct_clearForm = function() {
if (sct_timerId) sct_timerId.value = '';
if (sct_eventName) sct_eventName.value = '';
if (sct_eventDate) sct_eventDate.value = '';
if (sct_timerForm) sct_timerForm.reset();
}
/**
* Populates the form to edit a timer
*/
window.sct_editTimer = function(id) {
const timer = sct_timers.find(t => t.id === id);
if (timer && sct_timerId && sct_eventName && sct_eventDate) {
sct_timerId.value = timer.id;
sct_eventName.value = timer.name;
// Format for datetime-local input (YYYY-MM-DDTHH:MM)
const localDate = new Date(timer.date);
// Adjust for timezone offset
localDate.setMinutes(localDate.getMinutes() - localDate.getTimezoneOffset());
sct_eventDate.value = localDate.toISOString().slice(0, 16);
// Switch to config tab
sct_switchTab(1);
sct_eventName.focus();
}
}
/**
* Deletes a timer
*/
window.sct_deleteTimer = function(id) {
if (confirm("Are you sure you want to delete this timer?")) {
sct_timers = sct_timers.filter(t => t.id !== id);
sct_renderDashboard();
sct_renderManageList();
}
}
/**
* Loads a preset date into the form
*/
window.sct_addPreset = function() {
if (!sct_presetSelect || !sct_eventName || !sct_eventDate) return;
const preset = sct_presetSelect.value;
const now = new Date();
let year = now.getFullYear();
let targetDate;
let name = '';
switch (preset) {
case 'thanksgiving':
// 4th Thursday of November
name = 'Thanksgiving';
let firstNov = new Date(year, 10, 1);
let firstThursOffset = (4 - firstNov.getDay() + 7) % 7;
let thursDate = 1 + firstThursOffset + 21; // 1st + 3 weeks
targetDate = new Date(year, 10, thursDate, 12, 0, 0); // 12:00 PM
if (targetDate < now) { // If past, get next year's
firstNov = new Date(year + 1, 10, 1);
firstThursOffset = (4 - firstNov.getDay() + 7) % 7;
thursDate = 1 + firstThursOffset + 21;
targetDate = new Date(year + 1, 10, thursDate, 12, 0, 0);
}
break;
case 'christmas':
name = 'Christmas Day';
targetDate = new Date(year, 11, 25, 9, 0, 0); // 9:00 AM
if (targetDate < now) {
targetDate.setFullYear(year + 1);
}
break;
case 'new_year':
name = "New Year's Day";
targetDate = new Date(year + 1, 0, 1, 0, 0, 0); // Midnight
break;
case 'july_4th':
name = 'Independence Day';
targetDate = new Date(year, 6, 4, 20, 0, 0); // 8:00 PM (Fireworks)
if (targetDate < now) {
targetDate.setFullYear(year + 1);
}
break;
}
sct_eventName.value = name;
// Format for datetime-local input
targetDate.setMinutes(targetDate.getMinutes() - targetDate.getTimezoneOffset());
sct_eventDate.value = targetDate.toISOString().slice(0, 16);
sct_timerId.value = ''; // Ensure it's a new timer
}
// --- TAB & NAVIGATION FUNCTIONS ---
window.sct_switchTab = function(tabIndex) {
sct_currentTabIndex = tabIndex;
sct_tabContents.forEach((content, index) => {
content.classList.toggle('sct-active', index === tabIndex);
});
sct_tabs.forEach((tab, index) => {
tab.classList.toggle('sct-active', index === tabIndex);
});
sct_updateNavButtons();
}
window.sct_navigateTabs = function(direction) {
if (direction === 'next' && sct_currentTabIndex < sct_numTabs - 1) {
sct_switchTab(sct_currentTabIndex + 1);
} else if (direction === 'prev' && sct_currentTabIndex > 0) {
sct_switchTab(sct_currentTabIndex - 1);
}
}
function sct_updateNavButtons() {
sct_prevBtn.style.visibility = (sct_currentTabIndex === 0) ? 'hidden' : 'visible';
sct_nextBtn.style.visibility = (sct_currentTabIndex === sct_numTabs - 1) ? 'hidden' : 'visible';
}
// --- PDF GENERATION ---
window.sct_generatePdf = function() {
if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') {
alert('Error: PDF generation library (jsPDF) not loaded.');
return;
}
if (typeof window.jspdf.plugin.autotable === 'undefined') {
alert('Error: PDF generation library (jsPDF-AutoTable) not loaded.');
return;
}
if (sct_timers.length === 0) {
alert("You have no timers to download. Please add some timers first.");
return;
}
try {
const { jsPDF } = jspdf;
const doc = new jsPDF();
doc.setFont('helvetica', 'bold');
doc.setFontSize(20);
doc.setTextColor(varGet('--sct-primary-color', '#0073e6'));
doc.text("My Countdown Timers", 105, 20, { align: 'center' });
doc.setFontSize(11);
doc.setTextColor(varGet('--sct-text-color', '#333'));
doc.text(`Total Timers: ${sct_timers.length}`, 14, 30);
const tableColumn = ["Event Name", "Target Date & Time"];
const tableRows = [];
sct_timers.forEach(timer => {
const formattedDate = new Date(timer.date).toLocaleString('en-US', {
dateStyle: 'full',
timeStyle: 'short'
});
tableRows.push([timer.name, formattedDate]);
});
doc.autoTable({
head: [tableColumn],
body: tableRows,
startY: 40,
theme: 'striped',
headStyles: {
fillColor: varGet('--sct-primary-color', '#0073e6'),
textColor: varGet('--sct-text-light', '#fff')
},
styles: { font: 'helvetica', cellPadding: 3 },
alternateRowStyles: {
fillColor: varGet('--sct-light-primary', '#e6f1fc')
}
});
doc.save('my_countdown_timers.pdf');
} catch (e) {
console.error("PDF Generation Error: ", e);
alert("An error occurred while generating the PDF.");
}
}
// --- UTILITY FUNCTIONS ---
function varGet(varName, fallback = '#000') {
try {
return getComputedStyle(document.documentElement).getPropertyValue(varName).trim() || fallback;
} catch (e) {
return fallback;
}
}
function sct_escapeHTML(str) {
if (!str) return '';
return str.replace(/[&<>"']/g, function(m) {
return {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[m];
});
}
// --- INITIALIZATION ---
function sct_initTool() {
sct_switchTab(0); // Set initial tab
sct_renderDashboard();
sct_renderManageList();
sct_startTimerInterval();
}
sct_initTool(); // Run the tool
}); // End of DOMContentLoaded