Recently a question was raised by one of the MVP’s if somebody has an example of a PDF viewer in Business Central. That reminded me that I actually had an example, created almost one year ago. Should have published it way earlier! Anyway, I thought it still makes sense to polish that thing and share it.
However, the browser will use whichever PDF reader is installed on the system and there is no way to customize the look and feel. There is only a very limited set of API’s available and even these API’s are not supported in all browsers. In other words, how the PDF is rendered on the page is out of your control.
So I decided to move on and look for a solution that gives you full control over how the PDF is rendered, including an API to integrate with. And I stumbled over PDF.js, an open-source PDF viewer, built with HTML5 and supported by Mozilla Labs.
This tool proved to be very flexible and I got it to work pretty quickly. In the first place as a single page viewer, as explained in the examples. However, the option were still quite limited and I figured that it would be great to take the viewer, which has all the options you can think of, and embed that one into Business Central. Not just as-is, but integrated with Busines Central, and with a little re-skin applied, like they ask here: However, we do ask if you plan to embed the viewer in your own site, that it not just be an unmodified version. Please re-skin it or build upon it.
Allright, enough talking, let’s first look at the result and then see how it’s done.
And the same control can also be used in a factbox, without any modifications:
And now straight to the source code. The complete code can be found on GitHub: https://github.com/ajkauffmann/PDFViewer
Please read the explanation below how to use it, before you jump in and start using it right away!
The GitHub repository consists of two folders:
If you clone the repo, then you will find a PDFViewer.code-workspace file in the root. Open this file with VS Code and you will find both folders opened at once. Alternatively, you can open the folders individually.
Let’s first look at the folder pdfjs-2.0.943-dist. This is a download of the latest version of the viewer application, which can be found here. Alternatively, you can clone the full repo on GitHub, with all source code and build the viewer yourself by using gulp. But if you are not used to that, it’s easier to download the distributable file of the viewer and use that one.
So I decided to just grab the whole PDF.js viewer application and host it on Azure. I have used static website hosting in Azure storage. This is an option with Azure storage with no additional cost. Azure blob storage is pretty cheap, so it was a no-brainer. With extra options like CDN and custom domain names it is even more attractive.
So this is what I did: after modifying the PDF web viewer application to integrate with Business Central (see below) I have created a static website with the Azure portal as explained here. Then I uploaded the files using the Azure Storage Explorer. As a result, I have now the PDF web viewer application hosted here: https://bcpdfviewer.z6.web.core.windows.net/web/viewer.html. As a result, the AL extension is pretty small and easy to understand.
Warning: don’t use my PDF web viewer website for any production scenario! Instead use your own!
After I figured this hosting thing out, there were some other hurdles to take. I will save some of them for another blog post and just focus on the parts to integrate the web viewer application with Business Central. I will first go over the modifications I did to the web viewer application and then switch to the AL code.
This bcintegration.js must be added to the viewer.html page.
The viewer.css defines the look and feel of the viewer. I’ve made a few changes to better integrate the viewer into Business Central. Feel free to play with it and change to whatever you like. Look at the history of the file to see what changes I did.
That’s it, let’s now have a look at the AL code
The most important part you need to understand is how exactly the web viewer is embedded in the page. The web viewer is loaded in a nested <iframe> element that is added to the control add-in element. This is done in script.js.
Because it is not possible to directly communicate between the iframe, which has a different url then the parent, and the parent object, the script.js file implements to use postMessage and onMessage. This is a safe way to communicate between the two and supported by all browsers.
In the top of the script.js file, the url of the website where the PDF web viewer is hosted is specified. You should change this to the website where you have hosted your version of the web viewer.
Don’t use a trailing slash for the url setting. It wil fail the test in the onMessage function.
The rest of the code is just tableextensions, pages and pageextensions to add the viewer to the Incoming Document pages. I guess you will be able to figure out yourself what’s going on there.
Get luck with it and please let me know what you think! Feel free to grab the GitHub repository and to contribute to it if you have something cool to share.