Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Luckily, we’ve run into many of the issues ourselves and can provide some guidance to help you get your PDFs looking sharp.

Headers and Footers

iOS

When running on iOS Pulsar utilizes UIPrintPageRenderer to generate PDFs. Pulsar requires you to specify a node in the document that will represent your header. To do this, specify headernode in your saveAs request. This header will be printed at the top of each page. It’s important to note that you are responsible for ensuring that either the header is not included inside the docnode or that it is hidden from view.

When specifying a headernode you must also calculate and include the height in points for the header. We have done this in our own code by programmatically inspecting the scrollheight of the outermost node of the header. Once calculated, include headerheight/footerheight specified as an integer inside the printoptions of the saveAs request.

It is also important to note that any styles necessary for the header should be done inline. We’d like to enable custom css for headers and footers, but that is a future improvement. One way that we at Luminix have addressed this issue is to programmatically move our header and footer into iFrames and then supply the iFrame as the headernode/footernode. In doing this we are able to add CSS in the head tag of the iFrames.

It should also be noted that iOS will draw page numbers on the footer by default.

Windows

Windows follows the same https://github.com/luminixinc/PulsarForSalesforceAdvancedJSExamples

A Complete Example

We have developed a ready-to-use example of how a PDF might be generated and saved across all three platforms. The example is documented to explain what is going on at various stages and broken up using the Strategy Pattern to handle the differences between each platform.

Contained in the repository in the example-report folder is the example-report.pulsarapp which you can upload as a File to your Salesforce organization to see this in action while running the Pulsar for Salesforce App. Simply open the .pulsarapp from the Content Library.

The Complexity

Generating PDFs from HTML content is a complex procedure that is often achieved through online services or through the use of enterprise software. For comprehensive notes on these differences, please explore the strategies and htmlFragments for each platform in the example-report.

When running on iOS Pulsar utilizes UIPrintPageRenderer to generate PDFs. While this is a very useful tool, it has a number of confusing nuances that are addressed in the iOS strategy in our example-report. Many of these relate to identifying the header and footer regions and calculating their height. Page numbers however are provided by default and located in the footer.

Windows follows the same general format as iOS but it utilizes IronPDF. Windows requires you to add your own page numbers in the HTML. IronPDF gives you access to handlebars type variables like:

{page} {total-pages} {url} {date} {time} {html-title} & {pdf-title}

When specifying your headerheight/footerheight on Windows you should pass 0 and instead include the height of the header and footer in the topmargin/bottommargin values. The JSAPI provides a method to get the platform type. (These changes are present in Pulsar FSL versions after August 15th.)

Android

For Android, Pulsar makes use of the native Chrome browser present on Android devices in order to render PDFs. This is achieved in a completely different way and we recommend that you have different HTML templates for handling Android and iOS/Windows.

Android makes use of table structure to do repeating headers and footers.

Code Block
<table id="droid-table">
  <thead id="sr-header-droid">
    <!-- Your header goes here -->
    <tr>
      <th> ... </th>
    </tr>
  </thead>

  <div id="sr-footer-droid" style="display: table-footer-group; width: 100%; bottom: 0; position: fixed;">
    <!-- Your footer goes here, not that this is not a tfoot div and requires special styling -->
  </div>

  <tbody id="sr-body-droid" *ngIf="subTemplate.body() as body">
    <!-- Your document body goes here, it can be many rows -->
    <tr>
      <td>...</td>
    </tr>
  </tbody>
</table>

This pathway needs more testing but should work.

Using HTML/JS Tables:

If you need to generate a PDF offline from your HTML/JS app, we've determined that the best approach is to avoid the use of <table> elements and instead build the page structure with <div> elements.  It's been noted (https://stackoverflow.com/questions/9288802/avoid-page-break-inside-row-of-table/27209406) that <tr> elements do not appear to respect the break-inside/page-break-inside CSS attributes. Note: If you are building your app to run within Pulsar FSLapp:  Pulsar FSL app  is utilizing Bootstrap 4. In the discussions around page breaks and <table> elements, it's been suggested that Bootstrap may impact this. 

...

Additional Notes

Images and Canvas:

Using images, canvas elements and fonts will work in your custom HTML implementations, but it is possible to run into issues when attempting to generate PDF files, due to CORS rules or similar access restrictions imposed by the webview environment. Our recommendation is to convert each of these resources to a 'data URI' format with Base64 encoding.  

...