# Customizing the UI

From version 7.0, Foxit PDF SDK for Web comes with built-in UI design including the feature modules UI, which are implemented using Foxit PDF SDK for Web and are shipped in the UIExtension.js. Furthermore, customizing UI is straightforward. Foxit PDF SDK for Web provides a rich set of APIs for developers to customize and style the appearance of your web viewer.

The user interface of UIExtension consists of two parts: template and fragments. Template is equivalent to the extension of HTML, the components in the template should be declared by tags. Template is used to customize the UI layout (css style, icon, text, and so on) without interactions. Fragments are a set of UI snippets, which can be used to customize the configuration items and interaction logic of the components in the template. Each snippet has an operation type "action" that specifies the action mode (append, prepend, before, after, ext, replace, insert, and remove, the default is ext.) of the snippets. Through these action modes, you can insert, delete, replace and modify the components in the template.

# Customize the UI layout using template

Template is mainly used to customize the UI layout of the components. Following will list some examples to demonstrate the usage of template. Please note that all the examples are based on the Integrate the complete web viewer into your project in chapter Integration.

# Create a simple template

A simplest template is as follows:

var pdfui = new UIExtension.PDFUI({
    viewerOptions: {
        libPath: './lib', // the library path of web sdk.
        jr: {
            licenseSN: licenseSN,
            licenseKey: licenseKey
        }
    },
    renderTo: '#pdf-ui', // the div (id="pdf-ui").
    appearance: UIExtension.appearances.Appearance.extend({
        getLayoutTemplate: function() {
            return [
            '<webpdf>',
            '    <viewer></viewer>',
            '</webpdf>'
            ].join('');
        }
    })
});
  • <webpdf> tag listens the opening/closing document events, and then trigger the enableAll or disableAll function of the Appearance object to enable or disable the related components in the UI.
  • <viewer> tag is where the PDF contents are rendered. Each template must have a <viewer> tag. It can be placed anywhere you want, please refer to the examples in the following sections.

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see a simple web PDF viewer without any UI component.

# Add a new toolbar button

Use <toolbar> tag to add a new toolbar button.

var pdfui = new UIExtension.PDFUI({
    viewerOptions: {
        libPath: './lib', // the library path of web sdk.
        jr: {
            licenseSN: licenseSN,
            licenseKey: licenseKey
        }
    },
    renderTo: '#pdf-ui', // the div (id="pdf-ui").
    appearance: UIExtension.appearances.Appearance.extend({
        getLayoutTemplate: function() {
            return [
                '<webpdf>',
                '    <toolbar>',
                '        <open-file-dropdown></open-file-dropdown>',
                '    </toolbar>',
                '    <viewer></viewer>',
                '</webpdf>'
            ].join('')
        }
    })
});

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the new toolbar button.

# Add a new tab page

Use <gtab> tags to add a new tab page.

var CustomAppearance = UIExtension.appearances.Appearance.extend({
    getLayoutTemplate: function() {
        return [
            '<webpdf>',
            '    <toolbar>',
            '        <gtab group="custom-tabs" text="Home" body="home-tab-body">',
            '        </gtab>',
            '        <gtab group="custom-tabs" text="Comment" body="comment-tab-body">',
            '        </gtab>',
            '    </toolbar>',
            '   <div class="tab-bodies">',
            '       <div name="home-tab-body">',
            '            <open-file-dropdown></open-file-dropdown>',
            '       </div>',
            '       <div name="comment-tab-body" class="flex-row">',
            '           <create-strikeout-button></create-strikeout-button>',
            '           <create-underline-button></create-underline-button>',
            '           <create-squiggly-button></create-squiggly-button>',
            '           <create-replace-button></create-replace-button>',
            '           <create-caret-button></create-caret-button>',
            '           <create-note-button></create-note-button>',
            '       </div>',
            '   </div>',
            '    <viewer></viewer>',
            '</webpdf>'
        ].join('')
    }
})
var pdfui = new UIExtension.PDFUI({
    viewerOptions: {
        libPath: './lib', // the library path of web sdk.
        jr: {
            licenseSN: licenseSN,
            licenseKey: licenseKey
        }
    },
    renderTo: '#pdf-ui', // the div (id="pdf-ui").
    appearance: CustomAppearance
});

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the new tab page.

# Add a sidebar button

Use <sidebar> tag to add a sidebar button.

var CustomAppearance = UIExtension.appearances.Appearance.extend({
    getLayoutTemplate: function() {
        return [
            '<webpdf>',
            '    <toolbar>',
            '        <gtab group="custom-tabs" text="Home" body="home-tab-body">',
            '        </gtab>',
            '        <gtab group="custom-tabs" text="Comment" body="comment-tab-body">',
            '        </gtab>',
            '    </toolbar>',
            '   <div class="tab-bodies">',
            '       <div name="home-tab-body">',
            '            <open-file-dropdown></open-file-dropdown>',
            '       </div>',
            '       <div name="comment-tab-body" class="flex-row">',
            '           <create-strikeout-button></create-strikeout-button>',
            '           <create-underline-button></create-underline-button>',
            '           <create-squiggly-button></create-squiggly-button>',
            '           <create-replace-button></create-replace-button>',
            '           <create-caret-button></create-caret-button>',
            '           <create-note-button></create-note-button>',
            '       </div>',
            '   </div>',
            '    <div class="flex-row">',
            '        <sidebar>',
            '            <bookmark-sidebar-panel></bookmark-sidebar-panel>',
            '        </sidebar>',
            '        <viewer></viewer>',
            '    </div>',
            '</webpdf>'
        ].join('')
    }
})
var pdfui = new UIExtension.PDFUI({
    viewerOptions: {
        libPath: './lib', // the library path of web sdk.
        jr: {
            licenseSN: licenseSN,
            licenseKey: licenseKey
        }
    },
    renderTo: '#pdf-ui', // the div (id="pdf-ui").
    appearance: CustomAppearance
});

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the bookmark sidebar.

# Built-in layout template

The built-in layout template is placed in the \examples\UIExtension\layout_templates directory. For desktop, reference the built-in-pc-layout-template.tpl file, and for mobile, reference the built-in-mobile-layout-template.tpl file. You can modify the template directly to customize the UI layout as desired.

In the \examples\UIExtension\custom_appearance directory, Foxit PDF SDK for Web provides two custom template examples. " adaptive-to-the-device.html" is adaptive to the device desktop and mobile", and " not-adaptive-to-the-device.html" is not adaptive to the device, which only supports desktop.

# Customize the UI using fragments

Fragments are a set of UI snippets. It can be used to customize the configuration items and interaction logic of the components in the template.

# Create a new drop-down menu item

The sample code below creates a new drop-down menu including two drop-down buttons, and append it to the end of the list of children of the group component with the name of "home-tab-group-hand".

To get the name of a target component (only for widget), you can right-click the component in the browser, choose Inspect, and then find the value of the component-name attribute in the corresponding <a> tag. For a container component, for example target:"home-tab-group-hand", you can right-click one of the sub-components in the browser, choose Inspect, and then find the value of the component-name attribute in the related <div> tag.

const customModule = UIExtension.PDFUI.module('custom', []);
customModule.controller('CustomController', {
    mounted: function () {
        console.info(this.component, 'mounted');
    },
    handle: function (selectedFile) {
        alert(selectedFile.name);
    }
});
var CustomController = customModule.getControllerClass('CustomController');

var CustomAppearance = UIExtension.appearances.RibbonAppearance.extend({
    getDefaultFragments: function() {
        return [{
            // Add a component to the end of the list of children of a specified target component.
            action: UIExtension.UIConsts.FRAGMENT_ACTION.APPEND,
            // Specify the name of the target component that the new components defined in the above template will be appended to. All the target names of fragments are defined in the layout template.
            target: 'home-tab-group-hand',
            // Define the properties of the added component, such as icon, text, and css style.
            template: [
                '<dropdown icon-class="fv__icon-toolbar-stamp">',
                '    <dropdown-button name="show-hello-button" icon-class="fv__icon-toolbar-hand">say hello</dropdown-button>',
                '    <dropdown-button name="select-pdf-file-button" accept=".pdf" file-selector icon-class="fv__icon-toolbar-open">open</dropdown-button>',
                '</dropdown>'
            ].join(''),
            // Define the interaction logic of the added component.
            config: [{
                // specify the component in the above template that the configuration will be applied to.
                // For example, the configuration will be applied to the component with the name of "show-hello-button".
                target: 'show-hello-button',
                callback: function () {
                    alert('hello');
                }
            },
            {
                // The configuration will be applied to the component with the name of "select-pdf-file-button" which is defined in the above template of fragments.
                target: 'select-pdf-file-button',
                // Extend Controller, and implement the handle function.
                callback: CustomController
            }]
        }]
    }
})

var pdfui = new UIExtension.PDFUI({
    viewerOptions: {
        libPath: './lib', // the library path of web sdk.
        jr: {
            licenseSN: licenseSN,
            licenseKey: licenseKey
        }
    },
    renderTo: '#pdf-ui', // the div (id="pdf-ui").
    appearance: CustomAppearance
});

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see a new created drop-down menu.

# Delete a toolbar button

To delete a toolbar button through fragment is fairly simple. For example, to delete the Hand tool , you only need to add a new object to the fragment. Based on the above example, add the code below:

{
    target: 'hand-tool',
    action: UIExtension.UIConsts.FRAGMENT_ACTION.REMOVE
}

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the Hand tool has been removed from the group component.

# Modify a toolbar button

To modify a toolbar button through fragment is also fairly simple. Just like Delete a toolbar button, you only need to add a new object to the fragment.

# Change icon of a button

For example, to change the icon of the Hand tool, just add the code below:

{
    target: 'hand-tool',
    config: {
        iconCls: 'fv__icon-toolbar-note' // your custom icon.
    }
}

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the icon of the Hand tool has been changed.

# Change the tooltip of a button

For example, to change the tooltip of the Hand tool, just add the code below:

{
    target: 'hand-tool',
    config: {
        tooltip: {
            title: 'your custom tooltip'
        }
    }
}

Refresh your browser (http://127.0.0.1:8080/index.html (opens new window)), and then you can see the tooltip of the Hand tool has been changed to "your custom tooltip.

# Change the event of a button

To change the event of a button, there are two ways:

  1. Overwrite the built-in event. For example:

    {
        target: 'hand-tool',
        config: {
            callback: function() {
                alert('your click event handler');
            }
        }
    }
    
  2. Add custom behavior based on the built-in event (original logic). You can configure the button using the method as follows:

    {
        target: 'hand-tool',
        config: {
            callback: {
                before: function (handleMethodArguments ) {
                    console.info('called before handle callback with arguments: ', handleMethodArguments);
                },
                after: function (value, handleMethodArguments ) {
                    console.info('called after handle callback with returning value and arguments: ', value, handleMethodArguments);
                }
            }
        }
    }
    

# More examples

For more sample codes, please refer to the examples in the \examples\UIExtension\fragment_usage folder.

# Modularization

In order to differentiate the built-in components and user-defined components to avoid conflicts, UIExtension provides modularization feature, which allows you to register the components in different modules separately. Then, you only need to add the prefix of the module name when you declare the components in the template.

# Create your own custom module

If you want to define and use a custom component which has the same name with the built-in component, you can create a custom module and then register your custom component in the custom module.

For example, in the built-in component, there is already an existing component with the name of " dropdown", if you also want to define a custom component called " dropdown", you can refer to the simple code below:

Create a new module "my-widgets", and registers a user-defined component in this module:

// Create a new module. Please note that the second parameter must be an array if you create a new module.
var module = UIExtension.modular.module('my-widgets', []);

function UserDefinedDropdownComponent() {
    UIExtension.Component.apply(this, arguments);
}
UserDefinedDropdownComponent.getName = function() {
   return 'dropdown'; // Declare the tag name of the component. There is already an existing component with the same name of 'dropdown' in the built-in component.
}
UserDefinedDropdownComponent.prototype.constructor = UIExtension.Component;
UserDefinedDropdownComponent.prototype.render = function() {
UIExtension.Component.prototype.render.call(this);
       this.element.innerText = 'User-defined dropdown component';
}
module.registerComponent(UserDefinedDropdownComponent);

Then, the built-in dropdown and user-defined dropdown can be differentiated in the following way:

<!-- built-in dropdown -->
<dropdown></dropdown>
<!-- user-defined dropdown -->
<my-widgets:dropdown></my-widgets:dropdown>

For example, use the user-defined dropdown component:

var pdfui = new UIExtension.PDFUI({
    // Omit other parameters.
    appearance: UIExtension.appearances.RibbonAppearance.extend({
        getDefautFragments: function() {
            return [{
                action: UIExtension.UIConsts.FRAGMENT_ACTION.APPEND,
                target: 'home-tab-group-hand',
                template: '<my-widgets:dropdown></my-widgets:dropdown>' // use a colon to separate the module name and component name in the template.
            }];
        }
    })
});