pediatric-ai-scribe-v3/public/js/learningHub/slideController.js
2026-05-08 16:04:21 +02:00

149 lines
5.6 KiB
JavaScript

import { getJson, sendJson, sendJsonBlob } from './api.js';
export function createSlideController(deps) {
var previewSlides = [];
var previewIdx = 0;
function openSlidesFromSlug(slug) {
deps.showBusy('Loading slides...');
getJson('/api/learning/content/' + encodeURIComponent(slug) + '/slides')
.then(function(data) {
deps.hideBusy();
if (!data.success) { deps.showToast(data.error || 'Could not load slides', 'error'); return; }
openSlideModal(data.slides, data.css);
})
.catch(function(err) { deps.hideBusy(); deps.showToast(err.message, 'error'); });
}
function previewCurrentSlides() {
var md = deps.getMarkdown();
if (!md) { deps.showToast('No slide content yet. Use AI Generate first.', 'info'); return; }
deps.showBusy('Rendering slides...');
sendJson('/api/admin/learning/preview-slides', 'POST', { markdown: md })
.then(function(data) {
deps.hideBusy();
if (!data.success) { deps.showToast(data.error || 'Preview failed', 'error'); return; }
openSlideModal(data.slides, data.css);
})
.catch(function(err) { deps.hideBusy(); deps.showToast(err.message, 'error'); });
}
function openSlideModal(slides, css) {
closeSlideModal();
previewSlides = slides || [];
previewIdx = 0;
var modal = document.getElementById('slide-preview-modal');
var cssEl = document.getElementById('slide-preview-css');
var dotsEl = document.getElementById('slide-preview-dots');
if (!modal || !previewSlides.length) { deps.showToast('No slides to display', 'error'); return; }
if (cssEl) cssEl.textContent = css || '';
if (dotsEl) dotsEl.innerHTML = renderDots(previewSlides.length);
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
renderSlide(0);
wireModalInput(modal);
}
function renderSlide(idx) {
var content = document.getElementById('slide-preview-content');
var counter = document.getElementById('slide-preview-counter');
var dots = document.querySelectorAll('.slide-dot');
var prev = document.getElementById('slide-nav-prev');
var next = document.getElementById('slide-nav-next');
if (!content || !previewSlides.length) return;
previewIdx = Math.max(0, Math.min(idx, previewSlides.length - 1));
content.innerHTML = previewSlides[previewIdx];
if (counter) counter.textContent = (previewIdx + 1) + ' / ' + previewSlides.length;
if (prev) prev.style.opacity = previewIdx === 0 ? '0.3' : '1';
if (next) next.style.opacity = previewIdx === previewSlides.length - 1 ? '0.3' : '1';
dots.forEach(function(d, i) { d.classList.toggle('active', i === previewIdx); });
}
function slideStep(dir) { renderSlide(previewIdx + dir); }
function closeSlideModal() {
var modal = document.getElementById('slide-preview-modal');
if (modal) modal.classList.add('hidden');
document.body.style.overflow = '';
if (document._slideKeyHandler) {
document.removeEventListener('keydown', document._slideKeyHandler);
document._slideKeyHandler = null;
}
if (modal && modal._touchStart) {
modal.removeEventListener('touchstart', modal._touchStart);
modal._touchStart = null;
}
if (modal && modal._touchEnd) {
modal.removeEventListener('touchend', modal._touchEnd);
modal._touchEnd = null;
}
}
function downloadPptx() {
var md = deps.getMarkdown();
if (!md) { deps.showToast('No slide content yet', 'error'); return; }
var title = deps.getTitle() || 'presentation';
var btn = document.getElementById('btn-lh-download-pptx');
if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Building...'; }
sendJsonBlob('/api/admin/learning/generate-pptx', 'POST', { markdown: md, title: title })
.then(function(blob) {
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = makePptxFilename(title);
a.click();
URL.revokeObjectURL(url);
deps.showToast('PPTX downloaded!', 'success');
})
.catch(function(err) { deps.showToast(err.message, 'error'); })
.finally(function() {
if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-file-powerpoint"></i> Download PPTX'; }
});
}
function wireModalInput(modal) {
document._slideKeyHandler = function(e) {
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') slideStep(1);
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') slideStep(-1);
else if (e.key === 'Escape') closeSlideModal();
};
document.addEventListener('keydown', document._slideKeyHandler);
var touchStartX = 0;
modal._touchStart = function(e) { touchStartX = e.touches[0].clientX; };
modal._touchEnd = function(e) {
var dx = e.changedTouches[0].clientX - touchStartX;
if (Math.abs(dx) > 40) slideStep(dx < 0 ? 1 : -1);
};
modal.addEventListener('touchstart', modal._touchStart);
modal.addEventListener('touchend', modal._touchEnd);
}
return {
closeSlideModal: closeSlideModal,
downloadPptx: downloadPptx,
openSlidesFromSlug: openSlidesFromSlug,
previewCurrentSlides: previewCurrentSlides,
renderSlide: renderSlide,
slideStep: slideStep
};
}
export function makePptxFilename(title) {
return String(title || 'presentation').replace(/\s+/g, '-').toLowerCase() + '.pptx';
}
function renderDots(count) {
var html = '';
for (var i = 0; i < count; i++) {
html += '<button class="slide-dot" data-idx="' + i + '" aria-label="Go to slide ' + (i + 1) + '"></button>';
}
return html;
}