可扩展组件与使用指南
本节提供了可扩展组件的详细信息和使用指南,列举了可扩展组件的扩展方法,并帮助开发者更好地理解和使用组件的自定义功能。在以下文档中,我们将首先介绍可扩展组件的概念以及使用 Components API 和 Fragment 配置来扩展它们的方法。然后,我们将提供一个详细的可扩展组件列表,以便开发者可以清楚地了解哪些组件可以被修改。
前置知识
为了更好地理解本文档,您可能需要先了解以下知识点:
- 关于 Fragment 配置: 请参阅 UI Fragments 小节。
- 关于 Appearance 的使用:请参阅 Appearance 小节。
- 关于布局模板:请参阅 布局模板 小节。
- 关于组件选择器语法: 请参阅 组件选择器 小节。
- 关于 Components API: 请参阅 API Reference 小节。
- 关于
@controller
指令: 请参阅 @controller 小节。 - 关于
@tooltip
指令: 请参阅 @tooltip 小节。 - 关于
@on
指令: 请参阅 @on 小节。
接下来的内容将运用上述提到的知识。在阅读本节之前,请先了解这些知识,这里将不再重复介绍。
可扩展组件概述
什么是可扩展组件:通过 Fragment 配置或 Component API,可以在功能和外观上进行自定义和扩展的组件。
什么是不可扩展组件:与可扩展组件相反,这些组件不能被修改。这些组件在 SDK 内部进行了深度封装,因此无法对其进行细粒度的拆解和组合。但是其中一些组件可以作为一个整体进行替换 (例如,Annotation 属性对话框)。后续章节将提供更多具体细节。
注意事项: 有些组件没有唯一的名称标识符,因此无法直接通过名称来指定目标组件。在这种情况下,可以使用 组件选择器语法。
可扩展组件
可扩展组件涵盖以下组件:
头部区域
标签组件
标签组件放在名称为 toolbar-tabs
的 div 容器中,而标签面板放在名称为 toolbar-tab-bodies
的 div 容器中。如果要新增或删除标签,需要同时修改这两个容器中组件。以下是一个示例 (点击 run
按钮查看效果):
在末尾增加标签
在这个示例中,我们在标签栏末尾插入了一个名为
custom-tab
的新标签,并同时插入了一个名为fv--custom-tab-body
的 div 组件。详情
html<html> </html> <script> var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION var CustomAppearance = UIExtension.appearances.adaptive.extend({ getDefaultFragments: function() { return [{ target: 'toolbar-tabs', action: FRAGMENT_ACTION.APPEND, template: '<gtab name="custom-tab" group="toolbar-tab" body="fv--custom-tab-body" text="Custom Tab" @aria:toolbar.tab></gtab>' }, { target: 'toolbar-tab-bodies', action: FRAGMENT_ACTION.APPEND, template: '<div name="fv--custom-tab-body" style="padding:2em 1em;">Custom Tab Body</div>' // 自定义标签面板不限制组件类型,但请确保名称与 `gtab` 中指定的 `body` 属性值相同。 }]; } }); var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: CustomAppearance, addons: [] // No addon is loaded }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
删除指定标签
在这个示例中,我们删除了
edit-tab
和fv--edit-tab-paddle
两个组件,然后edit
标签将不会在界面中显示。详情
html<html> </html> <script> var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION var CustomAppearance = UIExtension.appearances.adaptive.extend({ getDefaultFragments: function() { return [{ target: 'edit-tab,fv--edit-tab-paddle', // 多个组件名可以使用逗号隔开,这些组件将被一起删除。 action: FRAGMENT_ACTION.REMOVE }]; } }); var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: CustomAppearance, addons: [] // No addon is loaded }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
替换指定标签
在这个示例中,
edit-tab
标签被替换为一个自定义标签。详情
html<html> </html> <script> var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION var CustomAppearance = UIExtension.appearances.adaptive.extend({ getDefaultFragments: function() { return [{ target: 'edit-tab', action: FRAGMENT_ACTION.REPLACE, template: '<gtab name="custom-tab" group="toolbar-tab" body="fv--edit-tab-paddle" text="Custom Tab" @aria:toolbar.tab></gtab>' }, { target: 'fv--edit-tab-paddle', action: FRAGMENT_ACTION.REPLACE, template: '<div style="padding:2em 1em;">Custom Tab Body</div>' }]; } }); var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: CustomAppearance, addons: [] // No addon is loaded }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
在指定位置插入标签
以下示例在指定位置之后插入一个自定义标签。类似地,还有一个
FRAGMENT_ACTION.BEFORE
操作,表示组件将插入到指定目标组件之前。详情
html<html> </html> <script> var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION var CustomAppearance = UIExtension.appearances.adaptive.extend({ getDefaultFragments: function() { return [{ target: 'edit-tab', action: FRAGMENT_ACTION.AFTER, // 将自定义标签插入到 fv--edit-tab 之后。 template: '<gtab name="custom-tab" group="toolbar-tab" body="fv--custom-tab-body" text="Custom Tab" @aria:toolbar.tab></gtab>' }, { target: 'fv--edit-tab-paddle', // 请注意,这里的顺序并不重要,因为标签面板一次只显示一个,此操作仅用于演示目的。 action: FRAGMENT_ACTION.AFTER, template: '<div name="fv--custom-tab-body" style="padding:2em 1em;">Custom Tab Body</div>' }]; } }); var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: CustomAppearance, addons: [] // No addon is loaded }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
使用 Components API
以下示例使用了选择器语法和
Component.after
接口,向页面中插入更多的标签组件。详情
html<html> </html> <script> var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: UIExtension.appearances.adaptive, addons: [] // No addon is loaded }); pdfui.getRootComponent().then(function(root){ var editTab = root.querySelector('edit-tab') var editTabBody = root.querySelector('fv--edit-tab-paddle'); editTab.after('<gtab name="custom-tab" group="toolbar-tab" body="fv--custom-tab-body" text="Custom Tab" @aria:toolbar.tab></gtab>'); editTabBody.after('<div name="fv--custom-tab-body" style="padding:2em 1em;">Custom Tab Body</div>') }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
与使用 Fragment 配置编辑组件相比(其只能在初始化时编辑),使用 Components API 允许您在 PDFUI 初始化后的任何时候动态编辑组件。
标签面板组件
标签面板组件是在选择一个标签页后显示的面板。目前, SDK 默认的布局模板使用的标签面板组件都是 paddle
组件。使用这个组件的目的是在浏览器视图宽度较小时,可以在左右两侧显示按钮,用于滚动面板内的组件。
paddle 组件可以被视为一个普通的 ContainerComponent
。您可以使用 Fragment 配置通过 FRAGMENT_ACTION.APPEND
操作将子组件插入到其中,或者使用 Components API 插入子组件。下面将举例进行说明。
使用 Fragment 配置插入组件
该示例使用 Fragment 配置向 paddle 组件默认插入了一个手型按钮。
详情
html<html> </html> <script> var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION var CustomAppearance = UIExtension.appearances.adaptive.extend({ getDefaultFragments: function() { return [{ target: 'fv--edit-tab-paddle', action: FRAGMENT_ACTION.APPEND, template: '<ribbon-button text="toolbar.tooltip.hand.title" name="hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"></ribbon-button>' }]; } }); var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: CustomAppearance, addons: [] // No addon is loaded }); </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
使用 Components API 插入组件
该示例使用 Components API 插入一个手形按钮。效果与前一个示例相同。
详情
html<html> </html> <script> var libPath = window.top.location.origin + '/lib'; var pdfui = new UIExtension.PDFUI({ viewerOptions: { libPath: libPath, jr: { licenseSN: licenseSN, licenseKey: licenseKey } }, renderTo: document.body, appearance: UIExtension.appearances.adaptive, addons: [] // No addon is loaded }); pdfui.getRootComponent().then(function(root) { var editTabBody = root.querySelector('fv--edit-tab-paddle') editTabBody.append('<ribbon-button text="toolbar.tooltip.hand.title" name="hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"></ribbon-button>') }) </script>
json{ "iframeOptions": { "style": "height: 300px;" } }
在默认的布局模板中,我们在 paddle
组件中使用了 group-list
组件对子组件进行分组。在实际应用中,更常见的是对 group-list
组件进行编辑。以下示例将使用 group-list
和 group
进行说明:
详情
html
<html>
</html>
<script>
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: UIExtension.appearances.adaptive,
addons: [] // No addon is loaded
});
pdfui.getRootComponent().then(function (root) {
var editTabBody = root.querySelector('fv--edit-tab-paddle>@group-list')
editTabBody.append('<group name="custom-group" retain-count="1"><ribbon-button text="toolbar.tooltip.hand.title" name="hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"><ribbon-button text="toolbar.tooltip.hand.title" name="hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"></ribbon-button></group>')
})
</script>
json
{
"iframeOptions": {
"style": "height: 300px;"
}
}
在此示例中,我们插入了一个新的 custom-group
,其中 group 包含两个手形按钮组件,并设置在收缩后只显示一个组件。
标签面板中的按钮组件 (ribbon-button)
ribbon-button
是一个功能强大的组件,可以作为普通按钮或下拉组件使用。首先探讨一下将 ribbon-button 作为普通按钮的自定义方法。
作为普通按钮,ribbon-button
组件可以通过以下方式进行自定义:
- 文本内容: 按钮上显示的文本内容。
- 图标: 按钮图标,通过
icon-class
属性指定,需要额外的 CSS 样式。 - 工具提示: 当鼠标悬停在按钮上时,通过
@tooltip
指令和tooltip-title
属性实现显示的浮动工具提示内容。 - Controller: 通常用于业务实现,在自定义按钮上复用 SDK 内部实现逻辑。
以下是一个使用 SDK 内置 controller 实现业务逻辑复用的自定义按钮的示例:
详情
html
<html>
</html>
<script>
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'fv--edit-tab-paddle',
action: FRAGMENT_ACTION.APPEND,
template: '<ribbon-button text="Hand button" name="custom-hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"></ribbon-button>' // Reuse states:HandController
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 300px;"
}
}
从这个示例可以看出,在复用 controller 时,可以使用 @controller=""
指令来指定需要复用的 Controller
。除了 states:HandController
以外,还有许多其它的 controller 可以被复用。更多详情,请参阅 Controllers 小节。
除了可以使用自定义按钮复用逻辑外,还可以直接修改 SDK 的内置组件。主要的方法是通过配置 Fragment 实现。例如,以下示例充分展示了如何自定义 hand-tool
(ribbon-button) 的内容:
详情
html
<html>
</html>
<style>
.custom-hand-icon {
background-image: linear-gradient(180deg, rgba(0, 245, 12, 1) 0%, rgba(0, 212, 255, 1) 100%);
}
</style>
<script>
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'hand-tool',
action: FRAGMENT_ACTION.EXT,
config: {
'icon-class': 'custom-hand-icon',
text: 'Custom Button Text',
attrs: {
'@tooltip': '',
'tooltip-title': 'Custom Tooltip Title'
}
}
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 300px;"
}
}
工具栏标签面板中的下拉 (dropdown) 组件
在工具栏上,dropdown
组件通常与 ribbon-button
组件一起使用。但是,也可以单独使用它。这两种使用方法之间的唯一区别是显示效果。以下是一个 ribbon-button
和 dropdown
配合使用的示例:
详情
html
<html>
</html>
<script>
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'hand-tool',
action: FRAGMENT_ACTION.AFTER,
template: `
<ribbon-button name="dropdown-zoom" @var.self="$component" @tooltip >
<dropdown name="fv--inner-zoom-ribbon-dropdown" @aria:label.list="aria:labels.setzoom" icon-class="fv__icon-toolbar-zoom-in" class="fv__ui-dropdown-hide-text" selected="0" @on.selected="self.select($args[0])">
<dropdown-button name="dropdown-zoom-in" action="zoomin" @controller="zoom:DropdownZoomInAndOutController" icon-class="fv__icon-toolbar-zoom-in" ribbon-icon="fx-icon-ribbon_home_zoomin-32" tooltip-title="toolbar.buttons.zoomin" tabindex="0">toolbar.buttons.zoomin</dropdown-button>
<dropdown-button name="dropdown-zoom-out" action="zoomout" @controller="zoom:DropdownZoomInAndOutController" icon-class="fv__icon-toolbar-zoom-out" ribbon-icon="fx-icon-ribbon_home_zoomout-32" tooltip-title="toolbar.buttons.zoomout" tabindex="0">toolbar.buttons.zoomout</dropdown-button>
</dropdown>
</ribbon-button>
`
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 300px;"
}
}
有关更多业务组件,您可以参阅 预配置组件 小节。本节描述了多个业务组件的默认配置,我们可以参考这些配置项使用 Fragment 配置来进行调整。
左侧面板
在默认布局中,左侧面板是使用 sidebar
组件构建的,其子组件对应不同业务模块封装的 sidebar-panel
组件。
在本节中,我们将学习左侧面板的一些自定义方式和细节。
创建一个 sidebar-panel
以下是一个包含基本属性的 sidebar-panel
组件模板:
html
<sidebar-panel
class="custom-sidebar-panel"
icon-class="custom-sidebar-icon"
title="Custom"
>
</sidebar-panel>
如果需要,您可以向其添加一些指令,比如 @tooltip
指令:
html
<sidebar-panel
class="custom-sidebar-panel"
icon-class="custom-sidebar-icon"
title="Custom"
@tooltip
tooltip-placement="right"
tooltip-title="Custom Sidebar"
>
</sidebar-panel>
如果您需要监听 active
事件(当 sidebar-panel 被展开时),您可以使用 @on.active
指令进行监听。请参考以下示例:
js
class CustomSidebarPanel extends SeniorComponentFactory.createSuperClass({
template: `
<sidebar-panel
class="custom-sidebar-panel"
icon-class="custom-sidebar-icon"
title="Custom"
@tooltip
tooltip-placement="right"
tooltip-title="Custom Sidebar"
@on.active="$component.handleActiveEvent()"
>
</sidebar-panel>
`
}) {
static getName() {
return 'custom-sidebar-panel'
}
handleActiveEvent() {
console.log('hello world')
}
}
以下是一个可运行的示例:
详情
html
<html>
</html>
<style>
.custom-sidebar-icon {
background-image: linear-gradient(180deg, rgba(0, 245, 12, 1) 0%, rgba(0, 212, 255, 1) 100%);
width: 24px;
height: 24px;
margin-top: 12px;
margin-left: 4px;
}
</style>
<script>
const {modular, SeniorComponentFactory} = UIExtension;
class CustomSidebarPanel extends SeniorComponentFactory.createSuperClass({
template: `
<sidebar-panel
class="custom-sidebar-panel"
icon-class="custom-sidebar-icon"
title="Custom"
@tooltip
tooltip-placement="right"
tooltip-title="Custom Sidebar"
@on.active="$component.handleActiveEvent()"
>
<div>Custom Sidebar Panel Body</div>
</sidebar-panel>
`
}) {
static getName() {
return 'custom-sidebar-panel'
}
handleActiveEvent() {
console.log('hello world')
}
}
modular.module('custom', []).registerComponent(CustomSidebarPanel);
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: '@sidebar',
action: FRAGMENT_ACTION.APPEND,
template: `
<custom:custom-sidebar-panel></custom:custom-sidebar-panel>
`
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 600px;"
}
}
删除一个 sidebar-panel
如果您想要删除 SDK 中内置的 sidebar-panel
组件,我们建议使用 Fragment 配置而不是 Components API 进行删除,除非确实有必要。这是因为初始化 sidebar-panel
组件可能需要比较多的资源,通过 Fragment 配置进行删除可以避免不必要的初始化。
js
{
target: '@layer-sidebar-panel',
action
:
UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE
}
自定义 SDK 内置的 sidebar-panel
组件
1. commentlist-sidebar-panel
在 commentlist 侧边栏面板中,可以自定义 CommentCardComponent 和 ReplyCardComponent。但与其他组件不同的是,它们是根据文档中当前的注释类型和数量动态生成的,无法通过 Fragment 配置修改其细节。不过,我们提供了事件,允许您在组件创建或删除时获取组件对象,然后使用 Components API 修改这些组件的细节。
以下是相关的事件说明:
UIExtension.UIEvents.appendCommentListComment
: CommentCardComponent 组件被插入时触发,事件回调可以获取到commentCardComponent
和annot
两个参数。UIExtension.UIEvents.destroyCommentListComment
: CommentCardComponent 组件被销毁时触发,回调参数和appendCommentListComment
事件相同UIExtension.UIEvents.appendCommentListReply
: ReplyCardComponent 组件被插入时触发,事件回调可以获取到replyCardComponent
和replyAnnot
两个参数。UIExtension.UIEvents.destroyCommentListReply
: ReplyCardComponent 组件被销毁时触发,回调参数和appendCommentListReply
事件相同。
您可以参考 API Reference 以获取使用信息:
2. thumbnail-sidebar-panel
关于 thumbnail-sidebar-panel,请参阅: 自定义缩略图。
3. bookmark-sidebar-panel
关于 bookmark-sidebar-panel,请参阅:自定义书签。
其它
除了上面提到的三个之外,layer-sidebar-panel
、 attachment-sidebar-panel
和 field-sidebar-panel
目前暂未提供自定义功能。
右键菜单
右键菜单是指基于 ContextMenuComponent
实现的组件。所有可自定义的右键菜单都是基于相同原理实现的:
每个具有特定功能的右键菜单都有一个固定的名称,替换右键菜单需要通过指定名称实现。替换后,名称不可更改,因为这可能导致右键菜单无法显示或覆盖其他右键菜单,影响其他功能的菜单显示。
通过 Fragment 配置和 Component API,可以添加、删除和替换右键菜单项。
开头,末尾或者连续的
contextmenu-separator
分割线会自动隐藏,一般不需要特别对其做显示隐藏控制。
接下来,将逐一介绍每个功能模块的右键菜单。
1. PDF 页面右键菜单
请参阅 自定义页面右键菜单 小节。
2. Annotation 右键菜单
请参阅 自定义 Annotation 右键菜单 小节。
需要注意的是,由于 Annotation 属性对话框不支持自定义,因此在实现自定义属性对话框时,需要替换 <contextmenu-item-properties>
的实现。您可以参考以下示例:
详情
html
<html>
</html>
<style>
.custom-sidebar-icon {
background-image: linear-gradient(180deg, rgba(0, 245, 12, 1) 0%, rgba(0, 212, 255, 1) 100%);
width: 24px;
height: 24px;
margin-top: 12px;
margin-left: 4px;
}
</style>
<script>
const {modular, SeniorComponentFactory} = UIExtension;
class CustomAnnotationPropertiesDialog extends SeniorComponentFactory.createSuperClass({
template: `
<layer
class="center"
@var.self="$component"
>
<layer-header @draggable="{'type': 'parent'}" title="Annotation Properties"></layer-header>
<layer-view style="padding: 1em">
<form-group label="Opacity">
<slider @model="self.properties.opacity" min="0" max="100" step="1" @on.change="self.updateOpacity($args[2])"></slider>
</form-group>
</layer-view>
</layer>
`
}) {
static getName() {
return 'annotation-properties-dialog'
}
init() {
super.init();
this.properties = {
opacity: 100
};
}
updateOpacity(newOpacity) {
this.getPDFUI().getAllActivatedElements().then(([element]) => {
element.annot.setOpacity(newOpacity / 100);
})
}
doShown() {
super.doShown();
this.getPDFUI().getAllActivatedElements().then(([element]) => {
this.properties.opacity = element.annot.getOpacity() * 100;
this.digest();
});
}
}
class CustomAnnotationPropertiesContextmenuItem extends SeniorComponentFactory.createSuperClass({
template: `<contextmenu-item @on.click="$component.showPropertiesDialog()">Show Properties</contextmenu-item>`
}) {
static getName() {
return 'contextmenu-item-show-properties'
}
showPropertiesDialog() {
const dialog = this.getRoot().querySelector('@custom:annotation-properties-dialog');
if (dialog) {
dialog.show();
}
}
}
modular.module('custom', [])
.registerComponent(CustomAnnotationPropertiesDialog)
.registerComponent(CustomAnnotationPropertiesContextmenuItem)
;
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'template-container',
action: FRAGMENT_ACTION.APPEND,
template: `
<custom:annotation-properties-dialog></custom:annotation-properties-dialog>
`
}, {
target: '@contextmenu-item-properties',
action: FRAGMENT_ACTION.REPLACE,
template: `
<custom:contextmenu-item-show-properties></custom:contextmenu-item-show-properties>
`
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 600px;"
}
}
3. 其它右键菜单
自定义其它右键菜单与上述的页面右键菜单和 Annotation 右键菜单类似。您可以参考这些文档进行自我扩展。相关的菜单组件模板可以参考 预配置组件 小节。
模态框
如果是 SDK 内部的弹出窗口,包括 alert、prompt、confirm 以及 loading 加载遮罩层,我们可以通过 Viewer UI 定义这些由 SDK 内部触发显示的组件。具体用法,请参阅 Viewer UI 小节。
控制器 (Controllers) 复用
下面是一个使用 @controller
指令语法的列表,列举了当前 SDK 可复用的 controller 实现。其中冒号之前是模块名,冒号之后是 controller 名。下面将为您详解:
UIExtension 内置 controller
获取:
内置 controller 可以直接通过 UIExtension.modular.module('module name').getController('controller name')
来获取类。
列表:
states:HandController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_HAND
。marquee:MarqueeToolController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_MARQUEE
。loupe:LoupeController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_LOUPE
。states:SnapshotToolController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_SNAPSHOT_TOOL
。file:DownloadFileController
: 用于下载当前打开的文档。zoom:ZoomInAndOutController
: 控制文档视图缩放,需要与action
属性搭配使用。可选值有:action="zoomin"
和action="zoomout"
。pagemode:SinglePageModeController
: 切换页面模式为单页模式。pagemode:ContinuousPageModeController
: 切换页面模式为连续页模式。pagemode:FacingPageModeController
: 切换页面模式为对开模式。pagemode:ContinuousFacingPageModeController
: 切换页面模式为连续对开模式。states:CreateTextController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_TEXT
。states:CreateFileAttachmentController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FILE_ATTACHMENT
。states:CreateHighlightController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_HIGHLIGHT
。states:CreateStrikeoutController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_STRIKE_OUT
。states:CreateUnderlineController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_UNDERLINE
。states:CreateSquigglyController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_SQUIGGLY
。states:CreateReplaceController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_REPLACE
。states:CreateCaretController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CARET
。states:CreateTypewriterController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_TYPEWRITER
。states:CreateCalloutController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FREETEXT_CALLOUT
。states:CreateTextboxController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FREETEXT_BOX
。states:CreateAreaHighlightController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_AREA_HIGHLIGHT。
states:CreatePencilController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.PENCIL
。states:EraserController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_ERASER
。states:CreateLinkController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_LINK
。states:CreateImageController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_IMAGE
。zoom:DropdownZoomInAndOutController
: 和zoom:ZoomInAndOutController
功能相同, 但是只能在 dropdown 子组件中使用。zoom:ZoomActionController
: 控制文档视图缩放,与zoom:ZoomInAndOutController
不同之处在于它需要指定目标缩放比例( 非数字):action='fitHeight'
,action='fitWidth'
,action='fitVisible'
。gotoview:GotoFirstPageController
: 跳转到第一页。gotoview:GotoPrevPageController
: 跳转到上一页。gotoview:GotoNextPageController
: 跳转到下一页。gotoview:GotoLastPageController
: 跳转到最后一页。states:CreateSquareController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_SQUARE
。states:CreateCircleController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CIRCLE
。states:CreatePolygonController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYGON
。states:CreatePolygonCloudController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYGON_CLOUD
。states:CreateArrowController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_ARROW
。states:CreateLineController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_LINE
。states:CreatePolylineController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYLINE
。distance:CreateDistanceController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_DISTANCE
。distance:CreatePerimeterController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_PERIMETER
。distance:CreateAreaController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_AREA
。distance:CreateCircleAreaController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CIRCLE_AREA
。comment-list:ExportCommentController
: 将当前文档的注释导出为指定格式,格式由 format 属性指定:format="XFDF"
, 支持 XFDF, FDF, JSON 三种格式。text-sel:CopySelectedTextController
: 复制选中文本。text-sel:CreateTextHighlightOnSelectedTextController
: 在选中的文本范围内创建文本高亮注释。text-sel:CreateStrikeoutOnSelectedTextController
: 在选中的文本范围内创建 Strikeout 注释。text-sel:CreateUnderlineOnSelectedTextController
: 在选中的文本范围内创建 Underline 注释。text-sel:CreateBookmarkOnSelectedTextController
: 将选中的文本添加到书签列表中。states:RibbonSelectTextImageController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_TEXT_IMAGE
。states:RibbonSelectTextAnnotationController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_ANNOTATION
。change-color:ChangeColorController
: 用于切换文档背景色。comment-list:ImportCommentButtonController
: 用于向文档中导入注释数据。states:SelectTextImageController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_TEXT_IMAGE
。states:SelectAnnotationController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_ANNOTATION
。zoom:ContextMenuZoomActionController
: 控制文档视图缩放,并需要指定action
属性。可选值有:fitWidth
,fitHeight
,fitVisible
以及数字。ui-rotation:RotateRightController
: 控制文档视图向右旋转90度。ui-rotation:RotateLeftController
: 控制文档视图向左旋转90度。annot-opr:ShowAnnotReplyController
: 用于打开左侧栏 commentlist 面板,定位所选注释,并聚焦到回复输入框。annot-opr:DeleteAnnotController
: 删除选中的注释。annot-opr:ShowAnnotPropertiesController
: 显示注释属性对话框。annot-opr:SetPropsDefault
: 将当前注释属性设置为默认属性,用户下次创建注释时将使用该默认值。
UIExtension Addon 中的 controller
获取:
获取 Addons 中的 controller class 和获取 UIExtension 中内置 controller class 的方法相同,但是请确保这些 Addons 在获取之前已经加载完成。请查阅 如何使用 addons 中的 controller, 了解 controller 在插件中使用的场景及限制。
列表:
- page-template addon:
page-template:ShowPageTemplateDialogController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER
。
- form-designer addon:
form-designer:CreatePushButtonController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_PUSH_BUTTON
。form-designer:CreateCheckBoxController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_CHECK_BOX
。form-designer:CreateRadioButtonController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_RADIO_BUTTON
。form-designer:CreateComboBoxController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_COMBO_BOX
。form-designer:CreateListBoxController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_LIST_BOX
。form-designer:CreateTextController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_TEXT
。form-designer:CreateSignController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_SIGNATURE
。form-designer:CreateImageController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_IMAGE
。form-designer:CreateDateController
: 切换当前 StateHandler 为STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_DATE
。
- page-editor addon:
page-editor:EditObjectController
: 切换当前 StateHandler 为 "页面对象编辑" 工具,页面对象包含文本、图像、形状和渐变。page-editor:AddImageAdvController
: 切换当前 StateHandler 为 "从文件添加图像" 工具。page-editor:AddShapesController
: 切换当前 StateHandler 为 "创建图形" 工具。page-editor:AddTextController
: 切换当前 StateHandler 为 "添加文本" 工具。
- fullscreen addon:
full-screen:FullscreenController
: 切换全屏模式。
- print addon:
print:ShowPrintDialogController
: 显示打印对话框。
- file-property addon:
fpmodule:FileInfoCallbackController
: 显示文档属性对话框。
- h-continuous addon:
h-continuous:HContinuousViewModeController
: 切换页面模式为横向连续页模式。
- export-form addon:
export-form-module:ExportToXMLController
: 将当前文档的表单导出为 XML 格式文件。export-form-module:ExportToFDFController
: 将当前文档的表单导出为 FDF 格式文件。export-form-module:ExportToXFDFController
: 将当前文档的表单导出为 XFDF 格式文件。export-form-module:ExportToCSVController
: 将当前文档的表单导出为 CSV 格式文件。export-form-module:ExportToTXTController
: 将当前文档的表单导出为 TXT 格式文件。
- comparison addon:
comparison:ShowCompareFileDialogButtonController
: 显示文档对比对话框。
- redaction addon:
redaction:RedactionTextAndImageController
: 切换当前 StateHandler 为创建标记文本、图像的 Redaction 工具。redaction:RedactionController
: 切换当前 StateHandler 为创建标记区域的 Redaction 工具。redaction:RedactionPageController
: 切换当前 StateHandler 为创建标记页面的 Redaction 工具。
通过这些 controller,我们可以在重写组件的同时复用 SDK 内置的实现逻辑。
复用控制器示例代码
以 states:HandController
为例,其允许将当前的 StateHandler 工具切换为手型工具,并且可以判断当前是否为手型工具来激活/取消激活组件:
详情
html
<html>
</html>
<style>
.custom-hand-icon {
background-image: linear-gradient(180deg, rgba(0, 245, 12, 1) 0%, rgba(0, 212, 255, 1) 100%);
}
</style>
<script>
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'hand-tool',
action: FRAGMENT_ACTION.REPLACE,
template: `<xbutton @tooltip tooltip-title="toolbar.tooltip.hand.title" name="hand-tool" icon-class="fv__icon-toolbar-hand" @controller="states:HandController"></xbutton>`
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 600px;"
}
}
当然, 并非所有的 controller 都像 states:HandController
那样简单。以下列出了几个比较特殊的 controller,在使用它们的时候,要按照示例中提供的方法使用:
详情
html
<style>
.fv__ui-paddle-horizontal .fv__ui-paddle-content {
display: flex;
align-items: center;
}
.custom-change-color-panel {
display: inline-flex;
align-items: center;
}
</style>
<script>
var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION
var CustomAppearance = UIExtension.appearances.adaptive.extend({
getDefaultFragments: function () {
return [{
target: 'fv--view-tab-paddle',
action: FRAGMENT_ACTION.APPEND,
template: '<group-list name="custom-component-group-list"></group-list>'
}, {
target: 'custom-component-group-list',
action: FRAGMENT_ACTION.APPEND,
template: `
<group>
<div class="custom-change-color-panel" name="change-color-panel" @controller="change-color:ChangeColorController as ctrl" @var.self="$component" >
<xbutton
@foreach="color in colors track by background"
@class="{'fv__ui-change-color-dropdown-color-round': true, 'moon': !!color.type, 'selected': selectedIndex === $index}"
@sync.attr.style="color.type === 'moon' ? '' : ('background-color:' + color.background)"
@on.click="ctrl.changeColor(color, $index)"
@tooltip
tooltip-title="@{color|json}"
></xbutton>
</div>
</group>
`
}, {
target: 'custom-component-group-list',
action: FRAGMENT_ACTION.APPEND,
template: `
<group>
<xbutton @controller="zoom:ZoomInAndOutController" action="zoomin" icon-class="fv__icon-toolbar-zoom-in"></xbutton>
</group>
`
}, {
target: 'custom-component-group-list',
action: FRAGMENT_ACTION.APPEND,
template: `
<group>
<dropdown name="fv--inner-zoom-ribbon-dropdown" @aria:label.list="aria:labels.setzoom" icon-class="fv__icon-toolbar-zoom-in" class="fv__ui-dropdown-hide-text" selected="0" @on.selected="self.select($args[0])">
<xbutton name="dropdown-zoom-in" action="zoomin" @controller="zoom:DropdownZoomInAndOutController" icon-class="fv__icon-toolbar-zoom-in" ribbon-icon="fx-icon-ribbon_home_zoomin-32" tooltip-title="toolbar.buttons.zoomin">toolbar.buttons.zoomin</xbutton>
<xbutton name="dropdown-zoom-out" action="zoomout" @controller="zoom:DropdownZoomInAndOutController" icon-class="fv__icon-toolbar-zoom-out" ribbon-icon="fx-icon-ribbon_home_zoomout-32" tooltip-title="toolbar.buttons.zoomout">toolbar.buttons.zoomout</xbutton>
<xbutton name="dropdown-zoom-fitpage" action="fitHeight" @controller="zoom:ZoomActionController" icon-class="fv__icon-toolbar-fit-page" ribbon-icon="fx-icon-ribbon_home_fitpage-32" tooltip-title="toolbar.buttons.fitHeight">toolbar.buttons.fitHeight</xbutton>
<xbutton name="dropdown-zoom-fitwidth" action="fitWidth" @controller="zoom:ZoomActionController" icon-class="fv__icon-toolbar-fit-width" ribbon-icon="fx-icon-ribbon_home_fitwidth-32" tooltip-title="toolbar.buttons.fitWidth">toolbar.buttons.fitWidth</xbutton>
<xbutton name="dropdown-zoom-fitvisible" action="fitVisible" @controller="zoom:ZoomActionController" icon-class="fv__icon-toolbar-fit-visible" ribbon-icon="fx-icon-ribbon_home_visible-32" tooltip-title="toolbar.buttons.fitVisible">toolbar.buttons.fitVisible</xbutton>
<li class="fv__ui-dropdown-separator"></li>
<xbutton @foreach="scale in $pdfui.customScalingValues" @setter.text="scale|percent" @controller="zoom:ZoomToScaleValueController"></xbutton>
</dropdown>
</group>
`
}, {
target: 'custom-component-group-list',
action: FRAGMENT_ACTION.APPEND,
// Note that comment-list:ImportCommentButtonController must be used together with the file-selector component.
template: `
<group>
<file-selector
@controller="comment-list:ImportCommentButtonController"
name="commentlist-import-comment"
icon-class="fv__icon-sidebar-import-comment"
@trigon.close.disable
@trigon.open.enable accept=".fdf,.xfdf,.json"
>sidebar.commentlist.dropdown.import-comment</file-selector>
</group>
`
}];
}
});
var libPath = window.top.location.origin + '/lib';
var pdfui = new UIExtension.PDFUI({
viewerOptions: {
libPath: libPath,
jr: {
licenseSN: licenseSN,
licenseKey: licenseKey
}
},
renderTo: document.body,
appearance: CustomAppearance,
addons: [] // No addon is loaded
});
</script>
json
{
"iframeOptions": {
"style": "height: 600px;"
}
}