Some test text!

menu
Opening and Saving Documentskeyboard_arrow_down

Opening and Saving Documents Stored in Salesforce

Documents stored in Salesforce have an entry in the ContentVersion table, and are thus accessed through the Contentversion.id primary key.

linkOpening Documents Stored in Salesforce

How to open a document stored in Salesforce

linkUpdate a Document Saved In Salesforce

// force-app\main\default\classes\ContentVersionController.cls
public with sharing class ContentVersionController {
    // ...

    /**
     * Creates a new version of the current document in the ContentVersion table
     * @param title The name of the file without the file extension
     * @param base64Data The document represented in base64 format, per the
     * requirements of the ContentVersion table
     * @param filename The name of the file, including the file extension
     * @param contentDocumentId The ContentDocument.id value of the original
     * document
     */
    @AuraEnabled
    public static Id createContenVersion(
      String title,
      String base64Data,
      String filename,
      Id contentDocumentId
    ) {
      ContentVersion cv = new ContentVersion();
      // 'S' = a Salesforce File
      cv.ContentLocation = 'S';
      cv.ContentDocumentId = contentDocumentId;
      cv.VersionData = EncodingUtil.base64Decode(base64Data);
      cv.Title = title;
      cv.PathOnClient = filename;
      cv.ReasonForChange = 'Saved from WebViewer';

      insert cv;

      return cv.Id;
    }
}

linkconfig.js

// force-app/main/default/staticresources/myfiles/config.js
/**
 * Bundles the relevant information from the document, and the document itself
 * in base64, passes them to the createContentVersion function via a postMessage
 * to webViewer.js
 */
async function saveDocument() {
  const doc = docViewer.getDocument();
  if (!doc) {
    return;
  }
  readerControl.openElement('loadingModal');

  const fileType = doc.getType();
  const filename = doc.getFilename();
  const xfdfString = await docViewer.getAnnotationManager().exportAnnotations();
  const data = await doc.getFileData({
    // Saves the document with annotations in it
    xfdfString
  });

  let binary = '';
  const bytes = new Uint8Array( data );
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }

  const base64Data = window.btoa(binary);

  const payload = {
    title: filename.replace(/\.[^/.]+$/, ""),
    filename,
    base64Data,
    contentDocumentId: doc.__contentDocumentId
  }
  // Post message to LWC
  parent.postMessage({type: 'SAVE_DOCUMENT', payload }, '*');
}

window.addEventListener('viewerLoaded', async function() {
  /**
   * On keydown of either the button combination Ctrl+S or Cmd+S, invoke the
   * saveDocument function
   */
  readerControl.hotkeys.on('ctrl+s, command+s', e => {
    e.preventDefault();
    saveDocument();
  });

  // Create a button, with a disk icon, to invoke the saveDocument function
  readerControl.setHeaderItems(function(header) {
    var myCustomButton = {
      type: 'actionButton',
      dataElement: 'saveDocumentButton',
      title: 'tool.SaveDocument',
      img: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>',
      onClick: function() {
        saveDocument();
      }
    }
    header.get('viewControlsButton').insertBefore(myCustomButton);
  });
});

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

function receiveMessage(event) {
  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      // Snipped for brevity
      case 'DOCUMENT_SAVED':
        readerControl.showErrorMessage('Document saved!')
        setTimeout(() => {
          readerControl.closeElements(['errorModal', 'loadingModal'])
        }, 2000)
        break;
      // Snipped for brevity
      default:
        break;
    }
  }
}

// Snupped for brevity

linkwebViewer.js

// force-app/main/default/lwc/webViewer/webViewer.js
// Snipped for brevity
import createContenVersion from '@salesforce/apex/ContentVersionController.createContenVersion';

export default class WebViewerComp extends LightningElement {
  // Snipped for brevity
  connectedCallback() {
      registerListener('fileSelected', this.handleFileSelected, this);
      this.showErrorMessage = this.showErrorMessage.bind(this);
      // Add event listener from WebViewer iframe
      window.addEventListener('message', this.handleReceiveMessage.bind(this), false);
  }

  disconnectedCallback() {
    unregisterAllListeners(this);
    // Remove event listener from WebViewer iframe
    window.removeEventListener('message', this.handleReceiveMessage, true);
  }

  showErrorMessage(error) {
    console.error(error);
    this.dispatchEvent(
      new ShowToastEvent({
        title: 'Error in WebViewer',
        message: error.body.message || 'error',
        variant: 'error',
      }),
    );
  }

  handleReceiveMessage(event) {
    const me = this;
    if (event.isTrusted && typeof event.data === 'object') {
      switch (event.data.type) {
        case 'SAVE_DOCUMENT':
          /**
           * Call our Apex API function to save new version of PDF to
           * ContentVersion
           */
          createContenVersion(event.data.payload).then((response) => {
            /**
             * Send a postMesage back to WebViewer to inform the user that
             */
            me.iframeWindow.postMessage({type: 'DOCUMENT_SAVED', response }, '*')
          }).catch(this.showErrorMessage);
          break;
        default:
          break;
      }
    }
  }

  // Snipped for brevity
}

You can also find the full source code for LWC app with WebViewer here on this Github repository

Get the answers you need: Support

close

Free Trial

Get unlimited trial usage of PDFTron SDK to bring accurate, reliable, and fast document processing capabilities to any application or workflow.

Select a platform to get started with your free trial.

Unlimited usage. No email address required.