# Extensible Components and Usage Guide

This document provides detailed information and usage guide for extensible components, listing the methods to extend extensible components and helping developers understand and use the custom features of components better. In the following document, we will first introduce the concept of extensible components and the methods to extend them using Component API and Fragment configuration. Then, we will provide a detailed list of extensible components, so that developers can have a clear understanding of which components can be modified.

# Prerequisites

To better understand this document, you may need to be familiar with the following concepts:

  1. For Fragment configuration: please refer to UI Fragments section.
  2. For Appearance usage: please refer to Appearance section.
  3. For layout templates: please refer to Layout Template section.
  4. For component selector syntax: please refer to Component Selector section.
  5. For Component API: please refer to the API Reference (opens new window).
  6. For the @controller directive: please refer to the @controller directive section.
  7. For the @tooltip directive: please refer to the @tooltip directive section.
  8. For the @on directive: please refer to the @on directive section.

The upcoming content will utilize the knowledge mentioned above. Please familiarize yourself with them before reading this document, as they will not be repeated here.

# Overview of Extensible Components

  1. What are extensible components: Components that can be customized and extended in terms of functionality and appearance through Fragment configuration or Component API.
  2. What are non-extensible components: The opposite of extensible components, which cannot be modified. These components are deeply encapsulated within the SDK, so they cannot be broken down and combined at a granular level. However, some of them can be replaced as a whole (e.g., Annotation Property Dialog). More specific details will be provided in subsequent sections.
  3. Note: Some components do not have unique name identifiers, so they cannot be directly targeted by name. In such cases, component selector syntax can be used.

# Extensible Components

# Header Area

# Tab Component

The tab component is wrapped in a div container named toolbar-tabs, while the tab panel is wrapped in a div container named toolbar-tab-bodies. If you want to add or remove tabs, you need to modify both of these containers. Here is an example (click the run button to see the effect):

  1. Add a tab at the end

    In this example, we inserted a new tab called custom-tab at the end of the tab bar, and also inserted a div component called fv--custom-tab-body.

  2. Remove a specific tab

    In this example, we remove both the edit-tab and fv--edit-tab-paddle components, and then the edit tab will not be visible in the view.

  3. Replace a specific tab

    In this example, the edit-tab tab is replaced with a custom tab.

  4. Insert a tab at a specified position

    The following example inserts a custom tab after a specified position. Similarly, there is a FRAGMENT_ACTION.BEFORE operation, which means that the component is inserted before the specified target component.

  5. Use Component API

    The following example uses selector syntax and the Component.after method to insert more tab components into the page.

    Compared to editing components with the Fragment configuration, which can only be done during initialization, using the Component API allows you to dynamically edit components at any time after PDFUI initialization.

# Tab Panel Components

The tab panel component is the panel displayed after selecting a tab. Currently, the default layout template used by the SDK uses the paddle component as the tab panel component. The purpose of using this component is to display buttons on the left and right sides when the browser view width is small, which can be used to scroll the components within the panel.

The paddle component can be seen as a normal ContainerComponent. You can use the Fragment configuration to insert child components into it using the FRAGMENT_ACTION.APPEND operation, or you can use the Component API to insert child components. The following examples will illustrate this.

  1. Insert components using the Fragment Configuration

    This example uses the Fragment configuration to insert a hand button into the paddle component by default.

  2. Insert components using the Component API

    This example uses the Component API to insert a hand button. The effect will be the same as the previous example.

In the default layout template, we use the group-list component to group the child components within the paddle component. In practice, it is more common to edit the group-list component. The following example will use group-list and group to illustrate:

In this example, we insert a new custom-group where the group contains two hand button components, and set it to only display one component when collapsed.

# Button Components in Tab Panels (ribbon-button)

The ribbon-button is a powerful component that can be used as a regular button or as a dropdown component. Let's first explore the custom methods for using ribbon-button as a regular button.

As a regular button, the ribbon-button component can be customized with the following:

  1. Text Content: the text displayed on the button.

  2. Icon: the button icon, specified through the icon-class attribute, which requires additional CSS styles.

  3. Tooltips: the floating tooltip content displayed when the mouse hovers over the button, implemented through the @tooltip directive and tooltip-title attribute.

  4. Controller: usually used for business implementation, and generally used to reuse internal SDK implementation logic on custom buttons.

The following is an example of a custom button that reuses business logic using the SDK's built-in controller:

From this example, we can see that when reusing a controller, the @controller="" directive can be used to specify the Controller that needs to be reused. Apart from states:HandController, there are many other controllers that can be reused. For more details, please refer to the Controllers section.

In addition to reusing logic with custom buttons, you can also directly modify the built-in components of the SDK. The main way to do this is through configuring Fragments. For example, the following example fully demonstrates how to customize the content of the hand-tool (ribbon-button):

On the toolbar, the dropdown component is usually used in conjunction with the ribbon-button component. However, you can also use it separately. The only difference between these two usage methods is the display effect. The following is an example of using ribbon-button and dropdown together:

For more business components, you can refer to the pre-configured components section. This section describes the default configurations of multiple business components, and we can adjust them using Fragment configuration based on these configuration options.

# Left Panel

In the default layout, the left panel is constructed using the sidebar component, and its child components correspond to different business modules encapsulated in the sidebar-panel component.

In this section, we will learn about some customization methods and details of the left panel.

# Create a sidebar-panel

Here is a template for the sidebar-panel component that includes basic properties:

<sidebar-panel
    class="custom-sidebar-panel"
    icon-class="custom-sidebar-icon"
    title="Custom"
>
</sidebar-panel>

If needed, you can add directives to it, such as the @tooltip directive:

<sidebar-panel
    class="custom-sidebar-panel"
    icon-class="custom-sidebar-icon"
    title="Custom"
    @tooltip
    tooltip-placement="right" 
    tooltip-title="Custom Sidebar"
>
</sidebar-panel>

If you need to listen to the active event (when the sidebar-panel is expanded), you can use the @on.active directive to listen to it. Please refer to the following example:

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')
    }
}

Finally, let's take a look at a runnable example:

# Delete a sidebar-panel

If you want to delete the built-in sidebar-panel component in the SDK, we recommend using Fragment configuration instead of the Component API to delete it, unless it is necessary. This is because initializing a sidebar-panel component may require a significant amount of resources, and deleting it through Fragment configuration can avoid unnecessary initialization.

{
    target: '@layer-sidebar-panel'action: UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE
}

# Customize the internal components of the built-in sidebar-panel in the SDK

# 1. commentlist-sidebar-panel

In the commentlist sidebar panel, the CommentCardComponent and ReplyCardComponent can be customized. However, unlike other components, they are dynamically generated based on the current type and number of comments in the document, and their details cannot be modified through Fragment configuration. But we provide events that allow you to obtain the component objects when they are created or deleted, and then modify the details of these components using the Component API.

Here are the descriptions of the relevant events:

1). UIExtension.UIEvents.appendCommentListComment: Triggered when the CommentCardComponent component is inserted. The event callback can obtain the commentCardComponent and annot parameters.

2). UIExtension.UIEvents.destroyCommentListComment: Triggered when the CommentCardComponent component is destroyed. The callback parameters are the same as those of the appendCommentListComment event.

3). UIExtension.UIEvents.appendCommentListReply: Triggered when the ReplyCardComponent component is inserted. The event callback can obtain the replyCardComponent and replyAnnot parameters.

4). UIExtension.UIEvents.destroyCommentListReply: Triggered when the ReplyCardComponent component is destroyed. The callback parameters are the same as those of the appendCommentListReply event.

You can refer to the API Reference for usage information:

1). CommentCardComponent (opens new window)

2). ReplyCardComponent (opens new window)

# 2. thumbnail-sidebar-panel

You can refer to the section: Customize Thumbnail

# 3. bookmark-sidebar-panel

You can refer to the section: Custom Bookmark

# 4. Others

Apart from the three mentioned above, layer-sidebar-panel, attachment-sidebar-panel, and field-sidebar-panel currently do not provide customization capabilities.

# Context Menu

The context menu refers to the component implemented based on ContextMenuComponent (opens new window). All customizable context menus are implemented based on the same principle:

  1. Each context menu for a specific functionality has a fixed name, and replacing a context menu requires specifying the name. After replacement, the name cannot be changed, as it may cause the context menu to not be displayed or overwrite other context menus, affecting the display of other functionalities.

  2. Context menu items can be added, deleted, and replaced through Fragment configuration and the Component API.

  3. The contextmenu-separator separators at the beginning, end, or in a continuous sequence will be automatically hidden and generally do not need to be specifically controlled for showing or hiding.

Next, the context menus for each functional module will be introduced one by one.

# 1. PDF Page Context Menu

Please refer to the section Customizing Page Context Menu.

# 2. Annotation Context Menu

Please refer to the section Customizing Annotation Context Menu.

It should be noted that since the Annotation property dialog does not support customization, when implementing a custom property dialog, the implementation of <contextmenu-item-properties> needs to be replaced. You can refer to the following example:

# 3. Other Context Menus

Customizing other context menus is similar to the Page context menu and Annotation context menu described above. You can refer to these documents for self-expansion. The templates for relevant menu components can be found in the section Pre-configured Components.

# Modals

If it is a pop-up within the SDK, including alert, prompt, confirm, and loading overlay, we can define these components triggered by the SDK internally through Viewer UI. For specific usage, please refer to the section Viewer UI.

# Controller Reusability

Below is a list utilizing the @controller directive syntax, enumerating the currently reusable controller implementations within the SDK. Module names are listed before the colon, and controller names are listed after the colon.

# Built-in Controllers in UIExtension

Built-in controllers can be directly accessed using UIExtension.modular.module('module name').getController('controller name') to retrieve the class.

  1. states:HandController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_HAND.
  2. marquee:MarqueeToolController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_MARQUEE.
  3. loupe:LoupeController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_LOUPE.
  4. states:SnapshotToolController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_SNAPSHOT_TOOL.
  5. file:DownloadFileController: Used to download the currently open document.
  6. zoom:ZoomInAndOutController: Controls document view zooming, and needs to be used with the action attribute. Optional values are: action="zoomin" and action="zoomout".
  7. pagemode:SinglePageModeController: Switches page mode to single page mode.
  8. pagemode:ContinuousPageModeController: Switches page mode to continuous page mode.
  9. pagemode:FacingPageModeController: Switches page mode to facing page mode.
  10. pagemode:ContinuousFacingPageModeController: Switches page mode to continuous facing page mode.
  11. states:CreateTextController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_TEXT.
  12. states:CreateFileAttachmentController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FILE_ATTACHMENT.
  13. states:CreateHighlightController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_HIGHLIGHT.
  14. states:CreateStrikeoutController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_STRIKE_OUT.
  15. states:CreateUnderlineController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_UNDERLINE.
  16. states:CreateSquigglyController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_SQUIGGLY.
  17. states:CreateReplaceController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_REPLACE.
  18. states:CreateCaretController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CARET.
  19. states:CreateTypewriterController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_TYPEWRITER.
  20. states:CreateCalloutController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FREETEXT_CALLOUT.
  21. states:CreateTextboxController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_FREETEXT_BOX.
  22. states:CreateAreaHighlightController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_AREA_HIGHLIGHT.
  23. states:CreatePencilController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.PENCIL.
  24. states:EraserController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_ERASER.
  25. states:CreateLinkController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_LINK.
  26. states:CreateImageController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_IMAGE.
  27. zoom:DropdownZoomInAndOutController: Same as zoom:ZoomInAndOutController, but can only be used in dropdown subcomponents.
  28. zoom:ZoomActionController: Controls document view zooming, and is different from zoom:ZoomInAndOutController in that it needs to specify the target zoom level (non-numeric): action='fitHeight', action='fitWidth', action='fitVisible'.
  29. gotoview:GotoFirstPageController: Jumps to the first page.
  30. gotoview:GotoPrevPageController: Jumps to the previous page.
  31. gotoview:GotoNextPageController: Jumps to the next page.
  32. gotoview:GotoLastPageController: Jumps to the last page.
  33. states:CreateSquareController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_SQUARE.
  34. states:CreateCircleController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CIRCLE.
  35. states:CreatePolygonController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYGON.
  36. states:CreatePolygonCloudController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYGON_CLOUD.
  37. states:CreateArrowController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_ARROW.
  38. states:CreateLineController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_LINE.
  39. states:CreatePolylineController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_POLYLINE.
  40. distance:CreateDistanceController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_DISTANCE.
  41. distance:CreatePerimeterController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_PERIMETER.
  42. distance:CreateAreaController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_AREA.
  43. distance:CreateCircleAreaController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.STATE_HANDLER_CREATE_CIRCLE_AREA.
  44. comment-list:ExportCommentController: Exports the comments of the current document in a specified format, with the format specified by the format attribute: format="XFDF", which supports XFDF, FDF, and JSON formats.
  45. text-sel:CopySelectedTextController: Copies the selected text.
  46. text-sel:CreateTextHighlightOnSelectedTextController: Creates a text highlight annotation within the selected text range.
  47. text-sel:CreateStrikeoutOnSelectedTextController: Creates a Strikeout annotation within the selected text range.
  48. text-sel:CreateUnderlineOnSelectedTextController: Creates a Underline annotation within the selected text range.
  49. text-sel:CreateBookmarkOnSelectedTextController: Adds the selected text to the bookmark list.
  50. states:RibbonSelectTextImageController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_TEXT_IMAGE.
  51. states:RibbonSelectTextAnnotationController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_ANNOTATION.
  52. change-color:ChangeColorController: Used to change the document background color.
  53. comment-list:ImportCommentButtonController: Used to import comment data into the document.
  54. states:SelectTextImageController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_TEXT_IMAGE.
  55. states:SelectAnnotationController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_SELECT_ANNOTATION.
  56. zoom:ContextMenuZoomActionController: Controls document view zooming, and needs to specify the action attribute. Available values are: fitWidth, fitHeight, fitVisible, and numeric values.
  57. ui-rotation:RotateRightController: Controls document view rotation to the right by 90 degrees.
  58. ui-rotation:RotateLeftController: Controls document view rotation to the left by 90 degrees.
  59. annot-opr:ShowAnnotReplyController: Used to open the commentlist on the left panel, locate the selected annotation, and focus on the reply input box.
  60. annot-opr:DeleteAnnotController: Deletes the selected annotation.
  61. annot-opr:ShowAnnotPropertiesController: Displays the annotation properties dialog.
  62. annot-opr:SetPropsDefault: Sets the current annotation properties as default, which will be used for creating annotations next time.

# Controllers in UIExtension Addons

To retrieve the controller classes in Addons, use the same method as retrieving the built-in controller classes in UIExtensions, but make sure that the Addons have been loaded before retrieval.

  1. page-template addon:
    1. page-template:ShowPageTemplateDialogController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER.
  2. form-designer addon:
    1. form-designer:CreatePushButtonController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_PUSH_BUTTON.
    2. form-designer:CreateCheckBoxController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_CHECK_BOX.
    3. form-designer:CreateRadioButtonController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_RADIO_BUTTON.
    4. form-designer:CreateComboBoxController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_COMBO_BOX.
    5. form-designer:CreateListBoxController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_LIST_BOX.
    6. form-designer:CreateTextController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_TEXT.
    7. form-designer:CreateSignController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_SIGNATURE.
    8. form-designer:CreateImageController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_IMAGE.
    9. form-designer:CreateDateController: Switches the current StateHandler to STATE_HANDLER_NAMES.STATE_HANDLER_CREATE_FIELD_DATE.
  3. page-editor addon:
    1. page-editor:EditObjectController: Switches the current StateHandler to "Page Object Editing" tool, including text, image, shape, and gradient objects.
    2. page-editor:AddImageAdvController: Switches the current StateHandler to "Add Image from File" tool.
    3. page-editor:AddShapesController: Switches the current StateHandler to "Create Shape" tool.
    4. page-editor:AddTextController: Switches the current StateHandler to "Add Text" tool.
  4. fullscreen addon:
    1. full-screen:FullscreenController: Toggles the full screen mode.
  5. print addon:
    1. print:ShowPrintDialogController: Displays the print dialog.
  6. file-property addon:
    1. fpmodule:FileInfoCallbackController: Displays the document property dialog.
  7. h-continuous addon:
    1. h-continuous:HContinuousViewModeController: Switches the page mode to horizontal continuous page mode.
  8. export-form addon:
    1. export-form-module:ExportToXMLController: Exports the form of the current document to an XML format file.
    2. export-form-module:ExportToFDFController: Exports the form of the current document to an FDF format file.
    3. export-form-module:ExportToXFDFController: Exports the form of the current document to an XFDF format file.
    4. export-form-module:ExportToCSVController: Exports the form of the current document to a CSV format file.
    5. export-form-module:ExportToTXTController: Exports the form of the current document to a TXT format file.
  9. comparison addon:
    1. comparison:ShowCompareFileDialogButtonController: Displays the document comparison dialog.
  10. redaction addon:
    1. redaction:RedactionTextAndImageController: Switches the current StateHandler to the Redaction tool for creating marked text and images.
    2. redaction:RedactionController: Switches the current StateHandler to the Redaction tool for creating marked areas.
    3. redaction:RedactionPageController: Switches the current StateHandler to the Redaction tool for creating marked pages.

With these controllers, we can rewrite the components while reusing the built-in implementation logic of the SDK. Let's take an example of states:HandController, which can switch the current StateHandler tool to the Hand tool and can determine whether the current tool is the hand tool to activate/deactivate the component:

Of course, some controllers are not as simple as states:HandController. Here are some of the more special controllers. When using them, we need to follow the methods provided in the examples: