// ES6 Compliant Syntax
// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-13
// File: showcase-demos/digital-signatures/ui-elements.js
// Class with static UI elements and related functions for the digital signature demo
class UIElements {
// The list of registered panels in the webviewer
static viewerPanels = null;
// The tab panel, representing the webviewer left panel
static tabPanel = {
handle: null,
dataElement: 'tabPanel'
};
// The digital signature sub-panel to be registered
static digitalSignaturePanel = {
handle: null,
dataElement: 'digitalSignaturePanel',
render: null,
};
// The password to open the private key file
static password = 'password';
static signatureInformation = [
{
id: 'Location',
label: 'Location',
value: 'Vancouver, BC, Canada'
},
{
id: 'Reason',
label: 'Reason',
value: 'Cryptographic signature demo'
},
{
id: 'ContactInfo',
label: 'Contact Information',
value: 'apryse.com'
}
];
// The url to the PKCS #12 private keyfile to use to certify this digital signature.
static certificateUrl = '/assets/certificates/apryse.pfx';
// Customize the webviewer left panel
static customizeUI = (instance) => {
const { UI } = instance;
// Close the tab panel (if it's open) for refreshment.
UI.closeElements([UIElements.tabPanel.dataElement]);
// Get the list of registered panels in the webviewer
UIElements.viewerPanels = UI.getPanels();
// Find the Tab Panel to modify. The digital signature sub-panel will be added to this Tab panel.
UIElements.tabPanel.handle = UIElements.viewerPanels.find((panel) => panel.dataElement === UIElements.tabPanel.dataElement);
// Register the digital signature sub-panel
UIElements.RegisterDigitalSignaturePanel(instance);
// Add the new digital signature sub-panel to list of sub-panels under the Tab Panel
UIElements.digitalSignaturePanel.handle = { render: UIElements.digitalSignaturePanel.dataElement };
UIElements.tabPanel.handle.panelsList = [UIElements.digitalSignaturePanel.handle, ...UIElements.tabPanel.handle.panelsList];
};
// Register the digital signature sub-panel
static RegisterDigitalSignaturePanel = (instance) => {
UIElements.digitalSignaturePanel.render = UIElements.createDigitalSignaturePanelElements(instance);
instance.UI.addPanel({
dataElement: UIElements.digitalSignaturePanel.dataElement,
location: 'left',
icon: '<svg fill="#000000" width="100px" height="100px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="m 1.0324444,11.139308 c 0.0179,-0.1218 0.061,-0.2215 0.0958,-0.2215 0.0348,0 0.0633,-0.064 0.0633,-0.1428 0,-0.079 0.0321,-0.1428 0.0714,-0.1428 0.0393,0 0.0714,-0.064 0.0714,-0.1427 0,-0.079 0.0321,-0.1428 0.0714,-0.1428 0.0393,0 0.0714,-0.047 0.0714,-0.1045 0,-0.058 0.08,-0.2479001 0.17776,-0.4230001 0.12606,-0.2258 0.16557,-0.3794 0.13583,-0.528 -0.0254,-0.1269 0.002,-0.2942 0.0687,-0.4236 0.0608,-0.1177 0.18066,-0.4193 0.26627,-0.6702 0.0856,-0.251 0.17774,-0.4885 0.20472,-0.5277 0.027,-0.039 0.0925,-0.216 0.14571,-0.3927 0.0532,-0.1766 0.1232,-0.3517 0.15563,-0.389 0.0324,-0.037 0.059,-0.1417 0.059,-0.232 0,-0.09 0.0321,-0.1642 0.0714,-0.1642 0.0393,0 0.0714,-0.094 0.0714,-0.21 0,-0.1154 0.0321,-0.2298 0.0714,-0.254 0.0393,-0.024 0.073,-0.099 0.0749,-0.1649 0.002,-0.066 0.16547,-0.2492 0.36338,-0.4062 0.1979,-0.1571 0.43577,-0.3579 0.5286,-0.4462 0.0928,-0.088 0.1866,-0.1606 0.20838,-0.1606 0.0218,0 0.13637,-0.093 0.25466,-0.2056 0.11829,-0.113 0.3509,-0.2977 0.51691,-0.4104 0.16601,-0.1128 0.31254,-0.2291 0.32563,-0.2585 0.0131,-0.029 0.0683,-0.053 0.12276,-0.053 0.0544,0 0.21335,-0.064 0.35316,-0.1428 0.26925,-0.1512 0.60679,-0.1909 0.60679,-0.071 0,0.039 0.0421,0.071 0.0936,0.071 0.0515,0 0.15589,0.058 0.23201,0.1285 0.24872,0.231 0.37942,0.24 0.55068,0.038 0.30396,-0.3586 1.0957,-1.1308 1.25041,-1.2194 0.18638,-0.1068 0.51461,-0.1182 0.51461,-0.018 0,0.039 0.043,0.071 0.0956,0.071 0.12754,0 0.26131,0.3072 0.26131,0.6002 0,0.2369 -0.24982,0.6817 -0.50955,0.9073 -0.0731,0.063 -0.13294,0.139 -0.13294,0.1677 0,0.029 -0.0964,0.1422 -0.21416,0.2523 -0.23429,0.2188 -0.26247,0.3229 -0.12217,0.4512 0.18171,0.1662 0.89017,0.5482 1.01669,0.5482 0.0577,0 0.10491,0.029 0.10491,0.063 0,0.035 0.20949,0.1202 0.46554,0.1895 0.4572796,0.1237 0.4683696,0.1234 0.6246396,-0.018 0.1522,-0.1379 0.20395,-0.1411 1.19421,-0.074 0.56932,0.038 1.0438,0.078 1.05441,0.087 0.0106,0.01 0.0719,0.2706 0.13625,0.5806 0.22137,1.0669 0.1397,2.7256 -0.19548,3.9704001 l -0.0726,0.2698 -1.10376,0 -1.10375,0 0,-0.2142 c 0,-0.1178 -0.0321,-0.2142 -0.0714,-0.2142 -0.0393,0 -0.0714,-0.068 -0.0714,-0.1504 0,-0.1163 -0.0283,-0.1381 -0.12493,-0.096 -0.0687,0.03 -0.2373696,0.067 -0.3747896,0.083 -0.13742,0.016 -0.31799,0.063 -0.40128,0.1034 -0.15948,0.078 -0.59017,0.053 -1.4191,-0.084 -0.56756,-0.093 -0.48797,-0.091 -1.12627,-0.028 -0.26608,0.026 -0.50088,0.076 -0.52177,0.1096 -0.0539,0.087 -1.79571,0.078 -1.84994,-0.01 -0.0243,-0.039 -0.15276,-0.071 -0.28555,-0.071 -0.13279,0 -0.26128,-0.032 -0.28555,-0.071 -0.0243,-0.039 -0.15836,-0.071 -0.29798,-0.071 -0.20152,0 -0.30517,0.055 -0.50271,0.2677 -0.13687,0.1473 -0.29749,0.34 -0.35693,0.4284 -0.0594,0.088 -0.16674,0.1606 -0.23843,0.1606 -0.0717,0 -0.15021,0.032 -0.17447,0.071 -0.0243,0.039 -0.10154,0.071 -0.17172,0.071 -0.0702,0 -0.22087,0.046 -0.33487,0.1034 -0.11401,0.057 -0.33873,0.1244 -0.49939,0.1501 l -0.29211,0.047 0.0325,-0.2215 z m 0.83725,-0.2929 c 0.0243,-0.039 0.10648,-0.071 0.18268,-0.071 0.0762,0 0.13857,-0.032 0.13857,-0.071 0,-0.039 0.0482,-0.071 0.10708,-0.071 0.0589,0 0.10708,-0.048 0.10708,-0.1065 0,-0.1314 -0.28157,-0.4646 -0.39263,-0.4646 -0.11106,0 -0.39263,0.3332 -0.39263,0.4646 0,0.059 -0.0321,0.1065 -0.0714,0.1065 -0.0393,0 -0.0714,0.064 -0.0714,0.1428 0,0.1038 0.0476,0.1428 0.17426,0.1428 0.0958,0 0.19411,-0.032 0.21837,-0.071 z m 9.7914796,-0.4796 c 0.56959,-0.044 0.51279,0.02 0.6796,-0.7697001 0.10998,-0.5207 0.15529,-2.1091 0.0628,-2.2016 -0.0416,-0.042 -0.0756,-0.1661 -0.0756,-0.2766 0,-0.1106 -0.0399,-0.329 -0.0888,-0.4855 l -0.0888,-0.2844 -0.54608,0 c -0.62148,0 -0.64971,0.026 -0.55725,0.5046 0.11336,0.5873 0.075,1.9136 -0.0772,2.6663 -0.15299,0.7568001 -0.13618,1.0112001 0.0617,0.9332001 0.0652,-0.026 0.34848,-0.064 0.62959,-0.086 z M 6.1529444,9.9283079 c 0.15705,-0.042 0.48897,-0.1306 0.73759,-0.1971 0.4275,-0.1144 0.48566,-0.1141 1.07082,0.01 0.34032,0.07 0.81151,0.1273 1.04709,0.1279 0.50257,0.001 1.3830896,-0.1952 1.5309896,-0.3415 0.10718,-0.1061 0.23238,-0.8318 0.23976,-1.3898 0.005,-0.3722 -0.0687,-0.9074 -0.18342,-1.3327 -0.0786,-0.2915 -0.0876,-0.2983 -0.44116,-0.3348 -0.5742096,-0.059 -0.8963196,-0.1281 -0.8963196,-0.1915 0,-0.032 -0.0723,-0.082 -0.16062,-0.1096 -0.0883,-0.028 -0.36468,-0.1746 -0.61409,-0.326 -0.24941,-0.1514 -0.48231,-0.2753 -0.51756,-0.2753 -0.0352,0 -0.0641,-0.032 -0.0641,-0.071 0,-0.1875 -0.27918,-0.03 -0.65538,0.3706 -0.37178,0.3956 -0.41543,0.474 -0.41543,0.7454 0,0.1668 -0.0321,0.3232 -0.0714,0.3474 -0.0393,0.024 -0.0714,0.1069 -0.0714,0.1837 0,0.1551 -0.11414,0.3784 -0.30339,0.5936 -0.0687,0.078 -0.12493,0.1681 -0.12493,0.1999 0,0.1 0.34485,0.063 0.75135,-0.079 0.38822,-0.1364 0.39085,-0.1364 0.39085,0 0,0.078 -0.0993,0.2321 -0.22063,0.3429 l -0.22062,0.2015 -1.10194,0 c -0.7526,0 -1.12849,0.023 -1.18571,0.08 -0.0461,0.046 -0.17371,0.084 -0.28365,0.084 -0.10994,0 -0.19989,0.032 -0.19989,0.071 0,0.039 -0.0642,0.071 -0.14277,0.071 -0.0785,0 -0.14278,0.027 -0.14278,0.059 0,0.033 -0.0779,0.101 -0.17302,0.152 -0.18219,0.098 -0.28332,0.3465 -0.21403,0.5271 0.0461,0.1201 0.52553,0.3324 0.75054,0.3324 0.0805,0 0.19232,-0.046 0.24841,-0.1019 0.1151,-0.1151 0.14054,-0.6833 0.0306,-0.6833 -0.0393,0 -0.0714,-0.064 -0.0714,-0.1428 0,-0.1852 0.0407,-0.18 0.25311,0.033 0.12743,0.1274 0.17522,0.2528 0.17522,0.4598 0,0.1565 -0.0321,0.3044 -0.0714,0.3287 -0.13127,0.081 -0.0734,0.2215 0.12493,0.3028 0.22116,0.091 0.76798,0.071 1.19574,-0.043 z m -3.49888,-1.0793 c 0.20573,-0.3259 0.22956,-0.6039 0.0658,-0.7677 -0.0966,-0.097 -0.12355,-0.099 -0.1804,-0.013 -0.0368,0.055 -0.0861,0.1892 -0.10953,0.2971 -0.0235,0.108 -0.0656,0.1964 -0.0937,0.1964 -0.0642,0 -0.2167,0.3289 -0.2167,0.4673 0,0.063 0.0699,0.1038 0.17757,0.1038 0.12939,0 0.22625,-0.077 0.35694,-0.2842 z m 0.48514,0.048 c 0.26307,-0.271 0.4081,-0.5016 0.4081,-0.6489 0,-0.056 0.0241,-0.1128 0.0535,-0.1259 0.0294,-0.013 0.13385,-0.1992 0.23201,-0.4135 0.0982,-0.2144 0.31499,-0.5268 0.48186,-0.6942 0.16687,-0.1674 0.3034,-0.321 0.3034,-0.3412 0,-0.068 0.24679,-0.3411 1.08866,-1.2037 0.46134,-0.4727 0.8388,-0.888 0.8388,-0.9229 0,-0.1533 -0.39705,-0.4103 -0.63371,-0.4103 -0.16776,0 -0.63626,0.2586 -0.80241,0.443 -0.0635,0.071 -0.14859,0.1281 -0.18909,0.1281 -0.0405,0 -0.23766,0.1606 -0.43816,0.3569 -0.20049,0.1963 -0.3832,0.3569 -0.40602,0.3569 -0.0846,0 -0.78643,0.7789 -0.8785,0.9749 -0.0525,0.1117 -0.12374,0.2588 -0.15842,0.327 -0.0347,0.068 -0.0631,0.1726 -0.0631,0.232 0,0.059 -0.0321,0.1081 -0.0714,0.1081 -0.0393,0 -0.0714,0.094 -0.0714,0.2082 0,0.1145 -0.0388,0.2211 -0.0862,0.2369 -0.0576,0.019 -0.0357,0.083 0.0658,0.1919 0.22734,0.2441 0.34549,0.5655 0.24483,0.6662 -0.0449,0.045 -0.0817,0.1537 -0.0817,0.2417 0,0.088 -0.0321,0.1798 -0.0714,0.2041 -0.0732,0.045 -0.10182,0.3212 -0.0333,0.3212 0.0209,0 0.1414,-0.1064 0.2677,-0.2365 z m 2.72831,-1.0663 c 0.13638,-0.088 0.24836,-0.2008 0.24885,-0.2499 4.8e-4,-0.049 0.033,-0.089 0.0723,-0.089 0.0393,0 0.0714,-0.064 0.0714,-0.1428 0,-0.079 0.0321,-0.1427 0.0714,-0.1427 0.0393,0 0.0714,-0.08 0.0714,-0.1785 0,-0.2216 -0.0932,-0.2288 -0.23214,-0.018 -0.0582,0.088 -0.26617,0.3284 -0.4622,0.5335 -0.19602,0.2051 -0.3395,0.3899 -0.31884,0.4105 0.0753,0.075 0.23533,0.034 0.4779,-0.123 z"/></svg>',
title: 'Digital Signature',
render: () => UIElements.digitalSignaturePanel.render,
});
};
// Create the digital signature panel elements.
static createDigitalSignaturePanelElements = (instance) => {
let panelDiv = document.createElement('div');
panelDiv.id = 'digitalSignaturePanel';
let paragraph = document.createTextNode('In this demo, a digital signature will be applied to the first signature field or an invisible signature field will be added. Sign PDFs with certificates using our JavaScript digital signature library and securely protect digital documents by creating a signing fingerprint uniquely identifying a sender.');
panelDiv.appendChild(paragraph);
let dividerDiv = document.createElement('div');
dividerDiv.style.borderTop = '1px solid #ccc';
dividerDiv.style.margin = '10px 0';
panelDiv.appendChild(dividerDiv);
// Digital ID division
let digitalIDDiv = document.createElement('div');
digitalIDDiv.id = 'digitalIDDiv';
let digitalIDDivTitle = document.createElement("h3");
digitalIDDivTitle.textContent = "Digital ID (Optional)";
digitalIDDiv.appendChild(digitalIDDivTitle);
paragraph = document.createTextNode('A default Apryse Digital ID will be used if no Digital ID is provided. We encourage using a non-confidential Digital ID file, but none of the provided data is saved to Apryse servers.');
digitalIDDiv.appendChild(paragraph);
panelDiv.appendChild(digitalIDDiv);
// Digital ID File button
let digitalIDFileButton = document.createElement('button');
digitalIDFileButton.textContent = 'Select Digital ID File';
enableButton(digitalIDFileButton, true);
digitalIDFileButton.onclick = () => {
// file input field
const inputFile = document.createElement('input');
inputFile.id = 'inputFile';
inputFile.type = 'file';
inputFile.style.display = 'none';
inputFile.accept = '.pfx';
inputFile.onchange = e => {
UIElements.certificateUrl = e.target.files[0];
if (UIElements.certificateUrl !== null) {
enableButton(clearDigitalIDButton, true);
digitalIDFileNameLabel.textContent = `${UIElements.certificateUrl.name}`;
}
passwordField.disabled = false;
}
inputFile.click();
}
panelDiv.appendChild(document.createElement('p'));
panelDiv.appendChild(digitalIDFileButton);
// Digital ID File name label
panelDiv.appendChild(document.createElement('p'));
const digitalIDFileNameLabel = document.createElement('span');
digitalIDFileNameLabel.id = 'digitalIDFileNameLabel';
digitalIDFileNameLabel.textContent = '';
panelDiv.appendChild(digitalIDFileNameLabel);
// Password label
panelDiv.appendChild(document.createElement('p'));
panelDiv.appendChild(document.createTextNode('Digital ID Password:'));
panelDiv.appendChild(document.createElement('p'));
// Password input field
const passwordField = document.createElement('input');
passwordField.id = 'inputPassword';
passwordField.type = 'password';
passwordField.disabled = true;
passwordField.value = UIElements.password;
passwordField.style.width = '100%';
passwordField.addEventListener("change", () => { UIElements.password = passwordField.value.trim(); });
panelDiv.appendChild(passwordField);
// Show password button
let showPasswordButton = document.createElement('button');
showPasswordButton.textContent = 'Show';
enableButton(showPasswordButton, true);
showPasswordButton.onclick = () => {
showPasswordButton.textContent = showPasswordButton.textContent === 'Show' ? 'Hide' : 'Show';
passwordField.type = passwordField.type === 'password' ? 'text' : 'password';
};
panelDiv.appendChild(showPasswordButton);
// Clear Digital ID File button
panelDiv.appendChild(document.createElement('p'));
let clearDigitalIDButton = document.createElement('button');
clearDigitalIDButton.textContent = 'Clear Digital ID Information';
enableButton(clearDigitalIDButton, false);
clearDigitalIDButton.onclick = () => {
clearDigitalIDInformation(instance);
passwordField.value = UIElements.password;
enableButton(clearDigitalIDButton, false);
}
panelDiv.appendChild(clearDigitalIDButton);
panelDiv.appendChild(dividerDiv.cloneNode());
// Signature Information division
let signatureInfoDiv = document.createElement('div');
signatureInfoDiv.id = 'signatureInfoDiv';
let signatureInfoDivTitle = document.createElement("h3");
signatureInfoDivTitle.textContent = "Signature Information (Optional)";
signatureInfoDiv.appendChild(signatureInfoDivTitle);
panelDiv.appendChild(signatureInfoDiv);
// signature information labels and input fields
UIElements.signatureInformation.forEach(info => {
// input field label
panelDiv.appendChild(document.createElement('p'));
panelDiv.appendChild(document.createTextNode(`${info.label}:`));
panelDiv.appendChild(document.createElement('p'));
// input field
const inputField = document.createElement('input');
inputField.id = `input${info.id}`;
inputField.type = 'text';
inputField.value = info.value;
inputField.style.width = '100%';
inputField.addEventListener("input", () => info.value = inputField.value.trim());
panelDiv.appendChild(inputField);
});
// Apply Approval Signature button
let applyApprovalButton = document.createElement('button');
applyApprovalButton.id = 'applyApprovalButton';
applyApprovalButton.textContent = 'Apply Approval Signature';
enableButton(applyApprovalButton, false);
applyApprovalButton.onclick = () => {
applyApproval(instance);
enableButton(verifySignatureButton, true);
}
panelDiv.appendChild(document.createElement('p'));
panelDiv.appendChild(applyApprovalButton);
// Verify Signature button
let verifySignatureButton = document.createElement('button');
verifySignatureButton.textContent = 'Verify Signature';
enableButton(verifySignatureButton, false);
verifySignatureButton.onclick = () => verifySignature(instance);
panelDiv.appendChild(document.createElement('p'));
panelDiv.appendChild(verifySignatureButton);
return panelDiv;
};
}
// Enable or disable a button based on the state
const enableButton = (button, state) => {
button.disabled = !state;
button.style.backgroundColor = (state) ? 'blue' : 'gray';
button.style.color = (state) ? 'white' : 'darkgray';
};