Annotations Permissions Showcase Demo Code Sample

Enable customization of user permissions to interact with annotations in the PDF file, completely client-side with three different levels of permissions: administrator, user, and read-only.

This demo lets you:

  • Upload a PDF file and add user permissions
  • Add permissions to users as administrator, user, or read-only
  • Interact with annotations in the PDF file according to the set permission

Implementation steps
To add annotations permissions capability to a PDF with WebViewer:

Step 1: Choose your preferred web stack
Step 2: Download any required modules listed in the Demo Dependencies section below
Step 3: Add the ES6 JavaScript sample code provided in this guide

Demo Dependencies
This sample uses the following:

Want to see a live version of this demo?

Try the Annotations Permissions demo

1
2/* ES6 Compliant Syntax */
3/* GitHub Copilot v1.0, Claude 3.5 Sonnet, September 1, 2025 */
4/* File: index.js */
5
6import WebViewer from '@pdftron/webviewer';
7
8// Annotation Permission section
9//
10// Code to customize user permissions, completely client-side with 3
11// different levels of permissions: administrator, user, and read-only
12//
13
14// Default Document
15const defaultDoc = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf';
16
17// Set default user
18let currentUser = 'Justin';
19
20// List of users with permissions
21let userList = {
22 Justin: { permissions: 'administrator', canView: true, hidden: [] },
23 Sally: { permissions: 'user', canView: true, hidden: [] },
24 Brian: { permissions: 'read-only', canView: true, hidden: [] }
25};
26
27// Annotation types that can be toggled for visibility
28let toggleableTypes = [];
29
30// Customize UI
31const customizeUI = async (instance) => {
32 const { Annotations } = instance.Core;
33
34 // Load default document
35 await instance.Core.documentViewer.loadDocument(defaultDoc, {
36 extension: 'pdf',
37 });
38 instance.UI.setToolbarGroup('toolbarGroup-Annotate', true);
39
40 // Add sticky note, free hand, and highlight to toggleable types
41 toggleableTypes = [
42 {
43 displayName: 'Sticky notes',
44 annotationType: Annotations.StickyAnnotation,
45 },
46 {
47 displayName: 'Free hand',
48 annotationType: Annotations.FreeHandAnnotation,
49 },
50 {
51 displayName: 'Highlight',
52 annotationType: Annotations.TextHighlightAnnotation,
53 },
54 ];
55
56 // Set user data for mentions in notes tool
57 const userData = Object.keys(userList).map((user) => ({
58 value: user,
59 email: `${user.toLowerCase()}@pdftron.com`,
60 }));
61 instance.UI.mentions.setUserData(userData);
62
63 // Set default user in the WebViewer
64 setUser(instance, currentUser);
65};
66
67// Set selected user in the WebViewer
68const setUser = (instance, username) => {
69 const { annotationManager }= instance.Core;
70 annotationManager.setCurrentUser(username);
71 const permissions = userList[username].permissions;
72
73 if (permissions === 'administrator') {
74 annotationManager.promoteUserToAdmin();
75 annotationManager.disableReadOnlyMode();
76 } else if (permissions === 'read-only') {
77 annotationManager.enableReadOnlyMode();
78 annotationManager.demoteUserFromAdmin();
79 } else {
80 annotationManager.disableReadOnlyMode();
81 annotationManager.demoteUserFromAdmin();
82 }
83
84 currentUser = username;
85 setAnnotationsForUser(instance);
86 updateUIControls();
87};
88
89// Set annotations for current user
90const setAnnotationsForUser = (instance) => {
91 const { annotationManager } = instance.Core;
92
93 const { hidden } = userList[currentUser];
94
95 // First get a list of all the types that should be hidden
96 const hiddenTypeMap = toggleableTypes.reduce((acc, type) => {
97 if (hidden.indexOf(type.displayName) > -1) {
98 acc.push(type.annotationType);
99 }
100 return acc;
101 }, []);
102
103 const allAnnots = annotationManager.getAnnotationsList();
104 const toShow = [];
105 const toHide = [];
106
107 // Generate lists of annotations to show and hide
108 allAnnots.forEach((annot) => {
109 const isType = hiddenTypeMap.some((type) => annot instanceof type);
110 if (isType) {
111 toHide.push(annot);
112 } else {
113 toShow.push(annot);
114 }
115 });
116
117 // Show and hide annotations
118 annotationManager.showAnnotations(toShow);
119 annotationManager.hideAnnotations(toHide);
120};
121
122// Add user to user list
123const addUser = (instance, name, p) => {
124 userList = {
125 ...userList,
126 [name]: { permissions: p, canView: true, hidden: [] },
127 };
128};
129
130// Toggle annotation type visibility for current user
131const toggleAnnotations = (instance, type) => {
132 const { displayName } = type;
133 const { hidden } = userList[currentUser];
134 const idx = hidden.indexOf(displayName);
135 const newArray = hidden.slice(0);
136
137 if (idx !== -1) {
138 newArray.splice(idx, 1);
139 } else {
140 newArray.push(displayName);
141 }
142
143 userList = {
144 ...userList,
145 [currentUser]: {
146 ...userList[currentUser],
147 hidden: newArray
148 }
149 };
150
151 setAnnotationsForUser(instance);
152 updateUIControls();
153};
154
155// Check if annotation type is visible for current user
156const isChecked = (type) => {
157 if (!currentUser) return;
158 const { displayName } = type;
159 const user = currentUser;
160 return userList[user].hidden.indexOf(displayName) === -1;
161};
162
163
164// Helper functions for configuration snippet modal
165const perm = () => {
166 return currentUser ? userList[currentUser].permissions : null;
167}
168const hiddenList = () => {
169 return currentUser ? userList[currentUser].hidden : [];
170};
171
172let text = '';
173let annotText = '';
174
175const setText = () => {
176 const permission = perm();
177 if (permission === 'administrator') {
178 text = 'annotationManager.promoteUserToAdmin()';
179 } else if (permission === 'read-only') {
180 text = 'annotationManager.enableReadOnlyMode()';
181 } else {
182 text = 'annotationManager.demoteUserFromAdmin();\n annotationManager.disableReadOnlyMode();';
183 }
184
185 return text;
186};
187
188const setAnnotText = () => {
189 const list = hiddenList();
190 if (list.length === 0) {
191 annotText = `
192 annotationManager.showAnnotations(allAnnots);
193 `;
194 } else {
195 let ifStatement = list.reduce((acc, hidden) => {
196 if (hidden === 'Sticky notes') {
197 acc += ' annot instanceof Annotations.StickyAnnotation || \n';
198 }
199 if (hidden === 'Free hand') {
200 acc += ' annot instanceof Annotations.FreeHandAnnotation || \n';
201 }
202 if (hidden === 'Highlight') {
203 acc += ' annot instanceof Annotations.TextHighlightAnnotation || \n';
204 }
205
206 return acc;
207 }, '');
208
209 ifStatement = ifStatement.substring(8, ifStatement.length - 5);
210
211 annotText = `
212 const hideList = allAnnots.filter(annot => {
213 return ${ifStatement};
214 });
215 annotationManager.hideAnnotations(hideList);
216 `;
217 }
218
219 return annotText;
220};
221
222// WebViewer section
223//
224// This code initializes the WebViewer with the basic settings
225// that are found in the default showcase WebViewer
226//
227
228const searchParams = new URLSearchParams(window.location.search);
229const history = window.history || window.parent.history || window.top.history;
230const licenseKey = 'YOUR_LICENSE_KEY';
231const element = document.getElementById('viewer');
232
233// Initialize WebViewer with the specified settings
234WebViewer({
235 path: '/lib',
236 serverUrl: null,
237 forceClientSideInit: true,
238 fullAPI: true,
239 css: '../styles/stylesheet.css',
240 ui: 'beta',
241 licenseKey: licenseKey,
242 enableFilePicker: true,
243}, element).then((instance) => {
244 // Enable the measurement toolbar so it appears with all the other tools, and disable Cloudy rectangular tool
245 const cloudyTools = [
246 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT,
247 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT2,
248 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT3,
249 instance.Core.Tools.ToolNames.CLOUDY_RECTANGULAR_AREA_MEASUREMENT4,
250 ];
251 instance.UI.enableFeatures([instance.UI.Feature.Measurement, instance.UI.Feature.Initials]);
252 instance.UI.disableTools(cloudyTools);
253
254 // Set default toolbar group to Annotate
255 instance.UI.setToolbarGroup('toolbarGroup-Annotate');
256
257 // Set default tool on mobile devices to Pan.
258 // https://apryse.atlassian.net/browse/WVR-3134
259 if (isMobileDevice()) {
260 instance.UI.setToolMode(instance.Core.Tools.ToolNames.PAN);
261 }
262
263 instance.Core.documentViewer.addEventListener('documentUnloaded', () => {
264 if (searchParams.has('file')) {
265 searchParams.delete('file');
266 history.replaceState(null, '', '?' + searchParams.toString());
267 }
268 });
269
270 instance.Core.annotationManager.enableAnnotationNumbering();
271
272 instance.UI.NotesPanel.enableAttachmentPreview();
273
274 // Add the demo-specific functionality
275 customizeUI(instance).then(() => {
276 // Create UI controls after demo is initialized
277 createUIControls(instance);
278 });
279});
280
281// Function to check if the user is on a mobile device
282const isMobileDevice = () => {
283 return (
284 /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
285 window.navigator.userAgent
286 ) ||
287 /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
288 window.navigator.userAgent.substring(0, 4)
289 )
290 );
291}
292
293// Cleanup function for when the demo is closed or page is unloaded
294const cleanup = (instance) => {
295 const { documentViewer } = instance.Core;
296
297 if (typeof instance !== 'undefined' && instance.UI) {
298
299 // Reset annotation user to default 'Guest' and promote to admin
300 const annotationManager = documentViewer.getAnnotationManager();
301 annotationManager.setCurrentUser('Guest');
302 annotationManager.promoteUserToAdmin();
303 annotationManager.disableReadOnlyMode();
304
305 console.log('Cleaning up compare-files demo');
306 }
307};
308
309// Register cleanup for page unload
310window.addEventListener('beforeunload', () => cleanup());
311window.addEventListener('unload', () => cleanup());
312
313
314// UI section
315//
316// Helper code to add controls to the viewer holding the buttons
317// This code creates a container for the buttons, styles them, and adds them to the viewer
318//
319
320// User selection
321const userPageSection = (instance) => {
322 // Create a wrapper div for the user section
323 const wrapper = document.createElement('div');
324 wrapper.className = 'user-page-section';
325
326 // Select User label
327 const selectUserLabel = document.createElement('h2');
328 selectUserLabel.className = 'header select-user-header';
329 selectUserLabel.textContent = 'Select User';
330
331 wrapper.appendChild(selectUserLabel);
332
333 // Users buttons container
334 const buttonsContainer = document.createElement('div');
335 buttonsContainer.className = 'buttons-container';
336
337 Object.keys(userList).map((username) => {
338 const button = document.createElement('button');
339 button.className = 'btn btn-user';
340 button.textContent = `${username} (${userList[username].permissions})`;
341 button.onclick = () => {
342 setUser(instance, username);
343 };
344
345 buttonsContainer.appendChild(button);
346 });
347 wrapper.appendChild(buttonsContainer);
348
349 // Add User clickable label
350 const addUserLabel = document.createElement('label');
351 addUserLabel.className = 'add-user-label';
352 addUserLabel.textContent = 'Add user';
353 addUserLabel.onclick = () => {
354 const addUserContainer = document.querySelector('.add-user-container');
355 if (addUserContainer.classList.contains('visible')) {
356 addUserContainer.classList.remove('visible');
357 addUserLabel.textContent = 'Add user';
358 } else {
359 addUserContainer.classList.add('visible');
360 addUserLabel.textContent = 'Close';
361 }
362 };
363
364 wrapper.appendChild(addUserLabel);
365
366 // Add User container
367 const addUserContainer = document.createElement('div');
368 addUserContainer.className = 'add-user-container';
369
370 // Add User input field
371 const input = document.createElement('input');
372 input.type = 'text';
373 input.placeholder = 'Username';
374 input.className = 'input add-user-input';
375
376 addUserContainer.appendChild(input);
377
378 // Add User permission dropdown
379 const permission = document.createElement('select');
380 permission.className = 'input add-user-permission';
381 permission.options.add(new Option('Administrator', 'administrator'));
382 permission.options.add(new Option('User', 'user'));
383 permission.options.add(new Option('Read-Only', 'read-only'));
384
385 addUserContainer.appendChild(permission);
386
387 // Add User add button
388 const addButton = document.createElement('button');
389 addButton.className = 'btn btn-submit-user';
390 addButton.textContent = 'Add';
391 addButton.onclick = () => {
392 // Validate input
393 const name = input.value;
394 if (name === '') return;
395 const p = permission.value;
396
397 // Add user to user list
398 addUser(instance, name, p);
399
400 // Add button for new user
401 const buttonsContainer = document.querySelector('.buttons-container');
402 const button = document.createElement('button');
403 button.className = 'btn btn-user';
404 button.textContent = `${name} (${p})`;
405 button.onclick = () => {
406 setUser(instance, name);
407 };
408 buttonsContainer.appendChild(button);
409
410 // Reset input fields
411 input.value = '';
412 permission.options.selectedIndex = 0;
413
414 // Close add user section
415 addUserLabel.click();
416 };
417
418 addUserContainer.appendChild(addButton);
419
420 wrapper.appendChild(addUserContainer);
421
422 return wrapper;
423};
424
425// Role permissions description
426const rolePermissionsPageSection = () => {
427 const wrapper = document.createElement('div');
428 wrapper.className = 'role-permissions-section';
429
430 const rolePermissionsLabel = document.createElement('h2');
431 rolePermissionsLabel.className = 'header role-permissions-header';
432 rolePermissionsLabel.textContent = 'Role Permissions';
433
434 wrapper.appendChild(rolePermissionsLabel);
435
436 const rolePermissionDescription = document.createElement('p');
437 rolePermissionDescription.className = 'text role-permission-paragraph';
438 const permission = perm();
439 if (permission === 'administrator') {
440 rolePermissionDescription.innerHTML = '<b> Admin: </b> Can add, edit, or remove any annotations created by anyone';
441 } else if (permission === 'read-only') {
442 rolePermissionDescription.innerHTML = '<b> Read-Only: </b> Can only view annotations';
443 } else { // user
444 rolePermissionDescription.innerHTML = '<b> User: </b> Can create, and edit or remove annotations created by themself';
445 }
446
447 wrapper.appendChild(rolePermissionDescription);
448
449 return wrapper;
450};
451
452// Viewing permissions checkboxes for selected user
453const viewingPermissionsPageSection = (instance) => {
454 const wrapper = document.createElement('div');
455 wrapper.className = 'viewing-permissions-section';
456
457 // Viewing Permissions label
458 const viewingPermissionsLabel = document.createElement('label');
459 viewingPermissionsLabel.className = 'header viewing-permissions-label';
460 viewingPermissionsLabel.textContent = `Set viewing permissions for ` + (currentUser ? currentUser : '...');
461
462 wrapper.appendChild(viewingPermissionsLabel);
463
464 // Viewing Permissions for each annotation type
465 const checkboxContainer = document.createElement('div');
466 checkboxContainer.className = 'checkbox-container';
467
468 toggleableTypes.map((type) => {
469 const checkboxRow = document.createElement('div');
470
471 const checkbox = document.createElement('input');
472 checkbox.type = 'checkbox';
473 checkbox.id = `view-${type.displayName}-checkbox`;
474 checkbox.checked = isChecked(type);
475 checkbox.onchange = () => {
476 toggleAnnotations(instance, type);
477 };
478
479 checkboxRow.appendChild(checkbox);
480
481 const label = document.createElement('label');
482 label.className = 'text checkbox-label';
483 label.ariaLabel = `Toggle ${type.displayName} annotations`;
484 label.textContent = `${type.displayName}`;
485
486 checkboxRow.appendChild(label);
487 checkboxContainer.appendChild(checkboxRow);
488 });
489 wrapper.appendChild(checkboxContainer);
490
491 return wrapper;
492};
493
494// Configuration Snippet button and modal
495const configSnippetModal = () => {
496 const modal = document.createElement('div');
497 modal.className = 'config-modal';
498
499 // Close the modal when clicking outside of it
500 modal.onclick = (event) => {
501 if (event.target === modal) {
502 modal.style.display = 'none';
503 }
504 };
505
506 // Modal content (non-shaded part)
507 const content = document.createElement('div');
508 content.className = 'config-modal-content';
509
510 // header
511 const header = document.createElement('div');
512 header.className = 'config-modal-header';
513
514 // Title
515 const title = document.createElement('h2');
516 title.textContent = 'Configuration Snippet';
517
518 // Copy button
519 const copyButton = document.createElement('button');
520 copyButton.className = 'btn-copy-config';
521 copyButton.innerHTML = '⧉';
522 copyButton.title = 'Copy to clipboard';
523 copyButton.onclick = async () => {
524 try {
525 // Get the text content to copy
526 const codeBlock = document.getElementById('config-snippet-code-block');
527 const textToCopy = codeBlock.textContent;
528 await navigator.clipboard.writeText(textToCopy);
529
530 // Change to checkmark
531 const originalContent = copyButton.innerHTML;
532 copyButton.innerHTML = '✓';
533
534 // Revert back after a short delay
535 setTimeout(() => {
536 copyButton.innerHTML = originalContent;
537 }, 200);
538 } catch (err) {
539 console.error('Failed to copy text: ', err);
540 }
541 };
542
543 // Close button
544 const close = document.createElement('button');
545 close.className = 'btn-close-config';
546 close.textContent = '×';
547 close.onclick = () => {
548 modal.style.display = 'none';
549 };
550
551 header.appendChild(title);
552 header.appendChild(copyButton);
553 header.appendChild(close);
554
555 // Code Block for configuration snippet
556 const codePre = document.createElement('pre');
557 codePre.className = 'config-snippet-code-pre';
558 const codeBlock = document.createElement('code');
559 codeBlock.id = 'config-snippet-code-block';
560 codeBlock.textContent = `const wvElement = document.getElementById('viewer');
561WebViewer({ ...options }, wvElement)
562.then(instance => {
563 const { annotationManager } = instance.Core;
564 annotationManager.setCurrentUser('${currentUser}');
565 ${setText()}
566 const allAnnots = annotationManager.getAnnotationsList();
567 ${setAnnotText()}
568})`;
569
570 // Append all elements
571 codePre.appendChild(codeBlock);
572 content.appendChild(header);
573 content.appendChild(codePre);
574 modal.appendChild(content);
575
576 return modal;
577};
578
579// Open configuration snippet button
580const configSnippetButton = () => {
581 const button = document.createElement('button');
582 button.className = 'btn-open-config';
583 button.textContent = 'Configuration Snippet';
584 button.onclick = () => {
585 const modal = document.querySelector('.config-modal');
586 modal.style.display = 'block';
587 };
588 return button;
589};
590
591
592// Helper function to create UI controls
593const createUIControls = (instance) => {
594 // Create a container for all controls (label, dropdown, and buttons)
595 const controlsContainer = document.createElement('div');
596 controlsContainer.className = 'controls-container';
597
598 // Add user section
599 controlsContainer.appendChild(userPageSection(instance));
600
601 // Add role permissions and viewing permissions sections side by side
602 const roleViewingPermissionsContainer = document.createElement('div');
603 roleViewingPermissionsContainer.className = 'role-viewing-permissions-container';
604 roleViewingPermissionsContainer.appendChild(rolePermissionsPageSection());
605 roleViewingPermissionsContainer.appendChild(viewingPermissionsPageSection(instance));
606 controlsContainer.appendChild(roleViewingPermissionsContainer);
607
608 // Add configuration snippet button
609 controlsContainer.appendChild(configSnippetButton());
610
611 element.insertBefore(controlsContainer, element.firstChild);
612 document.body.appendChild(configSnippetModal());
613};
614
615// Helper function to update UI controls
616const updateUIControls = () => {
617 // Update role permission description
618 const rolePermissionDescription = document.querySelector('.role-permission-paragraph');
619 if (rolePermissionDescription) {
620 const permission = perm();
621 if (permission === 'administrator') {
622 rolePermissionDescription.innerHTML = '<b> Admin: </b> Can add, edit, or remove any annotations created by anyone';
623 } else if (permission === 'read-only') {
624 rolePermissionDescription.innerHTML = '<b> Read-Only: </b> Can only view annotations';
625 } else { // user
626 rolePermissionDescription.innerHTML = '<b> User: </b> Can create, and edit or remove annotations created by themself';
627 }
628 }
629
630 // Update viewing permissions label
631 const viewingPermissionsLabel = document.querySelector('.viewing-permissions-label');
632 if (viewingPermissionsLabel) {
633 viewingPermissionsLabel.textContent = `Set viewing permissions for ` + (currentUser ? currentUser : '...');
634 }
635
636 // Update checkboxes
637 toggleableTypes.map((type) => {
638 const checkbox = document.getElementById(`view-${type.displayName}-checkbox`);
639 if (checkbox) {
640 checkbox.checked = isChecked(type);
641 }
642 });
643
644 // Update configuration snippet text
645 const codeBlock = document.getElementById('config-snippet-code-block');
646 if (codeBlock) {
647 codeBlock.textContent = `const wvElement = document.getElementById('viewer');
648WebViewer({ ...options }, wvElement)
649.then(instance => {
650 const { annotationManager } = instance.Core;
651 annotationManager.setCurrentUser('${currentUser}');
652 ${setText()}
653 const allAnnots = annotationManager.getAnnotationsList();
654 ${setAnnotText()}
655})`;
656 }
657};

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales