Skip to content

Customize the form properties dialog

This section explains how to replace the default form properties dialog, lay out a new dialog with built-in form property editors, and build new editors with PDFFormProperty.

NOTE

If your app is based on PDFViewCtrl rather than UIExtension, this chapter does not apply.

Replace the default form properties dialog

When the default dialog is not enough—for example, you need custom fields or a different layout—you can replace it as follows.

1. Replace with a custom dialog component

Use this when the dialog is built with the UIExtension framework. Override doShown to replace the default form properties dialog.

NOTE

The dialog name must be fv--form-designer-widget-properties-dialog to be recognized.

Steps

  • Create a custom dialog: Implement a dialog for your needs. The example below is minimal.

    js
    class CustomDialogComponent extends UIExtension.SeniorComponentFactory.createSuperClass({
        template: `
            <layer @var.dialog="$component">
                <layer-header
                    @draggable="{type: 'parent'}"
                    title="Widget Properties Dialog"
                ></layer-header>
                <div>
                    Field Name: @{dialog.properties.fieldName}
                </div>
            </layer>
        `
    }) {
        static getName() {
            return 'widget-properties-dialog'
        }
        properties = {
            fieldName: ''
        }
        doShown() {
            this.pdfUI.getAllActivatedElements().then(([widgetComponent]) => {
                if(widgetComponent.annot?.getType() === 'widget') {
                    this.properties.fieldName = widgetComponent.annot.getField().getName();
                } else {
                    this.properties.fieldName = 'No Widget Selected';
                }
                this.digest();
            })
            super.doShown();
        }
    }
  • Register the dialog in a custom module:

    js
    const customFormDesignerModule = UIExtension.modular.module('custom-form-designer', []);
    customFormDesignerModule.registerComponent(CustomDialogComponent);
  • Replace the built-in dialog via UI fragment configuration

    js
    new UIExtension.PDFUI({
        appearance: UIExtension.appearances.adaptive.extend({
            getDefaultFragments() {
                return [{
                    target: 'fv--form-designer-widget-properties-dialog',
                    action: 'replace',
                    template: `<custom-form-designer:widget-properties-dialog name="fv--form-designer-widget-properties-dialog"></custom-form-designer:widget-properties-dialog>`
                }];
            }
        }),
        // ......其他配置
    })

Complete example

Full demo:

demo
html
<script>
    const libPath = window.top.location.origin + '/lib';
    const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
    
    const customFormDesignerModule = UIExtension.modular.module('custom-form-designer', []);
    
    customFormDesignerModule.registerComponent(
        class CustomDialogComponent extends UIExtension.SeniorComponentFactory.createSuperClass({
            template: `
                <layer @var.dialog="$component">
                    <layer-header
                        @draggable="{type: 'parent'}"
                        title="Widget Properties Dialog"
                    ></layer-header>
                    <div>
                        Field Name: @{dialog.properties.fieldName}
                    </div>
                </layer>
            `
        }) {
            static getName() {
                return 'widget-properties-dialog'
            }
            properties = {
                fieldName: ''
            }
            doShown() {
                this.pdfUI.getAllActivatedElements().then(([widgetComponent]) => {
                    if(widgetComponent.annot?.getType() === 'widget') {
                        this.properties.fieldName = widgetComponent.annot.getField().getName();
                    } else {
                        this.properties.fieldName = 'No Widget Selected';
                    }
                    this.digest();
                })
                super.doShown();
            }
        }
    );
    
    const pdfui = new UIExtension.PDFUI({
        viewerOptions: {
            libPath: libPath,
            jr: {
                licenseSN: licenseSN,
                licenseKey: licenseKey
            }
        },
        renderTo: document.body,
        appearance: UIExtension.appearances.adaptive.extend({
            getDefaultFragments() {
                return [{
                    target: 'fv--form-designer-widget-properties-dialog',
                    action: 'replace',
                    template: `<custom-form-designer:widget-properties-dialog
                                    name="fv--form-designer-widget-properties-dialog"
                                ></custom-form-designer:widget-properties-dialog>`
                }];
            }
        }),
        addons: libPath + '/uix-addons/allInOne.js'
    });
</script>
json
{
    "iframeOptions": {
        "style": "height: 500px"
    }
}

2. Replace the form context menu item

If the dialog is not built with UIExtension or the layer component but should still open from a context menu, replace the context menu item as follows.

Steps

  • Create a custom form properties dialog: Implement the dialog for your needs. The example below uses a native <dialog> element.

    HTML structure:

    html
    <dialog id="form-properties-dialog">
        <label>
            <span>field name:</span>
            <input type="text" name="fieldName">
        </label>
        <button type="button" id="close-form-properties-dialog-button">Close</button>
    <dialog>

    JavaScript implementation:

    js
    class CustomFormPropertiesDialog {
        constructor(dialogId, pdfUI) {
            this.dialogId = dialogId;
            this.pdfUI = pdfUI;
            this.dialogElement = document.getElementById(this.dialogId);
            this.fieldNameElement = this.dialogElement.querySelector('input[name="fieldName"]');
            this.closeDialogBtn = this.dialogElement.querySelector('#close-form-properties-dialog-button');
            this.closeDialogBtn.addEventListener('click', () => {
                this.dialogElement.close();
            })
        }
        show() {
            this.pdfUI.getAllActivatedElements().then(([widgetComponent]) => {
                let fieldName;
                if(widgetComponent.annot?.getType() === 'widget') {
                    fieldName = widgetComponent.annot.getField().getName();
                } else {
                    fieldName = 'No Widget Selected';
                }
                this.fieldNameElement.value = fieldName;
            })
            this.dialogElement.showModal();
        }
    }
  • Create a controller for the context menu click:

    js
    const customFormDesignerModule = UIExtension.modular.module('custom-form-designer', []);
    customFormDesignerModule.registerController(
        class ShowCustomFormPropertiesDialogController extends UIExtension.Controller {
            static getName() {
                return 'ShowCustomFormPropertiesDialogController'
            }
            mounted() {
                super.mounted();
                this.dialog = new CustomFormPropertiesDialog('form-properties-dialog', this.pdfUI);
            }
            handle() {
                this.dialog.show();
            }
        }
    )
  • Replace the context menu item:

    js
    new UIExtension.PDFUI({
        appearance: UIExtension.appearances.adaptive.extend({
            getDefaultFragments() {
                return [{
                    target: 'fv--ui-show-widget-properties-contextmenu-item',
                    action: 'replace',
                    template: `<contextmenu-item @controller="custom-form-designer:ShowCustomFormPropertiesDialogController">Show properties</contextmenu-item>`
                }];
            }
        }),
        // ......其他配置
    })

Complete example

Full demo:

demo
html
<dialog id="form-properties-dialog">
    <label>
        <span>field name:</span>
        <input type="text" name="fieldName">
    </label>
    <button type="button" id="close-form-properties-dialog-button">Close</button>
<dialog>
<script>
    class CustomFormPropertiesDialog {
        constructor(dialogId, pdfUI) {
            this.dialogId = dialogId;
            this.pdfUI = pdfUI;
            this.dialogElement = document.getElementById(this.dialogId);
            this.fieldNameElement = this.dialogElement.querySelector('input[name="fieldName"]');
            this.closeDialogBtn = this.dialogElement.querySelector('#close-form-properties-dialog-button');
            this.closeDialogBtn.addEventListener('click', () => {
                this.dialogElement.close();
            })
        }
        show() {
            this.pdfUI.getAllActivatedElements().then(([widgetComponent]) => {
                let fieldName;
                if(widgetComponent.annot?.getType() === 'widget') {
                    fieldName = widgetComponent.annot.getField().getName();
                } else {
                    fieldName = 'No Widget Selected';
                }
                this.fieldNameElement.value = fieldName;
            })
            this.dialogElement.showModal();
        }
    }
    const libPath = window.top.location.origin + '/lib';
    const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
    
    const customFormDesignerModule = UIExtension.modular.module('custom-form-designer', []);
    customFormDesignerModule.registerController(
        class ShowCustomFormPropertiesDialogController extends UIExtension.Controller {
            static getName() {
                return 'ShowCustomFormPropertiesDialogController'
            }
            mounted() {
                super.mounted();
                this.dialog = new CustomFormPropertiesDialog('form-properties-dialog', this.pdfUI);
            }
            handle() {
                this.dialog.show();
            }
        }
    )
    
    const pdfui = new UIExtension.PDFUI({
        viewerOptions: {
            libPath: libPath,
            jr: {
                licenseSN: licenseSN,
                licenseKey: licenseKey
            }
        },
        renderTo: document.body,
        appearance: UIExtension.appearances.adaptive.extend({
            getDefaultFragments() {
                return [{
                    target: 'fv--ui-show-widget-properties-contextmenu-item',
                    action: 'replace',
                    template: `<contextmenu-item
                                    @controller="custom-form-designer:ShowCustomFormPropertiesDialogController"
                               >Show properties</contextmenu-item>`
                }];
            }
        }),
        addons: libPath + '/uix-addons/allInOne.js'
    });
</script>
json
{
    "iframeOptions": {
        "style": "height: 500px"
    }
}

Customize form properties dialog layout

The form properties dialog exposes fine-grained property editors by type (see Built-in form property editor components). Reuse those components to build a custom layout for the properties dialog.