var pdfjsLib = window['pdfjs-dist/build/pdf']; pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.1.266/build/pdf.worker.min.js'; class PdfRenderer { constructor(canvas) { this.numPages = 1; this.currentPage = 0; this.scale = 2; this.canvas = canvas; this.ctx = this.canvas.getContext("2d"); this.offScreenCanvas = document.createElement("canvas"); this.offScreenCtx = this.offScreenCanvas.getContext("2d"); this.dpr = window.devicePixelRatio || 1; this.pdf = null; this.rendering = false; this.renderPending = false; } update(b64, cb) { if (b64 == "") { this.pdf = null; this.numPages = 1; this.currentPage = 0; this.render(); cb(); return; } else if (b64 == null) { cb(); return; } let data = atob(b64); let loadingTask = pdfjsLib.getDocument({ data }); loadingTask.promise.then(pdf => { this.pdf = pdf; this.numPages = this.pdf.numPages; if (this.currentPage >= this.numPages) this.currentPage = this.numPages - 1; this.render(); cb(); }); } render() { if (this.rendering) { this.renderPending = true; return; } if (this.pdf == null) { this.canvas.width = this.canvas.width; return; } this.rendering = true; this.pdf.getPage(this.currentPage + 1).then(page => { let viewport = page.getViewport({ scale: this.scale }); this.offScreenCanvas.height = viewport.height * this.dpr; this.offScreenCanvas.width = viewport.width * this.dpr; this.offScreenCanvas.style.width = viewport.width + "px"; this.offScreenCanvas.style.height = viewport.height + "px"; this.offScreenCtx.scale(this.dpr, this.dpr); let renderTask = page.render({ canvasContext: this.offScreenCtx, viewport }); renderTask.promise.then(() => { this.canvas.width = this.offScreenCanvas.width; this.canvas.height = this.offScreenCanvas.height; this.canvas.style.width = this.offScreenCanvas.style.width; this.canvas.style.height = this.offScreenCanvas.style.height; this.ctx.drawImage(this.offScreenCanvas, 0, 0); this.rendering = false; if (this.renderPending) { this.renderPending = false; this.render(); } }); }); } } let renderer = new PdfRenderer(document.getElementById("preview")); let previewState = document.getElementById("preview-state"); let renderOutput = document.getElementById("pandoc-output"); function updatePreviewState() { previewState.innerText = (renderer.currentPage + 1) + "/" + renderer.numPages; } let markdownReqNum = 0; let markdownReqLast = 0; function renderMarkdown(canvas, text) { let num = markdownReqNum++; fetch("/pandoc", { method: "POST", body: editor.value(), }).then(res => res.json()).then(obj => { if (num < markdownReqLast) return; markdownReqLast = num; renderOutput.innerText = obj.output; renderer.update(obj.pdf, () => { updatePreviewState(); }); }); } function nextPage() { if (renderer.currentPage < renderer.numPages - 1) { renderer.currentPage += 1; renderer.render(); updatePreviewState(); } } function prevPage() { if (renderer.currentPage > 0) { renderer.currentPage -= 1; renderer.render(); updatePreviewState(); } } function debounce(ms, cb) { let timeout = null; return function() { if (timeout != null) { clearTimeout(timeout); timout = null; } timeout = setTimeout(cb, ms); } } let editor = new SimpleMDE({ element: document.getElementById("editor"), hideIcons: [ "side-by-side", "preview" ], spellChecker: false, autosave: true, }); let onChange = debounce(100, () => renderMarkdown(preview, editor.value())); editor.codemirror.on("change", onChange); renderMarkdown(preview, editor.value()); document.getElementById("preview-prev-btn").addEventListener("click", prevPage); document.getElementById("preview-next-btn").addEventListener("click", nextPage);