Skip to content

Instantly share code, notes, and snippets.

@albertmatyi
Last active July 16, 2023 20:49
Show Gist options
  • Save albertmatyi/7c23a679a4a81c61c3628f6c15480b76 to your computer and use it in GitHub Desktop.
Save albertmatyi/7c23a679a4a81c61c3628f6c15480b76 to your computer and use it in GitHub Desktop.
Bookstack PDF embedding support snippet

Bookstack PDF Embed plugin

Setup

On /settings page Custom HTML head content add paste in the script/style above

Usage

The setup will result in a PDF button in the toolbar whenever you open the editor.

Pressing the button pops up a dialog, where you may enter the URL to the PDF.

This in turn will add a:

<p>&nbsp;<canvas data-pdfurl="[URL]"></canvas></p>

to your content, which in edit mode renders as a simple gray block.

In view mode, it will load the referenced PDF and render it on canvas elements using the pdfjs library.

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.466/pdf.min.js"></script>
<style>
canvas[data-pdfurl] {
background-color: lightgrey;
width: 100%;
}
.page-content a {
color: #39f;
text-decoration: underline;
}
.pdf-wrapper {
position: relative;
height: 80vh;
width: 100%;
}
.pdf-wrapper .download-link {
position: absolute;
top: -2em;
right: 0;
z-index: 50;
}
.pdf-wrapper .pdf-scroller {
height: 100%;
overflow: auto;
}
</style>
<script type="text/javascript">
var createButton = function(text,details,id,callback) {
var btnWrapper = document.createElement('div');
btnWrapper.id = id;
btnWrapper.className='mce-widget mce-btn';
btnWrapper.tabindex=-1;
btnWrapper.role='button';
btnWrapper.ariaLabel=details;
var btn = document.createElement('button');
btn.id=id+'-button';
btn.innerText = text;
btn.role='presentation';
btn.type='button';
btn.tabindex='-1';
btn.style.border = 'solid 1px';
btn.style.padding = ' 3px 7px';
btnWrapper.append(btn);
btnWrapper.onclick = callback;
var ar =document.querySelectorAll('.mce-btn.mce-last');
var lastBtn = ar[ar.length-2];
lastBtn.parentNode.append(btnWrapper);
};
window.addEventListener('load', function () {
// ------------------- THIS SECTION ADDS A PDF BUTTON TO THE EDITOR TOOLBAR THAT ALLOWS YOU TO EMBED PDFS
var btn = document.querySelectorAll('#mceu_20')[0];
if (btn) {
createButton('pdf', 'Insert a PDF', 'mceu_pdf', function(e) {
// show dialog
var editor = tinyMCE.editors[0];
editor.windowManager.open({
title: 'Insert PDF',
body: [
{type: 'textbox', name: 'pdfurl', label: 'PDF URL'}
],
onsubmit: function(e) {
// Insert content when the window form is submitted
editor.insertContent('<p>&nbsp;<canvas data-pdfurl="' + e.data.pdfurl + '"></canvas>&nbsp;</p>');
}
});
});
}
//-------------------- THE CODE BELOW SHALL BE ACTIVE IN VIEWING MODE TO EMBED PDFS
var renderPdf=function(canvas) {
var url = canvas.dataset.pdfurl;
var pdf = null;
// wrap canvas in div
var wrapper = document.createElement('div');
wrapper.className='pdf-wrapper';
var scroller = document.createElement('div');
scroller.className='pdf-scroller';
wrapper.appendChild(scroller);
canvas.parentNode.insertBefore(wrapper, canvas.nextSibling);
scroller.insertBefore(canvas, null);
var downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.className="download-link";
downloadLink.innerText = 'Download PDF now ↓';
wrapper.appendChild(downloadLink);
var renderPage = function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
canvas.height = viewport.height;
canvas.width = viewport.width;
canvas.style.maxWidth='100%';
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport
};
// Render PDF page
page.render(renderContext);
if (currentPage < pdf.numPages) {
currentPage++;
var newCanvas = document.createElement('canvas');
scroller.insertBefore(newCanvas, canvas.nextSibling);
scroller.insertBefore(document.createElement('hr'), canvas.nextSibling);
canvas=newCanvas;
pdf.getPage(currentPage).then(renderPage);
}
};
var currentPage = 1;
pdfjsLib.getDocument(url)
.then(function(pdfLocal) {
pdf = pdfLocal;
return pdf.getPage(1);
})
.then(renderPage);
}
Array.prototype.forEach.call(
document.querySelectorAll('canvas[data-pdfurl]'),
renderPdf);
});
</script>
@workdojos
Copy link

workdojos commented Mar 9, 2021

<p id="bkmrk-"><embed src="https://xxx.xxx/xxx.pdf" type="application/pdf" width="100%" height="xxx"></embed></p>
Other solution

Thanks, this worked, but any idea why it can't be viewed on mobile whatsoever? Is the other solution above viewable on mobile at all?

Also, this only works for something like a PDF, but not a webpage? I tried to insert a URL into the above and it didn't work. TIA

@jadedmia
Copy link

Any idea how to get local files to render using file:///C:/path to document/file.pdf format?

@christianhz01
Copy link

Hi, since version 22 it stopped working 😐

@yuelu714
Copy link

yuelu714 commented Mar 3, 2022

We regret that we upgraded :( It would great if you can update the plugin to work with version 22. Thank you!

@mattisaoldgit
Copy link

Just showing support, myself and lots of others would be very grateful if you can find time to take a look.

Thanks

@sp4m4r
Copy link

sp4m4r commented Mar 24, 2022

Would be good to have it again. :)

@detritus420
Copy link

We'd like this as well

@Seventy-9DegreesNorth
Copy link

Matyas, thank you so much for this script. We just started using it on [BookStack v21.12.5] and it appears to be working great. Although, initially, I pasted in the script into the HTML head TWICE -- and it made the rendering really wonky and showed two buttons. After I figured out my dumb mistake, and repasted the code ONCE -- it works great.

The other great thing is that you can post multiple PDFs in one Bookstack page.

Thank you again -- much appreciated and very elegant and lightweight way to approach this issue.

Final question, do you think this is "upgrade safe"? Meaning, if we make a time investment to structure our PDF distribution around the ability to do these embeds, do you think Bookstack upgrades will break this capability?

@Nexow91
Copy link

Nexow91 commented Jul 16, 2023

Hello I would like to use the plugin to embed pdf as you described unfortunately I do not know exactly where and how I have to insert what where. Can you give more info about this ?

Do I have to insert it in a new page, in an .ini file and somewhere in the settings ?

/settings doesn't work you either end up at /settings/features or /settings/maintance etc.

Would be grateful for any info.

Edit. I have found the settings and the hmtl header option no buttons show on editor sites. what do im wrong ? My version is 23.06.2 its a version issue ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment