[Feature Request] Preview for PDF Attachments #571

Open
opened 2026-02-04 21:08:10 +03:00 by OVERLORD · 37 comments
Owner

Originally created by @ghost on GitHub (Feb 18, 2018).

Feature Request

Hey Everybody,
i am very happy to see the rapid progress about the App - great Work
But i miss the function, that I can get a preview of attached pdf-Files, before I downloading it.
It would be very nice, when these feature where implement in the next versions of Bookstack.

Originally created by @ghost on GitHub (Feb 18, 2018). ### Feature Request Hey Everybody, i am very happy to see the rapid progress about the App - great Work But i miss the function, that I can get a preview of attached pdf-Files, before I downloading it. It would be very nice, when these feature where implement in the next versions of Bookstack.
OVERLORD added the 🔨 Feature Request label 2026-02-04 21:08:10 +03:00
Author
Owner

@lommes commented on GitHub (Feb 19, 2018):

@Yoginth
I think you got the question wrong. It is not about the generation of PDF-files.

@ITforHome
Can you please give some details on how the preview should look?

Currently the attachements are only downloaded. In case of PDF there are severall possibilities to implement a "preview". There can be a real preview in form of a generated image including only the first page of the pdf, change the 'Content-Type' for this download (as suggested by @Yoginth) so the browser uses the defined preview(plugin) or embedd a preview using pdfjs or something. In the last 2 cases the file technically is already downloaded to your computer.

@lommes commented on GitHub (Feb 19, 2018): @Yoginth I think you got the question wrong. It is not about the generation of PDF-files. @ITforHome Can you please give some details on how the preview should look? Currently the attachements are only downloaded. In case of PDF there are severall possibilities to implement a "preview". There can be a real preview in form of a generated image including only the first page of the pdf, change the 'Content-Type' for this download (as suggested by @Yoginth) so the browser uses the defined preview(plugin) or embedd a preview using pdfjs or something. In the last 2 cases the file technically is already downloaded to your computer.
Author
Owner

@lommes commented on GitHub (Feb 19, 2018):

@Yoginth yes and no.
File attachments are handled by AttachmentController.php (not by the PageController) and Downloads by the get-method. If you change the Content-Type for all filetypes this will most likely result in errors when you attach and later download a zip, exe, ... file.

@lommes commented on GitHub (Feb 19, 2018): @Yoginth yes and no. File attachments are handled by AttachmentController.php (not by the PageController) and Downloads by the [get-method](https://github.com/BookStackApp/BookStack/blob/master/app/Http/Controllers/AttachmentController.php#L188). If you change the Content-Type for all filetypes this will most likely result in errors when you attach and later download a zip, exe, ... file.
Author
Owner

@ghost commented on GitHub (Feb 20, 2018):

@Yoginth
i have changed the Content-Type to 'Content-Type' => 'application/octet-stream' in the PageController.php file, but is not working. When i click on an attached pdf-File, i can only downloaded it, but i can't get a preview.

@lommes
i have changed the Content-Txpe to 'Content-Type' => 'application/pdf' in the AttachmentController.php file, but is not working too. When i also click on an attached pdf-File, i can only downloaded it, no preview.

General:
In my question i mean any attached pdf-File NO the generated PDF-File of a page in Bookstack

@ghost commented on GitHub (Feb 20, 2018): @Yoginth i have changed the Content-Type to `'Content-Type' => 'application/octet-stream'` in the PageController.php file, but is not working. When i click on an attached pdf-File, i can only downloaded it, but i can't get a preview. @lommes i have changed the Content-Txpe to `'Content-Type' => 'application/pdf'` in the AttachmentController.php file, but is not working too. When i also click on an attached pdf-File, i can only downloaded it, no preview. General: In my question i mean any attached pdf-File NO the generated PDF-File of a page in Bookstack
Author
Owner

@ghost commented on GitHub (Feb 24, 2018):

When I open the Bookstack App on Mobile Safari or Chrome I get a preview about attached PDF-Files when I click on it.

@ghost commented on GitHub (Feb 24, 2018): When I open the Bookstack App on Mobile Safari or Chrome I get a preview about attached PDF-Files when I click on it.
Author
Owner

@albertmatyi commented on GitHub (Mar 27, 2018):

I've created a small hack (quick solution for own deployment) to be able to view pdf attachments as embedded documents in a page.

"Installation"

Add the following script to the CUSTOM HTML HEAD content on the Settings pane.
2018-07-11-102632_835x87_scrot

    <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">
window.addEventListener('load', function () {
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>

Usage

  1. Attach pdf to the page
  2. In the source editing mode insert the line:
    <p>&nbsp;<canvas data-pdfurl="https://wiki.justrocket.de/attachments/3"></canvas>&nbsp;</p>
    where 3 is the id of the attachment (hover the attachment link to see the number)
@albertmatyi commented on GitHub (Mar 27, 2018): I've created a small hack (quick solution for own deployment) to be able to view pdf attachments as embedded documents in a page. # "Installation" Add the following script to the CUSTOM HTML HEAD content on the Settings pane. ![2018-07-11-102632_835x87_scrot](https://user-images.githubusercontent.com/1370078/42559581-d447a9e0-84f4-11e8-825c-faea1c57ef72.png) ``` <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"> window.addEventListener('load', function () { 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> ``` # Usage 1. Attach pdf to the page 1. In the source editing mode insert the line: ```<p>&nbsp;<canvas data-pdfurl="https://wiki.justrocket.de/attachments/3"></canvas>&nbsp;</p>``` where 3 is the id of the attachment (hover the attachment link to see the number)
Author
Owner

@shatteredsword commented on GitHub (Jul 10, 2018):

@albertmatyi your solution works great! thank you!

@shatteredsword commented on GitHub (Jul 10, 2018): @albertmatyi your solution works great! thank you!
Author
Owner

@albertmatyi commented on GitHub (Jul 18, 2018):

Created a more userfriendly version.

Code & Readme at: https://gist.github.com/albertmatyi/7c23a679a4a81c61c3628f6c15480b76

  1. Toolbar button
    2018-07-18-095853_235x88_scrot
  2. Popup dialog:
    2018-07-18-100325_590x429_scrot
  3. Edit mode PDF placeholder
    2018-07-18-100404_854x392_scrot
  4. Embedded PDF
    2018-07-18-100533_872x657_scrot
@albertmatyi commented on GitHub (Jul 18, 2018): Created a more userfriendly version. Code & Readme at: https://gist.github.com/albertmatyi/7c23a679a4a81c61c3628f6c15480b76 1. Toolbar button ![2018-07-18-095853_235x88_scrot](https://user-images.githubusercontent.com/1370078/42868001-7653be46-8a71-11e8-9ee3-6ac63dabe0de.png) 1. Popup dialog: ![2018-07-18-100325_590x429_scrot](https://user-images.githubusercontent.com/1370078/42868076-b280c684-8a71-11e8-8582-6a97cbf304cd.png) 1. Edit mode PDF placeholder ![2018-07-18-100404_854x392_scrot](https://user-images.githubusercontent.com/1370078/42868113-c87eeb64-8a71-11e8-9f51-deeaea23bd37.png) 1. Embedded PDF ![2018-07-18-100533_872x657_scrot](https://user-images.githubusercontent.com/1370078/42868184-fa2e53e8-8a71-11e8-9507-7567254605be.png)
Author
Owner

@rwjuk commented on GitHub (Jun 7, 2019):

For anyone coming across this and wanting to view PDF attachments in the browser, change the return statement of app/Http/Controllers/AttachmentController.php to this:

    $contentType = 'application/octet-stream';
    $contentDisposition = 'attachment';

    if ($attachment->extension === "pdf") {
            $contentType = 'application/pdf';
            $contentDisposition = 'inline';
    }

    return response($attachmentContents, 200, [
        'Content-Type' => $contentType,
        'Content-Disposition' => $contentDisposition.'; filename="'. $attachment->getFileName() .'"'
    ]);
@rwjuk commented on GitHub (Jun 7, 2019): For anyone coming across this and wanting to view PDF attachments in the browser, change the return statement of `app/Http/Controllers/AttachmentController.php` to this: $contentType = 'application/octet-stream'; $contentDisposition = 'attachment'; if ($attachment->extension === "pdf") { $contentType = 'application/pdf'; $contentDisposition = 'inline'; } return response($attachmentContents, 200, [ 'Content-Type' => $contentType, 'Content-Disposition' => $contentDisposition.'; filename="'. $attachment->getFileName() .'"' ]);
Author
Owner

@aldo-o commented on GitHub (Apr 7, 2020):

For anyone coming across this and wanting to view PDF attachments in the browser, change the return statement of app/Http/Controllers/AttachmentController.php to this:

    $contentType = 'application/octet-stream';
    $contentDisposition = 'attachment';

    if ($attachment->extension === "pdf") {
            $contentType = 'application/pdf';
            $contentDisposition = 'inline';
    }

    return response($attachmentContents, 200, [
        'Content-Type' => $contentType,
        'Content-Disposition' => $contentDisposition.'; filename="'. $attachment->getFileName() .'"'
    ]);

Where? There are a lot of functions in that file.
P.S. Not a php developer so excuse my stupidity.

@aldo-o commented on GitHub (Apr 7, 2020): > For anyone coming across this and wanting to view PDF attachments in the browser, change the return statement of `app/Http/Controllers/AttachmentController.php` to this: > > ``` > $contentType = 'application/octet-stream'; > $contentDisposition = 'attachment'; > > if ($attachment->extension === "pdf") { > $contentType = 'application/pdf'; > $contentDisposition = 'inline'; > } > > return response($attachmentContents, 200, [ > 'Content-Type' => $contentType, > 'Content-Disposition' => $contentDisposition.'; filename="'. $attachment->getFileName() .'"' > ]); > ``` Where? There are a lot of functions in that file. P.S. Not a php developer so excuse my stupidity.
Author
Owner

@ssddanbrown commented on GitHub (Apr 7, 2020):

@aldoblack I think it's intended to be a replacement of this line:
https://github.com/BookStackApp/BookStack/blob/v0.28.3/app/Http/Controllers/AttachmentController.php#L198

Note, Such changes to core files are not officially supported and may cause complications, or be lost, when you upgrade.

@ssddanbrown commented on GitHub (Apr 7, 2020): @aldoblack I think it's intended to be a replacement of this line: https://github.com/BookStackApp/BookStack/blob/v0.28.3/app/Http/Controllers/AttachmentController.php#L198 Note, Such changes to core files are not officially supported and may cause complications, or be lost, when you upgrade.
Author
Owner

@aldo-o commented on GitHub (Apr 8, 2020):

@aldoblack I think it's intended to be a replacement of this line:
https://github.com/BookStackApp/BookStack/blob/v0.28.3/app/Http/Controllers/AttachmentController.php#L198

Note, Such changes to core files are not officially supported and may cause complications, or be lost, when you upgrade.

I understand. Thank You very much.

@aldo-o commented on GitHub (Apr 8, 2020): > @aldoblack I think it's intended to be a replacement of this line: > https://github.com/BookStackApp/BookStack/blob/v0.28.3/app/Http/Controllers/AttachmentController.php#L198 > > Note, Such changes to core files are not officially supported and may cause complications, or be lost, when you upgrade. I understand. Thank You very much.
Author
Owner

@sprklinginfo commented on GitHub (May 12, 2021):

Tried out the solution by @albertmatyi. The pdf is successfully embedded on the page. Big thanks to @albertmatyi. But it also causes errors if you want to export that page as a pdf later.
Inspired by the solution, I tweaked it to have the pdf displayed in a popup window (an online pdf viewer) while the page itself only has a button for the popup window so it won't affect the export. Here is the readme and code: https://gist.github.com/sprklinginfo/624c4c431a0f802556071ec459b6ca76

@sprklinginfo commented on GitHub (May 12, 2021): Tried out the solution by @albertmatyi. The pdf is successfully embedded on the page. Big thanks to @albertmatyi. But it also causes errors if you want to export that page as a pdf later. Inspired by the solution, I tweaked it to have the pdf displayed in a popup window (an online pdf viewer) while the page itself only has a button for the popup window so it won't affect the export. Here is the readme and code: https://gist.github.com/sprklinginfo/624c4c431a0f802556071ec459b6ca76
Author
Owner

@ssddanbrown commented on GitHub (Jun 13, 2021):

Just to note on this, Within BookStack v21.05.2 it's now possible to open up attachments in an "inline" (Not forced download) via Ctrl+Click of the attachment (Or Cmd+click on Mac). Alternatively, an attachment link of this type can be manually formed by adding an ?open=true query parameter to the link.

@ssddanbrown commented on GitHub (Jun 13, 2021): Just to note on this, Within BookStack [v21.05.2](https://github.com/BookStackApp/BookStack/releases/tag/v21.05.2) it's now possible to open up attachments in an "inline" (Not forced download) via Ctrl+Click of the attachment (Or Cmd+click on Mac). Alternatively, an attachment link of this type can be manually formed by adding an `?open=true` query parameter to the link.
Author
Owner

@shatteredsword commented on GitHub (Jun 14, 2021):

ctrl+click doesn't work if the filesize is over the default upload size limit for some reason, which is weird

@shatteredsword commented on GitHub (Jun 14, 2021): ctrl+click doesn't work if the filesize is over the default upload size limit for some reason, which is weird
Author
Owner

@christianhz01 commented on GitHub (Feb 6, 2022):

Good evening @ssddanbrown ,

is there still an integrated solution planned here in the future or should users use @albertmatyi solution?

I think this would be an important feature for many people...

Christian

@christianhz01 commented on GitHub (Feb 6, 2022): Good evening @ssddanbrown , is there still an integrated solution planned here in the future or should users use @albertmatyi solution? I think this would be an important feature for many people... Christian
Author
Owner

@shatteredsword commented on GitHub (Feb 10, 2022):

my current hacked version of this feature is adding this to the source code of the page i want the PDF to be on (assuming the pdf is uploaded somewhere on the site as an attachment:
<embed src="http://mysite.mydomain.com/attachments/12?open=true" type="application/pdf" width="100%" height="500px"></embed>

What it looks like:

Screenshots

In Firefox:
image

In Chrome:
image

@shatteredsword commented on GitHub (Feb 10, 2022): my current hacked version of this feature is adding this to the source code of the page i want the PDF to be on (assuming the pdf is uploaded somewhere on the site as an attachment: `<embed src="http://mysite.mydomain.com/attachments/12?open=true" type="application/pdf" width="100%" height="500px"></embed>` What it looks like: <details> <summary>Screenshots</summary> In Firefox: ![image](https://user-images.githubusercontent.com/6646245/153307781-e00f401d-4979-492d-8f57-547dcd54ab3e.png) In Chrome: ![image](https://user-images.githubusercontent.com/6646245/153307972-ae8f5524-ac56-4fb9-bdbc-1459f65bf00b.png) </details>
Author
Owner

@ssddanbrown commented on GitHub (Feb 10, 2022):

Here's the above made into a bookmarklet:

javascript:(function()%7B(function()%20%7B%0A%09%09let%20link%20%3D%20window.prompt(%22Enter%20BookStack%20Attachment%20Link%3A%22)%3B%0A%09%09if%20(!link.endsWith(%22%3Fopen%3Dtrue%22))%20%7B%0A%09%09%09link%20%2B%3D%20%22%3Fopen%3Dtrue%22%3B%0A%09%09%7D%0A%09%09if%20(link%20%26%26%20tinymce%3F.activeEditor)%20%7B%0A%09%09%09tinymce.activeEditor.insertContent(%60%3Cembed%20src%3D%22%24%7Blink%7D%22%20type%3D%22application%2Fpdf%22%20width%3D%22100%25%22%20height%3D%22500px%22%3E%3C%2Fembed%3E%60)%3B%0A%09%09%7D%0A%09%7D)()%3B%7D)()%3B
Usage
  • Create a browser bookmark with the above content as the URL.
  • When in the editor, (With the cursor focused in the editor), click the bookmark.
  • You'll see a popup asking for a link. Paste in an PDF attachment link (Expects a BookStack PDF attachment URL) and press ok.
  • It'll insert the the snippet by @shatteredsword into the editor at the cursor position.
  • You'll have to save to see the embed.

Tested that on Firefox. This is all a hack and any of these workarounds may break upon update.

@ssddanbrown commented on GitHub (Feb 10, 2022): Here's the above made into a bookmarklet: ``` javascript:(function()%7B(function()%20%7B%0A%09%09let%20link%20%3D%20window.prompt(%22Enter%20BookStack%20Attachment%20Link%3A%22)%3B%0A%09%09if%20(!link.endsWith(%22%3Fopen%3Dtrue%22))%20%7B%0A%09%09%09link%20%2B%3D%20%22%3Fopen%3Dtrue%22%3B%0A%09%09%7D%0A%09%09if%20(link%20%26%26%20tinymce%3F.activeEditor)%20%7B%0A%09%09%09tinymce.activeEditor.insertContent(%60%3Cembed%20src%3D%22%24%7Blink%7D%22%20type%3D%22application%2Fpdf%22%20width%3D%22100%25%22%20height%3D%22500px%22%3E%3C%2Fembed%3E%60)%3B%0A%09%09%7D%0A%09%7D)()%3B%7D)()%3B ``` ##### Usage - Create a browser bookmark with the above content as the URL. - When in the editor, (With the cursor focused in the editor), click the bookmark. - You'll see a popup asking for a link. Paste in an PDF attachment link (Expects a BookStack PDF attachment URL) and press ok. - It'll insert the the snippet by @shatteredsword into the editor at the cursor position. - You'll have to save to see the embed. Tested that on Firefox. This is all a hack and any of these workarounds may break upon update.
Author
Owner

@nmpeckham commented on GitHub (Mar 10, 2022):

Updated script by @albertmatyi for Bookstack v22.02:

<!--Based on original by github.com/albertmatyi-->
<!--Updated March 10th 2022 by github.com/nmpeckham-->
<!--Confirmed working on Bookstack version 22.02-->

<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, callback) {
        var btnWrapper = document.createElement('button');
        btnWrapper.className = 'tox-btn';
        btnWrapper.tabindex = -1;
        btnWrapper.ariaLabel = details;
        btnWrapper.type = 'button';
        btnWrapper.title = details
        btnWrapper.ariaDisabled = "false";
        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('div.tox-toolbar__group')[5];
        ar.prepend(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('div.tox-toolbar__group')[5];

        if (btn) {
            createButton('pdf', 'Insert a PDF', function (e) {
                // show dialog
                var editor = tinyMCE.editors[0];
                editor.windowManager.open({
                    title: 'Insert PDF', // The dialog's title - displayed in the dialog header
                    body: {
                        type: 'panel', // Root panel
                        items: [
                            {
                                type: 'input', // HTML text input component
                                name: 'pdfurl'
                            }
                        ]
                    },
                    buttons: [ // A list of footer buttons
                        {
                            type: 'submit',
                            text: 'OK'
                        },
                        {
                            type: 'cancel',
                            text: "Cancel"
                        }
                    ],
                    onSubmit: function (api) {
                        // Insert content when the window form is submitted
                        var data = api.getData();
                        editor.insertContent('<p>&nbsp;<canvas data-pdfurl="' + data.pdfurl + '"></canvas>&nbsp;</p>');
                        api.close();
                    }
                });
        });
        }

    //-------------------- 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>
@nmpeckham commented on GitHub (Mar 10, 2022): Updated script by @albertmatyi for Bookstack v22.02: <details> ```html <!--Based on original by github.com/albertmatyi--> <!--Updated March 10th 2022 by github.com/nmpeckham--> <!--Confirmed working on Bookstack version 22.02--> <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, callback) { var btnWrapper = document.createElement('button'); btnWrapper.className = 'tox-btn'; btnWrapper.tabindex = -1; btnWrapper.ariaLabel = details; btnWrapper.type = 'button'; btnWrapper.title = details btnWrapper.ariaDisabled = "false"; 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('div.tox-toolbar__group')[5]; ar.prepend(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('div.tox-toolbar__group')[5]; if (btn) { createButton('pdf', 'Insert a PDF', function (e) { // show dialog var editor = tinyMCE.editors[0]; editor.windowManager.open({ title: 'Insert PDF', // The dialog's title - displayed in the dialog header body: { type: 'panel', // Root panel items: [ { type: 'input', // HTML text input component name: 'pdfurl' } ] }, buttons: [ // A list of footer buttons { type: 'submit', text: 'OK' }, { type: 'cancel', text: "Cancel" } ], onSubmit: function (api) { // Insert content when the window form is submitted var data = api.getData(); editor.insertContent('<p>&nbsp;<canvas data-pdfurl="' + data.pdfurl + '"></canvas>&nbsp;</p>'); api.close(); } }); }); } //-------------------- 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> ``` </details>
Author
Owner

@christianhz01 commented on GitHub (Mar 12, 2022):

@nmpeckham Hi, I just tested it in version 22.02.3, the function is also given. Unfortunately, no button icon is displayed (Edge and Firefox on the latest version). With me there is simply a teaching stelle (which can be clicked). But thanks for the work!

@christianhz01 commented on GitHub (Mar 12, 2022): @nmpeckham Hi, I just tested it in version 22.02.3, the function is also given. Unfortunately, no button icon is displayed (Edge and Firefox on the latest version). With me there is simply a teaching stelle (which can be clicked). But thanks for the work!
Author
Owner

@BertCurbit commented on GitHub (Mar 22, 2022):

Updated script by @albertmatyi for Bookstack v22.02:
...

I can confirm this works in version 22.02.3. The button is back

@BertCurbit commented on GitHub (Mar 22, 2022): > Updated script by @albertmatyi for Bookstack v22.02: > ... I can confirm this works in version 22.02.3. The button is back
Author
Owner

@christianhz01 commented on GitHub (Mar 27, 2022):

@nmpeckham Hi,

the butten is unfortunately still not there :(

@christianhz01 commented on GitHub (Mar 27, 2022): @nmpeckham Hi, the butten is unfortunately still not there :(
Author
Owner

@ssddanbrown commented on GitHub (Aug 3, 2022):

Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported:

View Code
<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">

  // ------------------- THIS SECTION ADDS A PDF BUTTON TO THE EDITOR TOOLBAR THAT ALLOWS YOU TO EMBED PDFS 

  // Use BookStack editor event to add custom "Insert PDF" button into main toolbar
  window.addEventListener('editor-tinymce::pre-init', event => {
      const mceConfig = event.detail.config;
      mceConfig.toolbar = mceConfig.toolbar.replace('link', 'link insertpdf')
  });

  // Use BookStack editor event to define the custom "Insert PDF" button.
  window.addEventListener('editor-tinymce::setup', event => {
    const editor = event.detail.editor;

    // Add PDF insert button
    editor.ui.registry.addButton('insertpdf', {
      tooltip: 'Insert PDF',
      icon: 'document-properties',
      onAction() {
        editor.windowManager.open({
          title: 'Insert PDF',
          body: {
            type: 'panel',
            items: [
              {type: 'textarea', name: 'pdfurl', label: 'PDF URL'}
            ]
          },
          onSubmit: function(e) {
            // Insert content when the window form is submitted
            editor.insertContent('<p>&nbsp;<canvas data-pdfurl="' + e.getData().pdfurl + '"></canvas>&nbsp;</p>');
            e.close();
          },
          buttons: [
            {
              type: 'submit',
              text: 'Insert PDF'
            }
          ]
        });
      }
    });

  });

//-------------------- 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);
};


window.addEventListener('DOMContentLoaded', function() {
  Array.prototype.forEach.call(document.querySelectorAll('canvas[data-pdfurl]'), renderPdf);
});
</script>
@ssddanbrown commented on GitHub (Aug 3, 2022): Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported: <details> <summary>View Code</summary> ```html <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"> // ------------------- THIS SECTION ADDS A PDF BUTTON TO THE EDITOR TOOLBAR THAT ALLOWS YOU TO EMBED PDFS // Use BookStack editor event to add custom "Insert PDF" button into main toolbar window.addEventListener('editor-tinymce::pre-init', event => { const mceConfig = event.detail.config; mceConfig.toolbar = mceConfig.toolbar.replace('link', 'link insertpdf') }); // Use BookStack editor event to define the custom "Insert PDF" button. window.addEventListener('editor-tinymce::setup', event => { const editor = event.detail.editor; // Add PDF insert button editor.ui.registry.addButton('insertpdf', { tooltip: 'Insert PDF', icon: 'document-properties', onAction() { editor.windowManager.open({ title: 'Insert PDF', body: { type: 'panel', items: [ {type: 'textarea', name: 'pdfurl', label: 'PDF URL'} ] }, onSubmit: function(e) { // Insert content when the window form is submitted editor.insertContent('<p>&nbsp;<canvas data-pdfurl="' + e.getData().pdfurl + '"></canvas>&nbsp;</p>'); e.close(); }, buttons: [ { type: 'submit', text: 'Insert PDF' } ] }); } }); }); //-------------------- 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); }; window.addEventListener('DOMContentLoaded', function() { Array.prototype.forEach.call(document.querySelectorAll('canvas[data-pdfurl]'), renderPdf); }); </script> ``` </details>
Author
Owner

@BertCurbit commented on GitHub (Aug 3, 2022):

Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported:
View Code

Thanks for this but...
I just updated to 22.07.1 (cleared cache) and inserted this code in the 'Custom HTML Head Content' section but I can't see the PDF button in edit mode. Is there something else that I should do?

@BertCurbit commented on GitHub (Aug 3, 2022): > Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported: > View Code Thanks for this but... I just updated to 22.07.1 (cleared cache) and inserted this code in the 'Custom HTML Head Content' section but I can't see the PDF button in edit mode. Is there something else that I should do?
Author
Owner

@ssddanbrown commented on GitHub (Aug 3, 2022):

@BertCurbit To confirm, do you see a little page icon next to the link toolbar icon?

@ssddanbrown commented on GitHub (Aug 3, 2022): @BertCurbit To confirm, do you see a little page icon next to the link toolbar icon?
Author
Owner

@BertCurbit commented on GitHub (Aug 3, 2022):

@ssddanbrown Oh my... I was looking for the button with PDF text in it, like the previous version. But now it's just a blank page icon that I completely overlooked. It looks way better now and works perfectly. Thanks for this!

@BertCurbit commented on GitHub (Aug 3, 2022): @ssddanbrown Oh my... I was looking for the button with PDF text in it, like the previous version. But now it's just a blank page icon that I completely overlooked. It looks way better now and works perfectly. Thanks for this!
Author
Owner

@airwolfhd commented on GitHub (Nov 23, 2022):

Is there a way to have this working offline? I have tried placing the pdf.min.js file inside the public folder in bookstack and pointing to it.

For example
<script src="https://192.168.0.10/pdf.min.js"></script>

I can reach this file at this address from a browser however embedded PDFs are not working. They work fine when I bring bookstacks online and point to the cdnjs address.

@airwolfhd commented on GitHub (Nov 23, 2022): Is there a way to have this working offline? I have tried placing the pdf.min.js file inside the public folder in bookstack and pointing to it. For example `<script src="https://192.168.0.10/pdf.min.js"></script>` I can reach this file at this address from a browser however embedded PDFs are not working. They work fine when I bring bookstacks online and point to the cdnjs address.
Author
Owner

@airwolfhd commented on GitHub (Nov 26, 2022):

Is there a way to have this working offline? I have tried placing the pdf.min.js file inside the public folder in bookstack and pointing to it.

For example <script src="https://192.168.0.10/pdf.min.js"></script>

I can reach this file at this address from a browser however embedded PDFs are not working. They work fine when I bring bookstacks online and point to the cdnjs address.

I eventually got it working by also having a second file named pdf.worker.min.js along side pdf.min.js.

@airwolfhd commented on GitHub (Nov 26, 2022): > Is there a way to have this working offline? I have tried placing the pdf.min.js file inside the public folder in bookstack and pointing to it. > > For example `<script src="https://192.168.0.10/pdf.min.js"></script>` > > I can reach this file at this address from a browser however embedded PDFs are not working. They work fine when I bring bookstacks online and point to the cdnjs address. I eventually got it working by also having a second file named pdf.worker.min.js along side pdf.min.js.
Author
Owner

@mvdgeijn commented on GitHub (Feb 12, 2023):

Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported:

View Code

I'm trying to implement this, but I don't know where to add the code. I inserted it in the settings table using the app-custom-head key. The code is added in the header, but no icon is added to the tinymce toolbar.

@mvdgeijn commented on GitHub (Feb 12, 2023): > Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported: > > View Code I'm trying to implement this, but I don't know where to add the code. I inserted it in the settings table using the app-custom-head key. The code is added in the header, but no icon is added to the tinymce toolbar.
Author
Owner

@dan-r95 commented on GitHub (Apr 27, 2023):

This issue hints at a potential fix https://github.com/BookStackApp/BookStack/issues/3586#issuecomment-1190485991 (worked for me).

@dan-r95 commented on GitHub (Apr 27, 2023): This issue hints at a potential fix https://github.com/BookStackApp/BookStack/issues/3586#issuecomment-1190485991 (worked for me).
Author
Owner

@DarkZoneSD commented on GitHub (Sep 5, 2023):

Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported:

View Code

Does someone have a working version of this script on the BookStack Version 23.06.2? Currently trying to implement it for use and i only get a grey window inside the page, i expected it to be like that in the editor, but its also not showing on the view page.

The download button points to the right .pdf though so it should be a working .pdf file.

bookstackPDFEmbed

@DarkZoneSD commented on GitHub (Sep 5, 2023): > Here's an altered version of the above scripts that I recently amended for a BookStack user, that was using the above hacks. Think I tested it in v22.06. This script is not official nor supported: > > View Code Does someone have a working version of this script on the BookStack Version 23.06.2? Currently trying to implement it for use and i only get a grey window inside the page, i expected it to be like that in the editor, but its also not showing on the view page. The download button points to the right .pdf though so it should be a working .pdf file. ![bookstackPDFEmbed](https://github.com/BookStackApp/BookStack/assets/113187443/34b574d0-b328-4ecd-8ca2-f358ce303dd5)
Author
Owner

@BabyLoves commented on GitHub (Oct 9, 2023):

Aqui está uma versão alterada dos scripts acima que alterei recentemente para um usuário do BookStack, que estava usando os hacks acima. Acho que testei na v22.06. Este script não é oficial nem suportado:
Ver código

Alguém tem uma versão funcional deste script no BookStack versão 23.06.2? Atualmente estou tentando implementá-lo para uso e só recebo uma janela cinza dentro da página, esperava que fosse assim no editor, mas também não aparece na página de visualização.

O botão de download aponta para o .pdf certo, portanto, deve ser um arquivo .pdf funcional.

pilha de livrosPDFEmbed

Anyone can help?

@BabyLoves commented on GitHub (Oct 9, 2023): > > Aqui está uma versão alterada dos scripts acima que alterei recentemente para um usuário do BookStack, que estava usando os hacks acima. Acho que testei na v22.06. Este script não é oficial nem suportado: > > Ver código > > Alguém tem uma versão funcional deste script no BookStack versão 23.06.2? Atualmente estou tentando implementá-lo para uso e só recebo uma janela cinza dentro da página, esperava que fosse assim no editor, mas também não aparece na página de visualização. > > O botão de download aponta para o .pdf certo, portanto, deve ser um arquivo .pdf funcional. > > ![pilha de livrosPDFEmbed](https://user-images.githubusercontent.com/113187443/265700107-34b574d0-b328-4ecd-8ca2-f358ce303dd5.PNG) Anyone can help?
Author
Owner

@GriwMF commented on GitHub (Nov 26, 2023):

this https://github.com/BookStackApp/BookStack/issues/705#issuecomment-1203691993 works like a charm in my case.

  1. Add the code from above to the settings/customization/Custom HTML Head Content
  2. On the edit page toolbar new button will appear to embed pdf - the one with page icon
    image
  3. Make sure to insert the correct url to pdf, in my case it was https://{myhostnamehere}.com/attachments/1

P.S. Would be nice to have it by default in BookStack

@GriwMF commented on GitHub (Nov 26, 2023): this https://github.com/BookStackApp/BookStack/issues/705#issuecomment-1203691993 works like a charm in my case. 1. Add the code from above to the settings/customization/Custom HTML Head Content 2. On the edit page toolbar new button will appear to embed pdf - the one with page icon ![image](https://github.com/BookStackApp/BookStack/assets/6000392/1f36d0d0-a53c-444e-a817-16f4c62fc6eb) 3. Make sure to insert the correct url to pdf, in my case it was https://{myhostnamehere}.com/attachments/1 P.S. Would be nice to have it by default in BookStack
Author
Owner

@cloverenergy commented on GitHub (Dec 7, 2023):

Anyone can help?

FWIW having the exact same issue.

Any yes "built in" PDf support would be great.

@cloverenergy commented on GitHub (Dec 7, 2023): > Anyone can help? FWIW having the exact same issue. Any yes "built in" PDf support would be great.
Author
Owner

@UvinduS commented on GitHub (Jan 5, 2024):

I did some change to @ssddanbrown's code. I think now it's working.

<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">

  // ------------------- THIS SECTION ADDS A PDF BUTTON TO THE EDITOR TOOLBAR THAT ALLOWS YOU TO EMBED PDFS 

  // Use BookStack editor event to add custom "Insert PDF" button into main toolbar
  window.addEventListener('editor-tinymce::pre-init', event => {
      const mceConfig = event.detail.config;
      mceConfig.toolbar = mceConfig.toolbar.replace('link', 'link insertpdf')
  });

  // Use BookStack editor event to define the custom "Insert PDF" button.
  window.addEventListener('editor-tinymce::setup', event => {
    const editor = event.detail.editor;

    // Add PDF insert button
    editor.ui.registry.addButton('insertpdf', {
      tooltip: 'Insert PDF',
      icon: 'document-properties',
      onAction() {
        editor.windowManager.open({
          title: 'Insert PDF',
          body: {
            type: 'panel',
            items: [
              {type: 'textarea', name: 'pdfurl', label: 'PDF URL'}
            ]
          },
          onSubmit: function(e) {
            // Insert content when the window form is submitted
            editor.insertContent('<p id="bkmrk-%C2%A0%C2%A0">&nbsp;<canvas data-pdfurl="' + e.getData().pdfurl + '"></canvas>&nbsp;</p>');
            e.close();
          },
          buttons: [
            {
              type: 'submit',
              text: 'Insert PDF'
            }
          ]
        });
      }
    });

  });

//-------------------- 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);
};


window.addEventListener('DOMContentLoaded', function() {
  Array.prototype.forEach.call(document.querySelectorAll('canvas[data-pdfurl]'), renderPdf);
});
</script>
@UvinduS commented on GitHub (Jan 5, 2024): I did some change to @ssddanbrown's code. I think now it's working. ```js <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"> // ------------------- THIS SECTION ADDS A PDF BUTTON TO THE EDITOR TOOLBAR THAT ALLOWS YOU TO EMBED PDFS // Use BookStack editor event to add custom "Insert PDF" button into main toolbar window.addEventListener('editor-tinymce::pre-init', event => { const mceConfig = event.detail.config; mceConfig.toolbar = mceConfig.toolbar.replace('link', 'link insertpdf') }); // Use BookStack editor event to define the custom "Insert PDF" button. window.addEventListener('editor-tinymce::setup', event => { const editor = event.detail.editor; // Add PDF insert button editor.ui.registry.addButton('insertpdf', { tooltip: 'Insert PDF', icon: 'document-properties', onAction() { editor.windowManager.open({ title: 'Insert PDF', body: { type: 'panel', items: [ {type: 'textarea', name: 'pdfurl', label: 'PDF URL'} ] }, onSubmit: function(e) { // Insert content when the window form is submitted editor.insertContent('<p id="bkmrk-%C2%A0%C2%A0">&nbsp;<canvas data-pdfurl="' + e.getData().pdfurl + '"></canvas>&nbsp;</p>'); e.close(); }, buttons: [ { type: 'submit', text: 'Insert PDF' } ] }); } }); }); //-------------------- 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); }; window.addEventListener('DOMContentLoaded', function() { Array.prototype.forEach.call(document.querySelectorAll('canvas[data-pdfurl]'), renderPdf); }); </script> ```
Author
Owner

@ddkhanh commented on GitHub (Mar 28, 2024):

Based on @UvinduS 's code, I did some change to use another pdf-viewer for better interactive (text selection, copy, zoom, navigation)

https://github.com/ddkhanh/bookstack-pdf-viewer/

@ddkhanh commented on GitHub (Mar 28, 2024): Based on @UvinduS 's code, I did some change to use another pdf-viewer for better interactive (text selection, copy, zoom, navigation) https://github.com/ddkhanh/bookstack-pdf-viewer/
Author
Owner

@DNF-SaS commented on GitHub (May 3, 2025):

The ability to view PDFs inline would be a really cool feature +1

@DNF-SaS commented on GitHub (May 3, 2025): The ability to view PDFs inline would be a really cool feature +1
Author
Owner

@dirkdrutschmann commented on GitHub (Jan 7, 2026):

Check out

https://github.com/pronomix-gmbh/bookstack_file_attachment_preview

@dirkdrutschmann commented on GitHub (Jan 7, 2026): Check out https://github.com/pronomix-gmbh/bookstack_file_attachment_preview
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#571