YetiForceCompany/YetiForceCRM

View on GitHub
public_html/layouts/basic/modules/Vtiger/resources/Edit.js

Summary

Maintainability
F
3 wks
Test Coverage
/*+***********************************************************************************
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
 * ("License"); You may not use this file except in compliance with the License
 * The Original Code is:  vtiger CRM Open Source
 * The Initial Developer of the Original Code is vtiger.
 * Portions created by vtiger are Copyright (C) vtiger.
 * All Rights Reserved.
 * Contributor(s): YetiForce S.A.
 *************************************************************************************/
'use strict';

$.Class(
    'Vtiger_Edit_Js',
    {
        //Event that will triggered when reference field is selected
        referenceSelectionEvent: 'Vtiger.Reference.Selection',
        //Event that will triggered when reference field is selected
        referenceDeSelectionEvent: 'Vtiger.Reference.DeSelection',
        //Event that will triggered before saving the record
        recordPreSave: 'Vtiger.Record.PreSave',
        editInstance: false,
        inventoryController: false,
        /**
         * Function to get Instance by name
         * @params moduleName:-- Name of the module to create instance
         */
        getInstanceByModuleName: function (moduleName) {
            if (typeof moduleName === 'undefined') {
                moduleName = app.getModuleName();
            }
            let parentModule = app.getParentModuleName(),
                moduleClassName,
                fallbackClassName,
                instance;
            if (parentModule === 'Settings') {
                moduleClassName = parentModule + '_' + moduleName + '_Edit_Js';
                if (typeof window[moduleClassName] === 'undefined') {
                    moduleClassName = moduleName + '_Edit_Js';
                }
                fallbackClassName = parentModule + '_Vtiger_Edit_Js';
                if (typeof window[fallbackClassName] === 'undefined') {
                    fallbackClassName = 'Vtiger_Edit_Js';
                }
            } else {
                moduleClassName = moduleName + '_Edit_Js';
                fallbackClassName = 'Vtiger_Edit_Js';
            }
            if (typeof window[moduleClassName] !== 'undefined') {
                instance = new window[moduleClassName]();
            } else {
                instance = new window[fallbackClassName]();
            }
            instance.moduleName = moduleName;
            return instance;
        },
        getInstance: function () {
            if (Vtiger_Edit_Js.editInstance == false) {
                let instance = Vtiger_Edit_Js.getInstanceByModuleName();
                Vtiger_Edit_Js.editInstance = instance;
                return instance;
            }
            return Vtiger_Edit_Js.editInstance;
        },
        /**
         * Record save ajax
         *
         * `Vtiger_Edit_Js.saveAjax({
         *        value: 'value',
         *        field: 'field'
         *    }).done(() => {})
         *    .fail((error, err) => {});`
         *
         * @param {object} params
         * @returns {Promise}
         */
        saveAjax: function (params, progressIndicator = false) {
            const aDeferred = $.Deferred();
            if (typeof params === 'undefined' || $.isEmptyObject(params)) {
                aDeferred.reject();
                return aDeferred.promise();
            }
            if (!params['record'] && app.getRecordId()) {
                params['record'] = app.getRecordId();
            }
            if (!params['module']) {
                params['module'] = app.getModuleName();
            }
            params['action'] = 'SaveAjax';
            params = {
                data: params,
                async: false,
                dataType: 'json'
            };
            if (progressIndicator) {
                document.progressLoader = $.progressIndicator({
                    message: app.vtranslate('JS_SAVE_LOADER_INFO'),
                    position: 'html',
                    blockInfo: {
                        enabled: true
                    }
                });
            }
            this.saveAjaxValidation(params).then((response) => {
                if (response === true) {
                    delete params.data.mode;
                    AppConnector.request(params)
                        .done(function (responseData) {
                            aDeferred.resolve(responseData);
                            if (progressIndicator) {
                                document.progressLoader.progressIndicator({ mode: 'hide' });
                            }
                        })
                        .fail((jqXHR, textStatus, errorThrown) => {
                            aDeferred.reject(jqXHR, textStatus, errorThrown);
                            if (progressIndicator) {
                                document.progressLoader.progressIndicator({ mode: 'hide' });
                            }
                            app.showNotify({
                                text: app.vtranslate('JS_ERROR'),
                                type: 'error'
                            });
                        });
                } else {
                    aDeferred.resolve({ success: false });
                    if (progressIndicator) {
                        document.progressLoader.progressIndicator({ mode: 'hide' });
                    }
                }
            });
            return aDeferred.promise();
        },
        /**
         * Record pre save validation
         * @param {object} params
         * @returns {Promise}
         */
        saveAjaxValidation: function (params) {
            const aDeferred = $.Deferred();
            if (this.getInstance().checkPreSaveValidation()) {
                let paramsTemp = JSON.parse(JSON.stringify(params));
                paramsTemp.data.mode = 'preSaveValidation';
                AppConnector.request(paramsTemp)
                    .done((data) => {
                        const response = data.result;
                        let lock = false;
                        for (let i in response) {
                            if (response[i].result !== true) {
                                if (response[i].type === 'confirm' && typeof response[i].hash !== 'undefined') {
                                    app.showConfirmModal({
                                        text: response[i].message || '',
                                        confirmedCallback: () => {
                                            let handlers = {};
                                            if (typeof params.data.skipHandlers !== 'undefined') {
                                                handlers = JSON.parse(params.data.skipHandlers);
                                            }
                                            handlers[i] = response[i].hash;
                                            params.data.skipHandlers = JSON.stringify(handlers);
                                            this.saveAjaxValidation(params, form).then((responsePart) => {
                                                aDeferred.resolve(responsePart);
                                            });
                                        },
                                        rejectedCallback: () => {
                                            aDeferred.resolve(false);
                                        }
                                    });
                                    lock = true;
                                    break;
                                } else if (
                                    typeof response[i].showModal !== 'undefined' &&
                                    typeof response[i].showModal.url !== 'undefined'
                                ) {
                                    app.showModalWindow(null, response[i].showModal.url, function (modalContainer) {
                                        app.registerModalController(undefined, modalContainer, function (_, instance) {
                                            instance.formContainer = form;
                                        });
                                    });
                                } else {
                                    app.showNotify({
                                        text: response[i].message ? response[i].message : app.vtranslate('JS_ERROR'),
                                        type: 'error'
                                    });
                                }
                            }
                        }
                        if (data.result.length <= 0) {
                            aDeferred.resolve(true);
                        } else if (!lock) {
                            aDeferred.resolve(false);
                        }
                    })
                    .fail((textStatus, errorThrown) => {
                        app.showNotify({
                            text: app.vtranslate('JS_ERROR'),
                            type: 'error'
                        });
                        aDeferred.resolve(false);
                    });
            } else {
                aDeferred.resolve(true);
            }
            return aDeferred.promise();
        }
    },
    {
        formElement: false,
        relationOperation: '',
        moduleName: app.getModuleName(),
        getForm: function () {
            if (this.formElement == false) {
                this.setForm($('#EditView'));
            }
            return this.formElement;
        },
        setForm: function (element) {
            this.formElement = element;
            let module;
            if ((module = $('input[name="module"]', element))) {
                this.moduleName = module.val();
            }
            return this;
        },
        getRecordsListParams: function (container) {
            let formElement = container.closest('form');
            let sourceModule = $('input[name="module"]', formElement).val();
            let popupReferenceModule = $('input[name="popupReferenceModule"]', container).val();
            let sourceFieldElement = $('input[class="sourceField"]', container);
            let sourceField = sourceFieldElement.attr('name');
            let sourceRecordElement = $('input[name="record"]', formElement);
            let sourceRecordId = '';
            if (sourceRecordElement.length > 0) {
                sourceRecordId = sourceRecordElement.val();
            }
            let isMultiple = false;
            if (sourceFieldElement.data('multiple') == true) {
                isMultiple = true;
            }
            let filterFields = {};
            let mappingRelatedField = formElement.find('input[name="mappingRelatedField"]').val();
            let mappingRelatedModule = mappingRelatedField ? JSON.parse(mappingRelatedField) : [];
            if (
                mappingRelatedModule[sourceField] != undefined &&
                mappingRelatedModule[sourceField][popupReferenceModule] != undefined
            ) {
                $.each(mappingRelatedModule[sourceField][popupReferenceModule], function (index, value) {
                    let mapFieldElement = formElement.find('[name="' + index + '"]');
                    if (mapFieldElement.length && mapFieldElement.val() != '') {
                        filterFields[index] = mapFieldElement.val();
                    }
                });
            }
            let listFilterFieldsJson = formElement.find('input[name="listFilterFields"]').val();
            let listFilterFields = listFilterFieldsJson ? JSON.parse(listFilterFieldsJson) : [];
            if (
                listFilterFields[sourceField] != undefined &&
                listFilterFields[sourceField][popupReferenceModule] != undefined
            ) {
                $.each(listFilterFields[sourceField][popupReferenceModule], function (index, value) {
                    let mapFieldElement = formElement.find('[name="' + index + '"]');
                    if (mapFieldElement.length && mapFieldElement.val() != '') {
                        filterFields[index] = mapFieldElement.val();
                    }
                });
            }
            let params = {
                module: popupReferenceModule,
                src_module: sourceModule,
                src_field: sourceField,
                src_record: sourceRecordId,
                filterFields: filterFields
            };
            let searchParamsElement = $('input[name="searchParams"]', container);
            let searchParams = searchParamsElement.length > 0 ? JSON.parse(searchParamsElement.val()) : null;
            if (searchParams && searchParams[popupReferenceModule]) {
                params['search_params'] = searchParams[popupReferenceModule];
            }
            let modalParamsElement = $('input[name="modalParams"]', container);
            if (modalParamsElement.length > 0) {
                params['modal_params'] = modalParamsElement.val();
            }
            let lockedFieldsElement = $('input[name="lockedFields"]', container);
            if (lockedFieldsElement.length > 0) {
                params['lockedFields'] = lockedFieldsElement.val();
            }
            $.each(['link', 'process'], function (index, value) {
                let fieldElement = formElement.find('[name="' + value + '"]');
                if (fieldElement.length && fieldElement.val() != '' && fieldElement.val() != 0) {
                    params[value] = fieldElement.val();
                }
            });
            if (isMultiple) {
                params.multi_select = true;
            }
            return params;
        },
        /**
         * Show records list modal
         * @param {jQuery.Event} e
         */
        showRecordsList: function (e) {
            let parentElem = $(e.target).closest('.fieldValue');
            if (parentElem.length <= 0) {
                parentElem = $(e.target).closest('td');
            }
            let params = this.getRecordsListParams(parentElem);
            app.showRecordsList(params, (_modal, instance) => {
                instance.setSelectEvent((data) => {
                    this.setReferenceFieldValue(parentElem, data);
                });
            });
        },
        setReferenceFieldValue: function (container, params) {
            const thisInstance = this;
            let sourceFieldElement = container.find('input.sourceField');
            let sourceField = sourceFieldElement.attr('name');
            let fieldElement = container.find('input[name="' + sourceField + '"]');
            let sourceFieldDisplay = sourceField + '_display';
            let fieldDisplayElement = container.find('input[name="' + sourceFieldDisplay + '"]');
            let popupReferenceModule = container.find('input[name="popupReferenceModule"]').val();
            let selectedName = params.name;
            let id = params.id;

            container.find('.clearReferenceSelection').trigger('click');

            fieldElement.val(id);
            fieldDisplayElement.val(app.decodeHTML(selectedName)).attr('readonly', true);
            fieldElement.trigger(Vtiger_Edit_Js.referenceSelectionEvent, {
                module: popupReferenceModule,
                record: id,
                selectedName: selectedName
            });
            fieldDisplayElement.validationEngine('closePrompt', fieldDisplayElement);
            if (sourceFieldElement.data('type') == 'inventory') {
                return params;
            }
            let formElement = container.closest('form');
            let mappingRelatedField = this.getMappingRelatedField(sourceField, popupReferenceModule, formElement);
            if (typeof mappingRelatedField !== 'undefined') {
                let params = {
                    module: popupReferenceModule,
                    record: id
                };
                app.getRecordDetails(params).done(function (data) {
                    let response = (params.data = data['result']['data']);
                    app.event.trigger('EditView.SelectReference', params, formElement, data);
                    $.each(mappingRelatedField, function (key, value) {
                        if (response[value[0]] != 0) {
                            let mapFieldElement = formElement.find('[name="' + key + '"]');
                            let fieldinfo = mapFieldElement.data('fieldinfo');
                            if (data['result']['type'][value[0]] === 'date' || data['result']['type'][value[0]] === 'datetime') {
                                mapFieldElement.val(data['result']['displayData'][value[0]]);
                            } else if (data['result']['type'][value[0]] === 'multipicklist') {
                                let mapFieldElementMultiselect = formElement.find('[name="' + key + '[]"]');
                                if (mapFieldElementMultiselect.length > 0) {
                                    let multipleAttr = mapFieldElementMultiselect.attr('multiple');
                                    let splitValues = response[value[0]].split(' |##| ');
                                    if (typeof multipleAttr !== 'undefined' && multipleAttr !== false && splitValues.length > 0) {
                                        mapFieldElementMultiselect.val(splitValues).trigger('change');
                                    }
                                }
                            } else if (mapFieldElement.is('select')) {
                                if (mapFieldElement.find('option[value="' + response[value[0]] + '"]').length) {
                                    mapFieldElement.val(response[value[0]]).trigger('change');
                                } else if (mapFieldElement.data('fieldinfo').picklistvalues.hasOwnProperty(response[value[0]])) {
                                    let newOption = new Option(response[value[0]], response[value[0]], true, true);
                                    mapFieldElement.append(newOption).trigger('change');
                                }
                            } else if (mapFieldElement.length == 0) {
                                $("<input type='hidden'/>").attr('name', key).attr('value', response[value[0]]).appendTo(formElement);
                            } else {
                                mapFieldElement.val(response[value[0]]);
                            }
                            let mapFieldDisplayElement = formElement.find('input[name="' + key + '_display"]');
                            if (mapFieldDisplayElement.length > 0) {
                                mapFieldDisplayElement.val(data['result']['displayData'][value[0]]).attr('readonly', true);
                                if (fieldinfo.type === 'reference') {
                                    let referenceModulesList = mapFieldElement.closest('.fieldValue').find('.referenceModulesList');
                                    if (referenceModulesList.length > 0 && value[1]) {
                                        referenceModulesList.val(value[1]).trigger('change');
                                    }
                                    thisInstance.setReferenceFieldValue(mapFieldDisplayElement.closest('.fieldValue'), {
                                        name: data['result']['displayData'][value[0]],
                                        id: response[value[0]]
                                    });
                                }
                            }
                        }
                    });
                });
            }
        },
        getRelationOperation: function () {
            if (this.relationOperation === '') {
                let relationOperation = $('[name="relationOperation"]');
                if (relationOperation.length) {
                    this.relationOperation = relationOperation.val();
                } else {
                    this.relationOperation = false;
                }
            }
            return this.relationOperation;
        },
        proceedRegisterEvents: function () {
            return $('.recordEditView').length > 0;
        },
        referenceModulePopupRegisterEvent: function (container) {
            container.on('click', '.relatedPopup', (e) => {
                this.showRecordsList(e);
            });
            let moduleList = container.find('.referenceModulesList');
            App.Fields.Picklist.showSelect2ElementView(container.find('.referenceModulesList:visible'));
            moduleList.on('change', (e) => {
                let element = $(e.currentTarget);
                let parentElem = element.closest('.fieldValue');
                let popupReferenceModule = element.val();
                let referenceModuleElement = $('input[name="popupReferenceModule"]', parentElem);
                let prevSelectedReferenceModule = referenceModuleElement.val();
                referenceModuleElement.val(popupReferenceModule);
                //If Reference module is changed then we should clear the previous value
                if (prevSelectedReferenceModule != popupReferenceModule) {
                    parentElem.find('.clearReferenceSelection').trigger('click');
                }
            });
        },
        getReferencedModuleName: function (parenElement) {
            return $('input[name="popupReferenceModule"]', parenElement).val();
        },
        searchModuleNames: function (params) {
            let aDeferred = $.Deferred();
            if (typeof params.module === 'undefined') {
                params.module = this.moduleName;
            }
            if (typeof params.action === 'undefined') {
                params.action = 'BasicAjax';
            }
            AppConnector.request(params)
                .done(function (data) {
                    aDeferred.resolve(data);
                })
                .fail(function (error) {
                    aDeferred.reject();
                });
            return aDeferred.promise();
        },
        /**
         * Function to get reference search params
         */
        getReferenceSearchParams: function (element) {
            let tdElement = $(element).closest('.fieldValue');
            let params = {};
            let searchModule = this.getReferencedModuleName(tdElement);
            params.search_module = searchModule;
            return params;
        },
        /**
         * Function which will handle the reference auto complete event registrations
         * @params - container <jQuery> - element in which auto complete fields needs to be searched
         */
        registerAutoCompleteFields: function (container) {
            let thisInstance = this;
            let formElement = container.closest('form');
            container.find('input.autoComplete').autocomplete({
                delay: '600',
                minLength: '3',
                source: function (request, response) {
                    //element will be array of dom elements
                    //here this refers to auto complete instance
                    let inputElement = $(this.element[0]);
                    let searchValue = request.term;
                    let params = thisInstance.getReferenceSearchParams(inputElement);
                    params.search_value = searchValue;
                    let sourceRecordElement = $('input[name="record"]', formElement);
                    if (sourceRecordElement.length > 0 && sourceRecordElement.val()) {
                        params.src_record = sourceRecordElement.val();
                    }
                    thisInstance.searchModuleNames(params).done(function (data) {
                        let reponseDataList = [];
                        let serverDataFormat = data.result;
                        if (serverDataFormat.length <= 0) {
                            $(inputElement).val('');
                            serverDataFormat = new Array({
                                label: app.vtranslate('JS_NO_RESULTS_FOUND'),
                                type: 'no results'
                            });
                        }
                        for (let id in serverDataFormat) {
                            let responseData = serverDataFormat[id];
                            reponseDataList.push(responseData);
                        }
                        response(reponseDataList);
                        app.event.trigger('EditView.AfterSearch', {
                            field: inputElement,
                            params: params
                        });
                    });
                },
                select: function (event, ui) {
                    let selectedItemData = ui.item;
                    //To stop selection if no results is selected
                    if (typeof selectedItemData.type !== 'undefined' && selectedItemData.type == 'no results') {
                        return false;
                    }
                    selectedItemData.name = selectedItemData.value;
                    let element = $(this);
                    let tdElement = element.closest('.fieldValue');
                    thisInstance.setReferenceFieldValue(tdElement, selectedItemData);
                },
                change: function (event, ui) {
                    let element = $(this);
                    //if you dont have readonly attribute means the user didnt select the item
                    if (element.attr('readonly') == undefined) {
                        element.closest('.fieldValue').find('.clearReferenceSelection').trigger('click');
                    }
                },
                open: function (event, ui) {
                    //To Make the menu come up in the case of quick create
                    $(this).data('ui-autocomplete').menu.element.css('z-index', '100001');
                },
                position: { collision: 'flipfit' }
            });
        },
        /**
         * Function which will register reference field clear event
         * @params - container <jQuery> - element in which auto complete fields needs to be searched
         */
        registerClearReferenceSelectionEvent: function (container) {
            let thisInstance = this;
            container.on('click', '.clearReferenceSelection', function (e) {
                let element = $(e.currentTarget);
                thisInstance.clearFieldValue(element);
                element.closest('.fieldValue').find('.sourceField').trigger(Vtiger_Edit_Js.referenceDeSelectionEvent);
                e.preventDefault();
            });
        },
        clearFieldValue: function (element) {
            const self = this;
            let fieldValueContener = element.closest('.fieldValue');
            let fieldNameElement = fieldValueContener.find('.sourceField');
            let fieldName = fieldNameElement.attr('name');
            let referenceModule = fieldValueContener.find('input[name="popupReferenceModule"]').val();
            let formElement = fieldValueContener.closest('form');
            if (fieldNameElement.data('fieldtype') == 'reference') {
                fieldNameElement.val(0);
            } else {
                fieldNameElement.val('');
            }
            fieldValueContener
                .find('#' + fieldName + '_display')
                .removeAttr('readonly')
                .val('');
            app.event.trigger('EditView.ClearField', {
                fieldName: fieldName,
                referenceModule: referenceModule
            });
            let mappingRelatedField = this.getMappingRelatedField(fieldName, referenceModule, formElement);
            $.each(mappingRelatedField, function (key, value) {
                let mapFieldElement = formElement.find('[name="' + key + '"]');
                if (mapFieldElement.is('select')) {
                    mapFieldElement.val(mapFieldElement.find('option:first').val()).trigger('change');
                } else {
                    mapFieldElement.val('');
                }
                let mapFieldDisplayElement = formElement.find('input[name="' + key + '_display"]');
                if (mapFieldDisplayElement.length > 0) {
                    mapFieldDisplayElement.val('').attr('readonly', false);
                    let referenceModulesList = formElement.find(
                        '#' + self.moduleName + '_editView_fieldName_' + key + '_dropDown'
                    );
                    if (referenceModulesList.length > 0 && value[1]) {
                        referenceModulesList.val(referenceModulesList.find('option:first').val()).trigger('change');
                    }
                }
            });
        },
        /**
         * Function which will register event to prevent form submission on pressing on enter
         * @params - container <jQuery> - element in which auto complete fields needs to be searched
         */
        registerPreventingEnterSubmitEvent: function (container) {
            container.on('keypress', function (e) {
                //Stop the submit when enter is pressed in the form
                let currentElement = $(e.target);
                if (e.which == 13 && !currentElement.is('textarea')) {
                    e.preventDefault();
                }
            });
        },
        registerTimeFields: function (container) {
            app.registerEventForClockPicker();
            App.Fields.Date.register(container);
            App.Fields.DateTime.register(container);
        },
        referenceCreateHandler: function (container) {
            let formData = this.getForm().serializeFormData();
            for (let i in formData) {
                if (!formData[i] || $.inArray(i, ['_csrf', 'action']) != -1) {
                    delete formData[i];
                }
            }
            App.Components.QuickCreate.createRecord(this.getReferencedModuleName(container), {
                data: {
                    sourceModule: formData['module'],
                    sourceRecordData: formData
                },
                callbackFunction: (data) => {
                    this.setReferenceFieldValue(container, {
                        name: data.result._recordLabel,
                        id: data.result._recordId
                    });
                },
                noCache: true
            });
        },
        /**
         * Function which will register event for create of reference record
         * This will allow users to create reference record from edit view of other record
         */
        registerReferenceCreate: function (container) {
            let thisInstance = this;
            container.on('click', '.createReferenceRecord', function (e) {
                let element = $(e.currentTarget);
                let controlElementDiv = element.closest('.fieldValue');
                thisInstance.referenceCreateHandler(controlElementDiv);
            });
        },
        addressFieldsMapping: [
            'buildingnumber',
            'localnumber',
            'addresslevel1',
            'addresslevel2',
            'addresslevel3',
            'addresslevel4',
            'addresslevel5',
            'addresslevel6',
            'addresslevel7',
            'addresslevel8',
            'pobox'
        ],
        addressFieldsMappingBlockID: {
            LBL_ADDRESS_INFORMATION: 'a',
            LBL_ADDRESS_BILLING: 'a',
            LBL_ADDRESS_MAILING_INFORMATION: 'b',
            LBL_ADDRESS_SHIPPING: 'b',
            LBL_ADDRESS_DELIVERY_INFORMATION: 'c'
        },
        addressFieldsData: false,
        /**
         * Function to register event for copying addresses
         */
        registerEventForCopyAddress: function () {
            let thisInstance = this;
            this.formElement
                .find(
                    '.js-toggle-panel:not(.inventoryHeader):not(.inventoryItems) .fieldValue, .js-toggle-panel:not(.inventoryHeader):not(.inventoryItems) .fieldLabel'
                )
                .each(function () {
                    let block = $(this);
                    let referenceModulesList = block.find('.referenceModulesList');
                    if (referenceModulesList.length > 0) {
                        referenceModulesList.on('change', function () {
                            thisInstance.formElement
                                .find('[class*="copyAddressFrom"]:not(.copyAddressFromMain, .copyAddressFromMailing)')
                                .addClass('d-none');
                            thisInstance.registerEventForCopyBlockAddress($(this).val(), block.find('.sourceField').attr('name'));
                        });
                        referenceModulesList.trigger('change');
                    } else {
                        let referenceFields = block.find('[name="popupReferenceModule"]');
                        if (referenceFields.length > 0) {
                            thisInstance.registerEventForCopyBlockAddress(
                                referenceFields.val(),
                                block.find('.sourceField').attr('name')
                            );
                        }
                    }
                });
            this.formElement.find('.js-toggle-panel').each(function () {
                let hideCopyAddressLabel = true;
                $(this)
                    .find('.adressAction button')
                    .each(function () {
                        if ($(this).hasClass('d-none') == false) {
                            hideCopyAddressLabel = false;
                        }
                    });
                if (hideCopyAddressLabel) {
                    $(this).find('.copyAddressLabel').addClass('d-none');
                }
            });
            this.formElement.find('.copyAddressFromMain').on('click', function (e) {
                let element = $(this);
                let block = element.closest('.js-toggle-panel');
                let from = element.data('label');
                let to = block.data('label');
                thisInstance.copyAddress(from, to, false, false);
            });
            this.formElement.find('.copyAddressFromMailing').on('click', function (e) {
                let element = $(this);
                let block = element.closest('.js-toggle-panel');
                let from = element.data('label');
                let to = block.data('label');
                thisInstance.copyAddress(from, to, false, false);
            });
            this.formElement.find('.copyAddressFromDelivery').on('click', function (e) {
                let element = $(this);
                let block = element.closest('.js-toggle-panel');
                let from = element.data('label');
                let to = block.data('label');
                thisInstance.copyAddress(from, to, false, false);
            });
        },
        registerEventForCopyBlockAddress: function (moduleName, fieldName) {
            const self = this;
            if (moduleName == 'Accounts') {
                self.enableCopyAddressFromModule(
                    moduleName,
                    self.formElement,
                    'copyAddressFromAccount',
                    fieldName,
                    'JS_PLEASE_SELECT_AN_ACCOUNT_TO_COPY_ADDRESS'
                );
            } else if (moduleName == 'Contacts') {
                self.enableCopyAddressFromModule(
                    moduleName,
                    self.formElement,
                    'copyAddressFromContact',
                    fieldName,
                    'JS_PLEASE_SELECT_AN_CONTACT_TO_COPY_ADDRESS'
                );
            } else if (moduleName == 'Leads') {
                self.enableCopyAddressFromModule(
                    moduleName,
                    self.formElement,
                    'copyAddressFromLead',
                    fieldName,
                    'JS_PLEASE_SELECT_AN_LEAD_TO_COPY_ADDRESS'
                );
            } else if (moduleName == 'Vendors') {
                self.enableCopyAddressFromModule(
                    moduleName,
                    self.formElement,
                    'copyAddressFromVendor',
                    fieldName,
                    'JS_PLEASE_SELECT_AN_VENDOR_TO_COPY_ADDRESS'
                );
            }
        },
        /**
         * Show button to copy the address details from selected module
         */
        enableCopyAddressFromModule: function (moduleName, formElement, className, fieldName, label) {
            let thisInstance = this;
            formElement
                .find('.' + className)
                .removeClass('d-none')
                .on('click', function (e) {
                    let element = $(this);
                    let recordRelativeAccountId = $('[name="' + fieldName + '"]').val();
                    if (recordRelativeAccountId == '' || recordRelativeAccountId == '0') {
                        app.showNotify({
                            text: app.vtranslate(label),
                            type: 'error'
                        });
                    } else {
                        let recordRelativeAccountName = $('#' + fieldName + '_display').val();
                        let data = {
                            record: recordRelativeAccountId,
                            selectedName: recordRelativeAccountName,
                            module: moduleName
                        };
                        thisInstance.copyAddressDetails(
                            element.data('label'),
                            element.closest('.js-toggle-panel').data('label'),
                            data,
                            element.closest('.js-toggle-panel')
                        );
                        element.attr('checked', 'checked');
                    }
                });
        },
        /**
         * Function which will copy the address details
         */
        copyAddressDetails: function (from, to, data, container) {
            app.getRecordDetails(data).done((response) => {
                this.addressFieldsData = response['result'];
                this.copyAddress(from, to, true, data['module']);
                app.event.trigger('Edit.CopyAddress', this, from, to, response, data, container);
            });
        },
        /**
         * Function to copy address between fields
         * @param strings which accepts value as either odd or even
         */
        copyAddress: function (fromLabel, toLabel, relatedRecord, sourceModule) {
            const thisInstance = this;
            let formElement = this.getForm(),
                status = false,
                addressMapping = this.addressFieldsMapping,
                BlockIds = this.addressFieldsMappingBlockID,
                from = BlockIds[fromLabel];
            if (relatedRecord === false || sourceModule === false) from = BlockIds[fromLabel];
            let to = BlockIds[toLabel],
                key,
                fromElement,
                fromElementLabel,
                nameElementFrom,
                nameElementTo;
            for (key in addressMapping) {
                nameElementFrom = addressMapping[key] + from;
                nameElementTo = addressMapping[key] + to;
                if (relatedRecord) {
                    fromElement = thisInstance.addressFieldsData['data'][nameElementFrom];
                    fromElementLabel = thisInstance.addressFieldsData['displayData'][nameElementFrom];
                } else {
                    fromElement = formElement.find('[name="' + nameElementFrom + '"]').val();
                    fromElementLabel = formElement.find('[name="' + nameElementFrom + '_display"]').val();
                }
                let toElement = formElement.find('[name="' + nameElementTo + '"]'),
                    toElementLable = formElement.find('[name="' + nameElementTo + '_display"]');
                if (fromElement !== '' && fromElement !== '0' && fromElement !== undefined) {
                    if (toElementLable.length > 0) toElementLable.attr('readonly', true);
                    status = true;
                    toElement.val(fromElement);
                    toElementLable.val(fromElementLabel);
                    if (toElement.is('[data-select2-id]')) {
                        if (toElement.val() !== fromElement) {
                            toElement.val('');
                        }
                        toElement.trigger('change');
                    }
                } else {
                    toElement.val('');
                    toElement.attr('readonly', false);
                }
            }
            if (status === false) {
                let errorMsg;
                if (sourceModule === 'Accounts') {
                    errorMsg = 'JS_SELECTED_ACCOUNT_DOES_NOT_HAVE_AN_ADDRESS';
                } else if (sourceModule === 'Contacts') {
                    errorMsg = 'JS_SELECTED_CONTACT_DOES_NOT_HAVE_AN_ADDRESS';
                } else {
                    errorMsg = 'JS_DOES_NOT_HAVE_AN_ADDRESS';
                }
                app.showNotify({
                    text: app.vtranslate(errorMsg),
                    type: 'error'
                });
            }
        },
        registerReferenceSelectionEvent: function (container) {
            let thisInstance = this;
            let relategField = container.find("input[name*='addresslevel']");
            relategField.on(Vtiger_Edit_Js.referenceSelectionEvent, function (e, data) {
                let blockContainer = $(e.currentTarget).closest('.js-toggle-panel');
                thisInstance.copyAddressDetailsRef(data, blockContainer);
            });
        },
        copyAddressDetailsRef: function (data, container) {
            let thisInstance = this;
            app
                .getRecordDetails(data)
                .done(function (data) {
                    let response = data['result'];
                    thisInstance.mapAddressDetails(response, container);
                })
                .fail(function (error, err) {});
        },
        mapAddressDetails: function (result, container) {
            for (let key in result) {
                if (key.indexOf('addresslevel') != -1) {
                    if (container.find('[name="' + key + '"]').length != 0) {
                        container.find('[name="' + key + '"]').val(result['data'][key]);
                        container.find('[name="' + key + '"]').attr('readonly', true);
                        container.find('[name="' + key + '_display"]').val(result['displayData'][key]);
                        container.find('[name="' + key + '_display"]').attr('readonly', true);
                    }
                    if (
                        container.find('[name="' + key + 'a"]').length != 0 &&
                        container.find('[name="' + key + 'a"]').val() == 0 &&
                        result['data'][key] != 0
                    ) {
                        container.find('[name="' + key + 'a"]').val(result['data'][key]);
                        container.find('[name="' + key + 'a"]').attr('readonly', true);
                        container.find('[name="' + key + 'a_display"]').val(result['displayData'][key]);
                        container.find('[name="' + key + 'a_display"]').attr('readonly', true);
                    }
                    if (
                        container.find('[name="' + key + 'b"]').length != 0 &&
                        container.find('[name="' + key + 'b"]').val() == 0 &&
                        result['data'][key] != 0
                    ) {
                        container.find('[name="' + key + 'b"]').val(result['data'][key]);
                        container.find('[name="' + key + 'b"]').attr('readonly', true);
                        container.find('[name="' + key + 'b_display"]').val(result['displayData'][key]);
                        container.find('[name="' + key + 'b_display"]').attr('readonly', true);
                    }
                    if (
                        container.find('[name="' + key + 'c"]').length != 0 &&
                        container.find('[name="' + key + 'c"]').val() == 0 &&
                        result['data'][key] != 0
                    ) {
                        container.find('[name="' + key + 'c"]').val(result['data'][key]);
                        container.find('[name="' + key + 'c"]').attr('readonly', true);
                        container.find('[name="' + key + 'c_display"]').val(result['displayData'][key]);
                        container.find('[name="' + key + 'c_display"]').attr('readonly', true);
                    }
                }
            }
        },
        registerMaskFields: function (container) {
            container.find('[data-inputmask]').inputmask();
        },
        registerSubmitEvent: function () {
            let editViewForm = this.getForm();
            editViewForm.on('submit', function (e) {
                //Form should submit only once for multiple clicks also
                if (typeof editViewForm.data('submit') !== 'undefined') {
                    return false;
                } else {
                    document.progressLoader = $.progressIndicator({
                        message: app.vtranslate('JS_SAVE_LOADER_INFO'),
                        position: 'html',
                        blockInfo: {
                            enabled: true
                        }
                    });
                    editViewForm.find('.js-toggle-panel').find('.js-block-content').removeClass('d-none');
                    if (editViewForm.validationEngine('validate')) {
                        //Once the form is submiting add data attribute to that form element
                        editViewForm.data('submit', 'true');
                        //on submit form trigger the recordPreSave event
                        let recordPreSaveEvent = $.Event(Vtiger_Edit_Js.recordPreSave);
                        editViewForm.trigger(recordPreSaveEvent, { value: 'edit' });
                        if (recordPreSaveEvent.isDefaultPrevented()) {
                            //If duplicate record validation fails, form should submit again
                            document.progressLoader.progressIndicator({ mode: 'hide' });
                            editViewForm.removeData('submit');
                            e.preventDefault();
                        }
                    } else {
                        //If validation fails, form should submit again
                        document.progressLoader.progressIndicator({ mode: 'hide' });
                        editViewForm.removeData('submit');
                        app.formAlignmentAfterValidation(editViewForm);
                    }
                }
            });
        },
        /*
         * Function to check the view permission of a record after save
         */
        registerRecordPreSaveEventEvent: function (form) {
            form.on(Vtiger_Edit_Js.recordPreSave, (e, data) => {
                this.preSaveValidation(form).done((response) => {
                    if (response !== true) {
                        e.preventDefault();
                    }
                });
            });
        },
        preSaveValidation: function (form) {
            const aDeferred = $.Deferred();
            if (form.find('#preSaveValidation').val()) {
                document.progressLoader = $.progressIndicator({
                    message: app.vtranslate('JS_SAVE_LOADER_INFO'),
                    position: 'html',
                    blockInfo: {
                        enabled: true
                    }
                });
                let formData = new FormData(form[0]);
                formData.append('mode', 'preSaveValidation');
                AppConnector.request({
                    async: false,
                    url: 'index.php',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false
                })
                    .done((data) => {
                        document.progressLoader.progressIndicator({ mode: 'hide' });
                        let response = data.result;
                        for (let i in response) {
                            if (response[i].result !== true) {
                                if (response[i].type === 'confirm' && typeof response[i].hash !== 'undefined') {
                                    app.showConfirmModal({
                                        text: response[i].message || '',
                                        confirmedCallback: () => {
                                            let handlers = {},
                                                handlerElement = form.find('input[name="skipHandlers"]');
                                            if (handlerElement.length) {
                                                handlers = JSON.parse(handlerElement.val());
                                                handlerElement.remove();
                                            }
                                            handlers[i] = response[i].hash;
                                            form.append(
                                                $('<input>', { name: 'skipHandlers', value: JSON.stringify(handlers), type: 'hidden' })
                                            );
                                            form.submit();
                                        }
                                    });
                                    aDeferred.resolve(false);
                                    break;
                                } else if (
                                    typeof response[i].showModal !== 'undefined' &&
                                    typeof response[i].showModal.url !== 'undefined'
                                ) {
                                    app.showModalWindow(null, response[i].showModal.url, function (modalContainer) {
                                        app.registerModalController(undefined, modalContainer, function (_, instance) {
                                            instance.formContainer = form;
                                        });
                                    });
                                } else {
                                    app.showNotify({
                                        text: response[i].message ? response[i].message : app.vtranslate('JS_ERROR'),
                                        type: 'error'
                                    });
                                }
                                if (response[i].hoverField != undefined) {
                                    form.find('[name="' + response[i].hoverField + '"]').focus();
                                }
                            }
                        }
                        aDeferred.resolve(data.result.length <= 0);
                    })
                    .fail((textStatus, errorThrown) => {
                        document.progressLoader.progressIndicator({ mode: 'hide' });
                        app.showNotify({
                            text: app.vtranslate('JS_ERROR'),
                            type: 'error'
                        });
                        app.errorLog(textStatus, errorThrown);
                        aDeferred.resolve(false);
                    });
            } else {
                aDeferred.resolve(true);
            }

            return aDeferred.promise();
        },
        registerLeavePageWithoutSubmit: function (form) {
            if (
                typeof CKEDITOR !== 'undefined' &&
                typeof CKEDITOR.instances !== 'undefined' &&
                Object.keys(CKEDITOR.instances).length
            ) {
                CKEDITOR.on('instanceReady', function (e) {
                    let initialFormData = form.serialize();
                    window.onbeforeunload = function (e) {
                        if (initialFormData != form.serialize() && form.data('submit') != 'true') {
                            return app.vtranslate('JS_CHANGES_WILL_BE_LOST');
                        }
                    };
                });
            } else {
                let initialFormData = form.serialize();
                window.onbeforeunload = function (e) {
                    if (initialFormData != form.serialize() && form.data('submit') != 'true') {
                        return app.vtranslate('JS_CHANGES_WILL_BE_LOST');
                    }
                };
            }
        },
        stretchCKEditor: function () {
            let row = $('.js-editor').parents('.fieldRow');
            let td = $('.js-editor').parent();
            $(row).find('.fieldLabel').remove();
            $(td).removeClass('col-md-10');
            $(td).addClass('col-md-12');
        },
        /**
         * Function to register event for ckeditor for description field
         */
        registerEventForEditor: function () {
            let form = this.getForm();
            $.each(form.find('.js-editor:not(.js-inventory-item-comment)'), (key, data) => {
                this.loadEditorElement($(data));
            });
        },
        loadEditorElement: function (noteContentElement) {
            App.Fields.Text.Editor.register(noteContentElement);
        },
        registerHelpInfo: function (form) {
            if (!form) {
                form = this.getForm();
            }
            app.showPopoverElementView(form.find('.js-help-info'));
        },
        registerBlockStatusCheckOnLoad: function () {
            let blocks = this.getForm().find('.js-toggle-panel');
            let module = this.moduleName;
            blocks.each(function (index, block) {
                let currentBlock = $(block);
                if (
                    currentBlock.find('.js-field-block-column').length !== 0 &&
                    currentBlock.find('.js-field-block-column:not(.d-none)').length === 0
                ) {
                    currentBlock.addClass('d-none');
                }
                let dynamicAttr = currentBlock.attr('data-dynamic');
                if (typeof dynamicAttr !== typeof undefined && dynamicAttr !== false) {
                    let headerAnimationElement = currentBlock.find('.js-block-toggle').not('.d-none');
                    let bodyContents = currentBlock.find('.blockContent');
                    let blockId = headerAnimationElement.data('id');
                    let cacheKey = module + '.' + blockId;
                    let value = app.cacheGet(cacheKey, null);
                    if (value != null) {
                        if (value == 1) {
                            headerAnimationElement.addClass('d-none');
                            currentBlock.find("[data-mode='show']").removeClass('d-none');
                            bodyContents.removeClass('d-none');
                        } else {
                            headerAnimationElement.addClass('d-none');
                            currentBlock.find("[data-mode='hide']").removeClass('d-none');
                            bodyContents.addClass('d-none');
                        }
                    }
                }
            });
        },
        /**
         * Visibility check block
         */
        checkVisibilityBlocks: function () {
            this.getForm()
                .find('.js-toggle-panel')
                .each(function (index, block) {
                    let currentBlock = $(block);
                    if (currentBlock.find('.js-field-block-column').length !== 0) {
                        if (currentBlock.find('.js-field-block-column:not(.d-none)').length === 0) {
                            currentBlock.addClass('d-none');
                        } else {
                            currentBlock.removeClass('d-none');
                        }
                    }
                });
        },
        registerAutoloadAddress: function () {
            const self = this;
            this.getForm()
                .find('.js-search-address')
                .each(function (_index, e) {
                    let search = $(e);
                    let container = search.closest('.js-block-content');
                    let input = search.find('.js-autoload-address');
                    input
                        .autocomplete({
                            source: function (request, response) {
                                AppConnector.request({
                                    module: self.moduleName,
                                    action: 'Fields',
                                    mode: 'findAddress',
                                    type: search.find('.js-select-operator').val(),
                                    value: request.term
                                })
                                    .done(function (requestData) {
                                        if (requestData.result === false) {
                                            app.showNotify({
                                                text: app.vtranslate('JS_ERROR'),
                                                type: 'error'
                                            });
                                        } else if (requestData.result.length) {
                                            response(requestData.result);
                                        } else {
                                            response([{ label: app.vtranslate('JS_NO_RESULTS_FOUND'), value: '' }]);
                                        }
                                    })
                                    .fail(function (_textStatus, _errorThrown, jqXHR) {
                                        app.showNotify({
                                            text: jqXHR.responseJSON.error.message,
                                            type: 'error',
                                            animation: 'show'
                                        });
                                        response([{ label: app.vtranslate('JS_NO_RESULTS_FOUND'), value: '' }]);
                                    });
                            },
                            minLength: input.data('min'),
                            select: function (_event, ui) {
                                $.each(ui.item.address, function (index, value) {
                                    let field = container.find('.fieldValue [name^=' + index + ']');
                                    if (field.length && value) {
                                        if (typeof value !== 'object') {
                                            value = [value];
                                        }
                                        $.each(value, function (_idx, v) {
                                            let select = false,
                                                element = false;
                                            if (field.prop('tagName') === 'SELECT') {
                                                if (typeof v === 'object') {
                                                    $.each(v, function (idx, x) {
                                                        element = field.find('option[data-' + idx + "='" + x + "']");
                                                        if (x && element.length) {
                                                            select = element.val();
                                                        }
                                                    });
                                                } else {
                                                    element = field.find('option:contains(' + v + ')');
                                                    if (v && element.length) {
                                                        select = element.val();
                                                    }
                                                    element = field.find('option[value="' + v + '"]');
                                                    if (v && element.length) {
                                                        select = element.val();
                                                    }
                                                }
                                            } else {
                                                select = v;
                                            }
                                            if (select) {
                                                field.val(select).change();
                                            }
                                        });
                                    } else {
                                        field.val('').change();
                                    }
                                });
                                ui.item.value = input.val();
                            }
                        })
                        .autocomplete('instance')._renderItem = function (ul, item) {
                        return $('<li>')
                            .append(`<div><span class="fi fi-${item.countryCode} mr-2"></span>${item.label}</div>`)
                            .appendTo(ul);
                    };
                });
        },
        setEnabledFields: function (element) {
            let fieldValue = element.closest('.fieldValue');
            let fieldName = fieldValue.find('input.sourceField').attr('name');
            let fieldDisplay = fieldValue.find('#' + fieldName + '_display');
            fieldValue.find('button').removeAttr('disabled');
            if (fieldDisplay.val() == '') {
                fieldValue.find('input').removeAttr('readonly');
            }
            fieldValue.find('.referenceModulesListGroup').removeClass('d-none');
            let placeholder = fieldDisplay.attr('placeholderDisabled');
            fieldDisplay.removeAttr('placeholderDisabled');
            fieldDisplay.attr('placeholder', placeholder);
            fieldValue.find('.referenceModulesList').attr('required', 'required');
        },
        setDisabledFields: function (element) {
            let fieldValue = element.closest('.fieldValue');
            let fieldName = fieldValue.find('input.sourceField').attr('name');
            let fieldDisplay = fieldValue.find('#' + fieldName + '_display');
            fieldValue.find('input').attr('readonly', 'readonly');
            fieldValue.find('button').attr('disabled', 'disabled');
            fieldValue.find('.referenceModulesListGroup').addClass('d-none');
            let placeholder = fieldDisplay.attr('placeholder');
            fieldDisplay.removeAttr('placeholder');
            fieldDisplay.attr('placeholderDisabled', placeholder);
            fieldValue.find('.referenceModulesList').removeAttr('required');
        },
        getMappingRelatedField: function (sourceField, sourceFieldModule, container) {
            const mappingRelatedField = container.find('input[name="mappingRelatedField"]').val();
            const mappingRelatedModule = mappingRelatedField ? JSON.parse(mappingRelatedField) : [];
            if (
                typeof mappingRelatedModule[sourceField] !== 'undefined' &&
                typeof mappingRelatedModule[sourceField][sourceFieldModule] !== 'undefined'
            ) {
                return mappingRelatedModule[sourceField][sourceFieldModule];
            }
            return [];
        },
        registerValidationsFields: function (container) {
            let params = app.validationEngineOptionsForRecord;
            container.validationEngine(params);
        },
        checkReferencesField: function (container, clear) {
            let thisInstance = this;
            let activeProcess = false,
                activeSubProcess = false;
            if (!CONFIG.fieldsReferencesDependent) {
                return false;
            }
            container.find('input[data-fieldtype="referenceLink"]').each(function (index, element) {
                element = $(element);
                let t = true;
                if (element.closest('.tab-pane').length > 0) {
                    t = false;
                    if (element.closest('.tab-pane.active').length > 0) {
                        t = true;
                    }
                }
                let referenceLink = element.val();
                if (t && referenceLink != '' && referenceLink != '0') {
                    activeProcess = true;
                }
            });
            container.find('input[data-fieldtype="referenceProcess"]').each(function (index, element) {
                element = $(element);
                if (activeProcess) {
                    thisInstance.setEnabledFields(element);
                } else {
                    if (clear) {
                        thisInstance.clearFieldValue(element);
                    }
                    thisInstance.setDisabledFields(element);
                }

                let t = true;
                if (element.closest('.tab-pane').length > 0) {
                    t = false;
                    if (element.closest('.tab-pane.active').length > 0) {
                        t = true;
                    }
                }

                let referenceLink = element.val();
                if (t && referenceLink != '' && referenceLink != '0') {
                    activeSubProcess = true;
                }
            });
            container.find('input[data-fieldtype="referenceSubProcess"]').each(function (index, element) {
                element = $(element);
                let processfieldElement = element.closest('.fieldValue');
                let length = processfieldElement.find('.referenceModulesList option[disabled!="disabled"]').length;
                if (activeSubProcess && length > 0) {
                    thisInstance.setEnabledFields(element);
                } else {
                    if (clear) {
                        thisInstance.clearFieldValue(element);
                    }
                    thisInstance.setDisabledFields(element);
                }
            });
        },
        checkSubProcessModulesList: function (element) {
            let option = element.find('option:selected');
            if (option.data('is-quickcreate') != 1) {
                element.closest('.fieldValue').find('.createReferenceRecord').addClass('d-none');
            } else {
                element.closest('.fieldValue').find('.createReferenceRecord').removeClass('d-none');
            }
        },
        checkReferenceModulesList: function (container) {
            let thisInstance = this;
            let processfieldElement = container.find('input[data-fieldtype="referenceProcess"]').closest('.fieldValue');
            let referenceProcess = processfieldElement.find('input[name="popupReferenceModule"]').val();
            let subProcessfieldElement = container.find('input[data-fieldtype="referenceSubProcess"]').closest('.fieldValue');
            Vtiger_Helper_Js.hideOptions(subProcessfieldElement.find('.referenceModulesList'), 'parent', referenceProcess);
            let subProcessValue = subProcessfieldElement.find('.referenceModulesList').val();
            subProcessfieldElement.find('[name="popupReferenceModule"]').val(subProcessValue);
            thisInstance.checkSubProcessModulesList(subProcessfieldElement.find('.referenceModulesList'));
        },
        registerReferenceFields: function (container) {
            let thisInstance = this;
            if (!CONFIG.fieldsReferencesDependent) {
                return false;
            }
            thisInstance.checkReferenceModulesList(container);
            thisInstance.checkReferencesField(container, false);
            container.find('.sourceField').on(Vtiger_Edit_Js.referenceSelectionEvent, function (e, data) {
                thisInstance.checkReferencesField(container, true);
            });
            container.find('.sourceField').on(Vtiger_Edit_Js.referenceDeSelectionEvent, function (e) {
                thisInstance.checkReferencesField(container, true);
            });
            container
                .find('input[data-fieldtype="referenceProcess"]')
                .closest('.fieldValue')
                .find('.referenceModulesList')
                .on('change', function () {
                    thisInstance.checkReferenceModulesList(container);
                });
            container
                .find('input[data-fieldtype="referenceSubProcess"]')
                .closest('.fieldValue')
                .find('.referenceModulesList')
                .on('change', function (e) {
                    thisInstance.checkSubProcessModulesList($(e.currentTarget));
                });
        },
        registerFocusFirstField: function (container, afterTimeout) {
            let elementToFocus, elementToFocusTabindex;
            if (afterTimeout === undefined && container.closest('.js-modal-container').length) {
                setTimeout((_) => {
                    this.registerFocusFirstField(container, true);
                }, 500);
                return;
            }
            container
                .find(
                    '.fieldValue input.form-control:not([type=hidden],.dateField,.clockPicker), .fieldValue input[type=checkbox], .select2-selection.form-control'
                )
                .each(function (i, e) {
                    let element = $(e);
                    if (!element.prop('readonly') && !element.prop('disabled')) {
                        element = element.get(0);
                        if (element.type !== 'number' && element.type !== 'checkbox' && element.value !== undefined) {
                            let elemLen = element.value.length;
                            element.selectionStart = elemLen;
                            element.selectionEnd = elemLen;
                        }
                        if (i === 0 || !elementToFocus) {
                            elementToFocus = element;
                        }
                        let tabindex = $(element).attr('tabindex');
                        if (tabindex > 0 && elementToFocusTabindex === undefined) {
                            elementToFocusTabindex = tabindex;
                            return;
                        }

                        if (tabindex > 0 && tabindex < elementToFocusTabindex) {
                            elementToFocusTabindex = tabindex;
                            elementToFocus = element;
                        }
                    }
                });
            if (elementToFocus) {
                elementToFocus.focus();
            }
        },
        registerCopyValue: function (container) {
            container.find('.fieldValue [data-copy-to-field]').on('change', function (e) {
                let element = $(e.currentTarget);
                container.find('[name="' + element.data('copyToField') + '"]').val(element.val());
            });
        },
        /**
         * Register multi image upload fields
         * @param {HTMLElement|jQuery} container
         */
        registerMultiImageFields(container) {
            return App.Fields.MultiImage.register(container);
        },
        /**
         * Register inventory controller
         * @param {jQuery} container
         */
        registerInventoryController(container) {
            if (typeof Vtiger_Inventory_Js !== 'undefined') {
                this.inventoryController = Vtiger_Inventory_Js.getInventoryInstance(container);
            }
        },
        /**
         * Register record collector modal
         * @param {jQuery} container
         */
        registerRecordCollectorModal: function (container) {
            const self = this;
            container.on('click', '.js-record-collector-modal', function (e) {
                e.preventDefault();
                let element = $(this);
                let formData = container.serializeFormData();
                formData['view'] = 'RecordCollector';
                formData['collectorType'] = element.data('type');
                delete formData['action'];
                AppConnector.request(formData).done(function (html) {
                    app.showModalWindow(
                        html,
                        (container) => {
                            let modalForm = container.find('form.js-record-collector__form');
                            let summary = container.find('.js-record-collector__summary');
                            modalForm.validationEngine(app.validationEngineOptions);
                            modalForm.on('submit', function (e) {
                                if (modalForm.validationEngine('validate')) {
                                    summary.html('');
                                    summary.progressIndicator({});
                                    e.preventDefault();
                                    AppConnector.request(modalForm.serializeFormData()).done(function (data) {
                                        summary.progressIndicator({ mode: 'hide' });
                                        summary.html(data);
                                    });
                                }
                            });
                            let recordForm = self.getForm();
                            container.on('click', '.js-record-collector__select', function () {
                                container
                                    .find(`.js-record-collector__column[data-column="${this.dataset.column}"] input`)
                                    .prop('checked', true);
                            });
                            container.on('click', '.js-record-collector__fill_fields', function () {
                                let formData = container.find('.js-record-collector__fill_form').serializeFormData();
                                $.each(formData, function (key, value) {
                                    if (value !== '') {
                                        let fieldElement = recordForm.find(`[name="${key}"]`);
                                        if (fieldElement.length) {
                                            fieldElement.setValue(value);
                                        } else {
                                            recordForm.append(`<input type="hidden" name="${key}" value="${value}" />`);
                                        }
                                    }
                                });
                                app.hideModalWindow(null, 'collectorModal');
                            });
                        },
                        { modalId: 'collectorModal' }
                    );
                });
            });
        },
        /**
         * Register account name function
         * @param {jQuery} container
         */
        registerAccountName: function (container) {
            let first = container.find('.js-first-name');
            let firstInput = first.find('input');
            let last = container.find('.js-last-name');
            let lastInput = last.find('input');
            let full = container.find('.js-account-name');
            let fullInput = full.find('input');
            let legalForm = container.find('select[name="legal_form"]');
            let legalFormVal = legalForm.val();
            firstInput.keyup(function () {
                fullInput.val(this.value + '|##|' + lastInput.val());
            });
            lastInput.keyup(function () {
                fullInput.val(firstInput.val() + '|##|' + this.value);
            });
            legalForm.change(function () {
                if (this.value == 'PLL_NATURAL_PERSON') {
                    full.addClass('d-none');
                    fullInput.val(firstInput.val() + '|##|' + lastInput.val());
                    first.removeClass('d-none');
                    last.removeClass('d-none');
                } else if (legalFormVal == 'PLL_NATURAL_PERSON') {
                    full.removeClass('d-none');
                    first.addClass('d-none');
                    last.addClass('d-none');
                    fullInput.val('');
                }
                legalFormVal = this.value;
            });
        },
        /**
         * Trigger record edit view events
         * @param {object} data
         */
        triggerRecordEditEvents: function (data) {
            const self = this,
                form = this.getForm();
            if (typeof data['changeValues'] == 'object') {
                $.each(data['changeValues'], function (_, field) {
                    self.setFieldValue(field);
                });
            }
            if (typeof data['changeOptions'] != 'undefined') {
                $.each(data['changeOptions'], function (fieldName, options) {
                    self.setFieldOptions(fieldName, options);
                });
            }
            if (typeof data['hoverField'] != 'undefined') {
                form.find(`[name="${data['hoverField']}"]`).focus();
            }
            if (typeof data['showNotify'] != 'undefined') {
                app.showNotify(data['showNotify']);
            }
            if (typeof data['showModal'] != 'undefined') {
                app.showModalWindow(null, data['showModal']['url']);
            }
            if (typeof data['showFields'] != 'undefined') {
                $.each(data['showFields'], function (_, fieldName) {
                    form.find(`.js-field-block-column[data-field="${fieldName}"]`).removeClass('d-none');
                    self.checkVisibilityBlocks();
                });
            }
            if (typeof data['hideFields'] != 'undefined') {
                $.each(data['hideFields'], function (_, fieldName) {
                    form.find(`.js-field-block-column[data-field="${fieldName}"]`).addClass('d-none');
                    self.checkVisibilityBlocks();
                });
            }
        },
        /**
         * Set field value
         * @param {object} params
         */
        setFieldValue: function (params) {
            const fieldElement = this.getForm().find(`[name="${params['fieldName']}"]`),
                fieldInfo = fieldElement.data('fieldinfo');
            if (fieldElement.is('select')) {
                if (fieldElement.find(`option[value="${params['value']}"]`).length) {
                    fieldElement.val(params['value']).trigger('change');
                } else if (fieldInfo.picklistvalues.hasOwnProperty(params['value'])) {
                    fieldElement.append(new Option(params['value'], params['value'], true, true)).trigger('change');
                }
            } else if (fieldElement.attr('type') == 'checkbox') {
                fieldElement.prop('checked', params['value'] == '1').trigger('change');
            } else if ('reference' === fieldElement.data('fieldtype')) {
                this.setReferenceFieldValue(fieldElement.closest('.js-field-block-column'), {
                    id: params['value'],
                    name: params['display']
                });
            } else {
                fieldElement.val(params['value']);
            }
        },
        /**
         * Set field options
         * @param {string} fieldName
         * @param {object} options
         */
        setFieldOptions: function (fieldName, options) {
            const fieldElement = this.getForm().find(`[name="${fieldName}"]`),
                fieldInfo = fieldElement.data('fieldinfo');
            if (fieldElement.is('select') && fieldInfo) {
                const val = fieldElement.val() ?? '',
                    fieldValue = fieldElement.closest('.fieldValue'),
                    currentValues = [...fieldElement.get(0).options]
                        .map((o) => o.value)
                        .filter((e) => e !== '')
                        .sort();
                let newOptions = new $();
                if (!fieldInfo.mandatory) {
                    newOptions = newOptions.add(
                        new Option(app.vtranslate('JS_SELECT_AN_OPTION'), '', false, !val || !options.includes(val))
                    );
                }
                $.each(options, (_, e) => {
                    newOptions = newOptions.add(new Option(fieldInfo['picklistvalues'][e], e, false, val == e));
                });

                const newValues = [...newOptions.map((_, e) => e.value)].filter((e) => e !== '').sort();
                if (currentValues.length === newValues.length && currentValues.every((e, i) => e === newValues[i])) {
                    return;
                }

                let selected = newOptions.filter(':selected').length > 0;
                fieldElement.html(newOptions);
                let change = val && val !== fieldElement.val();
                if ((val === '' && !selected) || change) {
                    fieldElement.val(null);
                }
                if (change) {
                    fieldValue.addClass('border border-info');
                    fieldElement.trigger('change');
                    setTimeout(function () {
                        fieldValue.removeClass('border border-info');
                    }, 5000);
                }
            }
        },
        /**
         * Check if pre save validation is active
         * @returns {bool}
         */
        checkPreSaveValidation: function () {
            let validation = true;
            if (
                typeof app.pageController.getForm !== 'undefined' &&
                app.pageController.getForm().find('#preSaveValidation').length !== 0
            ) {
                validation = app.pageController.getForm().find('#preSaveValidation').val() == 1;
            }
            return validation;
        },
        /**
         * Register change value handler events
         * @param {jQuery} container
         */
        registerChangeValueHandlerEvent: function (container) {
            const event = container.find('.js-change-value-event');
            if (event.length <= 0 || event.val() === '[]') {
                return;
            }
            const fields = JSON.parse(event.val());
            $.each(fields, (_, fieldName) => {
                container
                    .find(`[name="${fieldName}"],[name="${fieldName}[]"]`)
                    .on(`change ${Vtiger_Edit_Js.referenceSelectionEvent} ${Vtiger_Edit_Js.referenceDeSelectionEvent}`, () => {
                        this.sendChangeValueHandlerEvent(container.serializeFormData());
                    });
            });
            this.sendChangeValueHandlerEvent(container.serializeFormData());
        },
        /**
         * Send change value handler events
         * @param {object} formData
         */
        sendChangeValueHandlerEvent: function (formData) {
            formData['action'] = 'ChangeValueHandler';
            delete formData['view'];
            let progress = $.progressIndicator({ position: 'html', blockInfo: { enabled: true } });
            AppConnector.request(formData).done((response) => {
                    $.each(response.result, (_, data) => {
                        this.triggerRecordEditEvents(data);
                    });
                    progress.progressIndicator({ mode: 'hide' });
                });
        },
        /**
         * Register keyboard shortcuts events
         */
        registerKeyboardShortcutsEvent: function () {
            document.addEventListener('keydown', (event) => {
                if (event.shiftKey && event.ctrlKey && event.code === 'KeyS') {
                    let form = event.target.closest('form');
                    if (form) {
                        $(form).trigger('submit');
                    } else {
                        form = $(event.target).find('form');
                        if (form.length && form.hasClass('recordEditView')) {
                            form.last().trigger('submit');
                        }
                    }
                }
            });
        },
        /**
         * Function which will register basic events which will be used in quick create as well
         *
         */
        registerBasicEvents: function (container) {
            this.registerEventForEditor();
            this.stretchCKEditor();
            this.referenceModulePopupRegisterEvent(container);
            this.registerAutoCompleteFields(container);
            this.registerClearReferenceSelectionEvent(container);
            this.registerPreventingEnterSubmitEvent(container);
            this.registerTimeFields(container);
            this.registerRecordPreSaveEventEvent(container);
            this.registerReferenceSelectionEvent(container);
            this.registerChangeValueHandlerEvent(container);
            this.registerMaskFields(container);
            this.registerHelpInfo(container);
            this.registerReferenceFields(container);
            this.registerFocusFirstField(container);
            this.registerCopyValue(container);
            this.registerMultiImageFields(container);
            this.registerReferenceCreate(container);
            this.registerRecordCollectorModal(container);
            this.registerAccountName(container);
            this.registerKeyboardShortcutsEvent();
            App.Fields.MultiEmail.register(container);
            App.Fields.MultiDependField.register(container);
            App.Fields.Tree.register(container);
            App.Fields.MultiCurrency.register(container);
            App.Fields.MeetingUrl.register(container);
            App.Fields.ChangesJson.register(container);
            App.Fields.MultiReference.register(container);
            App.Fields.Password.register(container);
            App.Components.ActivityNotifier.register(container);
            App.Fields.MultiAttachment.register(container);
        },
        registerEvents: function () {
            let editViewForm = this.getForm();
            if (!this.proceedRegisterEvents()) {
                return;
            }
            this.registerInventoryController(editViewForm);
            app.registerBlockAnimationEvent(editViewForm);
            this.registerBlockStatusCheckOnLoad();
            this.registerBasicEvents(editViewForm);
            this.registerEventForCopyAddress();
            this.registerSubmitEvent();
            this.registerLeavePageWithoutSubmit(editViewForm);
            this.registerValidationsFields(editViewForm);
            this.registerAutoloadAddress();
            editViewForm.find('.js-form-submit-btn').prop('disabled', false);
        }
    }
);