Foxit PDF SDK for Web

How to Customize Right Click Annotation Menus with Foxit PDF SDK for Web

This guide will walk you through the following topics:

  • Customizing a right-click menu for supported annotations
  • Customizing a right-click menu for unsupported annotations
  • Hiding a right click menu or menu items
  • Showing a customized right-click menu

Customize right-click menu for supported annotations

Foxit’s JavaScript Web PDF Library supports most standard annotation types. Each type can have its own right-click menu. Below lists the supported annotation and their corresponding XML element name.

{
  "line": "fv--line-contextmenu",
  "linearrow": "fv--linearrow-contextmenu",
  "linedimension": "fv--linedimension-contextmenu",
  "polylinedimension": "fv--polylinedimension-contextmenu",
  "polygondimension": "fv--polygondimension-contextmenu",
  "circle": "fv--circle-contextmenu",
  "square": "fv--square-contextmenu",
  "polyline": "fv--polyline-contextmenu",
  "polygon": "fv--polygon-contextmenu",
  "polygoncloud": "fv--polygoncloud-contextmenu",
  "fileattachment": "fv--fileattachment-contextmenu",
  "freetexttypewriter": "fv--freetexttypewriter-contextmenu",
  "typewriter": "fv--typewriter-contextmenu",
  "freetextcallout": "fv--freetextcallout-contextmenu",
  "callout": "fv--callout-contextmenu",
  "freetexttextbox": "fv--freetexttextbox-contextmenu",
  "textbox": "fv--textbox-contextmenu",
  "freetext": "fv--freetext-contextmenu",
  "ink": "fv--ink-contextmenu",
  "stamp": "fv--stamp-contextmenu",
  "text": "fv--text-contextmenu",
  "areahighlight": "fv--areahighlight-contextmenu",
  "highlight": "fv--highlight-contextmenu",
  "caret": "fv--caret-contextmenu",
  "replace": "fv--replace-contextmenu",
  "squiggly": "fv--squiggly-contextmenu",
  "strikeout": "fv--strikeout-contextmenu",
  "redact": "fv--redact-contextmenu",
  "underline": "fv--underline-contextmenu",
  "media": "fv--media-contextmenu",
  "image": "fv--image-contextmenu",
  "link": "fv--link-contextmenu",
  "sound": "fv--sound-contextmenu"
}

The annotation element name can be accessed by using super.getAnnotsContextMenuName(owner) in the UIExtension.XViewerUI. You may refer to the section Customizing viewerUI for a code example.

For the supported annotations, you can use the method UIExtension.UIConsts.FRAGMENT_ACTION.APPEND action to replace, add and remove menu items.

Replacing menu items

```js
new PDFUI({
    fragments: [{
        target: 'fv--highlight-contextmenu',
        action: UIExtension.UIConsts.FRAGMENT_ACTION.REPLACE,
        template: `
            <contextmenu name="fv--highlight-contextmenu">
                <contextmenu-item-reply></contextmenu-item-reply>
                <contextmenu-item-delete-annot></contextmenu-item-delete-annot>
                <contextmenu-item-properties></contextmenu-item-properties>
                <contextmenu-item name="x-user-custom-contextmenu-item">Custom </contextmenu-item>
            </contextmenu>`,
        config:[{
            target: 'x-user-custom-contextmenu-item',
            callback: function() {
                alert('custom contextmenu item clicked!');
            }
        }]
    }]
})
```

Adding menu items

```js
new PDFUI({
    fragments: [{
        target: 'fv--textbox-contextmenu',
        action: UIExtension.UIConsts.FRAGMENT_ACTION.APPEND,
        template: `
            <contextmenu-item name="x-user-custom-contextmenu-item"></contextmenu-item>
        `,
        config: [{
            target: 'x-user-custom-contextmenu-item',
            callback: function() {
                alert('custom contextmenu item clicked!');
            }
        }]
    }]
});
```

Removing menu items

```js
new PDFUI({
    fragments: [{
        target: 'fv--media-contextmenu>fv--contextmenu-item-media-download',
        action: UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE
    }]
})
```

Customize right-click menu for unsupported annotations

Unsupported annotations are those not supported in the above list but have already been defined in the PDF references. To customize the context menu for an unsupported annotation, you should rewrite getAnnotsContextMenuName in XViewUI to create a new context menu and then add it in the template.

A quick way to check if the current annotation is supported or not in the Web Viewer, you may check their corresponding element name, which is by default labeled as “fv–default-annotcontextmenu“.

The following example is making the assumption that your current PDF file contains a ‘trapnet‘ annotation which is not yet supported in the Web Viewer, and you want to customize its right-click menu.

new PDFUI({
    viewerOptions: {
         new class extends UIExtension.XViewerUI {
                createContextMenu(owner, anchor, config) {
                    if(owner instanceof PDFViewCtrl.AnnotComponent) {
                        if(owner.annot.getType() === 'trapnet') {
                            return 'custom-trapnet-contextmenu-name';
                        }
                    }
                    return super.createContextMenu(owner, anchor, config);
                }
            } ()
    },
    fragments: [{
        target: 'template-container',
        action: UIExtension.UIConsts.FRAGMENT_ACTION.APPEND,
        template: `
            <contextmenu name="custom-trapnet-contextmenu-name">
                <contextmenu-item-reply></contextmenu-item-reply>
                <contextmenu-item-delete-annot></contextmenu-item-delete-annot>
                <contextmenu-item-properties></contextmenu-item-properties>
                <contextmenu-item name="x-user-custom-contextmenu-item">Custom </contextmenu-item>
            </contextmenu>
        `,
        config:[{
            target: 'x-user-custom-contextmenu-item',
            callback: function() {
                alert('custom contextmenu item clicked!');
            }
        }]
    }]
})

Hiding the right-click menu or items

You can use one of the following approaches to hide.

1. Configuring a class method in fragments to force the hiding action.

```js
new PDFUI({
    // the other options ...
    fragments: [{
        target: 'fv--underline-contextmenu',
        config: {
            cls: 'fv__ui-force-hide'
        }
    }]
})
```

The effect of this method is there is no response following the right-clicking on the underline.

2. Customizing viewerUI

```js
new PDFUI({
    viewerOptions: {
        viewerUI: new class extends UIExtension.XViewerUI {
            createContextMenu(owner, anchor, config) {
                if(owner instanceof PDFViewCtrl.AnnotComponent) {
                    const contextMenuName = super.getAnnotsContextMenuName(owner)
                    if(contextMenuName === 'fv--underline-contextmenu'){
                        return;
                    }
                }
                return super.createContextMenu(owner, anchor, config);
            }
        } ()
    }
});
```

This method will hide the built-in menu when a right-clicking occurs, and present the browser default menu.

3. Overwrite the showContextMenu of AnnotComponent

```js
const pdfui = new PDFUI({
    // ....
});
pdfui.initializePromise.then(function () {
    var annotMap = {};
    pdfui.registerMatchRule(function(annot, AnnotComponentClass) {
        let type = annot.getType();
        var intent = annot.getIntent && annot.getIntent() || "default";
        // You can add more annotation types
        if(type === 'underline') {
            return AnnotComponentClass;
        }
        if (annotMap[type] && annotMap[type][intent]) {
            return annotMap[type][intent];
        }
        annotMap[type] = annotMap[type] || {};
        return annotMap[type][intent] = (class extends AnnotComponentClass {
            showContextMenu() {
                // Do nothing
            }
        });
    });
});
```

This method will hide the build-in menu and show the browser default menu of a right-clicking.

Showing a customized right-click menu

You can overwrite the viewerUI to show your own right-click menu.

new PDFUI({
  viewerOptions: {
    viewerUI: new (class extends UIExtension.XViewerUI {
      createContextMenu(owner, anchor, config) {
        if (owner instanceof PDFViewCtrl.AnnotComponent) {
          const contextMenuName = super.getAnnotsContextMenuName(owner);
          if (contextMenuName === "fv--underline-contextmenu") {
            return new (class extends PDFViewCtrl.IContextMenu {
              constructor() {
                super();
                this.initContextmenu();
              }
              destroy() {
                $(anchor).contextMenu("destroy");
              }
              showAt(x, y) {
                $(anchor).contextMenu();
              }
              disable() {
                super.disable();
                $(anchor).contextMenu("destroy");
              }
              enable() {
                super.enable();
                this.initContextmenu();
              }
              initContextmenu() {
                // The code example below requires referencing Jquery libraries including contextMenu.min.css, contextMenu.min.js and min.js.
                $(anchor).contextMenu({
                  selector: config.selector,
                  items: [
                    {
                      name: 'show "Hello World"',
                      callback: function() {
                        alert("hello world");
                      }
                    },
                    {
                      name: 'show "Bye!"',
                      callback: function() {
                        alert("Bye!");
                      }
                    }
                  ]
                });
              }
            })();
          }
        }
        return super.createContextMenu(owner, anchor, config);
      }
    })()
  }
});

Updated on August 11, 2021

Was this article helpful?
Thanks for your feedback. If you have a comment on how to improve the article, you can write it here: