# 自定义 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 配置结合上述右键菜单名称进行修改,详情请参考下面的示例。

# 替换菜单项


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 Annotation 的右键菜单被强制隐藏,这样右键点击 underline Annotation 就不再会有任何响应。

# 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);
      }
    })()
  }
});

# Annotation 右键菜单匹配规则

在我们的默认布局模板中,可以看到这些 Annotation 相关的右键菜单组件:

<default-annot-contextmenu @lazy></default-annot-contextmenu>
<markup-contextmenu @lazy></markup-contextmenu>
<markup-contextmenu @lazy name="fv--line-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--linearrow-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--linedimension-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--polylinedimention-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--polygondimension-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--circle-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--square-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--polyline-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--polygon-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--polygoncloud-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--ink-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--stamp-contextmenu"></markup-contextmenu>
<markup-contextmenu @lazy name="fv--text-contextmenu"></markup-contextmenu>
<caret-contextmenu name="fv--areahighlight-contextmenu" @lazy></caret-contextmenu>
<caret-contextmenu name="fv--replace-contextmenu" @lazy></caret-contextmenu>
<measurement-contextmenu @lazy></measurement-contextmenu>
<caret-contextmenu name="fv--caret-contextmenu"></caret-contextmenu>
<textmarkup-contextmenu @lazy name="fv--highlight-contextmenu"></textmarkup-contextmenu>
<textmarkup-contextmenu @lazy name="fv--strikeout-contextmenu"></textmarkup-contextmenu>
<textmarkup-contextmenu @lazy name="fv--underline-contextmenu"></textmarkup-contextmenu>
<textmarkup-contextmenu @lazy name="fv--squiggly-contextmenu"></textmarkup-contextmenu>
<freetext-contextmenu @lazy name="fv--typewriter-contextmenu"></freetext-contextmenu>
<freetext-contextmenu @lazy name="fv--callout-contextmenu"></freetext-contextmenu>
<freetext-contextmenu @lazy name="fv--textbox-contextmenu"></freetext-contextmenu>
<action-annot-contextmenu @lazy name="fv--image-contextmenu"></action-annot-contextmenu>
<action-annot-contextmenu @lazy name="fv--link-contextmenu"></action-annot-contextmenu>
<comment-card-contextmenu @lazy ></comment-card-contextmenu>
<fileattachment-contextmenu @lazy></fileattachment-contextmenu>
<media-contextmenu @lazy ></media-contextmenu>
<sound-contextmenu @lazy ></sound-contextmenu>
<redact-contextmenu @lazy ></redact-contextmenu>

可以观察到,在开头的 <default-annot-contextmenu><markup-contextmenu> 中,如果某个注释类型无法在当前布局模板中精确匹配到右键菜单,将会根据以下规则匹配默认右键菜单:

  1. 如果该注释属于 Markup Annotation,则会匹配到 <markup-contextmenu>;
  2. 如果布局模板中也没有 <markup-context>,或者该注释不属于标记注释,那么将会匹配到 <default-annot-contextmenu>

最终用户将看到的右键菜单将以最后匹配到的为准。如果布局模板中没有定义任何右键菜单,则触发 Annotation 右键点击时,则会显示 PDFViewCtrl 层定义的菜单,如果不想在 Annotation 上显示任何菜单, 则请参考 自定义 ViewerUI 一节。