All checks were successful
RSE-PSI Website Scheduler / checkout (pull_request) Successful in 32s
109 lines
3.3 KiB
JavaScript
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.";
|
|
});
|
|
}
|