Some test text!

Search
Hamburger Icon

Salesforce / Guides / Without Viewer

Run without Viewer in Salesforce

Apryse's SDK provides full viewing of documentation formats and other capabilities but also provides access to Apryse's PDFNet SDK that allows document operations excluding a UI if necessary.

This is useful for Salesforce that needs additional processing without viewing a document. Although there are performance drawbacks as this is done on the client-side, it can be critical as part of your app's flow.

Here is a sample no-viewer Salesforce to follow with this guide:

Prerequisites

This guide assumes you will have downloaded WebViewer SDK and have Webviewer running on your Salesforce org.

If you have not done so, please check out the following to get started:

1. Create a hidden LWC

Webviewer still needs to be present on the page of your Salesforce org. You will need to create a lightning web component that has a hidden div to hold the iframe that would run no-viewer Webviewer.

<template>
  <div id="core-controls-iframe" class="slds-hidden" lwc:dom="manual"></div>
</template>

WebViewer Core is the core for WebViewer. The usual script that would be required with the UI is webviewer.min.js. Using this script would automatically import and use the core.

renderedCallback() {
    Promise.all([loadScript(this, libUrl + '/webviewer.min.js')])
        .then(() => {
          this.initUI();
        })
        .catch(console.error);
  }

webviewerConstructor is similar to custom tag in a Webviewer constructor, pass information through the iframe src and hash the information from the url in the config file. Set the iframe to take up no space in the lwc if you want a true no-viewer page. Create an iframe to host an html file that runs script tags pathed to webviewer.core.min.js and PDFNet.js

var webviewerConstructor = {
  cs_pdftron_core: libUrl + "/core/webviewer-core.min.js",
  pdfnet: myfilesUrl + "/PDFNet.js",
  full_api: true
};

initUI() {
    const viewerElement = this.template.querySelector("div");
    var queryParameter = `#param=${JSON.stringify(
      webviewerConstructor
    )}`;

    var rcFrame = document.createElement("iframe");
    rcFrame.style = "position: absolute; width:0; height:0; border:0;";

    rcFrame.src = `${myfilesUrl}/noviewer.html${queryParameter}`;
    viewerElement.appendChild(rcFrame);
    this.iframeWindow = rcFrame.contentWindow;
}

2. Setting the worker path

In a viewer-less scenario, we would only import the core script (webviewer-core.min.js; CoreControls.js prior to WebViewer 8.0) in the HTML, if needing the FULL api you need to reference a different script(PDFNet.js) also.

var script = document.createElement('script');
  script.onload = function () {
    init();
    var pdfnet = document.createElement('script');
    pdfnet.src = clientSidePdfGenerationConfig['pdfnet'];
    document.head.appendChild(pdfnet);
  };
  script.src = clientSidePdfGenerationConfig['cs_pdftron_core'];
  document.head.appendChild(script);

WebViewer requires web workers to function and work with documents. This is necessary regardless of the setup. Normally, this is done automatically via the path option in the WebViewer constructor. In a viewer-less scenario, we can load the workers with a simple JavaScript call:

window.Core.forceBackendType('ems');

window.Core.setOfficeAsmPath(resourceURL + 'office_asm');
window.Core.setOfficeWorkerPath(resourceURL + 'office');
window.Core.setOfficeResourcePath(resourceURL + 'office_resource');

// pdf workers
window.Core.setPDFResourcePath(resourceURL + 'resource');
if (clientSidePdfGenerationConfig['full_api']) {
  window.Core.setPDFWorkerPath(resourceURL + 'pdf_full');
  window.Core.setPDFAsmPath(resourceURL + 'asm_full');
} else {
  window.Core.setPDFWorkerPath(resourceURL + 'pdf_lean');
  window.Core.setPDFAsmPath(resourceURL + 'asm_lean');
}

// external 3rd party libraries
window.Core.setExternalPath(resourceURL + 'external');
window.Core.disableEmbeddedJavaScript(true)

window.Core.disableOptimizedWorkers();

3. Usage

Once the workers are ready, everything is in place to use the APIs and classes in the Core namespace .

Communicate with Salesforce

Often in Salesforce, sending information to our workers is common so having a communication method to recieve and send out information is required.

// Recieve
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event) {
  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'DOWNLOAD_DOCUMENT':
        transportDocument(event.data.payload, false)
        break;
      default:
        break;
    }
  }
}

// Send
parent.postMessage({ type: 'DOWNLOAD_DOCUMENT', file }, '*')

Building a custom UI

One special use case would be to create your own UI by leveraging the DocumentViewer class and object.

const documentViewer = new Core.DocumentViewer();

// Hook up the DocumentViewer object to your own elements
documentViewer.setScrollViewElement(document.getElementById('scroll-view'));
documentViewer.setViewerElement(document.getElementById('viewer'));

// Load your document
documentViewer.loadDocument('path/to/document.pdf', { l: licenseKey });
You can check out the full guide on how to build your own UI .

Processing documents (Full API - PDFNet)

Another use case is to use the APIs to process documents in the client (browser). We already establish Full API usage so now we just have to test them.

async function main() {
  // creates an empty pdf document (PDFDoc)
  const doc = await PDFNet.PDFDoc.create();
  doc.initSecurityHandler();
  // Locks all operations on the document
  doc.lock();

  // insert user code after this point
  const pgnum = await doc.getPageCount();
  alert(`Test Complete! Your file has ${pgnum} pages`);
};

PDFNet.runWithCleanup(main, /* License key goes here after purchase */)

Trial setup questions? Ask experts on Discord
Need other help? Contact Support
Pricing or product questions? Contact Sales