Files
pdga-rating/public/js/courses.js
T
Samuel Enocsson 7e5fa6cbf1 Add HTMX migration for server-rendered tables and lazy loading
- Add HTMX CDN to layout
- Replace client-side table rendering (displayRatings, displayCourses)
  with server-rendered EJS partials via hx-get
- Add server-side course search with debounced hx-trigger
- Lazy-load player history and course layouts via htmx.ajax()
- Render rating chart via htmx:afterSwap with data attributes
- Add partial routes: ratings-table, course-table, player-history,
  course-layouts
2026-02-19 08:29:56 +01:00

88 lines
3.0 KiB
JavaScript

function toggleAccordion(accordionId) {
const content = document.getElementById(accordionId);
const icon = document.getElementById(`${accordionId}-icon`);
if (content.classList.contains('expanded')) {
content.classList.remove('expanded');
icon.classList.remove('expanded');
} else {
content.classList.add('expanded');
icon.classList.add('expanded');
}
}
function toggleCourseLayouts(courseId) {
const layoutsRow = document.getElementById(`layouts-${courseId}`);
const layoutsContainer = document.getElementById(`layouts-container-${courseId}`);
if (layoutsRow.style.display === 'table-row') {
layoutsRow.style.display = 'none';
return;
}
layoutsRow.style.display = 'table-row';
if (layoutsContainer.dataset.loaded === 'true') {
return;
}
htmx.ajax('GET', `/partials/course-layouts/${courseId}`, {target: `#layouts-container-${courseId}`, swap: 'innerHTML'});
layoutsContainer.dataset.loaded = 'true';
}
async function scrapeCourses() {
const btn = document.getElementById('scrape-courses-btn');
btn.disabled = true;
btn.textContent = 'Scraping...';
try {
const response = await fetch('/api/scrape-courses', { method: 'POST' });
const data = await response.json();
if (data.success) {
alert(data.message);
htmx.ajax('GET', '/partials/course-table', '#courses-table');
} else {
alert('Failed to scrape courses');
}
} catch (error) {
console.error('Error scraping courses:', error);
alert('Error scraping courses');
} finally {
btn.disabled = false;
btn.textContent = 'Scrape Courses';
}
}
async function scrapeLayouts(courseId, courseName) {
const icon = document.querySelector(`#row-${courseId} .refresh-icon`);
icon.classList.add('spinning');
try {
const response = await fetch(`/api/scrape-layouts/${courseId}`, { method: 'POST' });
const data = await response.json();
if (response.status === 409) {
alert(data.message || 'Scrape already in progress for this course. Please wait.');
} else if (data.success) {
const layoutsContainer = document.getElementById(`layouts-container-${courseId}`);
layoutsContainer.dataset.loaded = 'false';
const layoutsRow = document.getElementById(`layouts-${courseId}`);
if (layoutsRow.style.display === 'table-row') {
htmx.ajax('GET', `/partials/course-layouts/${courseId}`, {target: `#layouts-container-${courseId}`, swap: 'innerHTML'});
layoutsContainer.dataset.loaded = 'true';
}
alert(data.message);
} else {
alert('Failed to scrape layouts');
}
} catch (error) {
console.error('Error scraping layouts:', error);
alert('Error scraping layouts');
} finally {
icon.classList.remove('spinning');
}
}