# # Customize Form Properties Dialog

This chapter explains how to replace the default form properties dialog and build a new properties dialog using built-in form properties editing components. Additionally, we will demonstrate how to create a new form properties editing component using PDFFormProperty.

Note:

> If your application is based on PDFViewCtrl rather than UIExtension, the content of this chapter is not applicable.

## # Replace the Default Form Properties Dialog

In some scenarios, the default form properties dialog may not meet your requirements. For example, you might need to add custom form properties or modify the configuration method for existing properties.

You can replace the default form properties dialog using one of the following methods.

### # 1. Replace with a Custom Dialog Component

This replacement method applies when the dialog component is implemented based on the UIExtension framework. You can override the `doShown` method to replace the default form properties dialog.

Note:

> The `name` attribute of the dialog must be set to `fv--form-designer-widget-properties-dialog`; otherwise, it will not be recognized.

#### # Steps

- Create a Custom Dialog: Design and implement a custom dialog component based on your requirements. Below is a simple example.

      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 into the custom module：

      const customFormDesignerModule = UIExtension.modular.module('custom-form-designer', []);
      customFormDesignerModule.registerComponent(CustomDialogComponent);

- Replace the built-in dialog component via UI Fragment configuration

      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>`
                  }];
              }
          }),
          // ...Other Configurations
      })

#### # Complete Example

Below is the complete example. Please run it yourself and open a PDF document with forms to see the effect.

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

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

### # 2. Replace Form Context Menu Items

If the properties dialog is not implemented using the UIExtension framework or layer components, but still needs to be triggered via the context menu, you can replace the context menu by following these steps.

#### # Steps

- Create a Custom Form Properties Dialog: Design and implement a custom dialog component based on your requirements. Below is an example of a dialog implemented using a simple native `dialog`.

  Define the HTML structure of the dialog:

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

  Define the JavaScript implementation class for the dialog:

      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 to handle the click events of context menu items:

      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 Context Menu Items:

      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>`
                  }];
              }
          }),
          // ...Other Configurations
      })

#### # Complete Example

Below is the complete example. Please run it yourself and open a PDF document with forms to see the effect.

    <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>
    </html>
    <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>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

## # Customize Form Properties Dialog Layout

In the form properties dialog, we provide fine-grained property editing components for different attribute types (as detailed in Built-in Form Properties Editing Components). Using these components, you can reuse property editing components based on your requirements and customize the layout of the form properties dialog.