Issue
Signature Pad functionality fails to load or operate correctly in the Pega Document/image upload feature in Pega platform Theme Cosmos and UI Kit-based application UI due to a JavaScript error.
Symptoms and Impact
Signature Pad functionality fails to load or operate in the UI. Users are unable to draw or capture signatures in the annotation area. The component appears unresponsive or broken when accessed.
Browser console logs JavaScript error: "signPad.enable is not a function".
The error prevents initialization of the Signature Pad, leading to complete feature failure. The issue was observed across both Theme Cosmos and UI Kit-based applications. Because the Signature Pad component enables users to add annotations and signatures within the application, this failure disrupts the functionality entirely and impacts user workflows that rely on digital signing.
Steps to reproduce
- Login to Smart investigate, any Theme Cosmos, or UI-KIT application.
- Open any Work Object.
- Add an annotation using the Add annotation option (which displays on clicking the 3 dots beside the attached image in the Recent Attachment pane). The browser console error displays.
Root Cause
The issue is caused by a version mismatch in the Signature Pad library bundled with the Pega platform. The application currently loads Signature Pad v5.0.4 (open-source implementation), while the OOTB rule pyAnnotateArea is designed to work with the Pega-specific Signature Pad v1.3.3.
The OOTB rule relies on legacy APIs such as,
- signPad.enable()
- removeListeners()
These APIs were supported in Signature Pad v1.3.3 but have been deprecated and are no longer available in Signature Pad v5.0.4. This mismatch results in the JavaScript error: "signPad.enable is not a function".
This behavior has been confirmed as a product regression impacting both Theme Cosmos and UI-Kit applications.
Solution
The deprecated APIs have been updated in the non-autogenerated section of,
- pyAnnotateArea: signPad.enable() → signPad.on()
- removeListeners() → signPad.off()
Bugs have been addressed in the upcoming patch versions of Infinity 25 and Infinity 26 versions.
Workaround
As the pyAnnotateArea is an available rule, replace the existing pyAnnotateArea code to the below code (either UI Kit or Cosmos).
<%
pega_rules_utilities.pzRegisterActivity(tools,"Work-.pzDeleteAndAttachNew");
ParameterPage primary = tools.getParameterPage();
String base64out = primary.getString("BASE64OutParam");
String draw = StringUtils.filterRichText(tools.getLocalizedTextForString(".pyButtonLabel", "Draw",StreamBuilder.FMT_LITERAL));
String clear = StringUtils.filterRichText(tools.getLocalizedTextForString(".pyButtonLabel", "Clear",StreamBuilder.FMT_LITERAL));
String save = StringUtils.filterRichText(tools.getLocalizedTextForString(".pyToolTip", "Save",StreamBuilder.FMT_LITERAL));
String stopEditing = StringUtils.filterRichText(tools.getLocalizedTextForString(".pyButtonLabel", "Stop editing",StreamBuilder.FMT_LITERAL));
String annotateImageCanvas = StringUtils.filterRichText(tools.getLocalizedTextForString(".pyButtonLabel", "Draw on Canvas",StreamBuilder.FMT_LITERAL));
%>
<pega:onlyonce name="SignaturePlugin">
<pega:static type="script" app="webwb">
<pega:bundle name="pzSignatureGadgetBundle" />
</pega:static>
</pega:onlyonce>
<!-- <img id="annotateImage" src=""/> -->
<canvas id="annotateImageCanvas" aria-label="<%= annotateImageCanvas%>"></canvas>
<div class="actionsContainer">
<button type="button" class="annotateDrawButton" title='<%= draw%>'>
<i class="pi pi-ink"></i>
<%= draw%>
</button>
<div class="editActions">
<button type="button" class="annotateClearButton annotateClearButtonDisable" title='<%= clear%>'>
<i class="pi pi-trash"></i>
<%= clear%>
</button>
<button type="button" class="annotateCross" aria-label="<%= stopEditing%>" title='<%= stopEditing%>'>
<i class="pi pi-times"></i>
</button>
<button type="button" class="annotateSaveButton annotateSaveButtonDisable" title='<%= save%>'>
<i class="pi pi-check"></i>
<%= save%>
</button>
</div>
</div>
<script>
$(function () {
var imageB64 = '<%=base64out%>';
var imageMime = "image/png";
var dirtyB64; /* added to fix BUG-350085 bajaa for browser zoom after making canvas dirty */
if (typeof imageB64 === 'string') {
var mime = imageB64.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/);
if (mime && mime.length) {
imageMime = mime[1];
}
}
var img = new Image();
var canvas = $('#annotateImageCanvas').get(0);
var context = canvas.getContext("2d");
var me = this;
var clearBtn = $(".annotateClearButton");
var saveBtn = $(".annotateSaveButton");
var $customExpandInnerDivStyle = $('.modal-wrapper-for-attachment-preview .customExpandInnerDivStyle');
var availableWidth = document.body.clientWidth - 10;
var availableHeight = document.body.clientHeight - 70;
var $img = $(img);
var $canvas = $(canvas);
var scale= 1;
var isEnabled = false;
$customExpandInnerDivStyle.css({
maxWidth: availableWidth,
maxHeight: availableHeight
});
var isInitiated = false;
var resizeCanvas = function(){
availableWidth = document.body.clientWidth - 10;
availableHeight = document.body.clientHeight - 70;
$customExpandInnerDivStyle.css({
maxWidth: availableWidth,
maxHeight: availableHeight
});
var currentMediaWidth = img.naturalWidth;
var currentMediaHeight = img.naturalHeight;
while (currentMediaHeight > availableHeight || currentMediaWidth > availableWidth) {
if (currentMediaHeight > availableHeight) {
currentMediaWidth = Math.round((availableHeight / currentMediaHeight) * currentMediaWidth);
currentMediaHeight = Math.round(availableHeight);
} else if (currentMediaWidth > availableWidth) {
currentMediaHeight = Math.round((availableWidth / currentMediaWidth) * currentMediaHeight);
currentMediaWidth = Math.round(availableWidth);
}
}
$canvas.css({
width: currentMediaWidth+"px",
height: currentMediaHeight+"px"
});
scale = img.naturalWidth/currentMediaWidth;
/* update sign pad pen width */
signPad.maxWidth = Math.max(((2.5) / scale), 1.0);
signPad.minWidth = Math.max(((0.5) / scale), 0.5);
};
var initCanvas = function () {
img.src=""; /* just, to trigger onload event - even during the first time */
img.src=dirtyB64?dirtyB64:imageB64;
img.onload = function () {
if(!isInitiated){
resizeCanvas();
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
context.save(); /* save context settings before doing scale, so that we can restore the canvas state on next init */
isInitiated = true;
}
context.restore();
context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);
context.save();
context.scale(scale, scale);
};
$(".annotateDrawButton").addClass("highlight");
if($("html").hasClass("tablet")){
var headerHeight = $("header.screen-layout-region-header").height();
$(".hd.modaldialog_hd_attachment_preview").css({'position' : 'relative', 'top' : headerHeight});
}
};
var canvasPenColor = $(canvas).css("color");
var signPad = new SignaturePad(canvas, {
penColor: canvasPenColor ? canvasPenColor : "#e25190",
});
/* BUG-994566 replaced drawEnd with endStroke */
signPad.addEventListener("endStroke", function () {
if(isEnabled){
clearBtn.removeClass("annotateClearButtonDisable");
saveBtn.removeClass("annotateSaveButtonDisable");
}
dirtyB64 = signPad.toDataURL(imageMime);
});
/* BUG-994566 moved onClear functionality to resetAnnotateState */
var resetAnnotateState = function () {
dirtyB64 = undefined;
setTimeout(initCanvas,0);/* onClear handler executes even before the instance is returned and assigned to the signPad variable */
clearBtn.addClass("annotateClearButtonDisable");
saveBtn.addClass("annotateSaveButtonDisable");
};
if (signPad && typeof signPad.off === "function") {
signPad.off();
};
/* BUG-994566 Initial loading of the image */
initCanvas();
var resizeAnnotateArea = function () {
resizeCanvas();
/*signPad.clear(); */
initCanvas(); /* .. onClear handler internally calls the init canvas */
};
/* resize event registration */
$(window).resize(resizeAnnotateArea);
/* close button handler */
pega.u.d.attachCloseBtnListeners({
closeBtnApi: function () {
/* unregister to events */
$(window).off('resize', resizeAnnotateArea);
pega.u.d.hideModalWindow();
$('.modal-overlay .modal-wrapper').removeClass('modal-wrapper-for-attachment-preview');
}
});
var actionsContainer = document.getElementsByClassName("actionsContainer");
var annotateDrawButton = document.getElementsByClassName("annotateDrawButton");
var actionButton = document.getElementsByClassName("editActions");
var annotateCrossButton = document.getElementsByClassName("annotateCross");
$(".annotateDrawButton").click(function () {
annotateDrawButton[0].classList.add("annotateDrawButtonHide");
actionButton[0].classList.add("actionsShow");
if (signPad && typeof signPad.on === "function") {
signPad.on();
};
isEnabled = true;
$(canvas).attr('tabindex',"0");
canvas.focus();
});
$(".annotateCross").click(function () {
actionButton[0].classList.remove("actionsShow");
annotateDrawButton[0].classList.remove("annotateDrawButtonHide");
if (signPad && typeof signPad.off === "function") {
signPad.off();
};
isEnabled = false;
annotateDrawButton[0].focus();
$(canvas).removeAttr('tabindex');
});
$(".annotateClearButton").click(function () {
if (!signPad.isEmpty()){
resetAnnotateState();
}
});
$(".annotateSaveButton").click(function () {
if (!signPad.isEmpty()) {
var finalImgData = signPad.toDataURL(imageMime);
finalImgData = finalImgData.replace("image/bmp","image/png");
/* SAVE */
var postUrl = SafeURL_createFromURL(pega.u.d.url),
postData, oscoHandler, postCallBack;
postUrl.put("pyActivity", "Work-.pzDeleteAndAttachNew");
postUrl.put("SuppressHTML", "true");
postUrl.put("pzKeepPageMessages", "true");
postData = new SafeURL();
postData.put("base64", finalImgData);
postCallBack = {
success: function () {
imageB64 = finalImgData;
resetAnnotateState();
if (pega.u.d.gBusyInd) {
pega.u.d.gBusyInd.hide();
}
},
failure: function () { }
};
oscoHandler = {
online: function (safeURL, jsonPostData, viewCallback) {
pega.u.d.asyncRequest("POST", safeURL, postCallBack, jsonPostData);
},
offline: function () { }
};
if (pega.u.d.setBusyIndicator) {
/* pega.u.d.gBusyInd.busyIndInterval = 0; */
pega.u.d.setBusyIndicatorWithDelay(document.body, 0);
}
pega.u.d.ServerProxy.doAction(postUrl, postData, oscoHandler, undefined);
}
});
$(".annotateSaveButton").on("keydown", function(ev){
if(!ev.shiftKey && ev.keyCode == 9){
setTimeout(function(){
document.getElementsByClassName("container-close")[0].focus();
}, 0);
}
});
$(".annotateDrawButton").on("keydown", function(ev){
if(!ev.shiftKey && ev.keyCode == 9){
setTimeout(function(){
document.getElementsByClassName("container-close")[0].focus();
}, 0);
}
});
/* BUG-347183 */
$('body').off('touchstart.annotateimage').on('touchstart.annotateimage','.modal-wrapper-for-attachment-preview', function(ev){
ev.preventDefault();
});
});
</script>