Skip to content

自定义 Annotation 右键菜单 ​

本章节将介绍以下内容:

自定义 SDK 支持的 Annotation 的右键菜单 ​

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

json
{
  "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) 来替换,添加和删除菜单项。

替换菜单项 ​

javascript
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!');
                    }
                }]
            }];
        }
    })
})

插入菜单项 ​

javascript
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!');
                    }
                }]
            }];
        }
    })
});

删除菜单项 ​

javascript
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
            }]
        }
    })
})

自定义 SDK 不支持的 Annotation 的右键菜单 ​

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

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

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

javascript
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 中配置一个类方法来强制隐藏 ​

javascript
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 ​

javascript
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 方法 ​

javascript
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 来显示自定义的右键菜单。

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