# # 自定义 Annotation 右键菜单

本章节将介绍以下内容：

- 自定义 Foxit PDF SDK for Web 支持的 Annotation 的右键菜单
- 自定义 Foxit PDF SDK for Web 不支持的 Annotation 的右键菜单
- 隐藏右键菜单或者菜单项
- 显示自定义的右键菜单

## # 自定义 Foxit PDF SDK for Web 支持的 Annotation 的右键菜单

Foxit PDF SDK for Web 支持大部分的标准 Annotation 类型。每种类型的 Annotation 都有自己的右键菜单。以下列出了 Foxit PDF SDK for Web 支持的 Annotation 以及其对应的 XML 元素名称。

    {
      "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"
    }

Annotation 元素名称可以通过 UIExtension.XViewerUI 中的 `super.getAnnotsContextMenuName(owner)` 函数获取。您可以参阅 自定义 viewerUI 小节中的代码示例。

对于支持的 annotation，您可以通过使用 fragment 配置 (`UIExtension.UIConsts.FRAGMENT_ACTION.REPLACE`, `UIExtension.UIConsts.FRAGMENT_ACTION.APPEND` 和 `UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE` action) 来替换，添加和删除菜单项。

### # 替换菜单项

    new UIExtension.PDFUI({
        appearance: UIExtension.appearances.AdaptiveAppearance.extend({
            getDefaultFragments: function() {
                return [{
                    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!');
                        }
                    }]
                }];
            }
        })
    })

### # 插入菜单项

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

### # 删除菜单项

    new UIExtension.PDFUI({
        appearance: UIExtension.appearances.AdaptiveAppearance.extend({
            getDefaultFragments: function() {
                return [{
                    target: 'fv--media-contextmenu>fv--contextmenu-item-media-download',
                    action: UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE
                }]
            }
        })
    })

## # 自定义 Foxit PDF SDK for Web 不支持的 Annotation 的右键菜单

不支持的 Annotation 是指不在上述支持列表中但已在 PDF references 中定义的 Annotation 。自定义 Foxit PDF SDK for Web 不支持的 Annotation 的右键菜单，您需要重写 XViewUI 中的 `getAnnotsContextMenuName` 方法，以创建一个新的上下文菜单并将其添加到 template 中。

如何快速检测当前 Annotation 是否是 Foxit PDF SDK for Web 所支持的 Annotation ，您可以检查其对应的元素名称，默认情况下支持的 Annotation 都被标记为 `"fv--default-annot-contextmenu"`。

以下示例假设当前 PDF 文件包含一个 'trapnet' Annotation ，该 Annotation 是 Foxit PDF SDK for Web 不支持的。以下代码展示了如何自定义其右键菜单。

    new UIExtension.PDFUI({
        viewerOptions: {
             viewerUI: 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);
                    }
                } ()
        },
        appearance: UIExtension.appearances.AdaptiveAppearance.extend({
            getDefaultFragments: function() {
                return [{
                    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!');
                        }
                    }]
                }]
            }
        })
    })

## # 隐藏右键菜单或者菜单项

您可以使用以下方法中的一种来隐藏右键菜单或者菜单项。

### # 1. 在 fragments 中配置一个类方法来强制隐藏

    new UIExtension.PDFUI({
        appearance: UIExtension.appearances.AdaptiveAppearance.extend({
            getDefaultFragments: function() {
                // the other options ...
                return [{
                    target: 'fv--underline-contextmenu',
                    config: {
                        cls: 'fv__ui-force-hide'
                    }
                }]
            }
        })
    })

上述代码的作用是使 underline 注释的右键菜单被强制隐藏，这样右键点击 underline 注释就不再会有任何响应。

### # 2. 自定义 viewerUI

    new UIExtension.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);
                }
            } ()
        }
    });

此方法将在点击右键时隐藏内置菜单，而显示浏览器的默认菜单。

### # 3. 重写 AnnotComponent 中的 showContextMenu 方法

    const pdfui = new UIExtension.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
                }
            });
        });
    });

此方法将在点击右键时隐藏内置菜单，而显示浏览器的默认菜单。

## # 显示自定义右键菜单

您需要重写 viewerUI 来显示自定义的右键菜单。

    new UIExtension.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);
          }
        })()
      }
    });