Files
gitea-pages/docs/_javascripts/pdf-viewer.js
Michael Weinold 6852076bb2
All checks were successful
RSE-PSI Website Scheduler / checkout (pull_request) Successful in 32s
added presentation viewers
2026-03-04 11:24:05 +01:00

109 lines
3.3 KiB
JavaScript

/**
* Reusable PDF Viewer for MkDocs Material
*
* Uses PDF.js to render PDF files in a canvas.
* Looks for elements with class 'pdf-viewer-container' and a 'data-url' attribute.
*/
document$.subscribe(({ body }) => {
const containers = body.querySelectorAll('.pdf-viewer-container[data-url]');
if (containers.length === 0) return;
// Load PDF.js worker if not already loaded
if (window['pdfjs-dist/build/pdf'] && !window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc) {
window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
}
containers.forEach(container => {
initPDFViewer(container);
});
});
function initPDFViewer(container) {
const url = container.getAttribute('data-url');
const canvas = container.querySelector('canvas');
const pageNumDisplay = container.querySelector('.page-num');
const pageCountDisplay = container.querySelector('.page-count');
const prevBtn = container.querySelector('.prev-btn');
const nextBtn = container.querySelector('.next-btn');
const loadingMsg = container.querySelector('.pdf-viewer-loading');
if (!canvas || !url) return;
let pdfDoc = null;
let pageNum = 1;
let pageRendering = false;
let pageNumPending = null;
const scale = 2.0;
const ctx = canvas.getContext('2d');
function renderPage(num) {
pageRendering = true;
pdfDoc.getPage(num).then(page => {
if (loadingMsg) loadingMsg.style.display = 'none';
const viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then(() => {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
if (pageNumDisplay) pageNumDisplay.textContent = num;
}
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
if (prevBtn) {
prevBtn.addEventListener('click', () => {
if (pageNum <= 1) return;
pageNum--;
queueRenderPage(pageNum);
});
}
if (nextBtn) {
nextBtn.addEventListener('click', () => {
if (pageNum >= pdfDoc.numPages) return;
pageNum++;
queueRenderPage(pageNum);
});
}
// Load the document
const pdfjsLib = window['pdfjs-dist/build/pdf'];
if (!pdfjsLib) {
console.error('PDF.js library not found');
return;
}
pdfjsLib.getDocument(url).promise.then(pdfDoc_ => {
pdfDoc = pdfDoc_;
if (pageCountDisplay) pageCountDisplay.textContent = pdfDoc.numPages;
renderPage(pageNum);
}).catch(err => {
console.error('Error loading PDF:', err);
if (loadingMsg) loadingMsg.textContent = "Error loading PDF.";
});
}