YetiForceCompany/YetiForceCRM

View on GitHub
public_html/layouts/basic/modules/Vtiger/resources/Detail.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';

jQuery.Class(
    'Vtiger_Detail_Js',
    {
        detailInstance: false,
        getInstance: function () {
            if (Vtiger_Detail_Js.detailInstance == false) {
                let moduleClassName = app.getModuleName() + '_' + app.getViewName() + '_Js',
                    instance;
                if (typeof window[moduleClassName] !== 'undefined') {
                    instance = new window[moduleClassName]();
                } else {
                    instance = new Vtiger_Detail_Js();
                }
                Vtiger_Detail_Js.detailInstance = instance;
            }
            return Vtiger_Detail_Js.detailInstance;
        },
        /*
         * function to trigger Detail view actions
         * @params: Action url , callback function.
         */
        triggerDetailViewAction: function (detailActionUrl, callBackFunction) {
            let detailInstance = Vtiger_Detail_Js.getInstance();
            let selectedIds = [];
            selectedIds.push(detailInstance.getRecordId());
            let postData = {
                selected_ids: JSON.stringify(selectedIds)
            };
            let actionParams = {
                type: 'POST',
                url: detailActionUrl,
                dataType: 'html',
                data: postData
            };

            AppConnector.request(actionParams)
                .done(function (data) {
                    if (data) {
                        app.showModalWindow(data, { 'text-align': 'left' });
                        if (typeof callBackFunction == 'function') {
                            callBackFunction(data);
                        }
                    }
                })
                .fail(function (error, err) {});
        },
        /**
         * Function to trigger SMS quick view actions
         */
        triggerSMSmodal: () => {
            App.Components.QuickCreate.createRecord('SMSNotifier', { noCache: true });
        },
        triggerTransferOwnership: function (massActionUrl) {
            let thisInstance = this;
            thisInstance.getRelatedModulesContainer = false;
            let actionParams = {
                type: 'POST',
                url: massActionUrl,
                dataType: 'html',
                data: {}
            };
            AppConnector.request(actionParams).done(function (data) {
                if (data) {
                    let callback = function (data) {
                        let params = { ...app.validationEngineOptions };
                        params.onValidationComplete = function (form, valid) {
                            if (valid) {
                                if (form.attr('name') == 'changeOwner') {
                                    thisInstance.transferOwnershipSave(form);
                                }
                            }
                            return false;
                        };
                        jQuery('#changeOwner').validationEngine(params);
                    };
                    app.showModalWindow(data, function (data) {
                        let selectElement = thisInstance.getRelatedModuleContainer();
                        App.Fields.Picklist.changeSelectElementView(selectElement, 'select2');
                        if (typeof callback == 'function') {
                            callback(data);
                        }
                    });
                }
            });
        },
        transferOwnershipSave: function (form) {
            let transferOwner = jQuery('#transferOwnerId').val();
            let relatedModules = jQuery('#related_modules').val();
            let recordId = jQuery('#recordId').val();
            let params = {
                module: app.getModuleName(),
                action: 'TransferOwnership',
                record: recordId,
                transferOwnerId: transferOwner,
                related_modules: relatedModules
            };
            AppConnector.request(params).done(function (data) {
                if (data.success) {
                    app.hideModalWindow();
                    let params = {
                        title: app.vtranslate('JS_MESSAGE'),
                        text: app.vtranslate('JS_RECORDS_TRANSFERRED_SUCCESSFULLY'),
                        type: 'info'
                    };
                    let oldValue = jQuery('.assigned_user_id').val();
                    let element = jQuery('.assigned_user_id ');

                    element.find('option[value="' + oldValue + '"]').removeAttr('selected');
                    element.find('option[value="' + transferOwner + '"]').attr('selected', 'selected');
                    element.trigger('liszt:updated');
                    let fieldName = element.find('option[value="' + transferOwner + '"]').data('picklistvalue');
                    element
                        .closest('.row-fluid')
                        .find('.value')
                        .html(
                            '<a href="index.php?module=Users&amp;parent=Settings&amp;view=Detail&amp;record=' +
                                transferOwner +
                                '">' +
                                fieldName +
                                '</a>'
                        );

                    app.showNotify(params);
                }
            });
        },
        /*
         * Function to get the related module container
         */
        getRelatedModuleContainer: function () {
            if (this.getRelatedModulesContainer == false) {
                this.getRelatedModulesContainer = jQuery('#related_modules');
            }
            return this.getRelatedModulesContainer;
        },
        reloadRelatedList: function () {
            let detailInstance = Vtiger_Detail_Js.getInstance();
            let params = {};
            if (jQuery('[name="currentPageNum"]').length > 0) {
                params.page = jQuery('[name="currentPageNum"]').val();
            }
            detailInstance.loadRelatedList(params);
        },
        runRecordChanger: function (id) {
            AppConnector.request({
                module: app.getModuleName(),
                record: app.getRecordId(),
                action: 'Save',
                mode: 'recordChanger',
                id: id
            })
                .done(function () {
                    window.location.reload();
                })
                .fail(function (jqXHR, textStatus, errorThrown) {
                    app.showNotify({
                        type: 'error',
                        text: textStatus
                    });
                });
        },
        showWorkflowTriggerView: function (instance) {
            $(instance).popover('hide');
            const detailInstance = Vtiger_Detail_Js.getInstance(),
                callback = function (data) {
                    let treeInstance = data.find('#treeWorkflowContents');
                    treeInstance.jstree({
                        core: {
                            data: JSON.parse(data.find('.js-tree-workflow-data').val()),
                            themes: {
                                name: 'proton',
                                responsive: true,
                                icons: false
                            }
                        },
                        checkbox: {
                            three_state: false
                        },
                        plugins: ['search', 'category']
                    });
                    data.find('[type="submit"]').on('click', function () {
                        let tasks = {};
                        let selected = treeInstance.jstree('getCategory', true);
                        $.each(selected, function (index, treeElement) {
                            if (treeElement.attr === 'record') {
                                tasks[treeElement.record_id] = [];
                            }
                        });
                        $.each(selected, function (index, treeElement) {
                            if (tasks[treeElement.parent] !== undefined && treeElement.attr === 'task') {
                                tasks[treeElement.parent].push(treeElement.record_id);
                            }
                        });
                        if (Object.keys(tasks).length === 0) {
                            app.showNotify({
                                title: app.vtranslate('JS_INFORMATION'),
                                text: app.vtranslate('JS_NOT_SELECTED_WORKFLOW_TRIGGER'),
                                type: 'error'
                            });
                        } else {
                            app.showNotify({
                                title: app.vtranslate('JS_MESSAGE'),
                                text: app.vtranslate('JS_STARTED_PERFORM_WORKFLOW'),
                                type: 'info'
                            });
                            AppConnector.request({
                                module: app.getModuleName(),
                                action: 'Workflow',
                                mode: 'execute',
                                user: data.find('[name="user"]').val(),
                                record: detailInstance.getRecordId(),
                                tasks: JSON.stringify(tasks)
                            })
                                .done(function () {
                                    app.showNotify({
                                        title: app.vtranslate('JS_MESSAGE'),
                                        text: app.vtranslate('JS_COMPLETED_PERFORM_WORKFLOW'),
                                        type: 'success'
                                    });
                                    app.hideModalWindow();
                                    detailInstance.loadWidgets();
                                })
                                .fail(function () {
                                    app.showNotify({
                                        title: app.vtranslate('JS_ERROR'),
                                        text: app.vtranslate('JS_ERROR_DURING_TRIGGER_OF_WORKFLOW'),
                                        type: 'error'
                                    });
                                    app.hideModalWindow();
                                });
                        }
                    });
                };
            AppConnector.request({
                module: app.getModuleName(),
                view: 'WorkflowTrigger',
                record: detailInstance.getRecordId()
            }).done(function (data) {
                if (data) {
                    app.showModalWindow(data, '', callback);
                }
            });
        }
    },
    {
        targetPicklistChange: false,
        targetPicklist: false,
        detailViewContentHolder: false,
        detailViewForm: false,
        detailViewDetailsTabLabel: 'LBL_RECORD_DETAILS',
        detailViewSummaryTabLabel: 'LBL_RECORD_SUMMARY',
        detailViewRecentCommentsTabLabel: 'ModComments',
        detailViewRecentActivitiesTabLabel: 'Activities',
        detailViewRecentUpdatesTabLabel: 'LBL_UPDATES',
        detailViewRecentDocumentsTabLabel: 'Documents',
        fieldUpdatedEvent: 'Vtiger.Field.Updated',
        //Filels list on updation of which we need to upate the detailview header
        updatedFields: ['company', 'designation', 'title'],
        //Event that will triggered before saving the ajax edit of fields
        fieldPreSave: 'Vtiger.Field.PreSave',
        tempData: [],
        //constructor
        init: function () {},
        loadWidgetsEvents: function () {
            const thisInstance = this;
            app.event.on('DetailView.Widget.AfterLoad', function (e, widgetContent, relatedModuleName, instance) {
                if (relatedModuleName === 'Calendar') {
                    thisInstance.reloadWidgetActivitesStats(widgetContent.closest('.activityWidgetContainer'));
                }
                if (relatedModuleName === 'ModComments') {
                    thisInstance.registerCommentEventsInDetail(widgetContent.closest('.updatesWidgetContainer'));
                }
                if (widgetContent.find('[name="relatedModule"]').length) {
                    thisInstance.registerShowSummary(widgetContent);
                }
                if (relatedModuleName === 'OSSMailView') {
                    Vtiger_Index_Js.registerMailButtons(widgetContent);
                    widgetContent.find('.showMailModal').on('click', function (e) {
                        e.preventDefault();
                        let progressIndicatorElement = jQuery.progressIndicator();
                        app.showModalWindow('', $(e.currentTarget).data('url') + '&noloadlibs=1', function (data) {
                            Vtiger_Index_Js.registerMailButtons(data);
                            progressIndicatorElement.progressIndicator({ mode: 'hide' });
                        });
                    });
                }
                thisInstance.registerEmailEvents(widgetContent);
                if (relatedModuleName === 'DetailView') {
                    thisInstance.registerBlockStatusCheckOnLoad();
                }
                thisInstance.registerCollapsiblePanels(widgetContent.closest('.js-detail-widget'));
            });
        },
        loadWidgets: function () {
            let container = this.getForm();
            let widgetList = jQuery('[class^="widgetContainer_"]');
            let length = widgetList.length;
            widgetList.each((index, widget) => {
                widget = $(widget);
                if (widget.is(':visible')) {
                    this.loadWidget(widget);
                }
                if (length === index + 1) {
                    container.validationEngine('detach');
                    container.validationEngine(app.validationEngineOptionsForRecord);
                }
            });
            this.registerRelatedModulesRecordCount();
        },
        loadWidget: function (widgetContainer, params) {
            const thisInstance = this,
                contentContainer = $('.js-detail-widget-content', widgetContainer);
            let relatedModuleName;
            this.registerFilterForAddingModuleRelatedRecordFromSummaryWidget(widgetContainer);
            if (widgetContainer.find('[name="relatedModule"]').length) {
                relatedModuleName = widgetContainer.find('[name="relatedModule"]').val();
            } else {
                relatedModuleName = widgetContainer.data('name');
            }
            if (params === undefined) {
                let urlParams = widgetContainer.data('url');
                if (urlParams == undefined) {
                    return;
                }
                let queryParameters = urlParams.split('&'),
                    keyValueMap = {},
                    index;
                for (index = 0; index < queryParameters.length; index++) {
                    let queryParamComponents = queryParameters[index].split('=');
                    keyValueMap[queryParamComponents[0]] = queryParamComponents[1];
                }
                params = keyValueMap;
            }
            let aDeferred = $.Deferred();
            contentContainer.progressIndicator({});
            AppConnector.request({
                type: 'POST',
                async: false,
                dataType: 'html',
                data: params
            })
                .done(function (data) {
                    contentContainer.progressIndicator({ mode: 'hide' });
                    contentContainer.html(data);
                    App.Fields.Picklist.showSelect2ElementView(widgetContainer.find('.select2'));
                    app.registerModal(contentContainer);
                    App.Components.DropFile.register(contentContainer);
                    if (relatedModuleName) {
                        let relatedController = Vtiger_RelatedList_Js.getInstanceByUrl(
                            widgetContainer.data('url'),
                            thisInstance.getSelectedTab()
                        );
                        relatedController.setRelatedContainer(contentContainer);
                        relatedController.registerRelatedEvents();
                        thisInstance.widgetRelatedRecordView(widgetContainer, true);
                        let chart = contentContainer.find('[name="typeChart"]');
                        if (chart.length && typeof window['Vtiger_Widget_Js'] !== 'undefined') {
                            let widgetInstance = Vtiger_Widget_Js.getInstance(contentContainer, chart.val());
                            widgetInstance.init(contentContainer);
                            widgetInstance.loadChart();
                        }
                    }
                    app.event.trigger('DetailView.Widget.AfterLoad', contentContainer, relatedModuleName, thisInstance);
                    aDeferred.resolve(params);
                })
                .fail(function () {
                    contentContainer.progressIndicator({ mode: 'hide' });
                    aDeferred.reject();
                });
            return aDeferred.promise();
        },

        /**
         * Adding relationships in the products and services widget.
         */
        registerWidgetProductAndServices: function () {
            let thisInstance = this;
            this.getForm().on('click', '.js-widget-products-services', (e) => {
                let currentTarget = $(e.currentTarget);
                let params = {
                    module: app.getModuleName(),
                    action: 'RelationAjax',
                    mode: 'updateRelation',
                    recordsToAdd: [],
                    src_record: app.getRecordId(),
                    related_module: currentTarget.closest('.js-detail-widget-header').find('[name="relatedModule"]').val()
                };
                let url = currentTarget.data('url');
                app.showRecordsList(url, (_, instance) => {
                    instance.setSelectEvent((data) => {
                        for (let i in data) {
                            params.recordsToAdd.push(i);
                        }
                        AppConnector.request(params).done(function () {
                            thisInstance.reloadTabContent();
                        });
                    });
                });
            });
        },

        widgetRelatedRecordView: function (container, load) {
            let cacheKey = this.getRecordId() + '_' + container.data('id');
            let relatedRecordCacheID = app.moduleCacheGet(cacheKey);
            if (relatedRecordCacheID !== null) {
                let newActive = container.find(".js-carousel-item[data-id = '" + relatedRecordCacheID + "']");
                if (newActive.length) {
                    container.find('.js-carousel-item.active').removeClass('active');
                    container.find(".js-carousel-item[data-id = '" + relatedRecordCacheID + "']").addClass('active');
                }
            }
            let controlBox = container.find('.control-widget');
            let prev = controlBox.find('.prev');
            let next = controlBox.find('.next');
            let active = container.find('.js-carousel-item.active');
            if (container.find('.js-carousel-item').length <= 1 || !active.next().length) {
                next.addClass('disabled');
            } else {
                next.removeClass('disabled');
            }
            if (container.find('.js-carousel-item').length <= 1 || !active.prev().length) {
                prev.addClass('disabled');
            } else {
                prev.removeClass('disabled');
            }
            if (load) {
                next.on('click', function () {
                    if ($(this).hasClass('disabled')) {
                        return;
                    }
                    let active = container.find('.js-carousel-item.active');
                    active.removeClass('active');
                    let nextElement = active.next();
                    nextElement.addClass('active');
                    if (!nextElement.next().length) {
                        next.addClass('disabled');
                    }
                    if (active.prev()) {
                        prev.removeClass('disabled');
                    }
                    app.moduleCacheSet(cacheKey, nextElement.data('id'));
                });
                prev.on('click', function () {
                    if ($(this).hasClass('disabled')) {
                        return;
                    }
                    let active = container.find('.js-carousel-item.active');
                    active.removeClass('active');
                    let prevElement = active.prev();
                    prevElement.addClass('active');
                    if (!prevElement.prev().length) {
                        prev.addClass('disabled');
                    }
                    if (active.next()) {
                        next.removeClass('disabled');
                    }
                    app.moduleCacheSet(cacheKey, prevElement.data('id'));
                });
            }
        },

        loadContents: function (url, data) {
            let thisInstance = this;
            let aDeferred = jQuery.Deferred();

            let detailContentsHolder = this.getContentHolder();
            let params = url;
            if (typeof data !== 'undefined') {
                params = {};
                params.url = url;
                params.data = data;
            }
            AppConnector.requestPjax(params).done(function (responseData) {
                detailContentsHolder.html(responseData);
                responseData = detailContentsHolder.html();
                thisInstance.registerBlockStatusCheckOnLoad();
                //Make select box more usability
                App.Fields.Picklist.changeSelectElementView(detailContentsHolder);
                //Attach date picker event to date fields
                App.Fields.Date.register(detailContentsHolder);
                thisInstance.getForm().validationEngine();
                app.event.trigger('DetailView.LoadContents.AfterLoad', responseData);
                aDeferred.resolve(responseData);
            });
            return aDeferred.promise();
        },
        getUpdateFieldsArray: function () {
            return this.updatedFields;
        },
        /**
         * Function to return related tab.
         * @return : jQuery Object.
         */
        getTabByLabel: function (tabLabel) {
            let tabs = this.getTabs();
            let targetTab = false;
            tabs.each(function (index, element) {
                let tab = jQuery(element);
                let labelKey = tab.data('labelKey');
                if (labelKey == tabLabel) {
                    targetTab = tab;
                    return false;
                }
            });
            return targetTab;
        },
        getTabByModule: function (moduleName, relationId = '') {
            let tabs = this.getTabs();
            let targetTab = false;
            tabs.each(function (index, element) {
                let tab = jQuery(element);
                if (
                    tab.data('reference') == moduleName &&
                    (!relationId || (relationId && relationId == tab.data('relation-id')))
                ) {
                    targetTab = tab;
                    return false;
                }
            });
            return targetTab;
        },
        selectModuleTab: function () {
            let relatedTabContainer = this.getTabContainer();
            let moduleTab = relatedTabContainer.find('li.module-tab');
            this.deSelectAllrelatedTabs();
            this.markTabAsSelected(moduleTab);
        },
        deSelectAllrelatedTabs: function () {
            this.getTabs().removeClass('active');
        },
        markTabAsSelected: function (tabElement) {
            tabElement.addClass('active');
            $(
                '.related .dropdown [data-reference="' +
                    tabElement.data('reference') +
                    '"][data-relation-id="' +
                    tabElement.data('relation-id') +
                    '"]'
            ).addClass('active');
        },
        reloadTabContent: function () {
            this.getSelectedTab().trigger('click');
        },
        getSelectedTab: function () {
            let tabContainer = this.getTabContainer();
            return tabContainer.find('.js-detail-tab.active:not(.d-none)');
        },
        getTabContainer: function () {
            return jQuery('div.related');
        },
        getTabs: function () {
            let topTabs = this.getTabContainer().find('li.baseLink:not(.d-none)');
            let dropdownMenuTabs = this.getTabContainer().find('li:not(.baseLink)');
            dropdownMenuTabs.each(function (n, e) {
                let currentTarget = jQuery(this);
                let iteration = currentTarget.data('iteration');
                let className = currentTarget.hasClass('mainNav') ? 'mainNav' : 'relatedNav';
                if (
                    iteration != undefined &&
                    topTabs.filter('.' + className + '[data-iteration="' + iteration + '"]').length < 1
                ) {
                    topTabs.push(currentTarget.get(0));
                }
            });
            return topTabs;
        },
        getContentHolder: function () {
            if (this.detailViewContentHolder == false) {
                this.detailViewContentHolder = jQuery('div.details div.contents');
            }
            return this.detailViewContentHolder;
        },
        /**
         * Function which will give the detail view form
         * @return : jQuery element
         */
        getForm: function () {
            if (this.detailViewForm == false) {
                this.detailViewForm = jQuery('#detailView');
            }
            return this.detailViewForm;
        },
        getRecordId: function () {
            return app.getRecordId();
        },
        getRelatedModuleName: function () {
            if (jQuery('.relatedModuleName', this.getContentHolder()).length == 1) {
                return jQuery('.relatedModuleName', this.getContentHolder()).val();
            }
        },
        getRelatedListCurrentPageNum: function () {
            return jQuery('input[name="currentPageNum"]', this.getContentHolder()).val();
        },

        /**
         * function to hide button action.
         */
        hideButtonAction: function () {
            $('.js-hb__container').removeClass('u-hidden-block__opened');
        },

        /**
         * function to get the Comment thread for the given parent.
         * params: Url to get the Comment thread
         */
        getCommentThread: function (url) {
            let aDeferred = jQuery.Deferred();
            AppConnector.request(url)
                .done(function (data) {
                    aDeferred.resolve(data);
                })
                .fail(function (error, err) {});
            return aDeferred.promise();
        },
        /**
         * Function to save comment
         */
        saveCommentAjax: function (
            element,
            commentMode,
            commentContentValue,
            editCommentReason,
            commentId,
            parentCommentId,
            aDeferred
        ) {
            let thisInstance = this;
            let progressIndicatorElement = jQuery.progressIndicator({});
            let commentInfoBlock = element.closest('.js-comment-single');
            let relatedTo = commentInfoBlock.find('.related_to').val();
            if (!relatedTo) {
                relatedTo = thisInstance.getRecordId();
            }
            let postData = {
                action: 'SaveAjax',
                commentcontent: commentContentValue,
                related_to: relatedTo,
                module: 'ModComments'
            };
            if (commentMode == 'edit') {
                postData['fromView'] = 'QuickEdit';
                postData['record'] = commentId;
                postData['reasontoedit'] = editCommentReason;
                postData['parent_comments'] = parentCommentId;
            } else if (commentMode == 'add') {
                postData['parent_comments'] = commentId;
            }
            AppConnector.request(postData)
                .done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    if (commentMode == 'add') {
                        thisInstance.addRelationBetweenRecords(
                            'ModComments',
                            data.result._recordId,
                            thisInstance.getTabByLabel(thisInstance.detailViewRecentCommentsTabLabel),
                            { relationId: null }
                        );
                    }
                    app.event.trigger('DetailView.SaveComment.AfterAjax', commentInfoBlock, postData, data);
                    aDeferred.resolve(data);
                })
                .fail(function (textStatus, errorThrown) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    element.removeAttr('disabled');
                    aDeferred.reject(textStatus, errorThrown);
                });
        },
        saveComment: function (e) {
            let aDeferred = jQuery.Deferred(),
                currentTarget = jQuery(e.currentTarget),
                commentMode = currentTarget.data('mode'),
                closestCommentBlock = currentTarget.closest('.js-add-comment-block'),
                commentContent = closestCommentBlock.find('.js-comment-content'),
                commentContentValue = commentContent.html(),
                errorMsg,
                editCommentReason;
            if ('' === commentContentValue) {
                errorMsg = app.vtranslate('JS_LBL_COMMENT_VALUE_CANT_BE_EMPTY');
                commentContent.validationEngine('showPrompt', errorMsg, 'error', 'bottomLeft', true);
                aDeferred.reject(errorMsg);
                return aDeferred.promise();
            }
            if ('edit' === commentMode) {
                editCommentReason = closestCommentBlock.find('[name="reasonToEdit"]').val();
            }
            let element = jQuery(e.currentTarget),
                commentInfoHeader = closestCommentBlock.closest('.js-comment-details').find('.js-comment-info-header'),
                commentId = commentInfoHeader.data('commentid'),
                parentCommentId = commentInfoHeader.data('parentcommentid');
            this.saveCommentAjax(
                element,
                commentMode,
                commentContentValue,
                editCommentReason,
                commentId,
                parentCommentId,
                aDeferred
            );
            return aDeferred.promise();
        },
        /**
         * function to return the UI of the comment.
         * return html
         */
        getCommentUI: function (commentId) {
            let aDeferred = jQuery.Deferred();
            let postData = {
                view: 'DetailAjax',
                module: 'ModComments',
                record: commentId
            };
            AppConnector.request(postData)
                .done(function (data) {
                    aDeferred.resolve(data);
                })
                .fail(function (error, err) {});
            return aDeferred.promise();
        },
        /**
         * function to return cloned add comment block
         * return jQuery Obj.
         */
        getCommentBlock: function () {
            let clonedCommentBlock = jQuery('.basicAddCommentBlock', this.getContentHolder())
                .clone(true, true)
                .removeClass('basicAddCommentBlock d-none')
                .addClass('js-add-comment-block');
            clonedCommentBlock
                .find('.commentcontenthidden')
                .removeClass('commentcontenthidden')
                .addClass('js-comment-content');
            return clonedCommentBlock;
        },
        /**
         * function to return cloned edit comment block
         * return jQuery Obj.
         */
        getEditCommentBlock: function () {
            let clonedCommentBlock = jQuery('.basicEditCommentBlock', this.getContentHolder())
                .clone(true, true)
                .removeClass('basicEditCommentBlock d-none')
                .addClass('js-add-comment-block');
            clonedCommentBlock
                .find('.commentcontenthidden')
                .removeClass('commentcontenthidden')
                .addClass('js-comment-content');
            new App.Fields.Text.Completions(clonedCommentBlock.find('.js-completions'));
            return clonedCommentBlock;
        },
        /*
         * Function to register the submit event for Send Sms
         */
        registerSendSmsSubmitEvent: function () {
            let thisInstance = this;
            jQuery('body').on('submit', '#massSave', function (e) {
                let form = jQuery(e.currentTarget);
                let smsTextLength = form.find('#message').html().length;
                if (smsTextLength > 160) {
                    let params = {
                        title: app.vtranslate('JS_MESSAGE'),
                        text: app.vtranslate('LBL_SMS_MAX_CHARACTERS_ALLOWED'),
                        type: 'error'
                    };
                    app.showNotify(params);
                    return false;
                }
                let submitButton = form.find(':submit');
                submitButton.attr('disabled', 'disabled');
                thisInstance.SendSmsSave(form);
                e.preventDefault();
            });
        },
        /*
         * Function to Save and sending the Sms and hide the modal window of send sms
         */
        SendSmsSave: function (form) {
            let progressInstance = jQuery.progressIndicator({
                position: 'html',
                blockInfo: {
                    enabled: true
                }
            });
            let SendSmsUrl = form.serializeFormData();
            AppConnector.request(SendSmsUrl)
                .done(function (data) {
                    app.hideModalWindow();
                    progressInstance.progressIndicator({
                        mode: 'hide'
                    });
                })
                .fail(function (error, err) {});
        },
        /**
         * Function which will register events to update the record name in the detail view when any of
         * the name field is changed
         */
        registerNameAjaxEditEvent: function () {
            let thisInstance = this;
            let detailContentsHolder = thisInstance.getContentHolder();
            detailContentsHolder.on(thisInstance.fieldUpdatedEvent, '.nameField', function (e, params) {
                let form = thisInstance.getForm();
                let nameFields = form.data('nameFields');
                let recordLabel = '';
                for (let index in nameFields) {
                    if (index != 0) {
                        recordLabel += ' ';
                    }

                    let nameFieldName = nameFields[index];
                    recordLabel += form.find('[name="' + nameFieldName + '"]').val();
                }
                let recordLabelElement = detailContentsHolder.closest('.contentsDiv').find('.recordLabel');
                recordLabelElement.text(recordLabel);
            });
        },
        updateHeaderNameFields: function () {
            let thisInstance = this;
            let detailContentsHolder = thisInstance.getContentHolder();
            let form = thisInstance.getForm();
            let nameFields = form.data('nameFields');
            let recordLabelElement = detailContentsHolder.closest('.contentsDiv').find('.recordLabel');
            let title = '';
            for (let index in nameFields) {
                let nameFieldName = nameFields[index];
                let nameField = form.find('[name="' + nameFieldName + '"]');
                if (nameField.length > 0) {
                    let recordLabel = nameField.val();
                    title += recordLabel + ' ';
                    recordLabelElement.find('[class="' + nameFieldName + '"]').text(recordLabel);
                }
            }
            let salutatioField = recordLabelElement.find('.salutation');
            if (salutatioField.length > 0) {
                let salutatioValue = salutatioField.text();
                title = salutatioValue + title;
            }
            recordLabelElement.attr('title', title);
        },
        registerAjaxEditEvent: function () {
            let thisInstance = this;
            let detailContentsHolder = thisInstance.getContentHolder();
            detailContentsHolder.on(thisInstance.fieldUpdatedEvent, 'input,select,textarea', function (e) {
                thisInstance.updateHeaderValues(jQuery(e.currentTarget));
            });
        },
        updateHeaderValues: function (currentElement) {
            let thisInstance = this;
            if (currentElement.hasClass('nameField')) {
                thisInstance.updateHeaderNameFields();
                return true;
            }

            let name = currentElement.attr('name');
            let updatedFields = this.getUpdateFieldsArray();
            let detailContentsHolder = thisInstance.getContentHolder();
            if (jQuery.inArray(name, updatedFields) != '-1') {
                let recordLabel = currentElement.val();
                let recordLabelElement = detailContentsHolder.closest('.contentsDiv').find('.' + name + '_label');
                recordLabelElement.text(recordLabel);
            }
        },
        /*
         * Function to register the click event of email field
         */
        registerEmailFieldClickEvent: function () {
            let detailContentsHolder = this.getContentHolder();
            detailContentsHolder.on('click', '.emailField', function (e) {
                e.stopPropagation();
            });
        },
        /*
         * Function to register the click event of phone field
         */
        registerPhoneFieldClickEvent: function () {
            let detailContentsHolder = this.getContentHolder();
            detailContentsHolder.on('click', '.phoneField', function (e) {
                e.stopPropagation();
            });
        },
        /*
         * Function to register the click event of url field
         */
        registerUrlFieldClickEvent: function () {
            let detailContentsHolder = this.getContentHolder();
            detailContentsHolder.on('click', '.urlField', function (e) {
                e.stopPropagation();
            });
        },
        /**
         * Function to register event for related list row click
         */
        registerRelatedRowClickEvent: function () {
            let detailContentsHolder = this.getContentHolder();
            detailContentsHolder.on('click', '.listViewEntries', function (e) {
                let targetElement = jQuery(e.target, jQuery(e.currentTarget));
                if (targetElement.is('td:first-child') && targetElement.children('input[type="checkbox"]').length > 0) return;
                if (jQuery(e.target).is('input[type="checkbox"]')) return;
                let elem = jQuery(e.currentTarget);
                let recordUrl = elem.data('recordurl');
                if (typeof recordUrl !== 'undefined') {
                    window.location.href = recordUrl;
                }
            });
        },
        loadRelatedList: function (params) {
            let aDeferred = jQuery.Deferred();
            if (params == undefined) {
                params = {};
            }
            let relatedListInstance = Vtiger_RelatedList_Js.getInstance(
                this.getRecordId(),
                app.getModuleName(),
                this.getSelectedTab(),
                this.getRelatedModuleName()
            );
            relatedListInstance
                .loadRelatedList(params)
                .done(function (data) {
                    aDeferred.resolve(data);
                })
                .fail(function (textStatus, errorThrown) {
                    aDeferred.reject(textStatus, errorThrown);
                });
            return aDeferred.promise();
        },
        /**
         * Function to register Event for Sorting
         */
        registerEventForRelatedList: function () {
            const self = this;
            let detailContentsHolder = this.getContentHolder();
            let relatedModuleName = self.getRelatedModuleName();
            if (relatedModuleName) {
                let relatedController = Vtiger_RelatedList_Js.getInstance(
                    self.getRecordId(),
                    app.getModuleName(),
                    self.getSelectedTab(),
                    relatedModuleName
                );
                relatedController.setRelatedContainer(detailContentsHolder);
                relatedController.registerRelatedEvents();
            }
            detailContentsHolder.find('.detailViewBlockLink').each(function (n, block) {
                self.reloadDetailViewBlock($(block), false);
            });
            detailContentsHolder.find('.detailViewBlockLink .blockHeader').on('click', function (e) {
                const target = $(e.target);
                if (
                    target.is('input') ||
                    target.is('button') ||
                    target.parents().is('button') ||
                    target.hasClass('js-stop-propagation') ||
                    target.parents().hasClass('js-stop-propagation')
                ) {
                    return false;
                }
                self.reloadDetailViewBlock($(this).closest('.js-toggle-panel'));
            });
        },
        /**
         * Function to reload detail view block
         * @param {$} block - Jquery container.
         */
        reloadDetailViewBlock: function (block, progressIndicator = true) {
            const self = this;
            const blockContent = block.find('.blockContent');
            const isEmpty = blockContent.is(':empty');
            let url = block.data('url');
            if (blockContent.is(':visible') && url) {
                if (progressIndicator) {
                    blockContent.progressIndicator();
                }
                AppConnector.request(url).done(function (response) {
                    blockContent.html(response);
                    const relatedController = Vtiger_RelatedList_Js.getInstanceByUrl(url, self.getSelectedTab());
                    relatedController.setRelatedContainer(blockContent);
                    if (isEmpty) {
                        relatedController.registerRelatedEvents();
                    } else {
                        relatedController.registerPostLoadEvents();
                        relatedController.registerListEvents();
                    }
                });
            }
        },
        registerBlockStatusCheckOnLoad: function () {
            let blocks = this.getContentHolder().find('.js-toggle-panel');
            let module = app.getModuleName();
            blocks.each(function (index, block) {
                let currentBlock = jQuery(block);
                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.closest('.js-toggle-panel').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');
                        }
                    }
                }
            });
        },
        /**
         * Function to handle the ajax edit for detailview and summary view fields
         * which will expects the currentTdElement
         */
        ajaxEditHandling: function (currentTdElement) {
            const thisInstance = this;
            let readRecord = $('.setReadRecord'),
                detailViewValue = $('.value', currentTdElement),
                editElement = $('.edit', currentTdElement),
                actionElement = $('.js-detail-quick-edit', currentTdElement),
                fieldElement = $('.fieldname', editElement);
            readRecord.prop('disabled', true);
            $(fieldElement).each(function (index, element) {
                let fieldName = $(element).val(),
                    elementTarget = $(element),
                    elementName =
                        $.inArray(elementTarget.data('type'), [
                            'taxes',
                            'sharedOwner',
                            'multipicklist',
                            'multiListFields',
                            'multiDomain',
                            'mailScannerFields',
                            'mailScannerActions'
                        ]) != -1
                            ? fieldName + '[]'
                            : fieldName;
                let fieldElement = $('[name="' + elementName + '"]:not([type="hidden"])', editElement);
                if (fieldElement.attr('disabled') == 'disabled' && fieldElement.attr('type') !== 'password') {
                    return;
                }
                if (editElement.length <= 0) {
                    return;
                }
                if (editElement.is(':visible')) {
                    return;
                }
                if (fieldElement.attr('data-inputmask')) {
                    fieldElement.inputmask();
                }
                detailViewValue.addClass('d-none');
                actionElement.addClass('d-none');
                editElement
                    .removeClass('d-none')
                    .children()
                    .filter('input[type!="hidden"]input[type!="image"],select')
                    .filter(':first')
                    .focus();
                let saveHandler = function (e) {
                    thisInstance.registerNameAjaxEditEvent();
                    let element = $(e.target);
                    if ($(e.currentTarget).find('.dateTimePickerField').length) {
                        if (element.closest('.drp-calendar').length || element.hasClass('drp-calendar')) {
                            return;
                        }
                    }
                    if (
                        element.closest('.fieldValue').is(currentTdElement) ||
                        element.closest('.pnotify-modal').length ||
                        element.hasClass('select2-selection__choice__remove') ||
                        element.closest('.select2-container--open').length ||
                        element.parents('.clockpicker-popover').length
                    ) {
                        return;
                    }
                    currentTdElement.removeAttr('tabindex');
                    currentTdElement.removeClass('is-edit-active');
                    let previousValue = elementTarget.data('prevValue'),
                        editElement = elementTarget.closest('.edit'),
                        ajaxEditNewValue =
                            editElement.find('[name="' + elementName + '"]').length > 0
                                ? editElement.find('[name="' + elementName + '"]').val()
                                : editElement.find('[name="' + fieldName + '"]').val(),
                        fieldInfo = Vtiger_Field_Js.getInstance(fieldElement.data('fieldinfo')),
                        dateTimeField = [],
                        dateTime = false;
                    if (editElement.find('[data-fieldinfo]').length == 2) {
                        editElement.find('[data-fieldinfo]').each(function () {
                            let field = {
                                name: $(this).attr('name'),
                                type: $(this).data('fieldinfo').type
                            };
                            if (field['type'] == 'datetime') {
                                dateTime = true;
                            }
                            dateTimeField.push(field);
                        });
                    }
                    if (fieldElement.is('input:checkbox')) {
                        if (fieldElement.is(':checked')) {
                            ajaxEditNewValue = '1';
                        } else {
                            ajaxEditNewValue = '0';
                        }
                        fieldElement = fieldElement.filter('[type="checkbox"]');
                    }
                    if (fieldElement.validationEngine('validate')) {
                        if (fieldElement.attr('data-inputmask')) {
                            fieldElement.inputmask();
                        }
                        return;
                    }
                    function toStr(v) {
                        return v === undefined || v === null ? '' : v + '';
                    }
                    fieldElement.validationEngine('hide');
                    if (toStr(previousValue) === toStr(ajaxEditNewValue)) {
                        editElement.addClass('d-none');
                        detailViewValue.removeClass('d-none');
                        actionElement.removeClass('d-none');
                        readRecord.prop('disabled', false);
                        editElement.off('clickoutside');
                    } else {
                        let preFieldSaveEvent = jQuery.Event(thisInstance.fieldPreSave);
                        fieldElement.trigger(preFieldSaveEvent, {
                            fieldValue: ajaxEditNewValue,
                            recordId: thisInstance.getRecordId()
                        });
                        if (preFieldSaveEvent.isDefaultPrevented()) {
                            readRecord.prop('disabled', false);
                            return;
                        }
                        editElement.addClass('d-none');
                        Vtiger_Edit_Js.saveAjax(
                            thisInstance.getCustomFieldNameValueMap({
                                field: fieldName,
                                value: ajaxEditNewValue
                            })
                        )
                            .done(function (response) {
                                editElement.off('clickoutside');
                                readRecord.prop('disabled', false);
                                detailViewValue.removeClass('d-none');
                                actionElement.removeClass('d-none');
                                if (!response.success) {
                                    return;
                                }
                                const postSaveRecordDetails = response.result;
                                let displayValue = postSaveRecordDetails[fieldName].display_value,
                                    prevDisplayValue = postSaveRecordDetails[fieldName].prev_display_value;
                                if (dateTimeField.length && dateTime) {
                                    displayValue =
                                        postSaveRecordDetails[dateTimeField[0].name].display_value +
                                        ' ' +
                                        postSaveRecordDetails[dateTimeField[1].name].display_value;
                                }
                                detailViewValue.html(displayValue);
                                app.showNotify({
                                    title: app.vtranslate('JS_SAVE_NOTIFY_OK'),
                                    text:
                                        '<b>' +
                                        fieldInfo.data.label +
                                        '</b><br>' +
                                        '<b>' +
                                        app.vtranslate('JS_SAVED_FROM') +
                                        '</b>: ' +
                                        prevDisplayValue +
                                        '<br> ' +
                                        '<b>' +
                                        app.vtranslate('JS_SAVED_TO') +
                                        '</b>: ' +
                                        displayValue,
                                    type: 'info',
                                    textTrusted: true
                                });
                                if (postSaveRecordDetails['_isViewable'] === false) {
                                    let urlObject = app.convertUrlToObject(window.location.href);
                                    if (window !== window.parent) {
                                        window.parent.location.href = 'index.php?module=' + urlObject['module'] + '&view=ListPreview';
                                    } else {
                                        window.location.href = 'index.php?module=' + urlObject['module'] + '&view=List';
                                    }
                                } else if (
                                    postSaveRecordDetails['_isEditable'] === false ||
                                    postSaveRecordDetails['_reload'] === true
                                ) {
                                    $.progressIndicator({
                                        position: 'html',
                                        blockInfo: {
                                            enabled: true
                                        }
                                    });
                                    if (window !== window.parent) {
                                        window.location.href = window.location.href.replace('view=Detail', 'view=DetailPreview');
                                    } else {
                                        window.location.reload();
                                    }
                                }
                                fieldElement.trigger(thisInstance.fieldUpdatedEvent, {
                                    old: previousValue,
                                    new: ajaxEditNewValue
                                });
                                ajaxEditNewValue = ajaxEditNewValue === undefined ? '' : ajaxEditNewValue; //data cannot be undefined
                                elementTarget.data('prevValue', ajaxEditNewValue);
                                fieldElement.data('selectedValue', ajaxEditNewValue);
                                if (thisInstance.targetPicklistChange) {
                                    if ($('.js-widget-general-info', thisInstance.getForm()).length > 0) {
                                        thisInstance.targetPicklist.find('.js-detail-quick-edit').trigger('click');
                                    } else {
                                        thisInstance.targetPicklist.trigger('click');
                                    }
                                    thisInstance.targetPicklistChange = false;
                                    thisInstance.targetPicklist = false;
                                }
                                let selectedTabElement = thisInstance.getSelectedTab();
                                if (selectedTabElement.data('linkKey') == thisInstance.detailViewSummaryTabLabel) {
                                    let detailContentsHolder = thisInstance.getContentHolder();
                                    thisInstance.reloadTabContent();
                                    thisInstance.registerSummaryViewContainerEvents(detailContentsHolder);
                                    thisInstance.registerEventForRelatedList();
                                }
                                thisInstance.updateRecordsPDFTemplateBtn(thisInstance.getForm());
                            })
                            .fail(function (jqXHR, textStatus, errorThrown) {
                                editElement.addClass('d-none');
                                detailViewValue.removeClass('d-none');
                                actionElement.removeClass('d-none');
                                editElement.off('clickoutside');
                                readRecord.prop('disabled', false);
                                app.showNotify({
                                    type: 'error',
                                    title: app.vtranslate('JS_SAVE_NOTIFY_FAIL'),
                                    text: textStatus
                                });
                            });
                    }
                };
                editElement.on('clickoutside', saveHandler);
            });
        },
        /**
         * Function updates the hidden elements which is used for creating relations
         */
        addElementsToQuickCreateForCreatingRelation: function (container, customParams) {
            jQuery('<input type="hidden" name="relationOperation" value="true" >').appendTo(container);
            jQuery.each(customParams, function (index, value) {
                jQuery('<input type="hidden" name="' + index + '" value="' + value + '" >').appendTo(container);
            });
        },
        /**
         * Function to register event for activity widget for adding
         * event and task from the widget
         */
        registerEventForActivityWidget: function () {
            let thisInstance = this;

            /*
             * Register click event for add button in Related Activities widget
             */
            jQuery('.createActivity').on('click', function (e) {
                let referenceModuleName = 'Calendar';
                let recordId = thisInstance.getRecordId();
                let module = app.getModuleName();
                let element = jQuery(e.currentTarget);

                let customParams = {};
                customParams['sourceModule'] = module;
                customParams['sourceRecord'] = recordId;
                let fullFormUrl = element.data('url');
                let preQuickCreateSave = function (data) {
                    thisInstance.addElementsToQuickCreateForCreatingRelation(data, customParams);
                    let taskGoToFullFormButton = data.find('[class^="CalendarQuikcCreateContents"]').find('.js-full-editlink');
                    let eventsGoToFullFormButton = data.find('[class^="EventsQuikcCreateContents"]').find('.js-full-editlink');
                    let taskFullFormUrl = taskGoToFullFormButton.data('url') + '&' + fullFormUrl;
                    let eventsFullFormUrl = eventsGoToFullFormButton.data('url') + '&' + fullFormUrl;
                    taskGoToFullFormButton.data('url', taskFullFormUrl);
                    eventsGoToFullFormButton.data('url', eventsFullFormUrl);
                };
                let callbackFunction = function () {
                    thisInstance.getFiltersDataAndLoad(e);
                    thisInstance.loadWidget($('.widgetContentBlock[data-type="Updates"]'));
                };
                let QuickCreateParams = {};
                QuickCreateParams['callbackPostShown'] = preQuickCreateSave;
                QuickCreateParams['callbackFunction'] = callbackFunction;
                QuickCreateParams['data'] = Object.assign({}, customParams);
                QuickCreateParams['noCache'] = false;
                App.Components.QuickCreate.createRecord(referenceModuleName, QuickCreateParams);
            });
        },
        /**
         * Function to add module related record from summary widget
         */
        registerFilterForAddingModuleRelatedRecordFromSummaryWidget: function (container) {
            let thisInstance = this;
            container
                .find('.createRecordFromFilter')
                .off()
                .on('click', function (e) {
                    let currentElement = jQuery(e.currentTarget);
                    let summaryWidgetContainer = currentElement.closest('.js-detail-widget');
                    let referenceModuleName = summaryWidgetContainer.data('moduleName');
                    let quickcreateUrl = currentElement.data('url');
                    let quickCreateParams = {};
                    let autoCompleteFields = currentElement.data('acf');
                    let moduleName = currentElement.closest('.js-detail-widget-header').find('[name="relatedModule"]').val();
                    let relatedParams = {};
                    let postQuickCreateSave = function (data) {
                        thisInstance.postSummaryWidgetAddRecord(data, currentElement);
                        if (referenceModuleName == 'ProjectTask') {
                            thisInstance.loadModuleSummary();
                        }
                    };
                    if (typeof autoCompleteFields !== 'undefined') {
                        $.each(autoCompleteFields, function (index, value) {
                            relatedParams[index] = value;
                        });
                    }
                    if (Object.keys(relatedParams).length > 0) {
                        quickCreateParams['data'] = relatedParams;
                    }
                    quickCreateParams['noCache'] = true;
                    quickCreateParams['callbackFunction'] = postQuickCreateSave;
                    let progress = jQuery.progressIndicator({
                        blockInfo: {
                            enabled: true
                        }
                    });
                    let quickCreate;
                    if (window !== window.parent) {
                        quickCreate = window.parent.App.Components.QuickCreate;
                    } else {
                        quickCreate = App.Components.QuickCreate;
                    }
                    quickCreate.getForm(quickcreateUrl, moduleName, quickCreateParams).done(function (data) {
                        quickCreate.showModal(data, quickCreateParams, currentElement);
                        progress.progressIndicator({ mode: 'hide' });
                    });
                });
            container
                .find('button.selectRelation')
                .off('click')
                .on('click', function (e) {
                    let summaryWidgetContainer = jQuery(e.currentTarget).closest('.js-detail-widget');
                    let referenceModuleName = summaryWidgetContainer.data('moduleName');
                    let restrictionsField = $(this).data('rf');
                    let params = {
                        module: referenceModuleName,
                        src_module: app.getModuleName(),
                        src_record: thisInstance.getRecordId(),
                        multi_select: true,
                        relationId: summaryWidgetContainer.data('relationId')
                    };
                    if (restrictionsField && Object.keys(restrictionsField).length > 0) {
                        params['search_key'] = restrictionsField.key;
                        params['search_value'] = restrictionsField.name;
                    }
                    app.showRecordsList(params, (_modal, instance) => {
                        instance.setSelectEvent((responseData) => {
                            thisInstance
                                .addRelationBetweenRecords(referenceModuleName, Object.keys(responseData), null, {
                                    relationId: params.relationId
                                })
                                .done(function () {
                                    thisInstance.loadWidget(summaryWidgetContainer.find('.widgetContentBlock'));
                                });
                        });
                    });
                });
        },
        registerAddingInventoryRecords: function () {
            jQuery('.createInventoryRecordFromFilter').on('click', function (e) {
                let currentElement = jQuery(e.currentTarget);
                let createUrl = currentElement.data('url');
                let autoCompleteFields = currentElement.data('acf');
                let addidtionalParams = '';
                if (typeof autoCompleteFields !== 'undefined') {
                    $.each(autoCompleteFields, function (index, value) {
                        addidtionalParams = '&' + index + '=' + value;
                        createUrl = createUrl.concat(addidtionalParams);
                    });
                }
                window.location.href = createUrl;
            });
        },
        registerEmailEvent: function () {
            this.getContentHolder()
                .find('.resetRelationsEmail')
                .on('click', function (e) {
                    app.showConfirmModal({
                        title: app.vtranslate('JS_EMAIL_RESET_RELATIONS_CONFIRMATION'),
                        confirmedCallback: () => {
                            AppConnector.request({
                                module: 'OSSMailView',
                                action: 'Relation',
                                moduleName: app.getModuleName(),
                                record: app.getRecordId()
                            }).done(function (d) {
                                Vtiger_Helper_Js.showMessage({ text: d.result });
                            });
                        }
                    });
                });
        },
        getFiltersDataAndLoad: function (e, params) {
            let data = this.getFiltersData(e, params);
            this.loadWidget(data['container'], data['params']);
        },
        getFiltersData: function (e, params) {
            let currentElement;
            if (e.currentTarget) {
                currentElement = jQuery(e.currentTarget);
            } else {
                currentElement = e;
            }
            let summaryWidgetContainer = currentElement.closest('.js-detail-widget');
            let widget = summaryWidgetContainer.find('.widgetContentBlock');
            let url = '&' + widget.data('url');
            let urlParams = {};
            url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
                urlParams[key] = value;
            });
            let urlNewParams = [];
            summaryWidgetContainer.find('.js-switch, .js-filter_field').each(function (n, item) {
                let value = '';
                let element = jQuery(item);
                let name = element.data('urlparams');
                if (element.attr('type') == 'radio') {
                    if (element.prop('checked')) {
                        value = typeof element.data('on-val') !== 'undefined' ? element.data('on-val') : element.data('off-val');
                        let additionalParams = element.data('params');
                        if (typeof additionalParams !== typeof undefined && additionalParams !== false) {
                            $.each(additionalParams, function (paramName, paramValue) {
                                if (paramName in urlNewParams) {
                                    urlNewParams[paramName].push(paramValue);
                                } else {
                                    urlNewParams[paramName] = paramValue;
                                }
                            });
                        }
                    }
                } else {
                    let selectedFilter = element.find('option:selected').val();
                    let fieldlable = element.data('fieldlable');
                    let filter = element.data('filter');
                    if (element.data('return') === 'value') {
                        value = selectedFilter;
                    } else {
                        if (selectedFilter != fieldlable) {
                            value = [[filter, 'e', selectedFilter]];
                        } else {
                            return;
                        }
                    }
                }
                if (name && value) {
                    if (element.data('return') === 'value') {
                        urlNewParams[name] = value;
                    } else {
                        if (name in urlNewParams) {
                            urlNewParams[name].push(value);
                        } else {
                            urlNewParams[name] = [value];
                        }
                    }
                }
            });
            if (params != undefined) {
                $.extend(urlNewParams, params);
            }
            return { container: $(widget), params: $.extend(urlParams, urlNewParams) };
        },
        registerChangeFilterForWidget: function () {
            let thisInstance = this;
            jQuery('.js-switch').on('change', function (e, state) {
                $(e.currentTarget).closest('.js-switch__btn').addClass('active').siblings().removeClass('active');
                thisInstance.getFiltersDataAndLoad(e);
            });
            jQuery('.js-filter_field').on('select2:select', function (e, state) {
                thisInstance.getFiltersDataAndLoad(e);
            });
        },
        /**
         * Function to register all the events related to summary view widgets
         */
        registerSummaryViewContainerEvents: function (summaryViewContainer) {
            let thisInstance = this;
            this.registerEventForActivityWidget();
            this.registerChangeFilterForWidget();
            this.registerAddingInventoryRecords();
            this.registerEmailEvent();
            /**
             * Function to handle the ajax edit for summary view fields
             */
            summaryViewContainer.off('click').on('click', '.row .js-detail-quick-edit', function (e) {
                let currentTarget = jQuery(e.currentTarget);
                currentTarget.addClass('d-none');
                let currentTdElement = currentTarget.closest('.fieldValue');
                thisInstance.ajaxEditHandling(currentTdElement);
            });
            /**
             * Function to handle actions after ajax save in summary view
             */
            summaryViewContainer.on(thisInstance.fieldUpdatedEvent, '.js-widget-general-info', function () {
                let updatesWidget = summaryViewContainer.find("[data-type='Updates']"),
                    params;
                if (updatesWidget.length) {
                    params = thisInstance.getFiltersData(updatesWidget);
                    updatesWidget.find('.btnChangesReviewedOn').parent().remove();
                    thisInstance.loadWidget(updatesWidget, params['params']);
                }
            });

            summaryViewContainer.on('click', '.editDefaultStatus', function (e) {
                let currentTarget = jQuery(e.currentTarget);
                currentTarget.popover('hide');
                let url = currentTarget.data('url');
                if (url) {
                    if (currentTarget.hasClass('showEdit')) {
                        let quickCreate = App.Components.QuickCreate;
                        if (window !== window.parent) {
                            quickCreate = window.parent.App.Components.QuickCreate;
                        }
                        quickCreate.getForm(url, 'Calendar', { noCache: true }).done((data) => {
                            quickCreate.showModal(
                                data,
                                {
                                    callbackFunction: () => {
                                        let widget = currentTarget.closest('.widgetContentBlock');
                                        if (widget.length) {
                                            thisInstance.loadWidget(widget);
                                            let updatesWidget = thisInstance.getContentHolder().find("[data-type='Updates']");
                                            if (updatesWidget.length > 0) {
                                                thisInstance.loadWidget(updatesWidget);
                                            }
                                        } else {
                                            thisInstance.loadRelatedList();
                                        }
                                        thisInstance.registerRelatedModulesRecordCount();
                                    }
                                },
                                currentTarget
                            );
                        });
                    } else {
                        app.showModalWindow(null, url);
                    }
                }
            });

            /*
             * Register the event to edit Description for related activities
             */
            summaryViewContainer.on('click', '.editDescription', function (e) {
                let currentTarget = jQuery(e.currentTarget),
                    currentDiv = currentTarget.closest('.activityDescription'),
                    editElement = currentDiv.find('.edit'),
                    detailViewElement = currentDiv.find('.value'),
                    descriptionText = currentDiv.find('.js-description-text'),
                    descriptionEmpty = currentDiv.find('.js-no-description'),
                    saveButton = currentDiv.find('.js-save-description'),
                    closeButton = currentDiv.find('.js-close-description'),
                    activityButtonContainer = currentDiv.find('.js-activity-buttons__container'),
                    fieldnameElement = jQuery('.fieldname', editElement),
                    fieldName = fieldnameElement.val(),
                    fieldElement = jQuery('[name="' + fieldName + '"]', editElement),
                    callbackFunction = () => {
                        let previousValue = fieldnameElement.data('prevValue'),
                            ajaxEditNewValue = fieldElement.val(),
                            ajaxEditNewLable = fieldElement.val(),
                            activityDiv = currentDiv.closest('.activityEntries'),
                            activityId = activityDiv.find('.activityId').val(),
                            moduleName = activityDiv.find('.activityModule').val(),
                            activityType = activityDiv.find('.activityType').val();
                        if (previousValue == ajaxEditNewValue) {
                            closeDescription();
                        } else {
                            currentDiv.progressIndicator();
                            editElement.add(activityButtonContainer).addClass('d-none');
                            return new Promise(function (resolve, reject) {
                                resolve(fieldElement.validationEngine('validate'));
                            }).then((errorExists) => {
                                //If validation fails
                                if (errorExists) {
                                    Vtiger_Helper_Js.addClickOutSideEvent(currentDiv, callbackFunction);
                                    return;
                                } else {
                                    ajaxEditNewValue = fieldElement.val(); //update editor value after conversion
                                    AppConnector.request({
                                        action: 'SaveAjax',
                                        record: activityId,
                                        field: fieldName,
                                        value: ajaxEditNewValue,
                                        module: moduleName,
                                        activitytype: activityType
                                    }).done(() => {
                                        currentDiv.progressIndicator({ mode: 'hide' });
                                        detailViewElement.removeClass('d-none');
                                        currentTarget.show();
                                        descriptionText.html(ajaxEditNewLable);
                                        fieldnameElement.data('prevValue', ajaxEditNewValue);
                                        if (ajaxEditNewValue === '') {
                                            descriptionEmpty.removeClass('d-none');
                                        } else {
                                            descriptionEmpty.addClass('d-none');
                                        }
                                    });
                                }
                            });
                        }
                    },
                    closeDescription = function () {
                        fieldElement.val(fieldnameElement.data('prevValue'));
                        editElement.add(activityButtonContainer).addClass('d-none');
                        detailViewElement.removeClass('d-none');
                        currentTarget.show();
                    };
                App.Fields.Text.Editor.register(currentDiv, { toolbar: 'Min' });
                currentTarget.hide();
                detailViewElement.addClass('d-none');
                activityButtonContainer.removeClass('d-none');
                editElement.removeClass('d-none').show();
                saveButton.off('click').one('click', callbackFunction);
                closeButton.off('click').one('click', closeDescription);
            });

            /*
             * Register click event for add button in Related widgets
             * to add record from widget
             */

            $('.changeDetailViewMode').on('click', function (e) {
                thisInstance
                    .getTabs()
                    .filter('[data-link-key="' + thisInstance.detailViewDetailsTabLabel + '"]:not(.d-none)')
                    .trigger('click');
            });
            this.registerFastEditingFields();
        },
        addRelationBetweenRecords: function (relatedModule, relatedModuleRecordId, selectedTabElement, params = {}, url) {
            let aDeferred = jQuery.Deferred();
            let thisInstance = this;
            let relatedController;
            if (selectedTabElement == undefined) {
                selectedTabElement = thisInstance.getSelectedTab();
            }
            if (url) {
                relatedController = Vtiger_RelatedList_Js.getInstanceByUrl(url, selectedTabElement);
            } else {
                relatedController = Vtiger_RelatedList_Js.getInstance(
                    thisInstance.getRecordId(),
                    app.getModuleName(),
                    selectedTabElement,
                    relatedModule
                );
            }
            relatedController
                .addRelations(relatedModuleRecordId, params)
                .done(function (data) {
                    let summaryViewContainer = thisInstance.getContentHolder();
                    let updatesWidget = summaryViewContainer.find("[data-type='Updates']");
                    if (updatesWidget.length > 0) {
                        let params = thisInstance.getFiltersData(updatesWidget);
                        updatesWidget.find('.btnChangesReviewedOn').parent().remove();
                        thisInstance.loadWidget(updatesWidget, params['params']);
                    }
                    aDeferred.resolve(data);
                })
                .fail(function (textStatus, errorThrown) {
                    aDeferred.reject(textStatus, errorThrown);
                });
            return aDeferred.promise();
        },
        /**
         * Function to handle Post actions after adding record from
         * summary view widget
         */
        postSummaryWidgetAddRecord: function (data, currentElement) {
            let summaryWidgetContainer = currentElement.closest('.js-detail-widget');
            let widgetContainer = summaryWidgetContainer.find('[class^="widgetContainer_"]');

            this.loadWidget(widgetContainer);
            let updatesWidget = this.getContentHolder().find("[data-type='Updates']");
            if (updatesWidget.length > 0) {
                let params = this.getFiltersData(updatesWidget);
                updatesWidget.find('.btnChangesReviewedOn').parent().remove();
                this.loadWidget(updatesWidget, params['params']);
            }
        },
        registerChangeEventForModulesList: function () {
            jQuery('#tagSearchModulesList').on('change', function (e) {
                let modulesSelectElement = jQuery(e.currentTarget);
                if (modulesSelectElement.val() == 'all') {
                    jQuery('[name="tagSearchModuleResults"]').removeClass('d-none');
                } else {
                    jQuery('[name="tagSearchModuleResults"]').removeClass('d-none');
                    let selectedOptionValue = modulesSelectElement.val();
                    jQuery('[name="tagSearchModuleResults"]')
                        .filter(':not(#' + selectedOptionValue + ')')
                        .addClass('d-none');
                }
            });
        },
        registerEventForRelatedTabClick: function () {
            let thisInstance = this;
            let detailContentsHolder = thisInstance.getContentHolder();
            let detailContainer = detailContentsHolder.closest('div.detailViewInfo');

            jQuery('.related', detailContainer).on('click', 'li:not(.spaceRelatedList)', function (e, urlAttributes) {
                let tabElement = jQuery(e.currentTarget);
                if (!tabElement.hasClass('dropdown')) {
                    let element = jQuery('<div></div>');
                    element.progressIndicator({
                        position: 'html',
                        blockInfo: {
                            enabled: true,
                            elementToBlock: detailContainer
                        }
                    });
                    let url = tabElement.data('url');
                    if (typeof urlAttributes !== 'undefined') {
                        let callBack = urlAttributes.callback;
                        delete urlAttributes.callback;
                    }
                    thisInstance
                        .loadContents(url, urlAttributes)
                        .done(function (data) {
                            thisInstance.deSelectAllrelatedTabs();
                            thisInstance.markTabAsSelected(tabElement);
                            Vtiger_Helper_Js.showHorizontalTopScrollBar();
                            element.progressIndicator({ mode: 'hide' });
                            app.registerModal(detailContentsHolder);
                            if (typeof callBack == 'function') {
                                callBack(data);
                            }
                            //Summary tab is clicked
                            if (tabElement.data('linkKey') == thisInstance.detailViewSummaryTabLabel) {
                                thisInstance.loadWidgets();
                            }
                            thisInstance.registerBasicEvents();
                            // Let listeners know about page state change.
                            app.notifyPostAjaxReady();
                            app.event.trigger('DetailView.Tab.AfterLoad', data, thisInstance);
                        })
                        .fail(function () {
                            element.progressIndicator({ mode: 'hide' });
                        });
                }
            });
        },
        /**
         * Function to get child comments
         */
        getChildComments: function (commentId) {
            let aDeferred = jQuery.Deferred();
            let url =
                'module=' +
                app.getModuleName() +
                '&view=Detail&record=' +
                this.getRecordId() +
                '&mode=showChildComments&commentid=' +
                commentId;
            let dataObj = this.getCommentThread(url);
            dataObj.done(function (data) {
                aDeferred.resolve(data);
            });
            return aDeferred.promise();
        },
        /**
         * Function to get parent comment
         * @param {number} commentId
         * @returns {string}
         */
        getParentComments(commentId) {
            let aDeferred = $.Deferred(),
                url =
                    'module=' +
                    app.getModuleName() +
                    '&view=Detail&record=' +
                    this.getRecordId() +
                    '&mode=showParentComments&commentid=' +
                    commentId;
            this.getCommentThread(url).done(function (data) {
                aDeferred.resolve(data);
            });
            return aDeferred.promise();
        },
        /**
         * Function to show total records count in listview on hover
         * of pageNumber text
         */
        registerEventForTotalRecordsCount: function () {
            let thisInstance = this;
            let detailContentsHolder = this.getContentHolder();
            detailContentsHolder.on('click', '.totalNumberOfRecords', function (e) {
                let element = jQuery(e.currentTarget);
                let totalNumberOfRecords = jQuery('#totalCount').val();
                element.addClass('d-none');
                element.parent().progressIndicator({});
                if (totalNumberOfRecords == '') {
                    let selectedTabElement = thisInstance.getSelectedTab();
                    let relatedModuleName = thisInstance.getRelatedModuleName();
                    let relatedController = Vtiger_RelatedList_Js.getInstance(
                        thisInstance.getRecordId(),
                        app.getModuleName(),
                        selectedTabElement,
                        relatedModuleName
                    );
                    relatedController.getRelatedPageCount().done(function () {
                        thisInstance.showPagingInfo();
                    });
                } else {
                    thisInstance.showPagingInfo();
                }
                element.parent().progressIndicator({ mode: 'hide' });
            });
        },
        showPagingInfo: function () {
            let totalNumberOfRecords = jQuery('#totalCount').val();
            let pageNumberElement = jQuery('.pageNumbersText');
            let pageRange = pageNumberElement.text();
            let newPagingInfo = pageRange + ' (' + totalNumberOfRecords + ')';
            let listViewEntriesCount = parseInt(jQuery('#noOfEntries').val());
            if (listViewEntriesCount != 0) {
                jQuery('.pageNumbersText').html(newPagingInfo);
            } else {
                jQuery('.pageNumbersText').html('');
            }
        },
        getCustomFieldNameValueMap: function (fieldNameValueMap) {
            return fieldNameValueMap;
        },
        registerSetReadRecord: function (detailContentsHolder) {
            let thisInstance = this;
            detailContentsHolder.on('click', '.setReadRecord', function (e) {
                let currentElement = jQuery(e.currentTarget);
                currentElement.closest('.btn-group').addClass('d-none');
                jQuery('#Accounts_detailView_fieldValue_was_read').find('.value').text(app.vtranslate('LBL_YES'));
                let params = {
                    module: app.getModuleName(),
                    action: 'SaveAjax',
                    record: thisInstance.getRecordId(),
                    field: 'was_read',
                    value: 'on'
                };
                AppConnector.request(params).done(function (data) {
                    let params = {
                        text: app.vtranslate('JS_SET_READ_RECORD'),
                        title: app.vtranslate('System'),
                        type: 'info'
                    };
                    app.showNotify(params);
                    let relatedTabKey = jQuery('.related li.active');
                    if (
                        relatedTabKey.data('linkKey') == thisInstance.detailViewSummaryTabLabel ||
                        relatedTabKey.data('linkKey') == thisInstance.detailViewDetailsTabLabel
                    ) {
                        thisInstance.reloadTabContent();
                    }
                });
            });
        },
        registerFastEditingFields: function () {
            let thisInstance = this;
            let fastEditingFiels = jQuery('.summaryWidgetFastEditing select');
            fastEditingFiels.on('change', function (e) {
                let fieldElement = jQuery(e.currentTarget);
                let fieldContainer = fieldElement.closest('.editField');
                let progressIndicatorElement = jQuery.progressIndicator({
                    message: app.vtranslate('JS_SAVE_LOADER_INFO'),
                    position: 'summaryWidgetFastEditing',
                    blockInfo: {
                        enabled: true
                    }
                });
                let fieldName = fieldContainer.data('fieldname');
                fieldName = fieldName.replace('q_', '');
                let fieldValue = fieldElement.val();
                let errorExists = fieldElement.validationEngine('validate');
                if (errorExists) {
                    fieldContainer.progressIndicator({ mode: 'hide' });
                    return;
                }
                let preFieldSaveEvent = jQuery.Event(thisInstance.fieldPreSave);
                fieldElement.trigger(preFieldSaveEvent, {
                    fieldValue: fieldValue,
                    recordId: thisInstance.getRecordId()
                });
                Vtiger_Edit_Js.saveAjax(
                    thisInstance.getCustomFieldNameValueMap({
                        field: fieldName,
                        value: fieldValue
                    }),
                    false
                ).always(() => {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    app.showNotify({
                        title: app.vtranslate('JS_SAVE_NOTIFY_OK'),
                        type: 'success'
                    });
                    thisInstance.reloadTabContent();
                });
            });
        },
        registerHelpInfo: function (form) {
            if (!form) {
                form = this.getForm();
            }
            app.showPopoverElementView(form.find('.js-help-info'));
        },
        /**
         * Register related modules record cound
         * @param {jQuery} tabContainer
         */
        registerRelatedModulesRecordCount(tabContainer) {
            const moreList = $('.related .nav .dropdown-menu');
            let relationContainer = tabContainer;
            if (!relationContainer || typeof relationContainer.length === 'undefined') {
                relationContainer = $(
                    '.related .nav > .relatedNav, .related .nav > .mainNav, .detailViewBlockLink, .related .nav .dropdown-menu > .relatedNav'
                );
            }
            relationContainer.each((n, item) => {
                item = $(item);
                let relationId = item.data('relationId'),
                    relatedModule = item.data('reference');
                if (item.data('count') === 1) {
                    AppConnector.request({
                        module: app.getModuleName(),
                        action: 'RelationAjax',
                        record: app.getRecordId(),
                        relatedModule: relatedModule,
                        mode: 'getRelatedListPageCount',
                        relationId: relationId,
                        tab_label: item.data('label-key')
                    }).done((response) => {
                        if (response.success) {
                            if (response.result.numberOfRecords === 0) {
                                response.result.numberOfRecords = '';
                            }
                            item.find('.count').text(response.result.numberOfRecords);
                            moreList
                                .find('[data-reference="${relatedModule}"][data-relation-id="${relationId}"] .count')
                                .text(response.result.numberOfRecords);
                        }
                    });
                }
            });
        },
        /**
         * Function to display a new comments
         */
        addComment: function (currentTarget, data) {
            const self = this;
            let mode = currentTarget.data('mode'),
                closestAddCommentBlock = currentTarget.closest('.js-add-comment-block'),
                commentTextAreaElement = closestAddCommentBlock.find('.js-comment-content'),
                commentInfoBlock = currentTarget.closest('.js-comment-single');
            commentTextAreaElement.html('');
            if (mode == 'add') {
                let commentHtml = self.getCommentUI(data['result']['_recordId']);
                commentHtml.done(function (data) {
                    let commentBlock = closestAddCommentBlock.closest('.js-comment-details'),
                        detailContentsHolder = self.getContentHolder(),
                        noCommentsMsgContainer = $('.js-noCommentsMsgContainer', detailContentsHolder);
                    noCommentsMsgContainer.remove();
                    if (commentBlock.length > 0) {
                        closestAddCommentBlock.remove();
                        let childComments = commentBlock.find('ul');
                        if (childComments.length <= 0) {
                            let currentChildCommentsCount = commentInfoBlock
                                    .find('.js-view-thread-block')
                                    .data('data-child-comments-count'),
                                newChildCommentCount = currentChildCommentsCount + 1;
                            commentInfoBlock.find('.js-child-comments-count').text(newChildCommentCount);
                            let parentCommentId = commentInfoBlock.find('.js-comment-info-header').data('commentid');
                            self.getChildComments(parentCommentId).done(function (responsedata) {
                                $(responsedata).appendTo(commentBlock);
                                commentInfoBlock.find('.js-view-thread-block').hide();
                                commentInfoBlock.find('.hideThreadBlock').show();
                            });
                        } else {
                            $('<li class="js-comment-details commentDetails">' + data + '</li>').appendTo(
                                commentBlock.find('.js-comments-body')
                            );
                        }
                    } else {
                        $('<li class="js-comment-details commentDetails">' + data + '</li>').prependTo(
                            closestAddCommentBlock.closest('.contents').find('.commentsList')
                        );
                    }
                    commentInfoBlock.find('.js-comment-container').show();
                    app.event.trigger('DetailView.SaveComment.AfterLoad', commentInfoBlock, data);
                });
            } else if (mode == 'edit') {
                let modifiedTime = commentInfoBlock.find('.js-comment-modified-time'),
                    commentInfoContent = commentInfoBlock.find('.js-comment-info'),
                    commentEditStatus = commentInfoBlock.find('.js-edited-status'),
                    commentReason = commentInfoBlock.find('.js-edit-reason-span');
                commentInfoContent.html(data['result']['commentcontent']['display_value']);
                commentReason.html(data['result']['reasontoedit']['display_value']);
                modifiedTime.html(data['result']['modifiedtime']['formatToViewDate']);
                modifiedTime.attr('title', data['result']['modifiedtime']['formatToDay']);
                if (commentEditStatus.hasClass('d-none')) {
                    commentEditStatus.removeClass('d-none');
                }
                if (data['result']['reasontoedit']['display_value'] != '') {
                    commentInfoBlock.find('.js-edit-reason').removeClass('d-none');
                }
                commentInfoContent.show();
                commentInfoBlock.find('.js-comment-container').show();
                closestAddCommentBlock.remove();
                app.event.trigger('DetailView.SaveComment.AfterUpdate', commentInfoBlock, data);
            }
        },
        /**
         * Register all comment events
         * @param {jQuery} detailContentsHolder
         */
        registerCommentEvents(detailContentsHolder) {
            const self = this;
            detailContentsHolder.on('click', '.js-close-comment-block', function (e) {
                let commentInfoBlock = $(e.currentTarget.closest('.js-comment-single'));
                commentInfoBlock.find('.js-comment-container').show();
                commentInfoBlock.find('.js-comment-info').show();
                commentInfoBlock.find('.js-add-comment-block').remove();
            });
            detailContentsHolder.on('click', '.js-reply-comment', function (e) {
                let commentInfoBlock = $(e.currentTarget).closest('.js-comment-single');
                commentInfoBlock.find('.js-add-comment-block').remove();
                self.hideButtonAction();
                commentInfoBlock.find('.js-comment-info').show();
                self.getCommentBlock().appendTo(commentInfoBlock).show();
            });
            detailContentsHolder.on('click', '.js-edit-comment', function (e) {
                let commentInfoBlock = $(e.currentTarget).closest('.js-comment-single');
                commentInfoBlock.find('.js-add-comment-block').remove();
                self.hideButtonAction();
                let commentInfoContent = commentInfoBlock.find('.js-comment-info'),
                    editCommentBlock = self.getEditCommentBlock();
                editCommentBlock.find('.js-comment-content').html(commentInfoContent.html());
                editCommentBlock.find('.js-reason-to-edit').html(commentInfoBlock.find('.js-edit-reason-span').text());
                commentInfoContent.hide();
                commentInfoBlock.find('.js-comment-container').hide();
                editCommentBlock.appendTo(commentInfoBlock).show();
            });
            detailContentsHolder.on('click', '.js-detail-view-save-comment', function (e) {
                let element = $(e.currentTarget);
                if (!element.is(':disabled')) {
                    self
                        .saveComment(e)
                        .done(function () {
                            self.registerRelatedModulesRecordCount();
                            self.loadWidget(detailContentsHolder.find("[data-type='Comments']")).done(function () {
                                element.removeAttr('disabled');
                            });
                        })
                        .fail(function (error, err) {
                            element.removeAttr('disabled');
                            app.errorLog(error, err);
                        });
                }
            });
            detailContentsHolder.on('click', '.js-save-comment', function (e) {
                let element = $(e.currentTarget);
                if (!element.is(':disabled')) {
                    self
                        .saveComment(e)
                        .done(function (data) {
                            self.registerRelatedModulesRecordCount(self.getTabByLabel(self.detailViewRecentCommentsTabLabel));
                            self.addComment(element, data);
                            element.removeAttr('disabled');
                        })
                        .fail(function (error, err) {
                            element.removeAttr('disabled');
                            app.errorLog(error, err);
                        });
                }
            });
            detailContentsHolder.on('click', '.js-more-recent-comments ', function () {
                self.getTabByLabel(self.detailViewRecentCommentsTabLabel).trigger('click');
            });
            detailContentsHolder.find('.js-detail-hierarchy-comments').on('change', function (e) {
                let recentCommentsTab = self.getTabByLabel(self.detailViewRecentCommentsTabLabel),
                    url = recentCommentsTab.data('url'),
                    regex = /&hierarchy=+([\w,]+)/;
                url = url.replace(regex, '');
                let hierarchy = [];
                detailContentsHolder.find('.js-detail-hierarchy-comments:checked').each(function () {
                    hierarchy.push($(this).val());
                });
                if (hierarchy.length !== 0) {
                    url += '&hierarchy=' + hierarchy.join(',');
                }
                recentCommentsTab.data('url', url);
                recentCommentsTab.trigger('click');
            });
            detailContentsHolder.on('keypress', '.js-comment-search', function (e) {
                if (13 === e.which) {
                    self.submitSearchForm(detailContentsHolder);
                }
            });
            detailContentsHolder.on('click', '.js-search-icon', function (e) {
                self.submitSearchForm(detailContentsHolder);
            });
        },
        /**
         * Submit search comment form
         * @param {jQuery} detailContentsHolder
         */
        submitSearchForm(detailContentsHolder) {
            let searchTextDom = detailContentsHolder.find('.js-comment-search'),
                widgetContainer = searchTextDom.closest('[data-name="ModComments"]'),
                progressIndicatorElement = $.progressIndicator();
            if (searchTextDom.data('container') === 'widget' && !searchTextDom.val()) {
                let request = widgetContainer.data('url');
                AppConnector.request(request).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    detailContentsHolder.find('.js-comments-container').html(data);
                });
            } else {
                let hierarchy = [],
                    limit = '',
                    isWidget = false;
                if (searchTextDom.data('container') === 'widget') {
                    (limit = widgetContainer.data('limit')), (isWidget = true);
                    widgetContainer.find('.js-hierarchy-comments:checked').each(function () {
                        hierarchy.push($(this).val());
                    });
                } else {
                    detailContentsHolder.find('.js-detail-hierarchy-comments:checked').each(function () {
                        hierarchy.push($(this).val());
                    });
                }
                AppConnector.request({
                    module: app.getModuleName(),
                    view: 'Detail',
                    mode: 'showSearchComments',
                    hierarchy: hierarchy.join(','),
                    limit: limit,
                    record: app.getRecordId(),
                    search_key: searchTextDom.val(),
                    is_widget: isWidget
                }).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    if (!searchTextDom.val()) {
                        detailContentsHolder.html(data);
                    } else {
                        detailContentsHolder.find('.js-comments-body').html(data);
                    }
                });
            }
        },
        /**
         * Register hierarchy comments buttons
         * @param {jQuery} widgetContainer
         */
        registerCommentEventsInDetail(widgetContainer) {
            new App.Fields.Text.Completions($('.js-completions').eq(0));
            widgetContainer.on('change', '.js-hierarchy-comments', function (e) {
                let hierarchy = [];
                widgetContainer.find('.js-hierarchy-comments').each(function () {
                    if ($(this).is(':checked')) {
                        hierarchy.push($(this).val());
                    }
                });
                if (!hierarchy.length) {
                    widgetContainer.find('.js-detail-widget-content').html('');
                    return false;
                }
                let progressIndicatorElement = $.progressIndicator();
                AppConnector.request({
                    module: app.getModuleName(),
                    view: 'Detail',
                    mode: 'showRecentComments',
                    hierarchy: hierarchy.join(','),
                    record: app.getRecordId(),
                    limit: widgetContainer.find('.widgetContentBlock').data('limit')
                }).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    let widgetDataContainer = widgetContainer.find('.js-detail-widget-content');
                    widgetDataContainer.html(data);
                    App.Fields.Picklist.showSelect2ElementView(widgetDataContainer.find('.select2'));
                });
            });
        },
        registerMailPreviewWidget: function (container) {
            const self = this;
            container.on('click', '.showMailBody', (e) => {
                let row = $(e.currentTarget).closest('.js-mail-row'),
                    mailBody = row.find('.mailBody'),
                    mailTeaser = row.find('.mailTeaser');
                mailBody.toggleClass('d-none');
                mailTeaser.toggleClass('d-none');
            });
            container.find('[name="mail-type"]').on('change', function (e) {
                self.loadMailPreviewWidget(container);
            });
            container.find('[name="mailFilter"]').on('change', function (e) {
                self.loadMailPreviewWidget(container);
            });
            container.on('click', '.showMailsModal', (e) => {
                let url = $(e.currentTarget).data('url');
                let type = container.find('[name="mail-type"]');
                let typeValue = '';
                if (type.length > 0) {
                    typeValue = type.val();
                } else {
                    typeValue = 'All';
                }
                url += '&type=' + typeValue;
                if (container.find('[name="mailFilter"]').length > 0) {
                    url += '&mailFilter=' + container.find('[name="mailFilter"]').val();
                }
                let progressIndicatorElement = jQuery.progressIndicator();
                app.showModalWindow('', url, (data) => {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    self.registerMailPreviewWidget(data);
                    Vtiger_Index_Js.registerMailButtons(data);
                    data.find('.expandAllMails').click();
                });
            });
            container.find('.expandAllMails').on('click', function (e) {
                container.find('.mailBody').removeClass('d-none');
                container.find('.mailTeaser').addClass('d-none');
                container.find('.showMailBody .js-toggle-icon').removeClass('fa-caret-down').addClass('fa-caret-up');
            });
            container.find('.collapseAllMails').on('click', function (e) {
                container.find('.mailBody').addClass('d-none');
                container.find('.mailTeaser').removeClass('d-none');
                container.find('.showMailBody .js-toggle-icon').removeClass('fa-caret-up').addClass('fa-caret-down');
            });
            container
                .find('.showMailModal')
                .off('click')
                .on('click', function (e) {
                    e.preventDefault();
                    let progressIndicatorElement = jQuery.progressIndicator();
                    app.showModalWindow('', $(e.currentTarget).data('url') + '&noloadlibs=1', function (data) {
                        Vtiger_Index_Js.registerMailButtons(data);
                        progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    });
                });
        },
        loadMailPreviewWidget: function (widgetContent) {
            let thisInstance = this;
            let widgetDataContainer = widgetContent.find('.js-detail-widget-content');
            let recordId = $('#recordId').val();
            let progress = widgetDataContainer.progressIndicator();
            let params = {};
            params['module'] = 'OSSMailView';
            params['view'] = 'Widget';
            params['smodule'] = $('#module').val();
            params['srecord'] = recordId;
            params['mode'] = 'showEmailsList';
            params['type'] = $('[name="mail-type"]').val();
            params['mailFilter'] = $('[name="mailFilter"]').val();
            AppConnector.request(params).done(function (data) {
                widgetDataContainer.html(data);
                app.event.trigger('DetailView.Widget.AfterLoad', widgetDataContainer, params['module'], thisInstance);
                progress.progressIndicator({ mode: 'hide' });
            });
        },
        registerEmailEvents: function (detailContentsHolder) {
            Vtiger_Index_Js.registerMailButtons(detailContentsHolder);
        },
        registerMapsEvents: function (container) {
            if (container.find('#coordinates').length) {
                let mapView = new OpenStreetMap_Map_Js();
                mapView.registerDetailView(container);
            }
        },
        registerShowSummary: function (container) {
            container.on('click', '.showSummaryRelRecord', function (e) {
                let currentTarget = $(e.currentTarget);
                let id = currentTarget.data('id');
                let summaryView = container.find('.summaryRelRecordView' + id);
                container.find('.listViewEntriesTable').css('display', 'none');
                summaryView.show();
            });
            container.on('click', '.hideSummaryRelRecordView', function (e) {
                let summaryView = container.find('.summaryRelRecordView');
                container.find('.listViewEntriesTable').css('display', 'table');
                summaryView.hide();
            });
        },
        /**
         * Show confirmation on event click
         * @param {jQuery} element
         * @param {string} picklistName
         */
        showProgressConfirmation(element, picklistName) {
            const picklistValue = $(element).data('picklistValue');
            app.showConfirmModal({
                title: $(element).data('picklistLabel'),
                text: app.vtranslate('JS_CHANGE_VALUE_CONFIRMATION'),
                confirmedCallback: () => {
                    Vtiger_Edit_Js.saveAjax({
                        value: picklistValue,
                        field: picklistName
                    })
                        .done((response) => {
                            if (!response || response.success !== false) {
                                window.location.reload();
                            }
                        })
                        .fail(function (error, err) {
                            app.errorLog(error, err);
                        });
                }
            });
        },
        /**
         * Change status from progress
         */
        registerProgress() {
            const self = this;
            $('.js-header-progress-bar').each((index, element) => {
                let picklistName = $(element).data('picklistName');
                $(element)
                    .find('.js-access')
                    .on('click', (e) => {
                        self.showProgressConfirmation(e.currentTarget, picklistName);
                    });
            });
        },
        loadChat() {
            let chatVue = $('#ChatRecordRoomVue', this.detailViewContentHolder);
            if (chatVue.length) {
                let chatContainer = this.detailViewContentHolder.find('.js-chat-container');
                const padding = 10;
                chatContainer.height(
                    $(document).height() - chatContainer.offset().top - $('.js-footer').outerHeight() - padding
                );
                window.ChatRecordRoomVueComponent.mount({
                    el: '#ChatRecordRoomVue'
                });
            }
        },
        registerChat() {
            if (window.ChatRecordRoomVueComponent !== undefined) {
                this.loadChat();
                app.event.on('DetailView.Tab.AfterLoad', (e, data, instance) => {
                    instance.detailViewContentHolder.ready(() => {
                        this.loadChat();
                    });
                });
            }
        },
        registerBasicEvents: function () {
            let thisInstance = this;
            let detailContentsHolder = thisInstance.getContentHolder();
            let selectedTabElement = thisInstance.getSelectedTab();
            //register all the events for summary view container

            if (this.getSelectedTab().data('labelKey') === 'ModComments') {
                new App.Fields.Text.Completions(detailContentsHolder.find('.js-completions'));
            }
            app.registerBlockAnimationEvent(this.getForm());
            thisInstance.registerSummaryViewContainerEvents(detailContentsHolder);
            thisInstance.registerCommentEvents(detailContentsHolder);
            thisInstance.registerEmailEvents(detailContentsHolder);
            thisInstance.registerMapsEvents(detailContentsHolder);
            thisInstance.registerSubProducts(detailContentsHolder);
            thisInstance.registerCollapsiblePanels(detailContentsHolder);
            App.Fields.Date.register(detailContentsHolder);
            App.Fields.DateTime.register(detailContentsHolder);
            App.Fields.MultiImage.register(detailContentsHolder);
            App.Fields.Password.register(detailContentsHolder);
            App.Fields.MultiAttachment.register(detailContentsHolder);
            //Attach time picker event to time fields
            app.registerEventForClockPicker();
            this.registerHelpInfo(detailContentsHolder);
            App.Fields.Picklist.showSelect2ElementView(detailContentsHolder.find('select.select2'));
            App.Fields.Text.Editor.register(detailContentsHolder, { toolbar: 'Min' });
            detailContentsHolder.on('click', '#detailViewNextRecordButton', function (e) {
                let url = selectedTabElement.data('url');
                let currentPageNum = thisInstance.getRelatedListCurrentPageNum();
                let requestedPage = parseInt(currentPageNum) + 1;
                let nextPageUrl = url + '&page=' + requestedPage;
                thisInstance.loadContents(nextPageUrl);
            });
            detailContentsHolder.on('click', '#detailViewPreviousRecordButton', function (e) {
                let url = selectedTabElement.data('url');
                let currentPageNum = thisInstance.getRelatedListCurrentPageNum();
                let requestedPage = parseInt(currentPageNum) - 1;
                let nextPageUrl = url + '&page=' + requestedPage;
                thisInstance.loadContents(nextPageUrl);
            });
            detailContentsHolder.on('click', '.js-detail-quick-edit', function (e) {
                thisInstance.ajaxEditHandling(jQuery(e.currentTarget).closest('.fieldValue'));
            });
            detailContentsHolder.on('click', 'div.recordDetails span.squeezedWell', function (e) {
                let currentElement = jQuery(e.currentTarget);
                let relatedLabel = currentElement.data('reference');
                jQuery('.detailViewInfo .related .nav > li[data-reference="' + relatedLabel + '"]').trigger('click');
            });
            detailContentsHolder.on('click', '.relatedPopup', function (e) {
                let editViewObj = new Vtiger_Edit_Js();
                editViewObj.showRecordsList(e);
                return false;
            });
            detailContentsHolder.on('click', '.viewThread', function (e) {
                thisInstance.hideButtonAction();
                let currentTarget = jQuery(e.currentTarget),
                    currentTargetParent = currentTarget.parent(),
                    commentActionsBlock = currentTarget.closest('.js-comment-actions'),
                    currentCommentBlock = currentTarget.closest('.js-comment-details'),
                    ulElements = currentCommentBlock.find('ul');
                if (ulElements.length > 0) {
                    ulElements.show();
                    commentActionsBlock.find('.hideThreadBlock').show();
                    currentTargetParent.hide();
                    return;
                }
                let commentId = currentTarget.closest('.js-comment-div').find('.js-comment-info-header').data('commentid');
                thisInstance.getChildComments(commentId).done(function (data) {
                    jQuery(data).appendTo(jQuery(e.currentTarget).closest('.js-comment-details'));
                    commentActionsBlock.find('.hideThreadBlock').show();
                    currentTargetParent.hide();
                });
            });
            detailContentsHolder.on('click', '.js-view-parent-thread', function (e) {
                let currentTarget = jQuery(e.currentTarget),
                    currentTargetParent = currentTarget.parent(),
                    commentId = currentTarget.closest('.js-comment-div').find('.js-comment-info-header').data('commentid');
                thisInstance.getParentComments(commentId).done(function (data) {
                    $(e.currentTarget.closest('.js-comment-details')).html(data);
                    currentTarget.closest('.js-comment-actions').find('.hideThreadBlock').show();
                    currentTargetParent.hide();
                });
            });
            detailContentsHolder.on('click', '.hideThread', function (e) {
                let currentTarget = jQuery(e.currentTarget);
                let currentTargetParent = currentTarget.parent();
                let commentActionsBlock = currentTarget.closest('.js-comment-actions');
                let currentCommentBlock = currentTarget.closest('.js-comment-details');
                currentCommentBlock.find('ul').hide();
                currentTargetParent.hide();
                commentActionsBlock.find('.js-view-thread-block').show();
            });
            detailContentsHolder.on('click', '.detailViewThread', function (e) {
                let recentCommentsTab = thisInstance.getTabByLabel(thisInstance.detailViewRecentCommentsTabLabel);
                let commentId = jQuery(e.currentTarget)
                    .closest('.js-comment-single')
                    .find('.js-comment-info-header')
                    .data('commentid');
                let commentLoad = function (data) {
                    window.location.href = window.location.href + '#' + commentId;
                };
                recentCommentsTab.trigger('click', { commentid: commentId, callback: commentLoad });
            });
            detailContentsHolder.on('click', '.moreRecentRecords', function (e) {
                e.preventDefault();
                let recentCommentsTab = thisInstance.getTabByModule($(this).data('label-key'), $(this).data('relation-id'));
                if (recentCommentsTab.length) {
                    recentCommentsTab.trigger('click');
                } else {
                    let currentTarget = $(e.currentTarget),
                        container = currentTarget.closest("[class^='widgetContainer_']");
                    if (container.length) {
                        let page = container.find('[name="page"]:last').val(),
                            url = container.data('url');
                        currentTarget.prop('disabled', true);
                        url = url.replace('&page=1', '&page=' + ++page);
                        AppConnector.request(url).done(function (data) {
                            let dataObj = $(data),
                                containerTable = container.find('.js-detail-widget-content table');
                            currentTarget.prop('disabled', false).addClass('d-none');
                            container.find('[name="page"]:last').val(dataObj.find('[name="page"]').val());
                            if (containerTable.length) {
                                containerTable.append(dataObj.find('tbody tr'));
                                if (dataObj.find('.moreRecentRecords').length) {
                                    currentTarget.removeClass('d-none');
                                }
                            } else {
                                container.find('.js-detail-widget-content').append(dataObj);
                            }
                        });
                    }
                }
            });
            detailContentsHolder.on('change', '.relatedHistoryTypes', function (e) {
                let widgetContent = jQuery(this).closest('.widgetContentBlock').find('.widgetContent'),
                    progressIndicatorElement = jQuery.progressIndicator({
                        position: 'html',
                        blockInfo: {
                            enabled: true,
                            elementToBlock: widgetContent
                        }
                    });
                AppConnector.request({
                    module: app.getModuleName(),
                    view: 'Detail',
                    record: app.getRecordId(),
                    mode: 'showRecentRelation',
                    page: 1,
                    limit: widgetContent.find('.js-relatedHistoryPageLimit').val(),
                    type: $(e.currentTarget).val()
                }).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    widgetContent.find('#relatedHistoryCurrentPage').remove();
                    widgetContent.find('#moreRelatedUpdates').remove();
                    widgetContent.html(data);
                    Vtiger_Index_Js.registerMailButtons(widgetContent);
                });
            });
            detailContentsHolder.on('click', '.moreProductsService', function () {
                jQuery('.related .mainNav[data-reference="ProductsAndServices"]:not(.d-none)').trigger('click');
            });
            detailContentsHolder.on('click', '.moreRelatedUpdates', function () {
                let widgetContainer = jQuery(this).closest('.widgetContentBlock');
                let widgetContent = widgetContainer.find('.widgetContent');
                let progressIndicatorElement = jQuery.progressIndicator({
                    position: 'html',
                    blockInfo: {
                        enabled: true,
                        elementToBlock: widgetContent
                    }
                });
                let currentPage = widgetContent.find('#relatedHistoryCurrentPage').val();
                let nextPage = parseInt(currentPage) + 1;
                let types = widgetContainer.find('.relatedHistoryTypes').val();
                let pageLimit = widgetContent.find('#relatedHistoryPageLimit').val();
                AppConnector.request({
                    module: app.getModuleName(),
                    view: 'Detail',
                    record: app.getRecordId(),
                    mode: 'showRecentRelation',
                    page: nextPage,
                    limit: pageLimit,
                    type: types
                }).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    widgetContent.find('#relatedHistoryCurrentPage').remove();
                    widgetContent.find('#moreRelatedUpdates').remove();
                    widgetContent.find('#relatedUpdates').append(data);
                });
            });
            detailContentsHolder.on('click', '.moreRecentUpdates', function (e) {
                const container = $(e.currentTarget).closest('.recentActivitiesContainer');
                let newChange = container.find('#newChange').val(),
                    nextPage = parseInt(container.find('#updatesCurrentPage').val()) + 1,
                    url;
                if (container.closest('.js-detail-widget').length) {
                    let data = thisInstance.getFiltersData(
                        e,
                        {
                            page: nextPage,
                            tab_label: 'LBL_UPDATES',
                            newChange: newChange
                        },
                        container.find('#updates')
                    );
                    url = data['params'];
                } else {
                    url = thisInstance.getTabByLabel(thisInstance.detailViewRecentUpdatesTabLabel).data('url');
                    url = url.replace('&page=1', '&page=' + nextPage) + '&skipHeader=true&newChange=' + newChange;
                    if (url.indexOf('&whereCondition') === -1) {
                        let switchBtn = jQuery('.active .js-switch--recentActivities');
                        url +=
                            '&whereCondition=' +
                            (typeof switchBtn.data('on-val') === 'undefined' ? switchBtn.data('off-val') : switchBtn.data('on-val'));
                    }
                }
                AppConnector.request(url).done(function (data) {
                    let dataContainer = jQuery(data);
                    container.find('#newChange').val(dataContainer.find('#newChange').val());
                    container.find('#updatesCurrentPage').val(dataContainer.find('#updatesCurrentPage').val());
                    container.find('.js-more-link').html(dataContainer.find('.js-more-link').html());
                    container.find('#updates ul').append(dataContainer.find('#updates ul').html());
                    app.event.trigger('DetailView.UpdatesWidget.AddMore', data, thisInstance);
                });
            });
            detailContentsHolder.on('click', '.btnChangesReviewedOn', function (e) {
                let progressInstance = jQuery.progressIndicator({
                    position: 'html',
                    blockInfo: {
                        enabled: true
                    }
                });
                let url = 'index.php?module=ModTracker&action=ChangesReviewedOn&record=' + app.getRecordId();
                AppConnector.request(url).done(function (data) {
                    progressInstance.progressIndicator({ mode: 'hide' });
                    jQuery(e.currentTarget).parent().remove();
                    thisInstance.getTabByLabel(thisInstance.detailViewRecentUpdatesTabLabel).find('.count.badge').text('');
                    if (selectedTabElement.data('labelKey') == thisInstance.detailViewRecentUpdatesTabLabel) {
                        thisInstance.reloadTabContent();
                    } else if (selectedTabElement.data('linkKey') == thisInstance.detailViewSummaryTabLabel) {
                        let updatesWidget = detailContentsHolder.find("[data-type='Updates']");
                        if (updatesWidget.length > 0) {
                            let params = thisInstance.getFiltersData(updatesWidget);
                            thisInstance.loadWidget(updatesWidget, params['params']);
                        }
                    }
                });
            });
            detailContentsHolder.on('click', '.moreRecentDocuments', function () {
                let recentDocumentsTab = thisInstance.getTabByLabel(thisInstance.detailViewRecentDocumentsTabLabel);
                recentDocumentsTab.trigger('click');
            });
            detailContentsHolder.on('click', '.moreRecentActivities', function (e) {
                let currentTarget = $(e.currentTarget);
                currentTarget.prop('disabled', true);
                let container = currentTarget.closest('.activityWidgetContainer');
                let page = container.find('.currentPage').val();
                let records = container.find('.countActivities').val();
                let data = thisInstance.getFiltersData(e, { page: ++page });
                AppConnector.request({
                    type: 'POST',
                    async: false,
                    dataType: 'html',
                    data: data['params']
                }).done(function (data) {
                    currentTarget.prop('disabled', false);
                    currentTarget.addClass('d-none');
                    container.find('.currentPage').remove();
                    container.find('.countActivities').remove();
                    container.find('.js-detail-widget-content').append(data);
                    let newRecords = container.find('.countActivities').val();
                    container.find('.countActivities').val(parseInt(newRecords) + parseInt(records));
                    thisInstance.reloadWidgetActivitesStats(container);
                });
            });
            detailContentsHolder.on('click', '.widgetFullscreen', function (e) {
                let currentTarget = $(e.currentTarget);
                let widgetContentBlock = currentTarget.closest('.widgetContentBlock');
                let url = widgetContentBlock.data('url');
                url = url.replace('&view=Detail&', '&view=WidgetFullscreen&');
                let progressIndicatorElement = jQuery.progressIndicator({
                    position: 'html',
                    blockInfo: {
                        enabled: true
                    }
                });
                app.showModalWindow(null, 'index.php?' + url, function (modal) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                });
            });
            thisInstance.registerEventForRelatedList();
            thisInstance.registerMailPreviewWidget(detailContentsHolder.find('.widgetContentBlock[data-type="EmailList"]'));
            thisInstance.registerMailPreviewWidget(
                detailContentsHolder.find('.widgetContentBlock[data-type="HistoryRelation"]')
            );
            detailContentsHolder
                .find('.js-switch--recentActivities')
                .off()
                .on('change', function (e) {
                    const currentTarget = jQuery(e.currentTarget),
                        tabElement = thisInstance.getTabByLabel(thisInstance.detailViewRecentUpdatesTabLabel),
                        variableName = currentTarget.data('urlparams'),
                        valueOn = $(this).data('on-val'),
                        valueOff = $(this).data('off-val');
                    let url = tabElement.data('url');
                    url = url.replace('&' + variableName + '=' + valueOn, '').replace('&' + variableName + '=' + valueOff, '');
                    if (typeof currentTarget.data('on-val') !== 'undefined') {
                        url += '&' + variableName + '=' + valueOn;
                    } else if (typeof currentTarget.data('off-val') !== 'undefined') {
                        url += '&' + variableName + '=' + valueOff;
                    }
                    tabElement.data('url', url);
                    tabElement.trigger('click');
                });
            app.registerIframeEvents(detailContentsHolder);
        },
        reloadWidgetActivitesStats: function (container) {
            let countElement = container.find('.countActivities');
            let totalElement = container.find('.totaltActivities');
            let switchBtn = container.find('.active .js-switch');
            if (!switchBtn.length) {
                switchBtn = container.find('.js-switch.previousMark');
            } else {
                container.find('.js-switch').removeClass('previousMark');
                switchBtn.addClass('previousMark');
            }
            container.find('.js-switch').toggleClass('previousMark');
            if (!countElement.length || !totalElement.length || totalElement.val() === '') {
                return false;
            }
            let stats = ' (' + countElement.val() + '/' + totalElement.val() + ')';
            let switchBtnParent = switchBtn.parent();
            let text = switchBtn.data('basic-text') + stats;
            switchBtnParent.removeTextNode();
            switchBtnParent.append(text);
        },
        refreshCommentContainer: function (commentId) {
            let thisInstance = this;
            let commentContainer = $('.commentsBody');
            let params = {
                module: app.getModuleName(),
                view: 'Detail',
                record: thisInstance.getRecordId(),
                mode: 'showThreadComments',
                commentid: commentId
            };
            let progressIndicatorElement = jQuery.progressIndicator({
                position: 'html',
                blockInfo: {
                    enabled: true,
                    elementToBlock: commentContainer
                }
            });
            AppConnector.request(params).done(function (data) {
                progressIndicatorElement.progressIndicator({ mode: 'hide' });
                commentContainer.html(data);
            });
        },
        updateRecordsPDFTemplateBtn: function (form) {
            const thisInstance = this;
            let btnToolbar = $('.js-btn-toolbar .js-pdf');
            if (btnToolbar.length) {
                AppConnector.request({
                    data: {
                        module: app.getModuleName(),
                        action: 'PDF',
                        mode: 'hasValidTemplate',
                        record: app.getRecordId(),
                        view: app.getViewName()
                    },
                    dataType: 'json'
                })
                    .done(function (data) {
                        if (data['result'].valid === false) {
                            btnToolbar.addClass('d-none');
                        } else {
                            btnToolbar.removeClass('d-none');
                        }
                    })
                    .fail(function (data, err) {
                        app.errorLog(data, err);
                    });
            }
        },
        updateWindowHeight: function (currentHeight, frame) {
            frame.height(currentHeight);
        },
        loadSubProducts: function (parentRow) {
            const thisInstance = this;
            let recordId = parentRow.data('product-id'),
                subProrductParams = {
                    module: 'Products',
                    action: 'SubProducts',
                    record: recordId
                };
            AppConnector.request(subProrductParams).done(function (data) {
                let responseData = data.result;
                thisInstance.addSubProducts(parentRow, responseData);
            });
        },
        addSubProducts: function (parentRow, responseData) {
            let subProductsContainer = $('.js-subproducts-container ul', parentRow);
            for (let id in responseData) {
                let productText = $('<li>').text(responseData[id]);
                subProductsContainer.append(productText);
            }
        },
        registerSubProducts: function (container) {
            const thisInstance = this;
            container.find('.inventoryItems .js-inventory-row').each(function (index) {
                thisInstance.loadSubProducts($(this), false);
            });
        },
        registerCollapsiblePanels(detailViewContainer) {
            const panels = detailViewContainer.find('.js-detail-widget-collapse');
            const storageName = `yf-${app.getModuleName()}-detail-widgets`;
            if (Quasar.plugins.LocalStorage.has(storageName)) {
                this.setPanels({ panels, storageName });
            } else {
                panels.collapse('show');
                let panelsStorage = {};
                panels.each((i, item) => {
                    panelsStorage[item.dataset.storageId] = 'shown';
                });
                Quasar.plugins.LocalStorage.set(storageName, panelsStorage);
            }
            panels.on('hidden.bs.collapse shown.bs.collapse', (e) => {
                this.updatePanelsStorage({ id: e.target.dataset.storageKey, type: e.type, storageName });
            });
            panels.on('hide.bs.collapse show.bs.collapse', function (e) {
                $(e.currentTarget).siblings('.js-detail-widget-header').toggleClass('collapsed');
            });
        },
        setPanels({ panels, storageName }) {
            const panelsStorage = Quasar.plugins.LocalStorage.getItem(storageName);
            panels.each((i, item) => {
                if (
                    panelsStorage[item.dataset.storageKey] === 'shown' ||
                    undefined === panelsStorage[item.dataset.storageKey]
                ) {
                    $(item).collapse('show');
                    $(item).siblings('.js-detail-widget-header').toggleClass('collapsed');
                }
            });
        },
        updatePanelsStorage({ id, type, storageName }) {
            const panelsStorage = Quasar.plugins.LocalStorage.getItem(storageName);
            panelsStorage[id] = type;
            Quasar.plugins.LocalStorage.set(storageName, panelsStorage);
        },
        registerSendPdfFromPdfViewer: function (container) {
            container.find('.js-email-pdf').on('click', function (e) {
                let selectedPdfTemplate = $(e.currentTarget).closest('.js-detail-widget').find('.js-pdf-viewer-template').val();
                let url = $(this).attr('data-url');
                if (url && selectedPdfTemplate && selectedPdfTemplate > 0) {
                    window.open(url + selectedPdfTemplate, '_blank');
                }
            });
        },
        /**
         * Register keyboard shortcuts events
         * @param {jQuery} container
         */
        registerKeyboardShortcutsEvent: function (container) {
            document.addEventListener('keydown', (event) => {
                if (event.shiftKey && event.ctrlKey && event.code === 'KeyD') {
                    container.find('.js-duplicate-btn').trigger('click');
                }
                if (event.shiftKey && event.ctrlKey && event.code === 'KeyE' && container.find('.js-edit-btn').length) {
                    container.find('.js-edit-btn').trigger('click');
                }
                if (event.shiftKey && event.ctrlKey && event.code === 'KeyW' && container.find('.js-edit-btn').length) {
                    App.Components.QuickEdit.showModal({
                        module: app.getModuleName(),
                        record: app.getRecordId(),
                        removeFromUrl: 'step'
                    });
                }
            });
        },
        registerEvents: function () {
            this.registerSendSmsSubmitEvent();
            this.registerAjaxEditEvent();
            this.registerRelatedRowClickEvent();
            this.registerBlockStatusCheckOnLoad();
            this.registerEmailFieldClickEvent();
            this.registerPhoneFieldClickEvent();
            this.registerEventForRelatedTabClick();
            Vtiger_Helper_Js.showHorizontalTopScrollBar();
            this.registerUrlFieldClickEvent();
            let detailViewContainer = jQuery('div.detailViewContainer');
            if (detailViewContainer.length <= 0) {
                // Not detail view page
                return;
            }
            this.registerWidgetProductAndServices();
            this.registerSetReadRecord(detailViewContainer);
            this.getForm().validationEngine(app.validationEngineOptionsForRecord);
            this.loadWidgetsEvents();
            this.loadWidgets();
            this.registerBasicEvents();
            this.registerEventForTotalRecordsCount();
            this.registerProgress();
            this.registerChat(detailViewContainer);
            this.registerSendPdfFromPdfViewer(detailViewContainer);
            this.registerKeyboardShortcutsEvent(detailViewContainer);
            App.Components.ActivityNotifier.register(detailViewContainer);
        }
    }
);