Sugarcrm支持产品指南糖开发人员糖开发人员指南10.3食谱将按钮添加到记录视图
此版本仅适用于Sugarcloud客户。

将按钮添加到记录视图

概述

此示例说明如何在记录视图和添加事件上创建其他按钮。我们将扩展并覆盖库存帐户记录视图以添加自定义按钮。自定义按钮将被称为“验证邮政编码”,并Ping Zippopotamus REST服务以验证记录计费状态和邮政编码。

完成步骤

本教程需要以下步骤,这些步骤在下面的部分中解释:

  1. 定义元数据
  2. 添加自定义按钮
  3. 定义按钮标签
  4. 扩展和覆盖控制器

定义元数据

To add a button to the record view, you will first need to create the custom metadata for the view if it doesn't exist. You can easily do this by opening and saving your modules record layout in studio. Depending on your module, the path will then be ./custom/modules/<module>/clients/base/views/record/record.php. Once your file is in place, you will need to copy the button array from ./clients/base/views/record/record.php and add it to the $viewdefs['<module>']['base']['view']['record'] portion of your metadata array. An example of the button array is shown below:

'buttons' => array(
        array(
            'type' => 'button',
            'name' => 'cancel_button',
            'label' => 'LBL_CANCEL_BUTTON_LABEL',
            'css_class' => 'btn-invisible btn-link',
            'showOn' => 'edit',
        ),
        array(
            'type' => 'rowaction',
            'event' => 'button:save_button:click',
            'name' => 'save_button',
            'label' => 'LBL_SAVE_BUTTON_LABEL',
            'css_class' => 'btn btn-primary',
            'showOn' => 'edit',
            'acl_action' => 'edit',
        ),
        array(
            'type' => 'actiondropdown',
            'name' => 'main_dropdown',
            'primary' => true,
            'showOn' => 'view',
            'buttons' => array(
                array(
                    'type' => 'rowaction',
                    'event' => 'button:edit_button:click',
                    'name' => 'edit_button',
                    'label' => 'LBL_EDIT_BUTTON_LABEL',
                    'acl_action' => 'edit',
                ),
                array(
                    'type' => 'shareaction',
                    'name' => 'share',
                    'label' => 'LBL_RECORD_SHARE_BUTTON',
                    'acl_action' => 'view',
                ),
                array(
                    'type' => 'pdfaction',
                    'name' => 'download-pdf',
                    'label' => 'LBL_PDF_VIEW',
                    'action' => 'download',
                    'acl_action' => 'view',
                ),
                array(
                    'type' => 'pdfaction',
                    'name' => 'email-pdf',
                    'label' => 'LBL_PDF_EMAIL',
                    'action' => 'email',
                    'acl_action' => 'view',
                ),
                array(
                    'type' => 'divider',
                ),
                array(
                    'type' => 'rowaction',
                    'event' => 'button:find_duplicates_button:click',
                    'name' => 'find_duplicates_button',
                    'label' => 'LBL_DUP_MERGE',
                    'acl_action' => 'edit',
                ),
                array(
                    'type' => 'rowaction',
                    'event' => 'button:duplicate_button:click',
                    'name' => 'duplicate_button',
                    'label' => 'LBL_DUPLICATE_BUTTON_LABEL',
                    'acl_module' => $module,
                ),
                array(
                    'type' => 'rowaction',
                    'event' => 'button:audit_button:click',
                    'name' => 'audit_button',
                    'label' => 'LNK_VIEW_CHANGE_LOG',
                    'acl_action' => 'view',
                ),
                array(
                    'type' => 'divider',
                ),
                array(
                    'type' => 'rowaction',
                    'event' => 'button:delete_button:click',
                    'name' => 'delete_button',
                    'label' => 'LBL_DELETE_BUTTON_LABEL',
                    'acl_action' => 'delete',
                ),
            ),
        ),
        array(
            'name' => 'sidebar_toggle',
            'type' => 'sidebartoggle',
        ),
    ),

笔记: When copying this array into your metadata, you will need to replace $module with the text string of your module's name.

对于标准按钮类型,按钮定义将包含以下属性:

财产 潜在价值 描述
类型 按钮,划痕,释放,ActionDropdown 小部件类型
名称   按钮的名称
标签   按钮显示文本的标签字符串键
css_class.   CSS类要附加到按钮
Showon. 编辑视图 按钮的ACL动作

对于此示例,我们将将自定义按钮添加到主下拉列表中。对于ActionDropdown类型,有一个附加按钮数组,可指定按钮的下拉列表。此数组中的按钮定义将包含以下属性:

财产 潜在价值 描述
类型 按钮,划痕,释放,ActionDropdown 小部件类型;大多数自定义按钮是'rowaction'
事件 按钮:Button_name:单击 按钮的事件名称
名称   按钮的名称
标签   按钮显示文本的标签字符串键
ACL_Action.  edit, view 按钮的ACL动作

添加自定义按钮

在此示例中,修改帐户的元数据以将按钮定义添加到main_dropdown:

array(
    'type' => 'rowaction',
    'event' => 'button:validate_postal_code:click',
    'name' => 'validate_postal_code',
    'label' => 'LBL_VALIDATE_POSTAL_CODE',
    'acl_action' => 'view',
),

一个完整的例子如下所示:

./custom/modules/accounts/clients/base/views/record/record.php.

<?php

$viewdefs['Accounts'] =
array (
  'base' =>
  array (
    'view' =>
    array (
      'record' =>
      array (
        'buttons' =>
        array (
          0 =>
          array (
            'type' => 'button',
            'name' => 'cancel_button',
            'label' => 'LBL_CANCEL_BUTTON_LABEL',
            'css_class' => 'btn-invisible btn-link',
            'showOn' => 'edit',
          ),
          1 =>
          array (
            'type' => 'rowaction',
            'event' => 'button:save_button:click',
            'name' => 'save_button',
            'label' => 'LBL_SAVE_BUTTON_LABEL',
            'css_class' => 'btn btn-primary',
            'showOn' => 'edit',
            'acl_action' => 'edit',
          ),
          2 =>
          array (
            'type' => 'actiondropdown',
            'name' => 'main_dropdown',
            'primary' => true,
            'showOn' => 'view',
            'buttons' =>
            array (
              0 =>
              array (
                'type' => 'rowaction',
                'event' => 'button:edit_button:click',
                'name' => 'edit_button',
                'label' => 'LBL_EDIT_BUTTON_LABEL',
                'acl_action' => 'edit',
              ),
              1 =>
              array (
                'type' => 'shareaction',
                'name' => 'share',
                'label' => 'LBL_RECORD_SHARE_BUTTON',
                'acl_action' => 'view',
              ),
              2 =>
              array (
                'type' => 'rowaction',
                'event' => 'button:validate_postal_code:click',
                'name' => 'validate_postal_code',
                'label' => 'LBL_VALIDATE_POSTAL_CODE',
                'acl_action' => 'view',
              ),
              3 =>
              array (
                'type' => 'divider',
              ),
              4 =>
              array (
                'type' => 'rowaction',
                'event' => 'button:duplicate_button:click',
                'name' => 'duplicate_button',
                'label' => 'LBL_DUPLICATE_BUTTON_LABEL',
                'acl_module' => 'Accounts',
              ),
              5 =>
              array (
                'type' => 'rowaction',
                'event' => 'button:audit_button:click',
                'name' => 'audit_button',
                'label' => 'LNK_VIEW_CHANGE_LOG',
                'acl_action' => 'view',
              ),
              6 =>
              array (
                'type' => 'divider',
              ),
              7 =>
              array (
                'type' => 'rowaction',
                'event' => 'button:delete_button:click',
                'name' => 'delete_button',
                'label' => 'LBL_DELETE_BUTTON_LABEL',
                'acl_action' => 'delete',
              ),
            ),
          ),
          3 =>
          array (
            'name' => 'sidebar_toggle',
            'type' => 'sidebartoggle',
          ),
        ),
        'panels' =>
        array (
          0 =>
          array (
            'name' => 'panel_header',
            'header' => true,
            'fields' =>
            array (
              0 =>
              array (
                'name' => 'picture',
                'type' => 'avatar',
                'width' => 42,
                'height' => 42,
                'dismiss_label' => true,
                'readonly' => true,
              ),
              1 => 'name',
              2 =>
              array (
                'name' => 'favorite',
                'label' => 'LBL_FAVORITE',
                'type' => 'favorite',
                'dismiss_label' => true,
              ),
              3 =>
              array (
                'name' => 'follow',
                'label' => 'LBL_FOLLOW',
                'type' => 'follow',
                'readonly' => true,
                'dismiss_label' => true,
              ),
            ),
          ),
          1 =>
          array (
            'name' => 'panel_body',
            'columns' => 2,
            'labelsOnTop' => true,
            'placeholders' => true,
            'fields' =>
            array (
              0 => 'website',
              1 => 'industry',
              2 => 'parent_name',
              3 => 'account_type',
              4 => 'assigned_user_name',
              5 => 'phone_office',
            ),
          ),
          2 =>
          array (
            'name' => 'panel_hidden',
            'hide' => true,
            'columns' => 2,
            'labelsOnTop' => true,
            'placeholders' => true,
            'fields' =>
            array (
              0 =>
              array (
                'name' => 'fieldset_address',
                'type' => 'fieldset',
                'css_class' => 'address',
                'label' => 'LBL_BILLING_ADDRESS',
                'fields' =>
                array (
                  0 =>
                  array (
                    'name' => 'billing_address_street',
                    'css_class' => 'address_street',
                    'placeholder' => 'LBL_BILLING_ADDRESS_STREET',
                  ),
                  1 =>
                  array (
                    'name' => 'billing_address_city',
                    'css_class' => 'address_city',
                    'placeholder' => 'LBL_BILLING_ADDRESS_CITY',
                  ),
                  2 =>
                  array (
                    'name' => 'billing_address_state',
                    'css_class' => 'address_state',
                    'placeholder' => 'LBL_BILLING_ADDRESS_STATE',
                  ),
                  3 =>
                  array (
                    'name' => 'billing_address_postalcode',
                    'css_class' => 'address_zip',
                    'placeholder' => 'LBL_BILLING_ADDRESS_POSTALCODE',
                  ),
                  4 =>
                  array (
                    'name' => 'billing_address_country',
                    'css_class' => 'address_country',
                    'placeholder' => 'LBL_BILLING_ADDRESS_COUNTRY',
                  ),
                ),
              ),
              1 =>
              array (
                'name' => 'fieldset_shipping_address',
                'type' => 'fieldset',
                'css_class' => 'address',
                'label' => 'LBL_SHIPPING_ADDRESS',
                'fields' =>
                array (
                  0 =>
                  array (
                    'name' => 'shipping_address_street',
                    'css_class' => 'address_street',
                    'placeholder' => 'LBL_SHIPPING_ADDRESS_STREET',
                  ),
                  1 =>
                  array (
                    'name' => 'shipping_address_city',
                    'css_class' => 'address_city',
                    'placeholder' => 'LBL_SHIPPING_ADDRESS_CITY',
                  ),
                  2 =>
                  array (
                    'name' => 'shipping_address_state',
                    'css_class' => 'address_state',
                    'placeholder' => 'LBL_SHIPPING_ADDRESS_STATE',
                  ),
                  3 =>
                  array (
                    'name' => 'shipping_address_postalcode',
                    'css_class' => 'address_zip',
                    'placeholder' => 'LBL_SHIPPING_ADDRESS_POSTALCODE',
                  ),
                  4 =>
                  array (
                    'name' => 'shipping_address_country',
                    'css_class' => 'address_country',
                    'placeholder' => 'LBL_SHIPPING_ADDRESS_COUNTRY',
                  ),
                  5 =>
                  array (
                    'name' => 'copy',
                    'label' => 'NTC_COPY_BILLING_ADDRESS',
                    'type' => 'copy',
                    'mapping' =>
                    array (
                      'billing_address_street' => 'shipping_address_street',
                      'billing_address_city' => 'shipping_address_city',
                      'billing_address_state' => 'shipping_address_state',
                      'billing_address_postalcode' => 'shipping_address_postalcode',
                      'billing_address_country' => 'shipping_address_country',
                    ),
                  ),
                ),
              ),
              2 =>
              array (
                'name' => 'phone_alternate',
                'label' => 'LBL_OTHER_PHONE',
              ),
              3 => 'email',
              4 => 'phone_fax',
              5 => 'campaign_name',
              6 =>
              array (
                'name' => 'description',
                'span' => 12,
              ),
              7 => 'sic_code',
              8 => 'ticker_symbol',
              9 => 'annual_revenue',
              10 => 'employees',
              11 => 'ownership',
              12 => 'rating',
              13 =>
              array (
                'name' => 'date_entered_by',
                'readonly' => true,
                'type' => 'fieldset',
                'label' => 'LBL_DATE_ENTERED',
                'fields' =>
                array (
                  0 =>
                  array (
                    'name' => 'date_entered',
                  ),
                  1 =>
                  array (
                    'type' => 'label',
                    'default_value' => 'LBL_BY',
                  ),
                  2 =>
                  array (
                    'name' => 'created_by_name',
                  ),
                ),
              ),
              14 => 'team_name',
              15 =>
              array (
                'name' => 'date_modified_by',
                'readonly' => true,
                'type' => 'fieldset',
                'label' => 'LBL_DATE_MODIFIED',
                'fields' =>
                array (
                  0 =>
                  array (
                    'name' => 'date_modified',
                  ),
                  1 =>
                  array (
                    'type' => 'label',
                    'default_value' => 'LBL_BY',
                  ),
                  2 =>
                  array (
                    'name' => 'modified_by_name',
                  ),
                ),
                'span' => 12,
              ),
            ),
          ),
        ),
        'templateMeta' =>
        array (
          'useTabs' => false,
          'tabDefs' =>
          array (
            'LBL_RECORD_BODY' =>
            array (
              'newTab' => false,
              'panelDefault' => 'expanded',
            ),
            'LBL_RECORD_SHOWMORE' =>
            array (
              'newTab' => false,
              'panelDefault' => 'expanded',
            ),
          ),
        ),
      ),
    ),
  ),
);

定义按钮标签

接下来,定义按钮的标签:

./custom/extension/modules/accounts/ext/language/en_us.validatePostalCode.php.

<?php

$mod_strings['LBL_VALIDATE_POSTAL_CODE'] = 'Validate Postal Code';

扩展和覆盖控制器

按钮已添加到元数据中,扩展并覆盖记录视图控制器:

./custom/modules/accounts/clients/base/views/record/record.js.

({

    extendsFrom: 'RecordView',

    zipJSON: {},

    initialize: function (options) {
        this._super('initialize', [options]);

        //add listener for custom button
        this.context.on('button:validate_postal_code:click', this.validate_postal_code, this);
    },

    validate_postal_code: function() {
        //example of getting field data from current record
        var AcctID = this.model.get('id');
        var currentCity = this.model.get('billing_address_city');
        var currentZip = this.model.get('billing_address_postalcode');

        //jQuery AJAX call to Zippopotamus REST API
        $.ajax({
            url: 'http://api.zippopotam.us/us/' + currentZip,
            success: function(data) {
                    this.zipJSON = data;
                    var city = this.zipJSON.places[0]['place name'];

                    if (city === currentCity)
                    {
                        app.alert.show('address-ok', {
                            level: 'success',
                            messages: 'City and Zipcode match.',
                            autoClose: true
                        });
                    }
                    else
                    {
                        app.alert.show('address-ok', {
                            level: 'error',
                            messages: 'City and Zipcode do not match.',
                            autoClose: false
                        });
                    }
                }
            });
    }
})

文件到位后,导航到Admin> Repair >快速修复和重建。

添加按钮而不覆盖视图控制器

有时,您的自定义可能需要将相同的按钮添加到多个视图,但您不希望覆盖视图上已有的其他可能的自定义项。以下将通过创建像上面示例的自定义按钮,添加添加按钮以查看,而无需覆盖模块视图控制器。

创建自定义按钮

按钮通常有两个形式,标准按钮和动作菜单中的“rowaction”。我们可以创建两个按钮来处理这两种情况。

./clients/base/fields/zipcode-check-button/zipcode-check-button.js.

/**
 * Zipcode Check button will check if zipcode matches city field
 *
 * @class View.Fields.Base.ZipcodeCheckButtonField
 * @alias SUGAR.App.view.fields.BaseZipcodeCheckButtonField
 * @extends View.Fields.Base.ButtonField
 */
({
    extendsFrom: 'ButtonField',

    defaultZipCodeField: 'billing_address_postalcode',

    defaultCityField: 'billing_address_city',

    /**
     * @inheritdoc
     */
    initialize: function(options) {
        options.def.events = _.extend({}, options.def.events, {
            'click .zip-check-btn': 'validatePostalCode'
        });

        this._super('initialize', [options]);

        this.def.zip_code_field = _.isEmpty(this.def.zip_code_field)?this.defaultZipCodeField:this.def.zip_code_field;
        this.def.city_field = _.isEmpty(this.def.city_field)?this.defaultCityField:this.def.city_field;
    },

    validatePostalCode: function(evt) {
        var currentCity = this.model.get(this.def.city_field);
        var currentZip = this.model.get(this.def.zip_code_field);

        //jQuery AJAX call to Zippopotamus REST API
        $.ajax({
            url: 'http://api.zippopotam.us/us/' + currentZip,
            success: function(data) {
                this.zipJSON = data;
                var city = this.zipJSON.places[0]['place name'];

                if (city === currentCity)
                {
                    app.alert.show('address-ok', {
                        level: 'success',
                        messages: 'City and Zipcode match.',
                        autoClose: true
                    });
                }
                else
                {
                    app.alert.show('address-ok', {
                        level: 'error',
                        messages: 'City and Zipcode do not match.',
                        autoClose: false
                    });
                }
            }
        });
    }
})

./clients/base/fields/zipcode-check-rowaction/zipcode-check-rowaction.js.

/**
 * Zipcode Check button will check if zipcode matches city field
 *
 * @class View.Fields.Base.ZipcodeCheckRowactionField
 * @alias SUGAR.App.view.fields.BaseZipcodeCheckRowactionField
 * @extends View.Fields.Base.RowactionField
 */
({
    extendsFrom: 'RowactionField',

    defaultZipCodeField: 'billing_address_postalcode',

    defaultCityField: 'billing_address_city',

    /**
     * @inheritdoc
     */
    initialize: function(options) {
        this._super('initialize', [options]);

        this.def.zip_code_field = _.isEmpty(this.def.zip_code_field)?this.defaultZipCodeField:this.def.zip_code_field;
        this.def.city_field = _.isEmpty(this.def.city_field)?this.defaultCityField:this.def.city_field;
    },

    /**
     * Rowaction fields have a default event which calls rowActionSelect
     */
    rowActionSelect: function(evt) {
        this.validatePostalCode(evt);
    },

    validatePostalCode: function(evt) {
        var currentCity = this.model.get(this.def.city_field);
        var currentZip = this.model.get(this.def.zip_code_field);

        //jQuery AJAX call to Zippopotamus REST API
        $.ajax({
            url: 'http://api.zippopotam.us/us/' + currentZip,
            success: function(data) {
                this.zipJSON = data;
                var city = this.zipJSON.places[0]['place name'];

                if (city === currentCity)
                {
                    app.alert.show('address-check-msg', {
                        level: 'success',
                        messages: 'City and Zipcode match.',
                        autoClose: true
                    });
                }
                else
                {
                    app.alert.show('address-check-msg', {
                        level: 'error',
                        messages: 'City and Zipcode do not match.',
                        autoClose: false
                    });
                }
            }
        });
    }
})

与按钮的JavaScript控制器一起,您可以通过seconde.hbs和sectent.hbs复制来自每个按钮从每个文件夹扩展的基本控制器。文件夹结构将如下所示:

./clients/base/fields/zipcode-check-button/

  • zipcode-check-button.js
  • 细节.HBS.
  • 编辑

./clients/base/fields/zipcode-check-rowaction/

  • zipcode-check-rowaction.js
  • 细节.HBS.
  • 编辑

 In the Handlebar files, you should add a custom CSS class called zip-check-btn to each of the layouts, as a way to find the elements on the page. This is also used for the ZipcodeCheckButton to isolate the event trigger. Example below:

。/ collents/base/fields/zipcode-check-button/edit.hbs.

<a href="{{#if fullRoute}}#{{fullRoute}}{{else}}{{#if def.route}}#{{buildRoute context=context model=model action=def.route.action}}{{else}}javascript:void(0);{{/if}}{{/if}}"
    class="btn{{#if def.primary}} btn-primary{{/if}} zip-check-btn"
    {{#if def.tooltip}}
        rel="tooltip"
        data-placement="bottom"
        title="{{str def.tooltip模块}}"
    {{/if}}
    {{#if ariaLabel}}aria-label="{{ariaLabel}}"{{/if}}
    role="button" tabindex="{{tabIndex}}" name="{{name}}">{{#if def.icon}}<i class="fa {{def.icon}}"></i> {{/if}}{{label}}</a>

一旦我们有按钮控制器和模板设置,我们就可以将按钮添加到特定模块的视图元数据。

将按钮附加到元数据

创建按钮后,您需要将按钮附加到视图元数据。为此,您可以使用 扩展框架。以下示例将在“帐户记录视图”视图和“联系人记录”视图上的“操作”菜单上添加一个按钮。请注意,此示例假定您已创建 划痕按钮 above.

./custom/extension/modules/accounts/ext/clients/base/views/record/addzipcodecheckrowaction.php.

$buttons = isset($viewdefs['Accounts']['base']['view']['record']['buttons'])?$viewdefs['Accounts']['base']['view']['record']['buttons']:array();

if (!empty($buttons)) {
    foreach ($buttons as $key => $button) {
        if ($button['type'] == 'actiondropdown' && $button['name'] == 'main_dropdown') {
            $viewdefs['Accounts']['base']['view']['record']['buttons'][$key]['buttons'][] = array(
                'type' => 'divider',
            );
            $viewdefs['Accounts']['base']['view']['record']['buttons'][$key]['buttons'][] = array(
                'type' => 'zipcode-check-rowaction',
                'event' => 'button:zipcode_check:click',
                'name' => 'zipcode_check_button',
                'label' => 'LBL_ZIPCODE_CHECK_BUTTON_LABEL',
                'acl_action' => 'edit',
                'showOn' => 'view',
            );
            break;
        }
    }
}

./custom/extension/modules/contacts/ext/clients/base/views/record/addzipcodecheckbutton.php.

$buttons = isset($viewdefs['Contacts']['base']['view']['record']['buttons'])?$viewdefs['Contacts']['base']['view']['record']['buttons']:array();
$zipCodeButton = array (
    'type' => 'zipcode-check-button',
    'event' => 'button:zipcode_check:click',
    'name' => 'zipcode_check_button',
    'label' => 'LBL_ZIPCODE_CHECK_BUTTON_LABEL',
    'acl_action' => 'edit',
    'zip_code_field' => 'primary_address_postalcode',
    'city_field' => 'primary_address_city'
);

if (!empty($buttons)){
    foreach($buttons as $key => $button){
        if ($button['type'] == 'actiondropdown' && $button['name'] == 'main_dropdown'){
            //Get everything from this point down
            $slicedBtns = array_slice($viewdefs['Contacts']['base']['view']['record']['buttons'],$key);
            //Remove everything from this point down
            array_splice($viewdefs['Contacts']['base']['view']['record']['buttons'],$key);
            //Add Zip Code Button
            $viewdefs['Contacts']['base']['view']['record']['buttons'][] = $zipCodeButton;
            //Add back the buttons we removed
            foreach($slicedBtns as $oldButton){
                $viewdefs['Contacts']['base']['view']['record']['buttons'][] = $oldButton;
            }
            break;
        }
    }
} else {
    $viewdefs['Contacts']['base']['view']['record']['buttons'] = array(
        $zipCodeButton
    );
}
unset($zipCodeButton);

现在需要的最后一件事是定义按钮的标签。

定义按钮标签

由于按钮在多个模块上全局工作,我们可以在应用程序级别定义标签。

./custom/extension/pplication/ext/language/en_us.zipcodecheckbutton.php.

$app_strings['LBL_ZIPCODE_CHECK_BUTTON_LABEL'] = 'Verify Zip Code';

 所有文件到位后,您可以运行快速修复和重建,并将显示按钮,并检查Zipcode字段,以查找联系人和帐户记录视图,而无需扩展模块记录视图控制器。

最后修改:2021-01-06 23:28:41