Some test text!
Salesforce / Salesforce-faq / FAQ
WebViewer is a pure client-side JavaScript library to annotate, view, and edit documents such as PDF, MS Office, Images, CAD, Video and more.
We can embed WebViewer UI in Salesforce, contained in an iframe. WebViewer source code can be stored in Salesforce static resources, which allows for advanced document working client side without external dependencies and without your data ever leaving your Salesforce organization.
In Salesforce, we need to upload our WebViewer source files to static resources. Salesforce imposes a file size limit of 5MB for static resources, so we need to optimize our WebViewer worker files.
Since static resources are served from a different origin, we need to use a config.js
file which runs in context of the WebViewer iframe. You can check out a sample config.js
file.
Due to Salesforce's Governor Limits, we can only use Salesforce files within the allowed heap size (6MB/12MB async). WebViewer supports external file storage, from providers such as AWS, GCP, Azure, Dropbox and others - this allows for file support for sizes up to 2GB.
After uploading your WebViewer worker files, make sure you use Salesforce's loadScript API to load the WebViewer entry point like so:
//in your pdftronInstance.js LWC file
renderedCallback() {
//your renderedCallback logic here...
var self = this;
if (this.uiInitialized) {
return; // prevent multiple initializations of WebViewer on each re-render
}
this.uiInitialized = true;
Promise.all([
loadScript(self, libUrl + '/webviewer.min.js'),
])
.then(() => this.initUI())
.catch(console.error);
}
In Salesforce, the config file is used to set worker paths for our optimized WebViewer files and to access WebViewer objects and APIs. You can check out WebViewer fundamentals , which explains how WebViewer creates the UI app inside an iframe, so that Core namespaces and classes are encapsulated.
The iframe window and document object are still accessible through contentWindow and contentDocument, but it can still be tricky to run scripts or listen to events happening inside the iframe.
The config file gives you easy access to the Document, DocumentViewer and AnnotationManager objects (among others) which can allow you to make more complicated customizations.
To instantiate WebViewer with a config file you just need to set the config
option in the WebViewer constructor. For example:
//in your pdftronInstance.js LWC file
const viewerElement = this.template.querySelector('div')
const viewer = new WebViewer({
// snipped for brevity
config: myfilesUrl + this.config, // path to the config.js file in your static resources
// l: 'YOUR_LICENSE_KEY_HERE',
}, viewerElement);
Before using WebViewer, you need to specify the worker paths for WebViewer with the below API calls. Keep in mind that some workers, such as office workers are only required if you want to include MS Office support and can be safely omitted if not required for your implementation.
// staticresource/config.js
// office workers - optional
window.Core.setOfficeWorkerPath(resourceURL + 'office')
window.Core.setOfficeAsmPath(resourceURL + 'office_asm');
window.Core.setOfficeResourcePath(resourceURL + 'office_resource');
// legacy office workers - optional
window.Core.setLegacyOfficeWorkerPath(resourceURL + 'office')
window.Core.setLegacyOfficeAsmPath(resourceURL + 'office_asm');
window.Core.setLegacyOfficeResourcePath(resourceURL + 'office_resource');
// pdf workers
window.Core.setPDFResourcePath(resourceURL + 'resource')
if (custom.fullAPI) {
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');
You can use a custom object and pass it to your WebViewer constructor to pass data from LWC to your config file upon initialization. To do this you can use the custom
option in the WebViewer constructor. The property expects a string value. So for example to pass an object:
// LWC js file
var myObj = {
libUrl: libUrl, // staticresources/lib.zip folder used for setting workerPaths
myfilesUrl: myfilesUrl,
fullAPI: this.fullAPI || false,
namespacePrefix: '', // pass a namespace prefix for managedpackages
};
//var url = myfilesUrl + '/WVSF-Account-info-sample.pdf';
const viewerElement = this.template.querySelector('div')
// eslint-disable-next-line no-unused-vars
const viewer = new WebViewer({
// snipped for brevity
custom: JSON.stringify(myObj),
// l: 'YOUR_LICENSE_KEY_HERE',
}, viewerElement);
Then inside the config file you access this data as follows:
instance.UI.addEventListener('viewerLoaded', () => {
const custom = JSON.parse(instance.UI.getCustomData());
console.log(custom.fullAPI); // outputs true or false
});
instance.UI.addEventListener('documentLoaded, () => {
const docViewer = instance.Core.documentViewer;
docViewer.setCurrentPage(custom.startPage);
});
If you have the WebViewer path on a different domain than your app, then to protect against XSS attacks you will need to edit the lib/ui/configorigin.txt
file to whitelist your app's domain(s). Add each domain on a separate line, for example:
http://localhost:3000
https://example.com
Domains in this list will be allowed to have WebViewer specify config files that can be loaded.
If you want to access the outer page from inside the iframe (for Salesforce it is the parent LWC component), for example from code in your config file, you can access the parent window using window.parent
. So if you defined an API that's loaded on your HTML page, you could access it from inside the iframe like window.parent.myApi.myFunction()
.
You could hook into WebViewer events and notify the parent LWC like so:
//config.js
window.addEventListener('viewerLoaded', () => {
// notify parent LWC that viewer has loaded and is ready for processing documents
window.parent.postMessage({ type: 'VIEWER_LOADED' }, window.origin);
}
Trial setup questions? Ask experts on Discord
Need other help? Contact Support
Pricing or product questions? Contact Sales