7e5fa6cbf1
- 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
88 lines
3.0 KiB
JavaScript
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');
|
|
}
|
|
}
|