Help with UI customization

Product: pdftron web

Product Version: 8.7.0

Please give a brief summary of your issue:
(Think of this as an email subject)

Need help to change UI Layout

Please describe your issue and provide steps to reproduce it:
(The more descriptive your answer, the faster we are able to help you)

I have seen several sites that use this library in the same way and i would like to do the same for my site, what they do is activate the pages panel on left side by default which i manage to do reading the docs and put a panel on right side with signatures tool as well as other tools like initials, text field, date field and so on, I would like to know how to do that, i checked the docs and manage to do some things but i really don’t know how to create the panel on right side and put the tools on that side, also i would like to have the option to hide it when clicking in a button, this last one i think i know how to do it but the panel on right side is absolutely necessary, for reference check Ilovepdf and smalpdf they have the right panel i’m talking about, I also need to implement drag and drop functionality when to those tools, if you check ilovepdf you will see what i’m talking about, any help will be greatly appreciated if you could provide an example in code that would be awesome

Please provide a link to a minimal sample where the issue is reproducible:

Hello, I’m Ron, an automated tech support bot :robot:

While you wait for one of our customer support representatives to get back to you, please check out some of these documentation pages:

Guides:APIs:Forums:

OK so upon checking other question i discovered that what i want to do is not possible without making a fork of the project which is something i have never done before and would like to know if is possible to edit the content for notes or search panel on right side, if yes then please provide me a with some code to implement the changes, if not but possible by making a fork i would need detailed instructions to do it, documentation ones say where i can find the code but doesn’t say how to get a working version out of the changes afterwards, because right now i have some js files and some folders and that works but editing the code of those files that don’t exist in my folders in the project confuse me, any help would be appreciated on this matter.

on the other hand i noticed that the sites i mentioned before use a div on right side to make space for the tools but i have been unable to create a tool on that space in the way they do, so any help with that matter will be greatly appreciated too

Hello,

Thank you for contacting us about WebViewer. I’m not too familiar with how “iLovePDF” and “eSign” are implementing their side panels but it seems like they have their main “viewer” element and are creating a custom sidebar for each of their samples outside of the viewer. You can do something like that too

<div style="width: 100%">
  <div id="viewer" style="width: calc(100% - 200px)">
  </div>
  <div class= "sidebar" style="width: 200px">
  </div>
</div>

You can either use the “instance” object returned when instantiating WebViewer or you can do something like

document.querySelector('#viewer > iframe').contentWindow.instance

to access the “instance” object from some other part of your codebase.

Besides adding a sidebar outside of WebViewer, you can fork the UI code and modify the UI like you mention. You can find a guide for it below
Guide for creating custom UI

Depending on the UI changes, this could be a lot more complex solution. Adding new panels to the right side would be pretty complicated but modifying existing panels isn’t too hard (depending on the change). If you are ok with adding a panel to the left side, we have the setCustomPanel API which let you add custom panel on the left side (we don’t have a similar API for the right side yet).

Also for the notes panel, we have the dangerouslySetNoteTransformFunction that could be helpful.

If you need to modify the current note or search panel, you can find the code under src/components. You’ll want to start looking at “notePanel” and “searchPanel”.

Would it be possible to know the customization you are trying to add (new panel, extra buttons, etc)?

Best Regards,

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

what i want to do is this, put these elements inside a panel on the right side, i though that i could get these elements out of a function in pdftron but it seems that’s not the case, forking and making my own right panel or any other component is too much work imo, so what i’m doing right now is taking your advice of making a div that will display next to the viewer where the iframe is and about the instance i have that stored in a vue property which is global so i can access it wherever i may need it, the problem i’m facing right now is how to link together my custom elements with the iframe elements, for example i have a button that say create signature and i want to attach a function that simulates the click on the button to create signature from the iframe but i can’t get the element reference with query selector, i suppose iframe elements are not selectable this way and they can only be accessed with instance methods so i need to know how to attach add and delete signature events from the iframe to the buttons i created, any help will be appreciated, thank you

Hello,

Thank you for the information. For signatures, we should have API for most features so you shouldn’t need to simulate clicks. You can get the built in popup to open by doing the following

instance.openElement('signatureModal');

You can get the saved signatures by doing the following

// will return an array of signature that are stored
const savedSignatures = instance.docViewer.getToolModeMap()['AnnotationCreateSignature'].getSavedSignatures();
// will return a base64 image of the signature
const signaturePreview = await instance.docViewer.getToolModeMap()['AnnotationCreateSignature'].getPreview(savedSignatures[0])

You can attach events like the following

const signatureEvents = instance.Core.Tools.SignatureCreateTool.Events;
const addEvent = signatureEvents.ANNOTATION_ADDED;
instance.docViewer.getToolModeMap()['AnnotationCreateSignature'].on(addEvent, () => {
  //your code here
});

We have a guide about working in with signatures in the link below
Signature guide

Also you should be able to access element in the iframe using the contentDocument like the following

document.querySelector('#viewer iframe').contentDocument.querySelector('.signature-create').click()

Feel free to let us know if you have any questions about getting a signature feature to work

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

hi Andrew, thank for answering, i ended up using something else as this helps in some situations but doesn’t always fulfills my needs, but i have another issue which needs to be resolved by monday 05/09/2022, i was given this design for the signature modal

and this is what i have so far

so my problem is that default modal doesn’t cover all screen because the webviewer is rendered in the a section of the page, so i though about creating a modal with same design as the one given to me but the problem is how to make it work in the same way as signature modal because i don’t know which events are called when create button is clicked also, i don’t know what info needs to be passed so it saves the signature, i though about extracting the elements from signature modal and put them in my custom modal but when i tried with a button from the header it extracted the button and placed it where i told it to but it didn’t work anymore, so for this time i would like to know the following

  1. is there is a way to edit default modal to make it look like the one in the design?

  2. is there is a way to extract an element and put it someplace else and not break it in the process?

  3. is there a way to link/simulate click/events from default modal on the custom modal?

if you have info on one or more please elaborate, and please answer as soon as possible because i need to have this done by monday (2 days), tuesday 10 am (malta time) at most

PD: disregard login and QR code those will be discarded

Hi Andrew, since our interactions are not instantaneous i’ll try to make the most out of them unless we can communicate by other channels where we can exchange messages right away, if possible please let me know if we can do that, now, in the past few days i have tried multiple approaches to make this work and have not succeed so far, first i tried to export the element out of the iframe as i mentioned before but that didn’t work, i tried to append the modal into the iframe but my modal uses bootstrap which doesn’t exist inside the iframe, i wanted to edit default modal and i manage to change some stuff but it won’t be the same as the one in the design, and i need two of each of the spaces to sign because there will be one list for signatures and another for initials, i tried to enter information in my bootstrap modal and then pass it to the default modal and simulate click on create button but it seems it rejects input of information that way, for example in the type field that input field always saves the word “guest” although i can put whatever word i need on the input field, is not saved when clicking on the button, this approach is the one that helps me the most to be honest, because it gives me full control over the layout and other functionalities and i simply need to pass the info to default modal but i don’t know if it is possible, or if i’m looking at this the wrong way

now the functions for the preview and the list were useful but the problem comes later when clicking on those previews because i need to trigger the same event that activates when i click on the signatures in the signature tool that attaches the preview to the cursor and then places the signature after clicking on the document, if the events are inside the instance i have access to all kind of instances at all times because i save them in global properties as they are created, so that’s not a problem just point the way to go and i’ll start testing, however the modal is the top priority right now, those tools are something that can be implemented later for the moment let’s focus on the modal and keep these pointer in mind

  1. has to look as in the picture as much as possible if it can’t be the exact one

  2. all functionalities need to work

  3. if possible it should use bootstrap for styles and control over the layout

  4. example sites mentioned before doesn’t seem to use this tool inside an iframe, apparently the have everything in one single site and use boostrap for styling, don’t know how they make it

thank you for your time and have a good day

Hello,

Sorry for the delayed response, Monday was a public holiday and I was busy yesterday. For making a custom signature popup you could either

  1. For a copy of our UI and modify the signature popup
    UI customization guide
    Public UI repo - the public repo could be useful for the below approach since you can see what the UI is doing

  2. Use the addCustomModal to create a custom signature popup

Webviewer({}, document.getElementById('viewer')).then(instance => {
  const customElementName = 'customSignatureModal';
  const modal = {
    dataElement: customElementName,
    render: () => {
      // besides passing a "render" method, you can use header, body, footer elements
      // see API doc for more information
      const customUI = document.createElement('div'); 
      customUI.style.width = '400px';
      customUI.style.height = '400px';

      const closeButton = document.createElement('button');
      closeButton.textContent = "Close";
      closeButton.onclick = () => {
        instance.UI.closeElements([customElementName]);
      };
      customUI.appendChild(closeButton);

      // return a DOM element that you want to display
      return customUI;
    },
  };
  
  instance.UI.addCustomModal(modal);

  // replace the default "signatureModal" with custom one
  instance.UI.addEventListener('visibilityChanged', (e) => {
    if (e.detail.element === 'signatureModal' && e.detail.isVisible) {
      instance.UI.closeElements(['signatureModal']);
      instance.UI.openElements([customElementName]);
    }
  });
});

The idea is when the default signatureModal is opened, closed it and open your custom signature popup. You can read more about using custom modal in the link below
AddCustomModal API doc

Also you can have WebViewer import a CSS file by providing a css option when initializing WebViewer
Styling WebViewer guide

Please let me know if the above helps or if you want me to clarify anything

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

dude is friday it’s been more than 5 days now, i already resolved that and many other problems by putting a bunch of DOM manipulation code in some functions and now the modal looks the way i need, i now have an issue setting default value for type signature input field, i can change it so the user sees a custom value the first time they open the modal but if they change the tab or close and open modal again then the value defaults to Guest and that’s not good, also i noticed image signature field doesn’t have a clear button and doesn’t allow you to put another picture in once you put something in that field, any idea on how to clear that field after loading the image without closing the modal and opening it again?

Hello,

Unfortunately there isn’t a way to clear the current uploaded images. The only way you can clear it is by closing and opening the modal like the below

instance.closeElements(['signatureModal']);
instance.openElements(['signatureModal']);

I added issue to our backlog but don’t have a timeline when we’ll have a “clear” button (or an API to clear it) for this

For the value in the “Type” tab (default to “Guess”), the starting value is the value from getCurrentUser. You can change it by setting the current user name like the following

instance.Core.annotationManager.setCurrentUser('Testing');

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

hi Andrew, i managed to implement drag and drop functionalities for text field and date field but i have not been able to implement the same for signatures, so here is what i have problems with.

  1. i have a list on right side of the screen, in which you can select the signature, i can drag and drop the element and it will execute a function, with text and date field i created an annotation then used

that.annotationManager.addAnnotation(freeText, {autoFocus: false});
that.annotationManager.redrawAnnotation(freeText);

and it adds the field is the way i need no problem, however for signatures there is no signature field, only signatureWidget which according to documentation requires a field, but i think that’s not what i need so i need to know how to insert a signature, regardless of the type (draw, type, image) into the document, something like default way when you create a signature and it is attached to cursor, i thought about using signatureTool.addSignature() but it didn’t work, i don’t know how to use that function nor if it is the right way, so in short please provide me a way to insert a signature into the document with js commands

  1. for draw and type signatures i would like to add an extra color to the color options, but haven’t been able to find a way, please provide me a function to add that

  2. is it possible to deactivate the function that attaches the signature to the cursor after is created?

  3. if i create a sign here field can i attach it to an email? i mean i need to create field that certain people can sign, in my mind i think we could have it like this, owner adds a list of people then they create sign here fields linked to added people, then invited people would be able to see all field but sign only the ones that matches an specific email, something like that

Hello,

For your questions

  1. Basic signatures can be “freehand” or “stamp” annotations. For your use case, you’ll probably want to convert all your signatures to “stamp” and place them in the location that users are dragging it to. See our custom annotation sample for how you can drag and drop stamp onto a page. You will want to make the stamp have the same X, Y, width, and height as the signature widget and associate the signature with the widget by setting the annot property
    Guide for associating signatures

For digital signature, it’s a similar idea but you’ll need to use our full API and add a “field” to a signature widget. You can see the following sample and guides for more information
Sample for signing a widget
Adding verify signature
Digital signature samples

  1. We don’t have a way to change the default color options currently. I added this feature to our backlog but we don’t have a timeline for when this will be added.

In the meantime you can try programmatically adding buttons and doing the following when they are pressed

const signatureTool = instance.docViewer.getToolModeMap().AnnotationCreateSignature;
signatureTool.annot.StrokeColor = new Annotations.Color(255,0,0)
signatureTool.resizeCanvas()
  1. The cursor should change back to normally after it’s created. However since you are probably overriding the default create button you might need to either call hidePreview or change the current tool mode like the following
instance.docViewer.setToolMode(instance.docViewer.getToolModeMap().Pan)
  1. Depends on the application they are opening the file in. If they open the file in Acrobat or some other application that support signatures, they should be able to sign it. However note that lot of browsers and email client don’t have support for advance PDF features (like signatures).

For associating fields with certain users, that is possible exist in the PDF 2.0 standard, however we don’t support the feature yet (there hadn’t been much demand for it). If you give users a link to your website that is hosting WebViewer, you could implement this yourself by showing and hiding form fields. If this is a critical improvement for you, and you need a fixed timeline for this to be completed by, then the next step would be to do a paid custom engineering project. If you are interested in that, please fill in this form.
Custom project form

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

Hi andrew, thanks for your answers, i need another advise for signatures, when inserting a signature using drag and drop I use this code

await that.signatureTool.setSignature(that.signatureList[index]);
                    that.signatureTool.location = {
                        x: dropPosition.x,
                        y: dropPosition.y,
                        pageNumber: dropPosition.pageNumber
                    }
                    await that.signatureTool.addSignature();

this works for me no problem however i have a couple of things i haven’t been able to do

  1. I need to define a height and width when inserting a signature with this code, if is not possible with this code then please provide me a way to define dimensions and insert a signature

  2. I need to auto-focus signatures when inserted into the document

  3. I need to select signatures when clicking inside any point of the space of the signature, right now you can only select a signature when you click on top on the letters or any actual part of the signature, however if I click in an empty space inside the space of the signature is not selected, I need to be able to select the signature when clicking in any point inside the containing rectangle.

  4. I don’t know why but in order to select any of the annotations I’m using, freeText and signatures i need to double click to access the annotation edit controls, i would like to be able to access edit controls with a single click

by the way this is the code i sue for inserting freeText fields

const freeText = new that.annotations.FreeTextAnnotation();
                    freeText.PageNumber = dropPosition.pageNumber;
                    freeText.X = dropPosition.x - 25;
                    freeText.Y = dropPosition.y -25;
                    freeText.Width = 100;
                    freeText.Height = 50;
                    freeText.TextAlign = 'center';
                    freeText.StrokeThickness = 0;
                    freeText.TextVerticalAlign = 'center';
                    freeText.TextColor = new that.annotations.Color(0, 0, 0);
                    freeText.setContents('Type Here');
                    freeText.FontSize = '16pt';

                    that.annotationManager.addAnnotation(freeText, {autoFocus: false});
                    that.annotationManager.redrawAnnotation(freeText);

ps: i noticed that after clicking twice on them and not inserting any other annotation the problem doesn’t happen again but if i click on them two times and then insert another annotation i need to click two times on each one of them if i want to access edit properties, all assistance will be greatly appreciated?

Hi Andrew, how are you? i come again looking for assistance, i still need to know the answers to the previous 4 question about inserting signature with specific size but now i was tasked to do the following, instead of handling a dropdown with a signature list they want a single signature which will b inserted into the document with drag and drop, then if the signature is deleted delete all the occurrences of that signature in the document, and if the signature is changed then search all occurrences and replace them with the new signature, i saw some function in the annotation manager which sound exactly to what i need but haven’t been able to do what i need to do, if you could provide an example that would be awesome, and last but not least for the next stage of this project they want to implement a function to cycle between placed annotation, which once again i have seen in annotation manager section but don’t know how to use, an example of that part would be greatly appreciated, thank you and have a good day

HI andrew i have another question, i need to develop a function that replaces existing signatures in the document when signature is uploaded, for type and image signatures i have it working like this

annotationList[i].image = this.signatureAnnotation[0].image
this.annotationManager.updateAnnotation(annotationList[i])

signature annotation is the objetc i get from the newly created signature and in this way i have been able to change the signatures on the document no problem if the initial and final type are typed and image, problem comes when is drawn to drawn because i use this

annotationList[i].Ra = this.signatureList[0]
 this.annotationManager.updateAnnotation(annotationList[i])

which changes the signature visually but breaks the signature as position is changed to 0,0 and can no longer be selected

i tried using the function setPath but i think i’m not using it correctly as getPaths from a working signature gives me an array with 20+ elements and after using setPath it becomes an array with one element but inside that element is the the right set of path in another arry with 20+ elements so i think this is the way to go but i’m doing something wrong if you can explain how to change the path so i can replace the signature body for drawn signatures that would be awesome

Hi,

Sorry for the delayed response, for your questions

  1. Signatures should have the same height and width as the signature widget they are attached to. You’ll have to do something like
  const sigtool = instance.docViewer.getToolModeMap().AnnotationCreateSignature;
 sigtool.addEventListener('locationSelected', (pageCoordinates, widget) => {
      // set the size of the signatureWidget that was selected. 
     // The signature added by using "addSignature" should have the same height/width
     if (widget) {
        widget.setHeight(140);
        widget.setWidth(140);
     }
   });
  1. You can do something like the following to focus on the newly added signature
      annotationManager.on('annotationChanged', (annots, action, option) => {
        if (action === 'add' 
        && !option.imported 
        && annots[0].Subject === 'Signature') {
          annotationManager.jumpToAnnotation(annots[0], {
              // options like "zoom" for zoom level can be used
          });
          instance.annotManager.selectAnnotation(annots[0]);
      }
    });
  1. Annotations use “selectionModel” to determine when they are being selected. You can change the default one used by signatures by doing the following
    annotManager.on('annotationChanged', (annots, action, option) => {
      if (action === 'add' && annots[0].Subject === 'Signature') {
        // can create a new custom one but for this case you can just use the "FreeText" selection model
        annots[0].selectionModel = instance.Core.Annotations.FreeTextSelectionModel;
      }
    });

See the following guide for more information
Custom selection model guide

  1. For accessing edit in one click, you can use the “annotationSelection” event to manually open the edit tool
    annotManager.on('annotationSelected', (annots, action) => {
      if (action === 'selected') {
         setTimeout(() => {
           document.querySelector('#viewer iframe').contentDocument.querySelector('button[data-element="annotationStyleEditButton"]').click();
         }, 0);
      }
});
  1. For updating existing signature, don’t update “Ra”. We minify/obfuscate our code and “Ra” is probably a “private” value, use setImageData instead to update the image.

Please let me know if the above helped or if you want me to clarify something

Best Regards

Andrew Yip
Software Developer
PDFTron Systems, Inc.
www.pdftron.com

HI Andrew thank you for the selection model tip, it was exactly what i needed however the single click selection problem solution is not the one i need but i can use it for other stuff so is good to have it,

now, the real problem is that after inserting an annotation anywhere in the document if i want to select an annotation, any annotation, i need to click 2 times in order to be able to select it but not exactly over the annotation, it can be in any place on the document viewer, and as i mentioned before after i add all the annotations i need, in order to select any of them the first time i will need to click once anywhere on the document and then after i click on the annotations they will be able to be selected as normal with one single click and that behavior will continue until i add a new annotation, deleting annotations or replacing them doesn’t seem to affect the one click behavior, but if i add a new annotation, i need to click one time anywhere in the document viewer and then i will be able to select annotations in the document with a single click again, i don’t know if it because there is a drag and drop event taking place that prevents me from selecting any annotation on the first click and is removed after first click, but that’s the last issue i have wit the annotations part

also if I want to create a type signature programmatically using a given string how could i make it happen? i’m looking forward to take some letter from type signature input and use them to create another signature automatically but my experiments have not given me the result i need.

and about type signature input, is there no other way to change the default value other than to change active user? because when i buy the license i don’t want to have to put “name and surname” as my username, is another small detail i need to fix , thank you for your time and have a good day

PS: yes it was a long time one week to be precise, i advanced in other stuff while waiting for an answer to my previous question but it is a long time and i’m almost done with this part of the project so please give me an answer for the other questions as soon as you can

Hi andrew, how are you? I need a tip on something i’m doing, i have built a functionality where you can drag and drop some fields related to an email as the identifier, when the owner of that email goes to sign that document, the sing here field i added, freetext annotations with a color background and sign here text, are added to the document in readonly mode to prevent user from doing anything that can alter the field added by the document owner, the function i have for replacing the sign here fields for the signature invited signer uses works fine if i remove the readonly attribute for the sign here field before replacing the annotation and then i need to add the readonly attribute to the added signature so the user can’t do anything to the signature, which works fine, however we have the undo controls on the top of the page and at the moment if i press undo after adding a signature the original field or the previous signature gets printed over current one and if i click redo more signatures keep appearing on top of the others, so i thought about using a several attributes like no move, delete, rotate and other useful ones but i was wondering if is a bad idea to use readonly and if it is possible to fix this small issue otherwise i’ll have to disable that function for this part, thank you and have good day