# 自定义 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.APPENDUIExtension.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);
      }
    })()
  }
});