YetiForceCompany/YetiForceCRM

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

Summary

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

$.Class(
    'Vtiger_DashBoard_Js',
    {
        grid: false,
        //static property which will store the instance of dashboard
        currentInstance: false,
        scrollContainer: false,
        restrictContentDrag: function (container) {
            container.on('mousedown.draggable', function (e) {
                let element = $(e.target);
                let isHeaderElement = element.closest('.dashboardWidgetHeader').length > 0 ? true : false;
                if (isHeaderElement) {
                    return;
                }
                //Stop the event propagation so that drag will not start for contents
                e.stopPropagation();
            });
        }
    },
    {
        container: false,
        noCache: false,
        instancesCache: {},
        init: function () {
            Vtiger_DashBoard_Js.currentInstance = this;
        },
        /**
         * Get container
         * @returns JQuery
         */
        getContainer: function () {
            if (this.noCache == true || this.container == false) {
                this.container = $('.grid-stack');
            }
            return this.container;
        },
        getCurrentDashboard: function () {
            let dashboardId = $('.selectDashboard li a.active').closest('li').data('id');
            if (!dashboardId) {
                dashboardId = 1;
            }
            return dashboardId;
        },
        getWidgetInstance: function (widgetContainer) {
            let id = widgetContainer.attr('id');
            if (this.noCache || !(id in this.instancesCache)) {
                let widgetName = widgetContainer.data('name');
                this.instancesCache[id] = Vtiger_Widget_Js.getInstance(widgetContainer, widgetName);
            }
            return this.instancesCache[id];
        },
        registerGrid: function () {
            const self = this;
            Vtiger_DashBoard_Js.grid = GridStack.init(
                {
                    margin: '5px',
                    cellHeight: '70px',
                    alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
                        navigator.userAgent
                    )
                },
                '.grid-stack'
            );
            Vtiger_DashBoard_Js.grid.on('change', function (event, ui) {
                self.savePositions(self.getContainer().find('.grid-stack-item'));
            });
            // load widgets after grid initialization to prevent too early lazy loading - visible viewport changes
            this.loadWidgets();
            // recalculate positions with scrollbars
            if (this.getContainer().width() !== this.getContainer().parent().width()) {
                const parentWidth = self.getContainer().parent().width();
                this.getContainer().css('width', parentWidth + 'px');
            }
        },
        /**
         * Save widgets positions
         * @param {JQuery} widgets
         */
        savePositions: function (widgets) {
            let widgetRowColPositions = {},
                widgetSizes = {};
            widgets.each((_index, element) => {
                let widget = $(element);
                let widgetId = widget.find('.grid-stack-item-content').attr('id');
                widgetRowColPositions[widgetId] = {
                    row: widget.attr('gs-y'),
                    col: widget.attr('gs-x')
                };
                widgetSizes[widgetId] = {
                    width: widget.attr('gs-w'),
                    height: widget.attr('gs-h')
                };
                this.getWidgetInstance(widget.find('.dashboardWidget')).loadScrollbar();
            });
            this.updateLazyWidget();
            AppConnector.request({
                module: app.getModuleName(),
                action: 'Widget',
                mode: 'positions',
                position: widgetRowColPositions,
                size: widgetSizes
            });
        },
        updateLazyWidget() {
            const scrollTop = this.scrollContainer.scrollTop();
            this.scrollContainer.scrollTop(scrollTop + 1).scrollTop(scrollTop);
        },
        loadWidgets: function () {
            const thisInstance = this;
            this.scrollContainer = App.Components.Scrollbar.page.element;
            if (!Quasar.plugins.Platform.is.desktop) {
                this.scrollContainer = $('.bodyContent');
                app.showNewScrollbar(this.scrollContainer);
            }
            thisInstance
                .getContainer()
                .find('.dashboardWidget')
                .Lazy({
                    threshold: 0,
                    appendScroll: this.scrollContainer,
                    widgetLoader(element) {
                        thisInstance.loadWidget(element);
                    }
                });
            this.updateLazyWidget();
        },
        loadWidget: function (widgetContainer) {
            const self = this;
            let urlParams = widgetContainer.data('url');
            let mode = widgetContainer.data('mode');
            let moduleName = app.getModuleName();
            let sourceModule = $('a.active', 'ul.selectDashboradView').parent().data('module');
            widgetContainer.progressIndicator();
            if (mode === 'open') {
                let name = widgetContainer.attr('id');
                let userId = CONFIG.userId;
                if (widgetContainer.data('cache') === 1) {
                    let cacheUrl = app.cacheGet(name + '_' + userId, false);
                    urlParams = cacheUrl ? cacheUrl : urlParams;
                }
                AppConnector.request(urlParams)
                    .done((data) => {
                        widgetContainer.html(data);
                        App.Fields.Picklist.showSelect2ElementView(widgetContainer.find('.select2'));
                        App.Fields.Tree.register(widgetContainer);
                        self.getWidgetInstance(widgetContainer);
                        widgetContainer.trigger(Vtiger_Widget_Js.widgetPostLoadEvent);
                        self.adjustHeightWidget(widgetContainer);
                        if (sourceModule && moduleName != sourceModule) {
                            $('.js-widget-remove', widgetContainer).remove();
                        }
                    })
                    .fail(function (textStatus, errorThrown, errorObj) {
                        widgetContainer.progressIndicator({ mode: 'hide' });
                        if (CONFIG.debug) {
                            widgetContainer.html(errorObj.responseText);
                        }
                        let url = app.convertUrlToObject(urlParams);
                        delete url.view, url.name;
                        url.action = 'Widget';
                        url.mode = 'remove';
                        url = app.convertObjectToUrl(url);
                        widgetContainer.prepend(
                            `<span style="float: right;"><button class="btn btn-sm btn-light js-widget-remove" data-url="${url}" data-js="click"><span class="fas fa-times"></span></button></span>`
                        );
                        app.showNotify({
                            title: app.vtranslate('JS_ERROR'),
                            type: 'error'
                        });
                    });
            }
        },
        /**
         * Adjust the height of the widget.
         * @param {jQuery} widgetContainer
         */
        adjustHeightWidget(widgetContainer) {
            const headerHeight = widgetContainer.find('.dashboardWidgetHeader').outerHeight();
            let adjustedHeight = widgetContainer.height() - headerHeight;
            if (widgetContainer.find('.dashboardWidgetFooter').length) {
                adjustedHeight -= widgetContainer.find('.dashboardWidgetFooter').outerHeight();
            }
            const widgetContent = widgetContainer.find('.dashboardWidgetContent');
            widgetContent.css('max-height', adjustedHeight + 'px');
            app.showNewScrollbar(widgetContent, { wheelPropagation: true });
        },
        registerRefreshWidget: function () {
            let thisInstance = this;
            this.getContainer().on('click', '.js-widget-refresh', function (e) {
                let element = $(e.currentTarget);
                thisInstance.getWidgetInstance(element.closest('.dashboardWidget')).refreshWidget();
                return;
            });
        },
        removeWidget: function () {
            const self = this;
            this.getContainer().on('click', '.js-widget-remove', function (e) {
                let element = $(e.currentTarget),
                    listItem = $(element).parents('.grid-stack-item'),
                    width = listItem.attr('gs-w'),
                    height = listItem.attr('gs-h'),
                    url = element.data('url'),
                    parent = element.closest('.dashboardWidgetHeader').parent(),
                    widgetTitle = parent.find('.js-widget__header__title').text().trim();
                app.showConfirmModal({
                    title: `${app.vtranslate('JS_ARE_YOU_SURE_TO_DELETE_WIDGET')} (${widgetTitle})<br>${app.vtranslate(
                        'JS_ARE_YOU_SURE_TO_DELETE_WIDGET_INFO'
                    )}`,
                    confirmedCallback: () => {
                        AppConnector.request(url).done(function (response) {
                            if (response.success) {
                                parent.fadeOut('slow', function () {
                                    parent.remove();
                                });
                                Vtiger_DashBoard_Js.grid.removeWidget(listItem.get(0));
                                $('.js-widget-list').prev('.js-widget-predefined').removeClass('d-none');
                                let data = `<a class="js-widget-list__item dropdown-item d-flex" href="#"
                                        data-widget-url="${response.result.url}" data-linkid="${response.result.linkid}"
                                        data-name="${response.result.name}" data-width="${width}" data-height="${height}"
                                        data-js="remove | click">${response.result.title}`;
                                if (response.result.deleteFromList) {
                                    data += `<span class="text-danger pl-5 ml-auto"><span class="fas fa-trash-alt removeWidgetFromList u-hover-opacity" data-widget-id="${response.result.id}" data-js="click"></span></span>`;
                                }
                                data += '</a>';
                                let divider = $('.js-widget-list .dropdown-divider');
                                if (divider.length) {
                                    $(data).insertBefore(divider);
                                } else {
                                    $('.js-widget-list').append(data);
                                }
                                self.updateLazyWidget();
                                self.showAndHideAlert(false);
                            }
                        });
                    }
                });
            });
        },
        registerSelectDashboard: function () {
            let thisInstance = this;
            $('.selectDashboard li').on('click', function (e) {
                let progressIndicatorElement = $.progressIndicator({
                    position: 'html',
                    blockInfo: {
                        enabled: true
                    }
                });
                let currentTarget = $(e.currentTarget);
                let dashboardId = currentTarget.data('id');
                let params = {
                    module: app.getModuleName(),
                    view: app.getViewName(),
                    dashboardId: dashboardId
                };
                AppConnector.request(params).done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    $('.dashboardViewContainer').html(data);
                    thisInstance.noCache = true;
                    thisInstance.registerEvents();
                });
            });
        },
        registerDatePickerHideInitiater: function () {
            let container = this.getContainer();
            container.on('click', 'input.dateRange', function (e) {
                let widgetContainer = $(e.currentTarget).closest('.dashboardWidget');
                let dashboardWidgetHeader = $('.dashboardWidgetHeader', widgetContainer);

                let callbackFunction = function () {
                    let date = $('.dateRange');
                    date.DatePickerHide();
                    date.blur();
                };
                //adding clickoutside event on the dashboardWidgetHeader
                Vtiger_Helper_Js.addClickOutSideEvent(dashboardWidgetHeader.find('.dateRange'), callbackFunction);
                return false;
            });
        },
        registerShowMailBody: function () {
            let container = this.getContainer();
            container.on('click', '.showMailBody', function (e) {
                let widgetContainer = $(e.currentTarget).closest('.mailRow');
                let mailBody = widgetContainer.find('.mailBody');
                let bodyIcon = $(e.currentTarget).find('.body-icon');
                if (mailBody.css('display') == 'none') {
                    mailBody.show();
                    bodyIcon.removeClass('fa-chevron-down').addClass('fa-chevron-up');
                } else {
                    mailBody.hide();
                    bodyIcon.removeClass('fa-chevron-up').addClass('fa-chevron-down');
                }
            });
        },
        registerMiniListWidget: function () {
            const thisInstance = this;
            $('.dashboardHeading')
                .off('click', '.js-add-filter')
                .on('click', '.js-add-filter', function (e) {
                    const element = $(e.currentTarget);
                    app.showModalWindow(null, 'index.php?module=Home&view=MiniListWizard&step=step1', function (wizardContainer) {
                        const form = $('form', wizardContainer);
                        form.on('keypress', function (event) {
                            return event.keyCode != 13;
                        });
                        const moduleNameSelectDOM = $('select[name="module"]', wizardContainer);
                        const filteridSelectDOM = $('select[name="filterid"]', wizardContainer);
                        const fieldHrefDOM = $('select[name="field_href"]', wizardContainer);
                        const fieldsSelectDOM = $('select[name="fields"]', wizardContainer);
                        const filterFieldsSelectDOM = $('select[name="filter_fields"]', wizardContainer);
                        const moduleNameSelect2 = App.Fields.Picklist.showSelect2ElementView(moduleNameSelectDOM, {
                            placeholder: app.vtranslate('JS_SELECT_MODULE')
                        });
                        const filteridSelect2 = App.Fields.Picklist.showSelect2ElementView(filteridSelectDOM, {
                            placeholder: app.vtranslate('JS_PLEASE_SELECT_ATLEAST_ONE_OPTION'),
                            dropdownParent: wizardContainer
                        });
                        const fieldHrefSelect2 = App.Fields.Picklist.showSelect2ElementView(fieldHrefDOM, {
                            allowClear: true
                        });
                        const fieldsSelect2 = App.Fields.Picklist.showSelect2ElementView(fieldsSelectDOM, {
                            placeholder: app.vtranslate('JS_PLEASE_SELECT_ATLEAST_ONE_OPTION'),
                            closeOnSelect: true,
                            maximumSelectionLength: 6
                        });
                        const filterFieldsSelect2 = App.Fields.Picklist.showSelect2ElementView(filterFieldsSelectDOM, {
                            placeholder: app.vtranslate('JS_PLEASE_SELECT_ATLEAST_ONE_OPTION')
                        });
                        const footer = $('.modal-footer', wizardContainer);
                        filteridSelectDOM.closest('tr').hide();
                        fieldsSelectDOM.closest('tr').hide();
                        fieldHrefDOM.closest('tr').hide();
                        footer.hide();
                        moduleNameSelect2.on('change', function () {
                            if (!moduleNameSelect2.val()) {
                                return;
                            }
                            footer.hide();
                            fieldsSelectDOM.closest('tr').hide();
                            AppConnector.request({
                                module: 'Home',
                                view: 'MiniListWizard',
                                step: 'step2',
                                selectedModule: moduleNameSelect2.val()
                            }).done(function (res) {
                                filteridSelectDOM.empty().html(res).trigger('change');
                                filteridSelect2.closest('tr').show();
                            });
                        });
                        filteridSelect2.on('change', function () {
                            if (!filteridSelect2.val()) {
                                return;
                            }
                            AppConnector.request({
                                module: 'Home',
                                view: 'MiniListWizard',
                                step: 'step3',
                                selectedModule: moduleNameSelect2.val(),
                                filterid: filteridSelect2.val()
                            }).done(function (res) {
                                const responseHTML = $(res);
                                const fieldsHTML = responseHTML.find('select[name="fields"]').html();
                                const filterFieldsHTML = responseHTML.find('select[name="filter_fields"]').html();
                                fieldsSelectDOM.empty().html(fieldsHTML).trigger('change');
                                fieldsSelect2.closest('tr').show();
                                fieldsSelect2.data('select2').$selection.find('.select2-search__field').parent().css('width', '100%');
                                filterFieldsSelectDOM.empty().html(filterFieldsHTML).trigger('change');
                                filterFieldsSelect2.closest('tr').show();
                                filterFieldsSelect2
                                    .data('select2')
                                    .$selection.find('.select2-search__field')
                                    .parent()
                                    .css('width', '100%');
                                fieldHrefSelect2.closest('tr').show();
                            });
                        });
                        fieldsSelect2.on('change', function () {
                            fieldHrefDOM.find('option:not([value=""]').remove();
                            $(this)
                                .find('option:checked')
                                .each(function (index, element) {
                                    let option = $(element);
                                    let newOption = new Option(option.text(), option.val(), true, true);
                                    fieldHrefSelect2.append(newOption);
                                });
                            fieldHrefSelect2.val('').trigger('change');
                            if (!fieldsSelect2.val()) {
                                footer.hide();
                            } else {
                                footer.show();
                            }
                        });
                        form.validationEngine(app.validationEngineOptions);
                        form.on('submit', (e) => {
                            e.preventDefault();
                            if (form.validationEngine('validate') === true) {
                                let selectedFields = [];
                                fieldsSelect2.select2('data').map((obj) => {
                                    selectedFields.push(obj.id);
                                });
                                thisInstance.saveMiniListWidget(
                                    {
                                        module: moduleNameSelect2.val(),
                                        fields: selectedFields,
                                        filterFields: filterFieldsSelect2.val(),
                                        fieldHref: fieldHrefSelect2.val()
                                    },
                                    element,
                                    moduleNameSelect2.find(':selected').text(),
                                    filteridSelect2.val(),
                                    filteridSelect2.find(':selected').text(),
                                    form
                                );
                            }
                        });
                    });
                });
        },
        saveMiniListWidget: function (data, element, moduleNameLabel, filterid, filterLabel, form) {
            const thisInstance = this,
                paramsForm = {
                    data: JSON.stringify(data),
                    blockid: element.data('block-id'),
                    linkid: element.data('linkid'),
                    label: moduleNameLabel + ' - ' + filterLabel,
                    title: form.find('[name="widgetTitle"]').val(),
                    name: 'Mini List',
                    filterid: filterid,
                    isdefault: 0,
                    height: 4,
                    width: 4,
                    owners_all: ['mine', 'all', 'users', 'groups'],
                    default_owner: 'mine',
                    dashboardId: thisInstance.getCurrentDashboard()
                },
                sourceModule = $('[name="selectedModuleName"]').val();
            thisInstance.saveWidget(paramsForm, 'add', sourceModule, paramsForm.linkid, 'MiniList').done(function (data) {
                let result = data['result'],
                    params = {};
                if (data['success']) {
                    app.hideModalWindow();
                    paramsForm['id'] = result['id'];
                    paramsForm['status'] = result['status'];
                    params['text'] = result['text'];
                    params['type'] = 'success';
                    let linkElement = element.clone();
                    linkElement.data('name', 'MiniList');
                    linkElement.data('id', result['wid']);
                    thisInstance.addWidget(
                        linkElement,
                        'index.php?module=Home&view=ShowWidget&name=MiniList&linkid=' +
                            element.data('linkid') +
                            '&widgetid=' +
                            result['wid'] +
                            '&active=0'
                    );
                    Vtiger_Helper_Js.showMessage(params);
                } else {
                    let message = data['error']['message'],
                        errorField;
                    if (data['error']['code'] != 513) {
                        errorField = form.find('[name="fieldName"]');
                    } else {
                        errorField = form.find('[name="fieldLabel"]');
                    }
                    errorField.validationEngine('showPrompt', message, 'error', 'topLeft', true);
                }
            });
        },
        saveWidget: function (form, mode, sourceModule, linkid, type) {
            let aDeferred = $.Deferred();
            let progressIndicatorElement = $.progressIndicator({
                position: 'html',
                blockInfo: {
                    enabled: true
                }
            });
            if (typeof sourceModule === 'undefined') {
                sourceModule = app.getModuleName();
            }
            let params = {
                form: form,
                module: app.getModuleName(),
                sourceModule: sourceModule,
                action: 'Widget',
                mode: mode,
                addToUser: true,
                linkid: linkid,
                name: type
            };
            AppConnector.request(params)
                .done(function (data) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    aDeferred.resolve(data);
                })
                .fail(function (error) {
                    progressIndicatorElement.progressIndicator({ mode: 'hide' });
                    aDeferred.reject(error);
                });
            return aDeferred.promise();
        },
        registerTabModules: function () {
            let thisInstance = this;
            $('.selectDashboradView li').on('click', function (e) {
                let currentTarget = $(e.currentTarget);
                $('.selectDashboradView li').removeClass('active');
                currentTarget.addClass('active');
                let params = {
                    module: currentTarget.data('module'),
                    view: app.getViewName(),
                    sourceModule: app.getModuleName(),
                    dashboardId: thisInstance.getCurrentDashboard()
                };
                AppConnector.request(params).done(function (data) {
                    $('.dashboardViewContainer').html(data);
                    thisInstance.noCache = true;
                    thisInstance.registerEvents();
                });
            });
        },
        /**
         * Remove widget from list
         */
        removeWidgetFromList: function () {
            const thisInstance = this;
            $('.dashboardHeading').on('click', '.removeWidgetFromList', function (e) {
                let currentTarget = $(e.currentTarget);
                let id = currentTarget.data('widget-id');
                let params = {
                    module: app.getModuleName(),
                    action: 'Widget',
                    mode: 'removeWidgetFromList',
                    widgetid: id
                };
                AppConnector.request(params).done(function (data) {
                    let params = {
                        text: app.vtranslate('JS_WIDGET_DELETED'),
                        type: 'success'
                    };
                    Vtiger_Helper_Js.showMessage(params);
                    currentTarget.closest('.js-widget-list__item').remove();
                    if ($('.js-widget-list .js-widget-list__item').length < 1) {
                        $('.js-widget-list').prev('.js-widget-predefined').addClass('d-none');
                    }
                    thisInstance.updateLazyWidget();
                });
            });
        },
        /**
         * Updates tablet scroll top position
         */
        registerTabletScrollEvent() {
            if (!app.touchDevice || !Quasar.plugins.Platform.is.desktop) {
                return;
            }

            let scollbarContainer = $('.js-tablet-scroll');
            scollbarContainer.parent().removeClass('d-none');

            let scollbarContainerH = scollbarContainer.outerHeight(),
                scollbarOffsetTop = scollbarContainer.offset().top,
                maxOffset = $('.js-header').outerHeight() + 8;

            this.scrollContainer.on('scroll', () => {
                if (this.scrollContainer.scrollTop() + maxOffset >= scollbarOffsetTop) {
                    scollbarContainer.css({ top: maxOffset });
                } else {
                    scollbarContainer.css({
                        top: scollbarOffsetTop - this.scrollContainer.scrollTop(),
                        height: scollbarContainerH + this.scrollContainer.scrollTop()
                    });
                }
            });
        },
        /**
         * Updates list of predefined widgets after changed dashboard
         */
        registerUpdatePredefinedWidgets: function () {
            let container = $('.js-predefined-widgets');
            container.off('click', '.js-widget-list__item');
            container.on('click', '.js-widget-list__item', (e) => {
                if (!$(e.target).hasClass('removeWidgetFromList')) {
                    this.addWidget($(e.currentTarget), $(e.currentTarget).data('widgetUrl'));
                }
            });
            AppConnector.request({
                view: 'BasicAjax',
                mode: 'getDashBoardPredefinedWidgets',
                module: app.getModuleName(),
                dashboardId: this.getCurrentDashboard()
            }).done((data) => {
                container.html(data);
            });
        },
        addWidget(element, url) {
            element = $(element);
            let linkId = element.data('linkid');
            let name = element.data('name');
            let widgetId = element.data('id');
            element.remove();
            if ($('.js-widget-list .js-widget-list__item').length < 1) {
                $('.js-widget-list').prev('.js-widget-predefined').addClass('d-none');
            }
            let widget = Vtiger_DashBoard_Js.grid.addWidget(
                `<div class="grid-stack-item js-css-element-queries" data-js="css-element-queries"><div id="${linkId}-${widgetId}" data-name="${name}" data-mode="open" class="grid-stack-item-content dashboardWidget new" data-url="${url}"></div></div>`,
                {
                    w: element.data('width'),
                    h: element.data('height'),
                    auto_position: true
                }
            );
            Vtiger_DashBoard_Js.currentInstance.loadWidget($(widget).find('.grid-stack-item-content'));
            this.showAndHideAlert('addWidget');
        },

        /**
         * Show or hide the alert for a dashboard.
         * @param {string} widgetAction
         */
        showAndHideAlert(widgetAction) {
            let container = this.getContainer();
            let alertContainer = container.find('.js-dashboards-alert');
            if (widgetAction === 'addWidget') {
                alertContainer.addClass('d-none');
            } else if (container.find('.js-css-element-queries').length == 0) {
                alertContainer.removeClass('d-none');
            }
        },

        registerEvents: function () {
            this.registerGrid();
            this.registerRefreshWidget();
            this.removeWidget();
            this.registerDatePickerHideInitiater();
            this.registerShowMailBody();
            this.registerMiniListWidget();
            this.registerTabModules();
            this.removeWidgetFromList();
            this.registerSelectDashboard();
            this.registerTabletScrollEvent();
            this.registerUpdatePredefinedWidgets();
            ElementQueries.listen();
        }
    }
);