Your IP : 18.219.40.177


Current Path : /usr/local/mgr5/skins/orion/src/
Upload File :
Current File : //usr/local/mgr5/skins/orion/src/App.Tabs.js

/**
 * Модуль отвечает за вкладки и их рендер
 * @param {object} window global object
 * @param {object|function} $ jQuery
 * @param {object} EventMgr Event manager
 * @param {object} App Application
 * @param {object} templates HTML templates
 */
App.Tabs = function(window, $, EventMgr, App, templates) {
  'use strict';
  var tabs = {},
      pageInfo = window.pageInfo,
      tabIndex = 1,

      tabN = 'tab',

      rowId = 0,

      activeTab = '', //current active tab id

      defaultTab = '', //defaultTab

      mainWrapperSel = '#main-wrapper',

      init = function() {
        EventMgr.bind('ajaxResponse', buildTabWrapper);
        EventMgr.bind('builtTab', appendTab);
        EventMgr.bind('comboCtrlShiftZKeyUp', closeAllTabs);
        EventMgr.bind('comboCtrlShiftXKeyUp', closeOthersTabs);
        EventMgr.on(mainWrapperSel, 'a.close', 'click', closeTabClickHandler);
        EventMgr.on(mainWrapperSel, 'span.back', 'click', backBtnHandler);
        EventMgr.on(mainWrapperSel, '#tabs .switch', 'click', switchTabs);
        EventMgr.on(mainWrapperSel, '#tabs .switch', 'mousedown', closeTabsByMiddleBtn);
        EventMgr.on(mainWrapperSel, '#tabs .switch', 'dblclick', upSwitchedTabs);
        EventMgr.bind('reloadTab', reloadTabData);
        EventMgr.bind('updateTab', updateTab);
        EventMgr.bind('ajaxFormResponse', formHandler);
        EventMgr.on(mainWrapperSel, '.i-button_type_cancel',
            'click', cancelBtnHandler);
        EventMgr.bind('ajaxResponseForDashboard', renderDashboardTable);
        EventMgr.bind('addedChart', addChartToTab);
        EventMgr.bind('formGetTreeBranch', formGetTreeBranch);
        EventMgr.bind('getActiveHint', getActiveHint);
        EventMgr.on(mainWrapperSel, 'input, textarea', 'change',
            formFieldChangeHandler);
        EventMgr.on(mainWrapperSel, '.i-list-icon__stop', 'click',
            stopAutoUpdate);
        EventMgr.addHook('formSetValues,formSubmit', addModelToSetvalues);
        EventMgr.bind('updateModel', updateModelBySetvalues);
        EventMgr.addHook('listMultiSelect,listSelect,listLiveFound,' +
            'listUnSelect,ajaxResponseEditInListSave,updateTotalList,' +
            'clickedGroupItem', addListModel);
        EventMgr.bind('saveFormPageState', saveFormPageState);
        EventMgr.on(mainWrapperSel, '.i-take-favorite', 'click', favoriteToggle);
        EventMgr.on(mainWrapperSel, '.i-pin', 'click', pinToggle);
        EventMgr.bind('loadPage', removeSfromParam);
        EventMgr.addHook('menuAction,testColCheck', addTabsModel);
        EventMgr.bind('changeTabSortIndex', changeTabSortIndex);
        EventMgr.bind('updateTotalWithConvertReport', updateTotalWithConvertReport);
        EventMgr.addToTriggerStack('escKeyUp', esckeyHandler, 1);
      },
      //remove sfrom param form url after login
      removeSfromParam = function() {
        var params = App.u.parseParams(window.location.search);
        if (params.sfrom) {
          if (window.history) {
            setTimeout(function() {
              window.history.pushState('default', '', pageInfo.binary);
            }, 10000);
          }
        }
      },

      checkDasboard = function(d) {
        if (d && d.dashboard) {
          $('#switch-tab0').trigger('click');
          return false;
        }
        return true;
      },

      checkFeatures = function(data) {
        //if has redirect keep new tabs
        if (data && data.__src !== 'okList' && data.__src !== 'okForm') {
          var params;
          if (data.features && pageInfo.features && !data.wizard &&
              data.features !== pageInfo.features) {
            params = App.u.parseParams(window.location.search);
            params.ssavetabs = 1;
            if (!params.scountreload) {
              params.scountreload = 1;
            } else {
              params.scountreload -= 0;
              params.scountreload += 1;
            }
            if (params.scountreload < 5) {
              window.location.search = '?' + App.u.getQueryString(params);
              return false;
            }
          } else {
            //remove params from url
            params = App.u.parseParams(window.location.search);
            if (params.ssavetabs) {
              setTimeout(function() {
                if (window.history) {
                  window.history.pushState('default', '', pageInfo.binary);
                }
              }, 10000);
            }
          }
        }
        return true;
      },

      checkReload = function(data) {
        if (data) {
          if (data.reload) {
            var newLocation = pageInfo.url;
            if (data.savetab) {
                newLocation += '?sfrom=sessionexpired';
            }
            if (data.__src && (data.__src === 'menuAction' ||
               data.__src === 'toolbarAction' ||
               data.__src === 'report' ||
               data.__src === 'reloadTab')) {
               makeFakeTab(data);
            }
            if (data.__src && data.__src === 'filterset') {
              addBeforeLoadRequest(data);
            }
            window.location = newLocation;
            return false;
          }
        }
        return true;
      },

      checkNewWin = function(data) {
        if (data) {
          if (data.location && data.newwin) {
            window.open(data.location, '_blank');
            //remove loading className
            $('.m-item.loading').removeClass('loading');
            return false;
          } else if (data.location) {
            window.location = data.location;
            return false;
          }
        }
        return true;
      },

      checkNewForm = function(data) {
        if (data) {
          var param, options,
              newFormParams = data.formParam,
              parent = data.parent;
          if (newFormParams) {
            param = App.u.parseParams(newFormParams);
            options = {
              noesc: true,
              param: param,
              invar: {
                waitingTabId: data.targetTabId,
                parent: parent,
                dataSaved: true,
                '__src_func': data.__src_func,
                '__src': 'okForm',
                '__srcBtn': data.__srcBtn,
                newtab: data.newtab
              },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponse',
              queue: 'noqueue' };
            if (data.openAsChild) {
              options.invar.parent = data.tabId;
            }
            EventMgr.trigger('ajaxRequest', options);
            return false;
          }
        }
        return true;
      },

      checkNewList = function(data) {
        if (data) {
          var param,
              newListParams = data.listParam,
              parent = data.parent;
          if (newListParams) {
            param = App.u.parseParams(newListParams);
            EventMgr.trigger('ajaxRequest', {
              noesc: true,
              param: param,
              invar: {
                waitingTabId: data.targetTabId,
                parent: parent,
                dataSaved: true,
                '__src': 'okList',
                '__srcBtn': data.__srcBtn,
                newtab: data.newtab
              },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponse',
              queue: 'noqueue' });
           if (data.openAsChild) {
             options.invar.parent = data.tabId;
           }
           EventMgr.trigger('tabLoading', { tabId: parent });
            return false;
          }
        }
        return true;
      },

      storage = App.Common.storage,
      //render breadcrumb
      getBreadcrumb = function(breadcrumb) {
        var str = '';
        /* jslint forin:true */
        for (var key in breadcrumb) {
          str += '<a href="#" data-id="' + key + '" class="breadcrumb">' +
              breadcrumb[key].name + '</a>';
        }
        return str;
      },

      resetToDefaultFormButton = function(tabId) {
        if (tabs[tabId] && tabs[tabId].type === 'form') {
          $('#frm-' + tabId + ' .b-button_st_disabled').each(function() {
            var $self = $(this);
            $self.html($self.attr('data-enabled'));
            $self.removeClass('b-button_st_disabled');
          });
        }
      },
      //cancel btn handler
      cancelBtnHandler = function(e) {
        var tabId = this.getAttribute('data-tabid'),
            func = this.getAttribute('data-func'),
            $self = $(this),
            form = $('#frm-' + tabId),
            isShowcaseForm = form.hasClass('b-form_showcase_yes'),
            flags = $self.getFlags(),
            parent, options;
        if (!tabs[tabId]) {
          return;
        }
        parent = tabs[tabId].parent;

        if (flags.refresh && parent) {
          EventMgr.trigger('reloadTab', { tabId: parent, __src: 'formCancelRefresh', filter: true });
        }
        //return list if it from sametab
        if (tabs[tabId].rParentObj) {
          var param = tabs[tabId].rParentObj,
              targetTabId = tabId;
          tabs[tabId].rParent = undefined;
          EventMgr.trigger('ajaxRequest', {
            url: pageInfo.url, param: param,
            invar: {
              parent: parent,
              targetTabId: targetTabId,
              iType: 'replace',
              dataSaved: true
            },
            type: 'get',
            outtype: 'json',
            trfunc: 'ajaxResponse',
            failfunc: 'failCommonAjaxResponse',
            queue: 'noqueue' });
          EventMgr.trigger('tabLoading', { tabId: tabId });
        } else if (func) {
          options = {
            param: {
              func: func
            },
            invar: {
              parent: parent,
              targetTabId: tabId,
              iType: 'replace',
              dataSaved: true
            },
            type: 'get',
            outtype: 'json',
            trfunc: 'ajaxResponse',
            failfunc: 'failCommonAjaxResponse',
            queue: 'noqueue'
          };
          EventMgr.trigger('ajaxRequest', options);
          EventMgr.trigger('tabLoading', { tabId: tabId });
        } else {
          closeTab(e, tabId);
        }
        e.preventDefault();
      },

      unsavedDataCheckboxHandler = function(val) {
        if (val === 'on') {
          var options = {
            param: {
              func: 'usrparam',
              elid: pageInfo.user,
              checkunsaved: 'off',
              sok: 'ok'
            },
            type: 'get',
            outtype: 'json',
            trfunc: 'DoNothing',
            queue: 'noqueue'
          };
          EventMgr.trigger('ajaxRequest', options);
          pageInfo.checkUnsaved = false;
        }
      },

      addBeforeLoadRequest = function(data) {
        var tabId = data.tabId;
        if (tabs[tabId]) {
          tabs[tabId].beforeRequest = data.sourceParamString;
        }
        EventMgr.trigger("changedTabs", {tabs: tabs, forceActive: true});
      },

      makeFakeTab = function(data) {
        var tabId, tabObj;
        tabId = tabN + tabIndex;
        tabObj = {
            status: 1,
            forceActive: true,
            title: '',
            paramObjAll: App.u.parseParams(data.sourceParamString)
        };
        //check for su func
        var func = tabObj.paramObjAll.func;
        if (String(func).match(/su$/) || func === 'chlevel') {
          return;
        }
        if (data.parent) {
          if (data.targetTabId || data.tabId) {
            tabId = data.targetTabId || data.tabId;
          }
          tabObj.hType = 'child';
          if (tabs[data.parent]) {
            tabs[data.parent].child = tabId;
          }
        } else {
          if (data.targetTabId) {
            tabId = data.targetTabId;
          }
          tabObj.hType = 'parent';
        }
        tabs[tabId] = tabObj;

        EventMgr.trigger('changedTabs', {tabs: tabs, forceActive: true});
      },
      //wrapper buildTab for check for unsaved form data
      buildTabWrapper = function(e, data) {
        var isChanged = false,
            tabId;
        //check for open in new tab & replace tab from redirect
        if (!data.newtab && !data.dataSaved && pageInfo.checkUnsaved) {
          //check for active tab is form
          if (tabs[activeTab]) {
            //find form in tab group
            tabId = findTabForm(activeTab);
            if (tabId !== activeTab) {
              //activate tab if not active
              if (tabs[tabId] && tabs[tabId].status === 0) {
                activateTab(tabId);
              }
            }
            var changedFields = checkFormChange(tabId);
            if (changedFields.isChanged) {
              isChanged = true;
              //show confirmBox
              EventMgr.trigger('confirmBoxShow', {
                callbackOk: buildTab,
                callbackCancel: function() {
                  $('.m-item.loading').removeClass('loading');
                },
                text: String(pageInfo.unsavedData)
                    .replace('__VALUE__', changedFields.count) +
                    '<br/><span class="b-text_style_bold">' + changedFields.labels +
                    '</span>',
                args: [e, data],
                checkbox: {
                  msg: pageInfo.unsavedDontShow,
                  cb: unsavedDataCheckboxHandler
                }
              });
            }
          }
        }
        if (!isChanged) {
          buildTab(e, data);
        }
      },

      findTabForm = function(tabId) {
        if (tabs[tabId] && tabs[tabId].type === 'form') {
          return tabId;
        } else {
          //form can be only last in tab group
          if (tabs[tabId].child) {
            return findTabForm(tabs[tabId].child);
          }
        }
        return false;
      },
      //build new tab
      buildTab = function(e, data) {
        EventMgr.trigger('hideHint');
        //check for user.su
        var parent = data.parent ? data.parent : '',
            ok = data.ok || false,
            tabId, obj, type, delay, timeId;
        //hide loader for parent tab
        if (parent) {
          EventMgr.trigger('tabLoadingHide', { tabId: parent});
          //reset btn on form if opened as a child
          resetToDefaultFormButton(parent);
        }
        //hide loader for targetTab (for case if has error)
        if (data.targetTabId) {
          EventMgr.trigger('tabLoadingHide', { tabId: data.targetTabId });
        }
        //hide loader for srcTab (when redirect) (for case if has error)
        if (data.srcTabId) {
          EventMgr.trigger('tabLoadingHide', { tabId: data.srcTabId });
        }

        if (!checkReload(data) ||
            !checkNewWin(data) ||
            !checkNewList(data) ||
            !checkNewForm(data)) {
          return false;
        }

        if (ok) {
          if (parent !== undefined) {
            EventMgr.trigger('reloadTab', { tabId: parent, filter: true, __src: 'buildTabOk' });
            return;
          }
        }

        EventMgr.trigger('startbuildTab', 'new empty tab');

        tabId = tabN + tabIndex;
        obj = data;
        type = obj.type || obj.id;

        if (obj.exType === 'dashboard') {
          tabId = 'tab0';
        } else if (obj.targetTabId) {
          tabId = obj.targetTabId;
        } else if (obj.showcase) {
          tabId = 'tab0';
        } else {
          tabIndex++;
        }

        //Гвозди
        //check for error on big Cicle
        if ((obj.error && !obj.ignErr &&
            (obj.type !== 'form' && obj.type !== 'inspectorForm' &&
                obj.type !== 'showcaseForm' && obj.type !== 'report')) ||
            (obj.userexpMsg === undefined &&
                obj.error &&
                obj.type === 'form')) {
          EventMgr.trigger('hideLoader');
          type = 'fatalerror';
        } else if (obj.error && obj.ignErr) {
          return;
        }
        if (type === '' && !tabs.tab0 || obj.exType === 'dashboard') {
          type = 'dashboard';
        }
        if (obj.msg) {
          $.extend(App.Common.msg, obj.msg);
        }

        switch (type) {
          case 'list':
            buildList(tabId, obj);
            break;
          case 'form':
            buildForm(tabId, obj);
            break;
          case 'dashboard':
            buildDashboard(tabId, obj);
            break;
          case 'report':
            buildReport(tabId, obj);
            EventMgr.trigger('reportLoad');
            break;
          case 'map':
          case 'rack':
            buildMap(tabId, obj);
            break;
          case 'fatalerror':
            buildFatalError(tabId, obj);
            break;
          case 'empty':
            buildEmpty(tabId, obj);
            break;
          case 'inspectorForm':
            buildInspectorForm(tabId, obj);
            break;
          case 'showcaseForm':
            buildShowcaseForm(tabId, obj);
            break;
          default:
            EventMgr.trigger('pullMsg', { msg: 'Do not support type = "' + type + '" of metadata' });
        }
        //handler for autoupdate
        //@TODO this shit must to rewrite
        delay = obj.autoupdate;

        if (!tabs[tabId]) { return; }

        if (tabs[tabId].timeId) {
          clearTimeout(tabs[tabId].timeId);
        }
        if (obj.autoupdate !== undefined) {
          timeId = setTimeout(function(tabId, delay) {
            return function() {
              EventMgr.trigger('updateTab', { tabId: tabId, delay: delay });
            };
          } (tabId, delay), obj.autoupdate * 1000);
          tabs[tabId].autoupdate = true;
          tabs[tabId].timeId = timeId;

        } else {
          tabs[tabId].autoupdate = false;
          tabs[tabId].timeId = undefined;
        }
        //show tips
        if (obj.tips) {
          setTimeout(function() {
            EventMgr.trigger('showTips', {
              tips: obj.tips,
              inTab: true,
              tabId: tabId,
              sameModule: obj.sameModule });
          }, 1);
        }
      },
      //build tab with list/table
      buildList = function(tabId, obj) {
        var plid = '',
            elid = '',
            pagerParam = '',
            breadcrumb,
            body = prepareTab(obj, tabId);
        if (obj.plid) {
          //what the hell?
          plid = '&plid=' + encodeURIComponent(obj.plid);
        }
        if (obj.elid) {
          elid = '&elid=' + encodeURIComponent(obj.elid);
        }

        if (obj.sortOrder) { pagerParam += '&p_order=' + obj.sortOrder; }
        if (obj.sortCol) { pagerParam += '&p_sort=' + obj.sortCol; }
        if (obj.pager.pager === 'true') {
          pagerParam += '&p_num=' + obj.pager.pageNum +
              '&p_cnt=' + obj.pager.pageCnt;
        }

        //flag for render bottom bar
        obj.sbar = true;
        if (App.Global.warning) {
          obj.warning = App.Global.warning;
        }
        if (obj.selid) {
          App.Global.selid = obj.selid;
        }
        if (obj.scrollTop) {
          App.Global.scrollTop = obj.scrollTop;
        }
        obj.tabId = tabId;

        //check for extra confirm
        if (obj.warning) {
          var warning = $.extend({}, obj.warning);
          EventMgr.trigger('checkWarningForConfirm', { d: obj, w: warning });
        }
        var table = renderTable(obj);
        //render pager
        var pager = '';
        if (obj.pager.pager === 'true') {
          pager = buildPager(obj.pager, tabId);
        }
        var filter = '';
        if (obj.filter === 'true') {
          if (obj.activeFilter.status) {
            filter = 'filter filter-hide filter-set';
          } else {
            filter = 'filter filter-hide';
          }
        }

        breadcrumb = getBreadcrumb(obj.breadcrumb);
        delete obj.breadcrumb.name;
        storage.breadcrumb[tabId] = obj.breadcrumb;

        body.autoupdate = (obj.autoupdate !== undefined);
        body.tsettings = App.u.escapeQuote(obj.hintTsettings) || '';
        body.hAutoupdate = App.u.escapeQuote(obj.hintAutoupdate) || '';
        body.hExport = App.u.escapeQuote(obj.hintExport) || '';
        body.hSelectAll = App.u.escapeQuote(obj.hintSelectAll) || '';
        body.fHelp = App.u.escapeQuote(obj.hintFilter) || '';
        body.pNum = obj.pager.pageNum;
        body.porder = obj.sortOrder;
        body.sortCol = obj.sortCol;
        body.pcnt = obj.pager.pageCnt;
        body.breadcrumb = breadcrumb;
        body.plidAttr = obj.plid ? 'data-plid= "' + filterXSS.safeAttrValue('div', 'data-plid', obj.plid) + '"' : '';
        body.convertAttr = obj.convert ? 'data-convert=' + obj.convert : '';
        body.oplid = obj.plid || '';
        body.tsplid = obj.tsplid || '';
        body.tsettingsParam = filterXSS.safeAttrValue('a', 'data-url', `?func=tsetting&elid=${obj.func}&plid=${obj.tsplid}`);
        body.table = table;
        body.progressid = obj.progressid;
        //for toolbar btn
        body.tabIdAttr = 'data-parent=' + tabId;
        body.pager = pager;
        body.filter = filter;
        body.afilter = obj.activeFilter;
        body.param = pagerParam;
        body.livefilter = obj.liveFilter || '';

        tabs[tabId].body = body;
        //save model
        tabs[tabId].__content = obj.content;
        tabs[tabId].__headers = obj.headers;

        App.Global.bannerHtml = null;
        App.Global.targetId = '';
        //APP.Global.warning = null;

        if (obj.filter === 'true') {
          tabs[tabId].filter = true;
          tabs[tabId].filterFunc = obj.filterFunc;
        } else {
          tabs[tabId].filter = false;
        }

        EventMgr.trigger('builtTab', {
          tab: tabs[tabId],
          newtab: obj.newtab,
          targetTabId: obj.targetTabId,
          iType: obj.iType,
          srcData: obj });

        activateNewTab(tabId, obj.newtab, obj.iType);

        if (obj.children) {
          EventMgr.trigger('loadChildren', {
            parent: tabId,
            children: obj.children });
        }
        //if tab have progressbar - run it
        if (obj.progressid) {
          var param = { elid: obj.progressid, func: 'progress.get' };
          EventMgr.trigger('ajaxRequest', {
            url: pageInfo.url,
            param: param,
            invar: { tabId: tabId, param: param, progresstype: undefined },
            type: 'get',
            outtype: 'json',
            trfunc: 'progressBarResponse',
            queue: 'noqueue' });
        }
        //if tab have diagram - insert it
        if (obj.diagram && obj.diagram[0]) {
          EventMgr.trigger('appendListWithDiagram', {
            diagram: obj.diagram[0],
            content: obj.content,
            tabId: tabId,
            gid: 'diagram-' + tabId });
        }
        //check for saved live filter
        if (obj.liveFilter) {
          $('#' + tabId + '-search').trigger('keyup');
        }
      },
      //build tab with form
      buildForm = function(tabId, obj) {
        var body = prepareTab(obj, tabId);

        if (!obj.form) { return; }

        obj.form.id = tabId;
        obj.form.formflags = obj.formflags || {};
        obj.form.parent = obj.parent || '';
        obj.form.func = obj.func;

        body = prepareFormTab(obj, tabId, body);

        tabs[tabId].formModel = body.model;
        tabs[tabId].formSource = body.formSource;

        tabs[tabId].body = body;

        EventMgr.trigger('builtTab', {
          tab: tabs[tabId],
          newtab: obj.newtab,
          targetTabId: obj.targetTabId,
          iType: obj.iType,
          srcData: obj });

        activateNewTab(tabId, obj.newtab, obj.iType);
        if (obj.error) {
          EventMgr.trigger('focusOnErrorField', { tabId: tabId });
        }
      },
      //build tab with dashboard
      buildDashboard = function(tabId, obj) {
        var msg;
        tabs[tabId] = new TabObj(tabId, 1, 'dashboard');

        if (!obj.error && obj.blocks) {
          tabs[tabId].body = renderDashboard(obj.blocks);
        } else if (obj.lateLoad) {
          msg = pageInfo.loading;
          /*jslint sub: true*/
          tabs[tabId].body = { id: tabId, top: msg, left: '', right: '' };
          /*jslint sub: false*/
        } else if (!obj.shithappend) {
          msg = templates.fatalError({ message: obj.ermsg, ref: false });
          tabs[tabId].body = { 'id': tabId, top: msg, left: '', right: '' };
        } else {
          msg = pageInfo.loading;
          tabs[tabId].body = { id: tabId, top: msg, left: '', right: '' };
          //shit happend trying again
          setTimeout(function() {
            var url = pageInfo.url,
                param = { func: 'dashboard' };
            EventMgr.trigger('ajaxRequest', {
              url: url,
              param: param,
              invar: { exType: 'dashboard' },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponse',
              queue: 'dashboard' });
          } , 500);
        }
        //if was error
        $('#cont-tab0').remove();

        tabs[tabId].func = obj.func;

        EventMgr.trigger('builtTab', { tab: tabs[tabId] });

        defaultTab = tabId;
        //if dashboard loaded after list/form
        /*jslint sub: true*/
        if (!tabs['tab1'] || !tabs['tab1'].active) {
          activateNewTab(tabId);
        } else {
          tabs['tab0'].deactive();
        }
        /*jslint sub: false*/
      },

      buildFatalError = function(tabId, obj) {
        var ref, refreshLink,
            sTabId = obj.targetTabId || tabId,
            cb;
        $('.m-item.loading').removeClass('loading');
        if (obj.__src === 'groupAction' || obj.__src === 'report' ||
             obj.__src === 'toolbarAction-refresh') {
          EventMgr.trigger('tabLoadingHide', { tabId: obj.tabId });
          if (obj.__src === 'groupAction') {
            EventMgr.trigger('reloadTab', { tabId: obj.tabId, filter: true });
          }
        } else if (obj.__src === 'wizardLink') {
          EventMgr.trigger('tabLoadingHide', { tabId: obj.tabId });
          sTabId = false;
        } else if (obj.targetTabId) {
          EventMgr.trigger('tabLoadingHide', { tabId: obj.targetTabId ||
                obj.waitingTabId });
        } else if (obj.waitingTabId) {
          //reset to default form state
          EventMgr.trigger('tabLoadingHide', { tabId: obj.waitingTabId });
          resetToDefaultFormButton(obj.waitingTabId);
        }
        if (obj.ref) {
          ref = pageInfo.url + obj.ref;
        }
        if (obj.ertype === 'unavailable') {
          refreshLink = obj.sourceParamString;
        }
        //check for exist tab, and close it
        if (sTabId) {
          if (tabs[sTabId]) {
            closeTab({ preventDefault: function() {} }, sTabId);
          }
        }
        //reload parent, becase it can be unexist elem
        if (obj.parent) {
          cb = function() {
            EventMgr.trigger('reloadTab', { tabId: obj.parent, __src: 'fatalError' });
          };
        }
        var html = templates.fatalAlert({
          msg: obj.ermsg,
          ref: ref,
          refreshLink: refreshLink,
          refreshLinkMsg: pageInfo.tryreload,
          moreMsg: pageInfo.moreinfo
        });
        EventMgr.trigger('showAlert', {
          msg: html,
          callback: cb });
      },

      buildReport = function(tabId, obj) {
        //@todo вынести
        var bands,
            body = prepareTab(obj, tabId);

        obj.form.id = tabId;
        obj.form.func = obj.func;
        obj.reports.func = obj.func;

        bands = renderBands(obj.reports, tabId);
        body = prepareFormTab(obj, tabId, body);

        body.helpType = 'default';
        body.helpurl = '';
        body.type = 'report';
        body.bands = bands;
        body.reportInfo = obj.reportInfo;

        tabs[tabId].body = body;

        EventMgr.trigger('builtTab', {
          tab: tabs[tabId],
          newtab: obj.newtab,
          bands: obj.reports,
          targetTabId: obj.targetTabId});

        activateNewTab(tabId, obj.newtab, obj.iType);
      },

      buildMap = function(tabId, obj) {
        var body = prepareTab(obj, tabId),
            ermsg,
            type = obj.type;

        if (obj.ermsg && !obj.erobj) {
          ermsg = templates.banner({ message: {
            status: 'error',
            classes: '',
            id: tabId,
            text: App.Common.wordWrap(obj.ermsg, 100),
            ref: false,
            refText: pageInfo.moreinfo,
            dismiss: obj.msg.dismiss
          } });
        }

        body.helpType = 'default';
        body.helpurl = '';
        body.type = type;
        body.plid = (obj.plid) ? String(obj.plid).replace(/"/g, '&quot;') : '';
        body.elid = (obj.elid) ? String(obj.elid).replace(/"/g, '&quot;') : '';
        body.parent = obj.parent ? obj.parent : '';
        body.ermsg = ermsg;
        body.btng = obj.btng ? obj.btng : [];
        body.btnview = obj.btnview ? 'o-' + obj.btnview : '';
        body.plidAttr = obj.plid ? 'data-plid= "' + filterXSS.safeAttrValue('div', 'data-plid', obj.plid) + '"' : '';
        body.convertAttr = obj.convert ? 'data-convert=' + obj.convert : '';

        tabs[tabId].body = body;

        EventMgr.trigger('builtTab', {
          tab: tabs[tabId],
          map: obj[type],
          newtab: obj.newtab,
          targetTabId: obj.targetTabId });

        activateNewTab(tabId, obj.newtab, obj.iType);
      },

      buildEmpty = function(tabId, obj) {
        var body = pageInfo.loading,
            curTab;
        prepareTab(obj, tabId);
        curTab = tabs[tabId];
        curTab.body = { id: tabId, text: '', comment: body };
        curTab.status = 0;
        curTab.notLoaded = true;
        curTab.pin = obj.pin;

        if (obj.children) {
          EventMgr.trigger('loadChildren', {
            parent: tabId,
            children: obj.children });
        }

        EventMgr.trigger('builtTab', {
          tab: curTab,
          newtab: obj.newtab,
          targetTabId: obj.targetTabId });
        EventMgr.trigger('changedTabs', { tabs: tabs });
      },

      buildInspectorForm = function(tabId, obj) {
        //if fatal error without form
        if (obj.error && obj.userexpMsg === undefined) {
          EventMgr.trigger('pullMsg', { msg: obj.ermsg });
          return;
        }
        var body = prepareTab(obj, tabId);
        //rename id
        delete tabs[tabId];
        tabId = 'modal1';
        body.id = tabId;

        if (!obj.form) { return; }

        obj.form.id = tabId;

        body = prepareFormTab(obj, tabId, body);

        body.parent = obj.sourceTab;

        var html = templates.tabContForm(body);
        EventMgr.trigger('readyInspectorFormHtml', html);
      },
      //build external form
      buildShowcaseForm = function(tabId, obj) {
        tabId = 'tab0';
        var body = prepareTab(obj, tabId);
        obj.form.id = tabId;

        obj.form.formflags = obj.formflags || {};

        obj.form.parent = obj.parent || '';

        body = prepareFormTab(obj, tabId, body);

        tabs[tabId].formModel = body.model;
        tabs[tabId].formSource = body.formSource;

        body.showcase = true;
        body.nostep = !pageInfo.wizard_step;
        body.notitle = !pageInfo.title;

//        body.parent = obj.sourceTab;

        var html = templates.tabContForm(body);
        EventMgr.trigger('readyShowcaseFormHtml', html);
      },
      //fill body object for form
      prepareFormTab = function(obj, tabId, body) {
        if (!body || !obj) { return; }
        var ermsg = '',
            userexpMsg = String(obj.userexpMsg)
                .replace('__value__', obj.userexpHideFields),
            renderObject;
        //banner
        if (obj.ermsg && !obj.erobj) {
          ermsg = templates.banner({ message: {
            status: 'error',
            classes: 'i-message__outer-link',
            id: tabId,
            text: App.Common.wordWrap(obj.ermsg, 100),
            ref: obj.ref ? obj.ref : false,
            refText: pageInfo.moreinfo,
            dismiss: obj.msg.dismiss || pageInfo.dismiss
          } });
        }

        body.form = obj.form;
        body.tabClass = obj.testMode ? ' tab-content_st_testmode' : '';
        body.formstatus = obj.formstatus;
        body.files = obj.withfiles ? 'withfiles' : 'withoutfiles';
        body.bands = '';
        body.progress = (obj.progress ? (obj.progress + '_' + body.itemId) : false);
        body.helpType = obj.helpType;
        body.helpurl = obj.helpurl;
        obj.form.testMode = obj.testMode;
        renderObject = renderFormItems(obj.form, tabId);
        body.pages = renderObject.html;
        body.model = renderObject.model;
        body.formSource = renderObject.source;
        body.action = pageInfo.binary;
        body.step = pageInfo.step;
        body.formflags = (obj.formflags) ? obj.formflags : {};
        body.buttons = obj.buttons;
        body.parent = obj.parent ? obj.parent : '';
        body.plid = (obj.plid) ? String(obj.plid).replace(/"/g, '&quot;') : '';
        body.elid = (obj.elid) ? String(obj.elid).replace(/"/g, '&quot;') : '';
        body.plidAttr = obj.plid ? 'data-plid= "' + filterXSS.safeAttrValue('div', 'data-plid', obj.plid) + '"' : '';
        body.type = 'form';
        //body.isUserexp = obj.isUserexp;
        body.userexp = obj.userexp;
        body.userexpMsg = userexpMsg;
        body.reportInfo = undefined;
        body.arePages = (obj.form.length > 1) ? 'a-lot-of-pages' : '';
        body.ermsg = ermsg;
        body.__innervars = obj.__innervars ? objectToString(obj.__innervars) : '';

        //add buttons to formModel
        if (obj.buttons) {
          body.model.__buttons = obj.buttons;
        }

        return body;
      },

      objectToString = function(object) {
        var stringVars = '',
            index = 0;
        for (var key in object) {
          if (index !== 0) {
            stringVars += '|';
          }
          index++;
          stringVars += key + ':' + object[key];
        }

        return stringVars;
      },

      isAlreadyPinTab = function(obj, tabId) {
        var func = obj.func || (obj.urlObj ? obj.urlObj.func : ''),
            already = false,
            tab;
        for (var key in tabs) {
          tab = tabs[key];
          if (key === tabId) {
            return true;
          }
          if (tab && tab.paramObjAll && tab.paramObjAll.func === func) {
            return true;
          } else if (tab && tab.urlObj && tab.urlObj.func === func) {
            return true;
          }
        }
        return already;
      },
      //fill body object for all types
      prepareTab = function(obj, tabId) {
        var body = {}, title, titleLen = 0, shortTitle,
            hint, tImg, tStyle, imgId,
            selfUrl = obj.selfUrl ?
                obj.selfUrl.replace(/sfrom=ajax/g, '') : '',
                curTab;

        //dont show pin when isPin && from menu
        obj.pin = (obj.pin && obj.__src !== 'menuAction');
        //check already same pin tab
        if (obj.pin && !isAlreadyPinTab(obj, tabId)) {
          obj.pin = true;
        }
        /* jshint camelcase: false*/
        body.commonDir = pageInfo.commonDir;
        body.itemId = obj.type + new Date().getTime();
        body.id = tabId;
        body.func = obj.func;
        body.theme = obj.theme;
        body.hReload = App.u.escapeQuote(obj.hintReload) || '';
        body.comment = App.u.escapeQuote(obj.msg_loading) || '';
        body.hFavorite = App.u.escapeQuote(obj.hintFavorite) || '';
        body.hUnfavorite = App.u.escapeQuote(obj.hintUnFavorite) || '';
        body.hPrint = App.u.escapeQuote(obj.hintPrint) || '';
        body.hCopy = App.u.escapeQuote(obj.hintCopy) || '';
        body.hPdf = App.u.escapeQuote(obj.hintPdf) || '';
        body.hHelp = App.u.escapeQuote(obj.hHelp) || '';
        body.hintUnpin = App.u.escapeQuote(obj.hintPin) || '';
        body.hintPin = App.u.escapeQuote(obj.hintUnpin) || '';
        body.hDevel = 'out=devel';
        body.breadcrumb = '';
        body.message = '';
        body.selfurl = pageInfo.url + '?' + getQueryString(obj.urlObj);
        body.devMode = devMode;
        body.testMode = obj.testMode;
        body.pdfOn = pdfOn;
        body.btng = obj.btng ? obj.btng : [];
        body.btnview = obj.btnview ? 'o-' + obj.btnview : '';
        body.favorite = obj.favorite || false;
        body.pin = obj.pin || false;
        body.inmenu = !!App.Dom.byId('l-' + String(obj.func).replace(/\./g, '_'));
        //for btn in form
        body.parentAttr = obj.parent ? 'data-parent=' + obj.parent : '';
        //for toolbar btn
        body.tabIdAttr = 'data-parent=' + tabId;
        //make permalink
        var permaLinkObj = $.extend({}, obj.urlObj);
        delete permaLinkObj.sfrom;
        delete permaLinkObj.operafake;
        delete permaLinkObj.clickstat;
        permaLinkObj.startform = permaLinkObj.func;
        delete permaLinkObj.elname;
        delete permaLinkObj.func;
        body.permaLink = pageInfo.url + '?' + getQueryString(permaLinkObj);
        //remove error if not tagret tab
        if (App.Global.targetId && App.Global.targetId !== tabId &&
            App.Global.bannerHtml && App.Global.bannerHtml.length > 0) {
          var msgLen = App.Global.bannerHtml.length;
          while (msgLen--) {
            if (App.Global.bannerHtml[msgLen].status === 'error') {
              App.Global.bannerHtml.splice(msgLen, 1);
            }
          }
        }
        if (obj.message) {
          if (App.Global.bannerHtml) {
            body.message = obj.message.concat(App.Global.bannerHtml);
          } else {
            body.message = obj.message;
          }
        } else {
          if (App.Global.bannerHtml) {
            body.message = App.Global.bannerHtml;
          }
        }
        if (body.message) {
          //check for message exists
          var l = body.message.length;
          while (l--) {
            if (body.message[l].refText === '') {
              body.message[l].refText = obj.msg.moreinfo;
            }
            if (body.message[l].dismiss === '') {
              body.message[l].dismiss = obj.msg.dismiss || pageInfo.dismiss;
            }
          }
        }

        if (!obj.targetTabId) {
          tabs[tabId] = new TabObj(tabId, 1, obj.type, selfUrl);
        } else {
          tabs[tabId].type = obj.type;
          tabs[tabId].selfUrl = selfUrl;
        }
        //set menu func name
        if (obj.__src_func) {
          tabs[tabId].menuFunc = obj.__src_func;
        }

        curTab = tabs[tabId];

        if (obj.iType !== 'hardUpdate' && obj.iType !== 'replace') {
          if (!obj.parent) {
            curTab.hType = 'parent';
          } else {
            if (tabs[obj.parent] === undefined) { return; }
            curTab.hType = 'child';
            curTab.parent = obj.parent;
            curTab.gParent = tabs[obj.parent].gParent ?
                tabs[obj.parent].gParent : obj.parent;
            if (obj.type === 'empty') {
              tabs[obj.parent].child = tabId;
            }
          }
        } else {
          obj.parent = curTab.parent;
        }

        //get title
        if (obj.title && obj.title !== '') {
          titleLen = obj.title.length;
          if (titleLen < 25) {
            title = obj.title;
          } else {
            title = obj.title.substr(0, 25) + '...';
          }
          if (titleLen < 10) {
            shortTitle = obj.title;
          } else {
            shortTitle = obj.title.substr(0, 10) + '...';
          }
          hint = App.u.escapeQuote(obj.title);
        } else {
          title = '...';
        }
        curTab.title = obj.title;
        body.tabTitle = obj.title;

        //get icon for title
        if (obj.parent) {
          imgId = tabs[tabs[tabId].gParent].func;
        } else {
          imgId = obj.id;
        }
        tImg = getMainImg(imgId, obj.selfIcon, pageInfo.commonDir);
        tStyle = getMainImg(imgId, obj.selfIcon, pageInfo.commonDir, true);

        body.tImg = tImg;
        body.tStyle = tStyle;
        //remember parent params for return parent by cancel
        if (obj.rParent) {
          curTab.rParentObj = tabs[tabId].paramObjAll;
        } else {
          curTab.rParentObj = undefined;
        }

        //set tabs props
        curTab.paramObjAll = obj.urlObj;

        if (obj.type !== 'empty') {
          curTab.notLoaded = false;
        }

        curTab.iType = obj.iType;
        curTab.pinIcon = obj.pinIcon ? obj.pinIcon : getGroupIcon(imgId);
        curTab.pin = obj.pin || false;

        curTab.header = {
          tabId: tabId,
          title: title,
          hint: hint,
          isPin: obj.pin,
          pinIcon: curTab.pinIcon,
          shortTitle: shortTitle,
          theme: pageInfo.theme };


        curTab.func = obj.func;

        curTab.favorite = obj.favorite;

        curTab.features = obj.features;
        curTab.wizard = obj.wizard;
        //make help param
        if (obj.help) {
          curTab.help = obj.help;
        } else if (obj.__src === 'toolbarAction' ||
                   obj.__src === 'okForm' ||
                   obj.__src === 'tSetting') {
          if (obj.parent && tabs[obj.parent]) {
            curTab.help = tabs[obj.parent].help + '.' + obj.__srcBtn;
          } else {
            curTab.help = obj.func;
          }
        } else {
          //obj.__src === 'menuAction' ||
          //  obj.newtab ||
          //  obj.__src === 'dashboardBtn'
          curTab.help = obj.func;
        }
        body.help = curTab.help;

        return body;
      },

      getQueryString = function(queryObj) {
        var paramString = '', j = 0, curValue;
        for (var key in queryObj) {
          if (key !== '') {
            if (j !== 0) {
              paramString += '&';
            }
            //encode params
            paramString += key + '=' + encodeURIComponent(queryObj[key]);
            j++;
          }
        }
        return paramString;
      },

      /**
       * activate tab when switching
       * @param {String} tabId
       */
      activateTab = function(tabId) {
        var gParent = '', prevTabId = activeTab, pTabId = '', selid = [], func;
        //checking, probably deleted it early
        if (tabs[activeTab]) {
          tabs[activeTab].deactive();
          //remove actChild from gParent if child
          if (tabs[activeTab].gParent) {
            gParent = tabs[activeTab].gParent;
            tabs[gParent].actChild = null;
          }
        }
        //write actChild to gParent if child
        if (tabs[tabId].gParent) {
          gParent = tabs[tabId].gParent;
          tabs[gParent].actChild = tabId;
        }
        tabs[tabId].activate();
        if (!gParent) {
          pTabId = tabId;
        } else {
          pTabId = gParent;
        }

        EventMgr.trigger('activateTab', { tabId: tabId });
        EventMgr.trigger('changedTab', { tabId: tabId, prevTabId: prevTabId });
        EventMgr.trigger('changeTabStatus', {
          func: getMenuFunction(pTabId),
          type: 'activate' });
        EventMgr.trigger('changedTabs', { tabs: tabs });
        //EventMgr.trigger('switchTab', {tabId : tabId});
        activeTab = tabId;
        //updateTab or load if notloaded
        if (tabs[tabId].aupdate || tabs[tabId].notLoaded) {
          selid = true;
          EventMgr.trigger('reloadTab', {
            tabId: tabId,
            selid: selid,
            help: true,
            filter: true });
        }
      },

      isPinTab = function(tabId) {
        var isPin = false;
        if (tabs[tabId] && tabs[tabId].pin) {
           isPin = true;
        } else if (tabs[tabId] && tabs[tabId].gParent) {
          if (tabs[tabs[tabId].gParent] && tabs[tabs[tabId].gParent].pin) {
            isPin = true;
          }
        }
        return isPin;
      },

      getMenuFunction = function(pTabId) {
        var func = '';
        //get func name
        if (tabs[pTabId]) {
          if (tabs[pTabId].menuFunc) {
            func = tabs[pTabId].menuFunc;
          } else if (tabs[pTabId].func) {
            func = tabs[pTabId].func;
          } else if (tabs[pTabId].paramObjAll) {
            func = tabs[pTabId].paramObjAll.func;
          }
        }
        return func;
      },
      /**
       * activate new opened tab
       * @param {String} tabId Activated tabId
       * @param {Boolean} empty Empty Tabrea
       * @param {String} iType
       */
      activateNewTab = function(tabId, empty, iType) {
        var isPin = isPinTab(activeTab);
        if (activeTab === tabId) {
          tabs[tabId].activate();
          return;
        }
        var hType = tabs[tabId].hType,
            parent = tabs[tabId].parent || null,
            gParent = tabs[tabId].gParent || null,
            pTabId, child,
            update = (iType === 'hardUpdate' || iType === 'softUpdate'),
            replace = (iType === 'replace');
        //delete active tab if not default and not child
        if (activeTab && activeTab !== defaultTab &&
            !empty && hType !== 'child' && tabId !== 'tab0' &&
            !update && !replace && !isPin) {
          //close tabs group (parents & children)
          closeTabGroup(activeTab);
        }
        //delete sibling child
        if (parent && tabs[parent].child && !update && !replace) {
          child = tabs[parent].child;
          closeChildTab(child);
        }

        if (hType === 'child') {
          //write child to parent
          tabs[parent].child = tabId;
          //write actChild to greatParent
          tabs[gParent].actChild = tabId;
        }
        if (tabs[activeTab]) {
          tabs[activeTab].deactive();
        }
        tabs[tabId].activate();

        if (!gParent) {
          pTabId = tabId;
        } else {
          pTabId = gParent;
        }
        activeTab = tabId;
        //remove loading className
        $('.m-item.loading').removeClass('loading');
        EventMgr.trigger('activateTab', { tabId: tabId });
        EventMgr.trigger('changeTabStatus', {
          func: getMenuFunction(pTabId),
          type: 'activate' });
        EventMgr.trigger('changedTabs', { tabs: tabs });
      },
      /**
       * finding out new active tab
       * @param {String} tabId closed TabId
       */
      newActiveTab = function(tabId, src) {
        var newActTab, gParent, pTabId;
        //check actChild
        if (!tabs[tabId]) { return; }
        if (tabs[tabId].gParent) {
          gParent = tabs[tabId].gParent;
          if (!tabs[gParent].actChild) {
            return;
          }
        } else if (tabs[tabId].actChild) {

        } else if (tabId !== activeTab) {
          return;
        }
        //set active to dashboard
        if (tabs[tabId].hType === 'parent') {
          if (src === 'backBtn') {
            newActTab = 'tab0';
          } else {
            newActTab = getNextTab(tabId);
          }
        } else {
          //set active to parent
          newActTab = tabs[tabId].parent;
          if (tabs[tabId].gParent) {
            gParent = tabs[tabId].gParent;
            tabs[gParent].actChild = newActTab;
          }
        }
        //set actChild for
        if (tabs[newActTab].gParent) {
          tabs[tabs[newActTab].gParent].actChild = newActTab;
        }

        tabs[newActTab].activate();

        if (!gParent) {
          pTabId = newActTab;
        } else {
          pTabId = gParent;
        }
        activeTab = newActTab;
        EventMgr.trigger('activateTab', { tabId: newActTab });
        EventMgr.trigger('changeTabStatus', {
          func: getMenuFunction(pTabId),
          type: 'activate' });
        EventMgr.trigger('changedTab', { tabId: newActTab });
        EventMgr.trigger('changedTabs', { tabs: tabs });

        if (tabs[newActTab].aupdate || tabs[newActTab].notLoaded) {
          EventMgr.trigger('reloadTab', {
            tabId: newActTab,
            __src: 'activateTab',
            selid: true,
            filter: true });
        }
      },
      //get right or left tab
      getNextTab = function(tabId) {
        var tabsArr = [], ind = 0, selfIndex, next, prev;
        for (var key in tabs) {
          if (tabs[key].hType === 'parent') {
            tabsArr.push(key);
            if (key === tabId) {
              selfIndex = ind;
            }
            ind++;
          }
        }
        next = selfIndex + 1;
        prev = selfIndex - 1;
        if (tabsArr[next]) {
          return getChild(tabsArr[next]);
        } else if (tabsArr[prev]) {
          return getChild(tabsArr[prev]);
        } else {
          return defaultTab;
        }
      },
      //get last child tab
      getChild = function(tabId) {
        var childTabId = tabId;
        if (tabs[tabId].child) {
          childTabId = getChild(tabs[tabId].child);
        }
        return childTabId;
      },
      //switch tabs
      switchTabs = function(e) {
        e.preventDefault();
        var tabId = this.getAttribute('data-tabid');

        if (activeTab === tabId) {
          return;
        }
        activateTab(tabId);
        if (tabs[tabId].type === 'form' || tabs[tabId].type === 'report') {
          EventMgr.trigger('switchTabForm', { tabId: tabId });
          EventMgr.trigger('updFormHeight', { tabId: tabId });
        } else {
          EventMgr.trigger('updTableHeight');
        }
        EventMgr.trigger('switchTab', { tabId: tabId });
      },

      closeTabsByMiddleBtn = function(e) {
        if (e.which === 2 || e.button === 1) {
          var tabId = this.getAttribute('data-tabid');
          e.preventDefault();
          if (tabId !== 'tab0') {
            closeTabClickHandler.apply(this, [e]);
          }
        }
      },
      //update tab by dbclick
      upSwitchedTabs = function(e) {
        e.preventDefault();
        var tabId = this.getAttribute('data-tabid');
        EventMgr.trigger('reloadTab', { tabId: tabId, __src: 'dblclickTab', filter: true });
      },
      //append new tab
      appendTab = function(e, data) {
        var tabObj = data.tab,
            newtab = data.newtab || false,
            bands = data.bands || '',
            map = data.map || '',
            tabId,
            isPin = isPinTab(activeTab);
        if (activeTab !== defaultTab && !newtab && !isPin) {
          if (tabs[activeTab].gParent) {
            tabId = tabs[activeTab].gParent;
          } else {
            tabId = activeTab;
          }
        }
        if (!tabObj.iType) {
          tabObj.render().append(tabId).clean();
        } else if (tabObj.iType === 'hardUpdate') {
          tabObj.render().update().clean();
        } else if (tabObj.iType === 'softUpdate') {
          tabObj.softUpdate().clean();
        } else if (tabObj.iType === 'replace') {
          tabObj.render().replace().clean();
        }

        EventMgr.trigger('appended', { tabId: tabObj.id });
        //trigger events
        if (tabObj.type === 'form') {
          EventMgr.trigger('appendForm', {
            tabId: tabObj.id,
            tabObj: tabObj,
            srcData: data.srcData });
        } else if (tabObj.type === 'list') {
          EventMgr.trigger('appendList', { tabId: tabObj.id, srcData: data.srcData });
        } else if (tabObj.type === 'dashboard') {
          EventMgr.trigger('appendDashboard', {});
        } else if (tabObj.type === 'report') {
          EventMgr.trigger('appendReport', { tabId: tabObj.id, bands: bands });
        } else if (tabObj.type === 'map' || tabObj.type === 'rack') {
          EventMgr.trigger('appendMap', { tabId: tabObj.id, map: map });
        }
        //get filter
        if (tabObj.filter === true) {
          EventMgr.trigger('appendFilter', {
            tabId: tabObj.id,
            listParam: tabObj.paramObjAll,
            func: tabObj.filterFunc });
        }
        data = null;
        checkFeatures(tabObj);
      },

      closeTabClickHandler = function(e) {
        e.stopPropagation();
        var tabId = this.getAttribute('rel') || this.getAttribute('data-tabid'),
            isChanged = false,
            isPin = tabs[tabId].pin;
        if (isPin) {
          return;
        }
        if (tabs[tabId] && tabs[tabId].type === 'form' &&
            pageInfo.checkUnsaved) {
          var changedFields = checkFormChange(tabId);
          if (changedFields.isChanged) {
            isChanged = true;
            EventMgr.trigger('confirmBoxShow', {
              callbackOk: closeTab,
              callbackCancel: '',
              self: this,
              text: String(pageInfo.unsavedData)
                  .replace('__VALUE__', changedFields.count) +
                  '<br/><span class="b-text_style_bold">' +
                  changedFields.labels + '</span>',
              args: [e, tabId],
              checkbox: {
                msg: pageInfo.unsavedDontShow,
                cb: unsavedDataCheckboxHandler
              }
            });
          }
        }
        if (!isChanged) {
          closeTab(e, tabId);
        }
      },

      //close tab
      closeTab = function(e, data, src) {
        EventMgr.trigger('closeTab', {});
        var tabId, parent;
        if (data) {
          tabId = data;
        } else {
          tabId = this.getAttribute('rel');
        }
        if (!tabs[tabId]) { return; }
        //check for tab is pin
        if (tabs[tabId] && tabs[tabId].pin) {
          //reload tab if it form
          if (tabs[tabId].type === 'form') {
            EventMgr.trigger('reloadTab', { tabId: tabId, __src: 'pinForm' });
          }
          return;
        }
        EventMgr.trigger('closeTabEvent', { tabId: tabId });

        newActiveTab(tabId, src); //set new active tab
        //killing children
        if (tabs[tabId] && tabs[tabId].child) {
          closeChildTab(tabs[tabId].child);
        }
        //clear child from parent
        if (tabs[tabId] && tabs[tabId].hType === 'child') {
          parent = tabs[tabId].parent;
          tabs[parent].child = null;
        }
        tabs[tabId].close();
        delete tabs[tabId];
        if (e) { e.preventDefault(); }

        EventMgr.trigger('updTableHeight');
        EventMgr.trigger('changedTabs', { tabs: tabs });
      },
      /**
       * close tab's group
       * @param {Stirng} tabId closing tab
       */
      closeTabGroup = function(tabId) {
        EventMgr.trigger('closeTab', { tabId: tabId });
        if (tabs[tabId].child) {
          closeChildTab(tabs[tabId].child);
        }
        if (tabs[tabId].parent) {
          closeParentTab(tabs[tabId].parent);
        }
        if (tabId !== 'tab0') {
          tabs[tabId].close();
          delete tabs[tabId];
          EventMgr.trigger('closeTabEvent', { tabId: tabId });
        }
      },
      /**
       * close tab's parent
       * @param {String} tabId closing tab parent (will remove)
       */
      closeParentTab = function(tabId) {
        EventMgr.trigger('closeTabEvent', { tabId: tabId });
        if (tabs[tabId].parent) {
          closeParentTab(tabs[tabId].parent);
        }
        tabs[tabId].close();
        delete tabs[tabId];
      },
      /**
       * close tab's child
       * @param {Stirng} tabId closing tab child (will remove)
       */
      closeChildTab = function(tabId) {
        EventMgr.trigger('closeTabEvent', { tabId: tabId });
        if (tabs[tabId].child) {
          closeChildTab(tabs[tabId].child);
        }
        tabs[tabId].close();
        delete tabs[tabId];
      },
      //close all tabs
      closeAllTabs = function(e) {
        if (tabs) {
          for (var key in tabs) {
            if (tabs.hasOwnProperty(key)) {
              if (key !== 'tab0') {
               closeTab(e, key);
              }
            }
          }
        }
      },
      //close all tabs expect active
      closeOthersTabs = function(e) {
        if (tabs) {
          var actTabId = $('.tab-content_st_active').attr('data-tabid'),
              actParentTabId = tabs[actTabId].gParent ? tabs[actTabId].gParent : actTabId;
           for (var key in tabs) {
            if (tabs.hasOwnProperty(key)) {
              if (key !== 'tab0' && tabs[key].hType === 'parent' && key !== actParentTabId) {
               closeTab(e, key);
              }
            }
          }
        }
      },
      //back btn handler
      backBtnHandler = function(e, data) {
        e.preventDefault();
        var tabId, parentId, selid = [],
            self = $(this),
            plid = filterXSS.friendlyAttrValue(self.parents('.toolbar').attr('data-plid')|| ''),
            isReport = self.closest('.tab-content').attr('data-report') === 'report';
        if (data) {
          tabId = data;
        } else {
          tabId = this.getAttribute('rel');
        }
        selid.push(plid);
        parentId = tabs[tabId].parent;
        if (App.Dom.hasClass(this, 'updatetab')) {
          var pos = plid.lastIndexOf('/'),
              url = pageInfo.url,
              parent = null,
              targetId = tabId,
              funcName = (this.getAttribute('data-url')).replace('func=', ''),
              param = {};
          param.func = funcName;
          if (pos !== -1) {
            plid = plid.substring(0, pos);
            pos = plid.lastIndexOf('/');
            if (pos === -1) {
              param.elid = plid;
            } else {
              param.plid = plid.substring(0, pos);
              param.elid = plid.substr(pos + 1);
            }
          }
          EventMgr.trigger('ajaxRequest', {
            url: url,
            param: param,
            invar: { parent: parent, targetTabId: targetId, iType: 'replace', __src: 'toolbarAction' },
            type: 'get',
            outtype: 'json',
            trfunc: 'ajaxResponse',
            failfunc: 'failCommonAjaxResponse',
            queue: 'noqueue' });
          EventMgr.trigger('tabLoading', { tabId: tabId });
        } else {
          closeTab.apply(this, [e, tabId, 'backBtn']);
          if (parentId && !isReport) {
            EventMgr.trigger('reloadTab', {
              tabId: parentId,
              __src: 'backBtn',
              selid: selid,
              filter: true });
            EventMgr.trigger('tabLoading', { tabId: parentId });
          }
        }
      },
      //update tab by autoupdate
      updateTab = function(e, data) {
        var tabId = data.tabId,
            delay = data.delay,
            selid;
        if (activeTab !== tabId) {
          if (tabs[tabId] !== undefined && tabs[tabId].autoupdate) {
            setTimeout(function(tabId, delay) {
              return function() {
                EventMgr.trigger('updateTab', { tabId: tabId, delay: delay });
              };
            } (tabId, delay), delay * 1000);
            tabs[tabId].autoupdate = true;
          }
        } else {
          selid = true;
          EventMgr.trigger('reloadTab', {
            tabId: tabId,
            __src: 'autoUpdate',
            selid: selid,
            filter: true });
        }
      },
      //stop autoupdate by click button
      stopAutoUpdate = function(e) {
        e.preventDefault();
        var tabId = this.getAttribute('data-tabid');
        if (tabs[tabId]) {
          tabs[tabId].autoupdate = false;
          clearTimeout(tabs[tabId].timeId);
          App.Dom.removeClass(this, 'i-list-icon__stop');
          App.Dom.addClass(this, 'b-elem_style_gracescale');
        }
      },
      //get elid selected elements
      getSelectedElems = function(tabId) {
        var selid = [],
            elid;
        $('#cont-' + tabId + ' .list_table tr.selected:not(".filtred")')
            .each(function() {
              elid = this.getAttribute('data-elid');
              selid.push(elid);
            });
        return selid;
      },
      getScrollTop = function(tabId) {
        var elem = App.Dom.byId('ltwr-' + tabId + '-scrollbar-handler'),
            top = 0;
        if (elem) {
          top = parseFloat(elem.style.top, 10);
        }
        return top;
      },
      //render table
      //return with unopenned <div>,
      // for external usage need to add unclosed <div>
      renderTable = function(args) {
        var keyVar,
            headers = args.headers,
            headersName = {},
            tableHead, tableBody, output;
        /* jslint forin: true */
        for (keyVar in headers) {
          headersName[headers[keyVar].name] = {
            type: headers[keyVar].type,
            hidden: headers[keyVar].hidden ? true : false
          };
        }
        args.headersName = headersName;
        tableHead = renderTableHeader(args);
        tableBody = renderTableBody(args);
        output = tableHead.output;
        output += tableBody;
        if (args.sbar) {
          output += '<div class="bottom-bar">';
          output += tableHead.sBar;
        }
        return output;
      },

      renderTableHeader = function(args) {
        var output = '',
            dHeader = '',
            sBar = '',
            tabId = args.tabId,
            headers = args.headers,
            props = args.props,
            elKeyName = args.elKeyName || args.elKey,
            elKey = args.elKey,
            colLen = headers.length,
            keyVar, header, className, triangle, thAttr, divAttr, rowHandler,
            dataSorttype, text, total, first;

        output += '<table class="list_table init b-list__table_type_body" id="lt-' + tabId + '">' +
            '<thead><tr>';
        dHeader += '<table id="sort_table-' + tabId +
            '" class="sort_table b-list__table_type_head">' +
            '<thead class="1"><tr>';
        sBar += '<table id="statusbar-' + tabId +
            '" class="statusbar b-list__table_type_footer">' +
            '<tbody class="1"><tr>';
        /* jslint forin: true */
        for (keyVar in headers) {
          header = headers[keyVar];
          //check for only data diagram col
          if (header && header.hidden) {
            continue;
          }
          className = header.hint ? ' hint ' : '';
          className += header.align ? ' align-' + header.align : '';
          if (header.minimize) {
            className += ' i-minimize-col ';
          }
          triangle = '';
          first = (keyVar - 0 === 0);
          thAttr = ' data-colname="' + header.name + '" ';
          divAttr = ' data-colname="' + header.name + '" ';
          divAttr += ' data-coln="' + keyVar + '" ';
          thAttr += header.total ? ' data-type="' + header.type + '" ' : '';
          thAttr += header.nestedreport ?
              ' data-nestedreport="' + header.nestedreport + '" ' : '';
          thAttr += header.nestedlist ?
              ' data-nestedlist="' + header.nestedlist + '" ' : '';
          thAttr += header.nestedlistBlank ?
              ' data-nestedlist-blank="true" ' : '';
          thAttr += header.editform ?
              ' data-editform="' + header.editform + '" ' : '';
          header.hint = header.hint ?
              App.u.escapeQuote(header.hint) : undefined;
          thAttr += header.hint ? ' data-hint="' + header.hint + '" ' : '';
          thAttr += header.width ? ' width="' + header.width + '"' : '';
          //resize col handler
          rowHandler = (keyVar - 0 !== 0) ?
              '<div class="rowHandler"><div class="rowLine1"></div>' +
                  '<div class="rowLine2"></div></div>' : '';
          thAttr += header.edit ? ' data-edit-func="' + header.edit + '" ' : '';
          if (elKey === header.name) {
            className += ' keyfield ';
          }
          if (elKeyName === header.name) {
            className += ' keynamefield ';
          }
          if (first) {
            className += 'first ';
            text = pageInfo.selected + ' - 1';
          } else {
            text = '';
          }
          if (colLen - 1 === keyVar) {
            className += 'last';
          }
          //sorting cols
          if (header.sort && !args.band) {
            className += ' td_sort i-tip-target_st_sort i-tip-target_st_msort';
            dataSorttype = header.sort;
          } else if (header.sort && args.band) {
            className += ' td_client_sort i-tip-target_st_sort i-tip-target_st_msort';
            dataSorttype = header.sort;
          }
          divAttr += dataSorttype ? ' data-sorttype="' + dataSorttype + '" ' : '';
          //sorted col
          if (header.sorted) {
            if (String(header.sorted).match(/\+/)) {
              //asc
              triangle = '<div class="triangl-bot triangle"></div>';
            } else {
              //desc
              triangle = '<div class="triangl-top triangle"></div>';
            }
            if (args.sortedCount > 1) {
              triangle += '<div class="b-sort-table__sort-order">' +
                  String(header.sorted).charAt(1) + '</div>';
            }
            divAttr += 'sorting="' + header.sorted + '"';
          } else {
            triangle = '<div class="triangle"></div>';
          }

          triangle += '<div class="filter-icon hint"  data-hint=""></div>';
          //check for development flag
          if (devMode) {
            triangle += '<a href="#" class="devel-link-settings devel-link-settings--col" data-elid="' + header.name + '" data-tabid="' + tabId + '"></a>';
            triangle += '<a href="#" class="devel-link-delete devel-link-delete--col" data-elid="' + header.name + '" data-name="' + header.pName + '" data-tabid="' + tabId + '"></a>';
            if (first) {
              triangle += '<a href="#" class="devel-link-add devel-link-add--col"  data-tabid="' + tabId + '"></a>';
            }
          }

          if (header.type === 'button') {
            for (keyVar in header.confirm) {
              if (header.confirm[keyVar] !== '') {
                divAttr += ' data-confirm-' + keyVar + '="' +
                    header.confirm[keyVar] + '" ';
              }
            }
          }
          //@todo warning!!! diff html
          output += '<th  class="' + className + '" ' + thAttr + '>' +
              '<div class="ovf" ' + divAttr +'><span class="data-wrapper" data-mn="' + header.name + '" data-fn="' + args.func + '">' +
              header.pName + '</span>' + triangle +  '</div> ' + rowHandler + '</th>';
          dHeader += '<td  class="' + className + '" ' + thAttr + '>' +
              '<div class="ovf"  ' + divAttr + '><span class="data-wrapper" data-mn="' + header.name + '" data-fn="' + args.func + '">' +
              header.pName + '</span>' + triangle +  '</div> ' + rowHandler + '</td>';
          //row selected
          if (keyVar - 0 === 0) {
            sBar += '<td ' + thAttr + '>' +
                '<div class="ovf"><span class="sb-result sb-result_index_0 sb-result_st_active" data-mn="msg_total" data-fn="desktop">' +
                pageInfo.total + ': ' + args.pager.pageElems +
                '</span><span class="sb-selected sb-selected_index_0" data-mn="msg_selected" data-fn="desktop">' + pageInfo.selected +
                ': 1</span></div></td>';
          } else {
          //count total row
            if (header.total !== '') {
              //check for type props or not
              if (typeof header.total === 'object') {
                total = renderPropsStat(header.total, props);
                className += ' data';
              } else {
                total = header.total;
                className += ' data';
              }
            } else {
              total = '';
              className += ' empty';
            }

            sBar += '<td ' + thAttr + '>' +
                '<div class="ovf">' +
                '<span class="sb-result sb-result_st_active sb-result_index_' + keyVar + '">' + total + ' </span>' +
                '<span class="sb-selected sb-selected_index_' + keyVar + '">' + text + '</span></div></td>';
          }
        }

        output += '</tr></thead>';
        dHeader += '</tr></thead></table>';
        output = dHeader + output;
        sBar += '</tr></thead></table>';

        return {
          output: output,
          sBar: sBar };
      },

      renderTableBody = function(args) {
        var output = '<tbody>',
            plid = args.plid ? ' data-plid="' + filterXSS.safeAttrValue('div', 'data-plid', args.plid) + '" ' : '',
            keyVar, contentItem, elid, className, curElKeyName, curElKey,
            id, hint, attr, len,
            headers = args.headers,
            elKeyName = args.elKeyName || args.elKey,
            elKey = args.elKey,
            ii = 0,
            content = args.content;
        args.defProp = args.props ? findDefProp(args.props) : null;
        if (args.backBtn) {
          len = args.headers.length;
          output += '<tr class="back-btn"><td colspan="' + len + '">' +
              '<div class="back-btn-row hint" data-tabid="' + args.tabId + '" >' +
              '<div class="hint back-btn-row-hint" data-hint="' +
              App.u.escapeQuote(App.Common.msg.hintBack) + '"></div></td></tr>';
          ii++;
        }
        //render tbody
        /* jslint forin:true */
        for (keyVar in content) {
          contentItem = content[keyVar];
          elid = '';
          className = '';
          curElKeyName = '';
          curElKey = '';
          ii++;
          rowId++;
          id = '';
          hint = '';
          attr = plid;
          attr += ' id="i-' + rowId + '" ';
          //data-index for detect row in model
          attr += ' data-index="' + keyVar + '"';
          if (elKey !== undefined && contentItem[elKey] !== undefined) {
            curElKey = contentItem[elKey].v.replace(/"/g, '&quot;');
            attr += ' data-elid="' + curElKey + '" ';
            elid = contentItem[elKey].v;
          }
          if (elKeyName !== undefined && contentItem[elKeyName] !== undefined) {
            curElKeyName = contentItem[elKeyName].v.replace(/"/g, '&quot;');
            attr += ' data-elkeyname ="' + curElKeyName + '" ';
          }
          if (ii % 2 === 0) {
            className = ' even ';
          } else {
            className = '';
          }
          if (contentItem._ovcol) {
            className += ' ' + contentItem._ovcol + ' ';
          }
          if (contentItem._ovhide) {
            attr += ' data-hide="' + contentItem._ovhide + '" ';
            className += ' toolbtn-hide ';
          }
          if (contentItem._ovremove) {
            attr += ' data-remove="' + contentItem._ovremove + '" ';
            className += ' toolbtn-remove ';
          }
          if (contentItem._ovshow) {
            attr += ' data-show="' + contentItem._ovshow + '" ';
            className += ' toolbtn-show ';
          }
          if (args.warning) {
            if (args.warning[elid] !== undefined) {
              if (args.warning[elid].msg !== undefined) {
                className += ' warning';
                hint = App.u.escapeQuote(args.warning[elid].msg);
                delete args.warning[elid];
              }
            }
          }

          className += ' b-list__table-row';
          output += '<tr class="' + className + '"' + attr + ' >';
          output += buildRow(contentItem, args, hint);
          output += '</tr>';
        }
        if (args.warning) {
          EventMgr.trigger('nextEventBind', {
            event: 'appendList',
            tData: args.warning,
            cb: function(e, data) {
              if (e.data) {
                var tabId = data.tabId,
                    bannerText = $('#cont-' + tabId +
                        ' .b-message__text_warning').get(0),
                    warning = e.data,
                    extraText = '';

                if (bannerText) {
                  for (var key in warning) {
                    if (warning[key]) {
                      extraText += warning[key].msg + '<br/>';
                    }
                  }
                  if (extraText) {
                    bannerText.innerHTML = extraText;
                  }
                  EventMgr.trigger('updateScroll', { id: 'cont-' + tabId });
                }
              }
            }
          });
        }
        output += '</tbody>';
        output += buildLastRow(args);
        output += '</table>';
        output += '</div>'; //close table div from template
        return output;
      },

      //render Row
      buildRow = function(row, args, hint) {
        var headers = args.headersName,
            output = '',
            elKey = args.elKey,
            i = 0, ind = 0,
            warning, color, keyVar, usage, type, currentRow, editableClass,
            contentClassName, colNameClass,
            contentAttrs,
            attr, className, value, id, per, buttons, j, button, func, form, name,
            btnMsg, onlyForm;
        /* jslint forin:true */
        for (keyVar in headers) {
          //check for only diagram col
          if (headers[keyVar] && headers[keyVar].hidden) {
            continue;
          }
          i++;
          warning = '';
          className = '';
          editableClass = '';
          colNameClass = 'b-list__table-col_name_' + keyVar;
          color = '';
          value = '';
          attr = '';
          usage = '';
          per = '';
          contentAttrs = '';
          buttons = '';
          onlyForm = false;
          if (elKey === keyVar) {
            className += ' key-field ';
          }
          if (i === 1 && hint !== '' && hint !== undefined) {
            warning = '<div class="warning-img hint" data-hint="' + hint + '"></div>';
          }
          currentRow = row[keyVar];
          if (args.headers[ind].edit) {
            editableClass += ' editable ';
          }
          if (args.testMode) {
            editableClass += ' i-testmode-field ';
          }
          if (args.headers[ind].fastFilter && !args.blockId) {
            editableClass += ' i-filter-field ';
          }
          contentClassName = (args.headers[ind].nestedlist !== undefined && !currentRow.nestedlist) ?
              ' i-nestedlist b-list__table-col-content_type_link' : '';
          contentClassName += (args.headers[ind].editform !== undefined && !currentRow.nolink) ?
              ' i-editform b-list__table-col-content_type_link ' +
                  'b-list__table-col-content_style_underline' : '';
          if (currentRow !== undefined) {
            type = headers[keyVar].type;
            //data/prop/money
            if (type === 'data' || type === 'prop' || type === 'money') {
              if (currentRow.color !== undefined) {
                className += ' status-' + currentRow.color;
              }
              if (args.headers[ind].acthint) {
                className += ' acthint ';
              }
              value = args.headers[ind].noescaping ?
                  window.filterXSS(window.htmlDecode(currentRow.v)) : currentRow.v;
              id = currentRow.id ? window.filterXSS(window.htmlDecode(currentRow.id)) : null;
              contentClassName += args.headers[ind].wrap ? ' b-list__table-col-content_is_wrap ' : '';
              className += (args.headers[ind].nestedreport !== undefined) ?
                  ' nestedreport ' : '';
              className += (args.headers[ind].align) ?
                  ' align-' + args.headers[ind].align : '';
              attr += (currentRow.link) ?
                  ' data-child-id="' + args.oTabId + '-' +
                      currentRow.childid + '" ' : '';
              attr += (currentRow.elid) ?
                  ' data-elid="' + currentRow.elid + '" ' : '';
              contentAttrs += id ? ` data-v-id="${id}"` : '';
              contentAttrs += currentRow.orig ? 'data-orig="' + currentRow.orig + '"' : '';
              if (currentRow.props) {
                attr += currentRow.psp ?
                    ' data-stat="' + currentRow.psp + '" ' : '';
                output += `
                  <td>
                    <div class="ovf i-text-content ${editableClass}">
                      ${warning}
                      <span class="data-wrapper " ${attr}>
                        ${makeProps(currentRow, args, row)}
                      </span>
                      <span class="data middle ${className}">
                        <span class="b-list__table-col-content ${contentClassName}" ${contentAttrs}>${currentRow.v}</span>
                      </span>
                    </div>
                  </td>`;
              } else {
                output += `
                  <td class="first ${colNameClass}">
                    ${warning}
                    <span class="i-text-content data-wrapper data ${className} ${editableClass}" ${attr}>
                      <span class="b-list__table-col-content ${contentClassName}" ${contentAttrs}>${value}</span>
                    </span>
                  </td>`;
              }
            //indicator
            } else if (type === 'indicator') {
              if (currentRow.u && currentRow.l) {
                if (currentRow.color !== undefined) {
                  className = ' status-' + currentRow.color;
                }
                if (parseInt(currentRow.l, 10) !== 0) {
                  if (parseInt(currentRow.u, 10) === 0) {
                    per = 0;
                  } else {
                    per = Math.round((currentRow.u / currentRow.l) * 100);
                    if (per === 0 || !per) { per = 0; }
                    per = per > 100 ? 100 : per;
                  }
                  usage = '<div class="used-wr">' +
                      '<div class="used" style="width:' + per + '%"></div></div>';
                }
              }
              output += '<td class="first">' +
                  '<span class="i-text-content data-wrapper data ' + className + editableClass + '">' +
                   warning +
                  '<span class="b-list__table-col-content ' + contentClassName + '">' +
                      window.htmlDecode(currentRow.v) + '</span>' +
                    '</span>' +
                  usage + '</td>';
            //indicator brackets
            } else if (type === 'indicatorbrackets') {
              if (currentRow.color !== undefined) {
                className = ' status-' + currentRow.color;
              }
              value = currentRow.l || '';
              if (currentRow.u !== '') {
                value += ' (<span class="' + className + '">' + currentRow.u + '</span>)';
              }
              output += '<td class="first">' +
                  '<span class="i-text-content data-wrapper data">' +
                  warning +
                  '<span class="b-list__table-col-content ' + contentClassName + '">' +
                  value + '</span>' +
                  '</span></td>';
            //buttons
            } else if (type === 'button') {
              for (j = 0; j < currentRow.buttons.length; j++) {
                button = currentRow.buttons[j];
                if (button !== '') {
                  name = button;
                  //for billing dashboard show msg for btn from col & open only form
                  onlyForm = (args.btn[name].msgsrc && row[args.btn[name].msgsrc]);
                  attr = '';
                  if (!onlyForm) {
                    attr += ' data-func="func=' + args.func + '" ';
                  }
                  attr += ' data-type="' + args.btn[button].type + '" ';
                  attr += ' data-name="' + button + '" ';
                  type = args.btn[button].type;
                  if (onlyForm) {
                    btnMsg = row[args.btn[name].msgsrc].v;
                  } else {
                    btnMsg = args.btn[name].name;
                  }
                  if (type === 'edit' ||
                      type === 'group' ||
                      type === 'editlist') {
                    attr += ` data-form="func=${args.btn[button].func}&elid=${row[args.elKey].v}" `;
                  }

                  buttons += `<a href="#" ${attr} class="dashboard-button">${btnMsg}</a> `;

                  //buttons += args.btn[currentRow.buttons[i]].name + ' ';
                }
              }
              output += `<td><span class="data-wrapper">${buttons}</span></td>`;
            }
          } else {
            output += `<td><span class="data-wrapper ${className}"></span></td>`;
          }
          ind++;
        }
        return output;
      },

      /**
       * Рендерем props и xprop для статусбара
       * @param total
       */
      renderPropsStat = function(total, props) {
        var stat = '',
            i = 0,
            keyVar,
            cumma = '',
            propName,
            prop,
            sprite = false,
            extension,
            className = '';
        /* jslint forin:true */
        for (keyVar in total) {
          if (i !== 0) { cumma = ',</span> '; } else { cumma = ''; }
          if (total[keyVar] - 0 === 0) {
            className = 'no';
          } else {
            className = 'default';
          }
          prop = props[keyVar];
          sprite = prop.style === '';
          if (!sprite) {
            extension = prop.animated ? '.gif' : '.png';
            stat += cumma + '<span class="' + className + '"><img class="props" src="' + pageInfo.commonDir  + 'img/' + prop.onImg + extension + '"/>' + total[keyVar];
          } else {
            stat += cumma + '<span class="' + className + '"><div class="props s-icon s16x16 ' + prop.onImg + ' i-total-prop-' + keyVar + '"></div>' + total[keyVar];
          }
          i++;
        }
        stat += '</span>';
        return stat;
      },
      //render props
      makeProps = function(row, args, rows) {
        var output = '',
            propName, func, type, className, hide,
            hint, attr, props = row.props,
            len = props.length, i;
        for (i = 1; i < len; i++) {
          if (props[i].n) {
            propName = props[i].n;
            hint = App.u.escapeQuote(args.props[propName].hint);
            func = args.props[propName].func;
            type = args.props[propName].type;
            hide = args.props[propName].hide;
            attr = '';
            className = '';
            if (func && checkFunc(hide, rows)) {
              attr += ' data-func="' + func + '" ';
              attr += ' data-type="' + type + '" ';
              attr += ' data-value="' + props[i].v.replace(/"/g, '&quot;') + '" ';
              className += 'controlprop';
              if (type === 'group') {
                attr += ' data-confirm="' + args.props[propName].confirm + '" ';
              }
              if (args.props[propName].cgi) {
                attr += ' data-cgi="' + args.props[propName].cgi + '" ';
              }
            }
            attr += 'data-name="' + args.props[propName].name + '"';
            // I don't why this rules
            //if (args.props[propName].name !== propName) {
            //check for don't rewrite func attr
            if (!func) {
              attr += ' data-value="' + props[i].v.replace(/"/g, '&quot;') + '" ';
            }

            if (args.props[propName].acthint) {
              className += ' acthint';
            } else {
              className += ' hint';
            }
            if (hint !== '' && hint) {
              hint = App.u.escapeQuote(hint.replace('__value__', props[i].v));
              attr += ' data-hint="' + hint + '" ';
            } else if (props[i].v !== '' && props[i].v) {
              attr += ' data-hint="' + App.u.escapeQuote(props[i].v) + '" ';
            }
            if (args.props[propName].style) {
              attr += args.props[propName].style;
            }
            if (args.props[propName].animated) {
              output += '<img class="props ' + className + ' " ' + attr + ' src="' + pageInfo.commonDir  + 'img/' + args.props[propName].onImg + '.gif"/>';
            } else {
              output += '<div class="s-icon s16x16 props ' + className + ' ' + args.props[propName].onImg + '" ' + attr + '></div>';
            }
          }
        }
        return output;
      },
      //check for hide rule for function
      checkFunc = function(hide, rows) {
        if (!hide) { return true; }
        var l = hide.length,
            name, value;
        while (l--) {
          name = hide[l].n;
          value = hide[l].v;
          if (rows[name] && (rows[name].v === value)) {
            return false;
          }
        }
        return true;
      },
      //find default prop
      findDefProp = function(props) {
        var keyVar;
        for (keyVar in props) {
          if (props[keyVar].defImg) {
            return keyVar;
          }
        }
        return null;
      },
      //update total report for convert col
      updateTotalWithConvertReport = function(e, data) {
         var id = data.id;
         $('#' + id).html(data.convertValue);
      },

      buildLastRow = function(args) {
        var headers = args.headers,
            colCount = headers.length,
            tFoot = '<tfoot><tr>',
            content = args.content,
            total, hint = '', msg = App.Common.msg,
            align = '',
            name,
            id;

        for (var i = 0; i < colCount; i++) {
          if (headers && headers[i] && headers[i].hidden) {
            continue;
          }
          total = '';
          id = '';
          align = 'align-' + (headers[i].align || '');
          if (headers[i].total === 'sum') {
            name = headers[i].name;
            total = sumRows(name, content);
            hint = msg.totalSum || '';
          } else if (headers[i].total === 'sumsuffix') {
            hint = msg.totalSum || '';
            total = sumRowsSuffix(name, content, headers[i].convert);
            name = headers[i].name;
          } else if (headers[i].total === 'count') {
            total = content.length;
            hint = msg.totalCount || '';
          } else if (headers[i].total === 'avg') {
            name = headers[i].name;
            total = avgRows(name, content);
            hint = msg.totalAvg || '';
          }

          if (headers[i].convert && total !== '') {
            id = args.tabId + '-' + name;
            EventMgr.trigger('ajaxRequest', {
               param: {
                 func: 'convert',
                 name: headers[i].convert,
                 value: total
               },
               invar: {
                 id: id
               },
               type: 'get',
               outtype: 'json',
               trfunc: 'updateTotalWithConvertReport',
               failfunc: 'failMenuAjaxResponse',
               queue: 'multiload'
            });
          }
          tFoot += '<td id="' + id + '" class="hint ' + align + '" data-hint="' +
            App.u.escapeQuote(hint) + '">' + total + '</td>';
        }
        tFoot += '</tfoot>';
        return tFoot;
      },

      sumRows = function(name, rows) {
        var len = rows.length,
            sum = 0, v, maxDec = 0, curDec;
        while (len--) {
          if (rows[len][name].orig) {
            v = rows[len][name].orig - 0;
          } else if ((rows[len][name].v) === '') {
            v = 0;
          } else {
            v = parseFloat(rows[len][name].v.replace(/\s/g, ''));
          }
          curDec = decimalPlaces(v);
          maxDec = curDec > maxDec ? curDec : maxDec;
          sum += v;
        }
        if (maxDec > 0) {
          sum = sum.toFixed(maxDec);
        }
        return sum;
      },

      sumRowsSuffix = function(name, rows, convert) {
        var len = rows.length,
            resultC, resultSum = '';
        while (len--) {
          resultC = App.List.dataCalc(resultC, rows[len][name]);
        }
        /* jslint forin: true */
        for (var key in resultC) {
          if (resultSum !== '') {
            resultSum += '; ';
          }
          if (convert === 'money') {
            resultSum += App.Tabs.moneyFormat(resultC[key]) +
                ' ' + key;
          } else {
            resultSum += resultC[key] + ' ' + key;
          }
        }
        return resultSum;
      },

      avgRows = function(name, rows) {
        var len = rows.length,
            lenForLoop = len,
            sum = 0,
            avg, v;
        while (lenForLoop--) {
          v = ((rows[lenForLoop][name].v) === '') ?
              0 : parseFloat(rows[lenForLoop][name].orig || rows[lenForLoop][name].v);
          sum += v;
        }
        avg = sum / len;
        if (avg.toFixed) { avg = avg.toFixed(2); }
        return avg;
      },

      moneyFormat = function(num) {
        var strNum = '' + parseFloat(num).toFixed(2),
            parts = strNum.split('.'),
            head = parts[0] || '',
            tail = parts[1] || '',
            s = [];
        if (head) {
          var l = head.length,
              p = Math.floor(l / 3);
          for (var i = 0; i < p; i++) {
            s.push(head.substr(l - (i * 3) - 3, 3));
          }
          s.push(head.substr(0, (l % 3)));
          s.reverse();
        }
        if (s.length > 0) {
          return s.join(' ') + '.' + tail;
        } else {
          return num;
        }
      },

      decimalPlaces = function(num)  {
        var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
        if (!match) { return 0; }
        return Math.max(
            0,
            // Number of digits right of decimal point.
            (match[1] ? match[1].length : 0),
            // Adjust for scientific notation.
            - (match[2] ? +match[2] : 0));
      },
      /**
       * get Image for group
       * check for selficon, else get icon from menu group
       * @param {String} id
       * @param {String} name
       * @param {String} theme
       * @param {Boolean} style
       */
      getMainImg = function(id, name, theme, style) {
        var elem, output, pElem, extImg;
        elem = App.Dom.byId('l-' + id);
        pElem = $(elem).parent();
        extImg = pElem.attr('data-img');
        if (!name) {  //use this way because id can have dot.
          name = pElem.attr('data-group');
        }
        if (name && name.indexOf(".") != -1) {
          output = '';
        } else {
          output = 'mb-' + name;
        }

        if (style && extImg) {
          if (name && name.indexOf(".") != -1) {
             output = 'style="background: url(' + name + ') left top no-repeat"';
          } else {
             var prefix = 'img/mb-',
                 suffix = '.png';
             output = 'style="background: url(' +
                      theme + prefix + name + suffix + ') left top no-repeat"';
          }
        }
        if (!extImg && style) {
          output = '';
        }

        //output = theme + prefix + name + suffix;
        return output;
      },

      getGroupIcon = function(id) {
        var elem, pElem, output, extImg;
        id = String(id).replace(/\./g, '_');
        elem = App.Dom.byId('l-' + id);
        pElem = $(elem).parent();
        name = pElem.attr('data-group');
        extImg = pElem.attr('data-img');

        if (extImg) {
          output = 'class="subtab__text_for_pin s16x16 s-icon" style="background: url(/manimg/common/img/m-' + name + '.png) left top no-repeat"';
        } else {
          output = 'class="subtab__text_for_pin s16x16 s-icon m-' + name + '"';
        }
        return output;
      },

      devMode = pageInfo.devmode,

      pdfOn = pageInfo.pdfOn,

      dateTimeId,

      renderFormItem = function(item, tabId, classes) {
        var itemHTML = '';
        classes = classes || '';
        //render input text ||hidden || password
        if (item.type === 'text' ||
            item.type === 'hidden' ||
            item.type === 'color' ||
            item.type === 'password') {
          item.setvalue = item.setvalue || '';
          if (item.value) {
            item.value = App.u.escapeQuote(item.value);
          }
          if (item.test && !item.zoom) {
            classes += ' test';
          } else if (item.test && item.zoom) {
            classes += ' testzoom';
          }
          //render help buttons
          if (item.passwd) {
            itemHTML += '<div class="b-input-btn b-input-btn_type_passwd hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintGenBtn) + '"' +
                ' data-control-field="' + item.name + '"></div>';
          }
          if (item.showpwd) {
             itemHTML += '<div class="' + (item.passwd ? 'b-input-btn_is_left' : '') + ' b-input-btn b-input-btn_type_showpwd hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintShowPwdBtn) + '"' +
                ' data-control-field="' + item.name + '"' +
                ' data-tabid="' + tabId + '"></div>';
          }
          if (item.date) {
            itemHTML += '<div class="b-input-btn b-input-btn_type_calendar hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintBtn) + '"' +
                ' data-control-field="' + item.name + '"' +
                ' data-type="' + item.date + '"></div>';
          }
          if (item.unlimit) {
            itemHTML += '<div class="b-input-btn b-input-btn_type_unlimit hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintBtn) + '"' +
                ' data-control-field="' + item.name + '"></div>';
          }
          if (item.change) {
            itemHTML += '<div class="b-input-btn b-input-btn_type_change hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintBtn) + '"></div>';
          }
          if (item.zoom) {
            itemHTML += '<div class="b-input-btn b-input-btn_type_zoom hint"' +
                ' data-hint="' + App.u.escapeQuote(item.hintBtn) + '" ' +
                'data-control-field="' + item.name + '"></div>';
            item.inputAttr = item.attr;
            item.inputClasses = classes;
            item.inputName = item.name;
            item.textareaClasses = ' b-textarea_for_zoom';
            itemHTML += templates.formItemInputWithZoom(item);

          } else if (item.type === 'password') {
            item.classes += classes;
            if (item.confirm) {
              item.confirmField = item.confirmField +
                  '-' + tabId;
              item.classes += ' b-form-confirm-field';
            } else if (item.passwd) {
              item.classes += ' b-form-passwd-field';
            }
            itemHTML += templates.formItemPassword(item);
            if (item.passwd) {
              item.pwcheck.id = tabId;
              item.pwcheck.name = item.name;
              itemHTML += templates.passwdCheck(item.pwcheck);
            } else if (item.confirm) {
              itemHTML += templates.confirmCheck(item);
            }
          } else {
            item.classes += classes;
            itemHTML += templates.formItemInput(item);
          }
          //render input@type=file
        } else if (item.type === 'file') {
          item.classes += classes;
          item.setvalue = '';
          item.value = '';
          itemHTML += templates.formItemFile(item);
        } else if (item.type === 'textarea') {
          //render textarea
          item.classes += item.editor;
          item.value = window.htmlEscape(item.value);
          itemHTML += templates.formItemTextarea(item);
          //data for plugin
          if (item.variables) {
            EventMgr.trigger('saveVarsTinyMCE', {
              name: item.name,
              tabId: tabId,
              vars: item.variables
            });
          }
        } else if (item.type === 'desc') {
          //render description
          itemHTML += templates.formItemDesk(item);
        } else if (item.type === 'htmldata') {
          //render htmldata
          itemHTML += templates.formItemHtmldata(item);
        } else if (item.type === 'select') {
          //render select
          //separate image & value for filtred value
          item.msg = window.filterXSS(item.msg);
          item.msg = item.img + item.msg;
          itemHTML += templates.formItemSelect(item);
        } else if (item.type === 'mselect') {
          //render multi select
          itemHTML += templates.formItemMSelect(item);
          if (item.msg_select_all && pageInfo && pageInfo.messages) {
            pageInfo.messages.msg_select_all = item.msg_select_all;
          }
        } else if (item.type === 'aselect') {
          //render select autocomplete
          itemHTML += templates.formItemSelectAutocomplete(item);
        } else if (item.type === 'radio') {
          if (item.hint === '') {
            item.readonly += ' nohint';
          }
          //render radio
          itemHTML += templates.formItemRadio(item);
        } else if (item.type === 'radioimg') {
          //render radio-img
          itemHTML += templates.formItemRadioImg(item);
        }
        else if (item.type === 'checkbox') {
          if (item.hint === '') {
            item.dependFields += ' nohint';
          }
          if (item.desc === '') {
            item.dependFields += ' nodesc';
          }
          itemHTML += templates.formItemCheckbox(item);
          //render slider
        } else if (item.type === 'slider') {
          //@TODO change with value
          itemHTML += templates.formItemSlider(item);
          //render mgrview
        } else if (item.type === 'mgrview') {
          itemHTML += templates.formItemMgrview({
            tabId: tabId, theme: pageInfo.theme });
          //render textdata
        } else if (item.type === 'textdata') {
          item.value = window.htmlDecode(item.value);
          itemHTML += templates.formItemTextData(item);
          //render tree
        } else if (item.type === 'tree') {
          itemHTML += renderTree(item, tabId);
        } else if (item.type === 'ticket') {
          itemHTML += templates.formItemTicket(item);
        } else if (item.type === 'link') {
          itemHTML += templates.formItemLink(item);
        } else if (item.type === 'frame') {
          itemHTML += templates.formItemFrame(item);
        } else if (item.type === 'datetime') {
          var d = App.u.parseDate(item.value);
          item.difftime = (new Date().getTime() - d.getTime());
          item.value = App.u.formatDateTime(d.getTime());
          itemHTML += templates.formItemDateTime(item);
          dateTimeId = setInterval(function(tabId, name) {
            return function() {
              var elem = App.Dom.byId(tabId + '-' + name);
              if (!tabs[tabId] || !elem) {
                clearInterval(dateTimeId);
                return;
              }
              var dt = elem.getAttribute('data-difftime') - 0;
              elem.innerHTML = App.u.formatDateTime(new Date().getTime() - dt);
            };
          } (tabId, item.name), 500);

        } else if (item.type === 'listfilter') {
          itemHTML += templates.formListFilterWrapper({ name: item.name, id: item.id, content: templates.formListFilter(item)});
        } else if (item.type === 'captcha') {
          itemHTML += templates.formItemCaptcha(item);
          EventMgr.trigger('appendCaptcha', { id: tabId + '-' + item.name });
        }
        return itemHTML;
      },
      //render form items
      renderFormItems = function(form, tabId) {
        var length = form.length,
            i, pages = '', formHtml, formItemsLen, j, formItems,
            formItemLen, k, formItem, formRow, classes, valuesForm = {},
            sourceForm = {};
        for (i = 0; i < length; i++) {
          formHtml = {
            name: form[i].name,
            title: '',
            content: '',
            classes: '',
            withList: form[i].withList,
            display: form[i].collapsed ? 'none' : 'block',
            collapsed: form[i].collapsed,
            hide: form[i].hide ? form[i].hide : {},
            show: form[i].show ? form[i].show : {},
            tabId: tabId
          };
          if (form[i].title !== '') {
            //render title Page
            formHtml.title = templates.formPageTitle({
              title: form[i].title,
              name: form[i].name,
              id: form[i].name,
              type: 'page',
              collapsed: form[i].collapsed,
              hintCollapse: pageInfo.pageCollapse,
              hintExpand: pageInfo.pageExpand,
              blockType: '',
              theme: pageInfo.theme,
              reload: false });
          }
          if (!form[i].formItems) { continue; }
          formItemsLen = form[i].formItems.length;

          formItems = form[i].formItems;
          //foreach for fields
          for (j = 0; j < formItemsLen; j++) {
            formItemLen = formItems[j].length;
            formItem = formItems[j];
            //foreach for elems
            for (k = 0; k < formItemLen; k++) {
              if (formItem[k].skip) {
                continue;
              }
              sourceForm[formItem[k].name] = formItem[k];
              //make form model for watching
              valuesForm[formItem[k].name] = {
                'defValue': formItem[k].value,
                'isChanged': false,
                'value': formItem[k].value,
                'label': formItem[k].label || formItem[k].desc || false
              };
              if (formItem[k].type === 'textarea') {
                if (formItem[k].value === '\n') {
                  formItem[k].value = '';
                  valuesForm[formItem[k].name].value = '';
                  valuesForm[formItem[k].name].defValue = '';
                }
              }
              formRow = {};
              formRow.first = '';
              formRow.second = '';
              formRow.third = '';
              formRow.hint = '';
              formRow.classes = '';
              formRow.hide = formItem[k].hide || {};
              formRow.show = formItem[k].show || {};
              formRow.id = formItem[k].name + '-' + form.id;
              formRow.desc = '';
              formRow.error = formItem[k].error ? formItem[k].error : '';
              formRow.colspan = formItem[k].error ? 'colspan="2"' : '';
              formRow.fname = formItem[k].name;
              formRow.label = formItem[k].label;
              formRow.tabId = form.id;
              formRow.devMode = devMode;
              formRow.testMode = form.testMode;
              formItem[k].id = form.id;
              //render label
              if (formItem[k].label) {
                formRow.first += templates.formItemLabel({
                  label: formItem[k].label,
                  img: formItem[k].l_img || '',
                  required: formItem[k].required,
                  tabId: form.id,
                  func: form.func,
                  id: formItem[k].name,
                  devMode: devMode });
              } else if (formItem[k].type !== 'textdata') {
                formRow.first += '<div></div>';
              }
              //render hint
              if (formItem[k].hint !== '' && formItem[k].hint) {
                formRow.third += App.u.escapeQuote(formItem[k].hint);
                if (formItem[k].shadowHint) {
                  formRow.third += " <span class='hint-shadow'>" +
                     App.u.escapeQuote(formItem[k].shadowHint) +
                      '</span>';
                  formRow.hint += ' shadow ';
                }
                formRow.hint += 'field-help_available_yes';
              }
              if (formItem[k].setvalue) {
                var timeout = parseInt(formItem[k].setvalue, 10),
                    timeId;
                if (!isNaN(timeout)) {
                  /* jslint loopfunc:true*/
                  timeId = setInterval(function(tabId, name) {
                    return function() {
                      if (!tabs[tabId]) {
                        clearInterval(timeId);
                      }
                      EventMgr.trigger('forceSetValues', {
                        tabId: tabId, name: name
                      });
                    };
                  } (tabId, formItem[k].name), timeout * 1000);
                }
              }
               else if (formItem[k].type === 'textarea') {
                if (formItem[k].quote) {
                  formRow.classes += ' b-form-row_with_quote ';
                }
                formItem[k].third = formRow.third;
                formItem[k].error = formRow.error;
              }
              //@todo move to template
              if (formItem[k].desc && formItem[k].desc !== '') {
                formRow.desc = formItem[k].desc || '';
                //check for checkbox desc
                if (formItem[k].type === 'checkbox') {
                  if (formItem[k].desc !== '') {
                    formRow.desc = '';
                  }
                }
                formRow.descName = formItem[k].descName || '';
              }
              if (formItem[k].type === 'checkbox' && !formItem[k].desc) {
                formRow.classes += ' row-with-no-desc ';
              }
              formRow.classes += ' l-form__row_type_' + formItem[k].type;
              if (formItem[k].fixed) {
                formRow.classes += ' i-form__row_fixed_yes b-form__row_fixed_yes';
              }
              if (formItem[k].error) {
                formRow.classes += ' row-error';
              }
              //check for hide/show rules
              if (formItem[k].show !== undefined) {
                if (formItem[k].shadow) {
                  formRow.classes += ' depended-shadow-s';
                } else {
                  formRow.classes += ' depended-hidden-s';
                }
              }
              //render form item
              formRow.second = renderFormItem(formItem[k], tabId, '');
              //render extra field
              if (formItem[k].hasAddition) {
                var nextFormItem = formItem[k + 1];
                if (nextFormItem) {
                  if (nextFormItem.type === 'checkbox') {
                    if (nextFormItem.desc !== '') {
                      formRow.desc = '';
                    }
                  } else if (nextFormItem.type === 'text') {
                     formRow.id = nextFormItem.name + '-' + form.id;
                  }
                  nextFormItem.id = form.id;
                  formRow.second += renderFormItem(nextFormItem, tabId, '');
                  formRow.classes += ' l-form__row_has_addition';
                  if (formItem[k].propWidth) {
                    formRow.classes += ' l-form__row_propwidth';
                  }
                  //check for error
                 if (nextFormItem.error) {
                   formRow.error = nextFormItem.error;
                   formRow.classes += ' row-error';
                   formRow.colspan = 'colspan="2"';
                 }
                }
              }
              //render form row
              //render input@type=hidden row
              if (formItem[k].type === 'hidden') {
                formHtml.content += templates.formItemRowHidden(formRow);
                //render fullwidth row
              } else if (formItem[k].fullwidth) {
                formRow.classes += ' fullwidth-row';
                formHtml.content += templates.formItemFullWidthRow(formRow);
                //render desc row
              } else if (formItem[k].formwidth) {
                formRow.classes += ' formwidth-row';
                formHtml.content += templates.formItemFormWidthRow(formRow);
                //render desc row
              } else if (formItem[k].type === 'desc') {
                formRow.third = '';
                formRow.hint = '';
                formHtml.content += templates.formItemRowDesc(formRow);
                //render row without label
              } else if (formItem[k].type === 'list') {
                formItem[k].id = form.id;
                formItem[k].formflags = form.formflags;
                formItem[k].parent = form.parent;
                formItem[k].testMode = form.testMode;
                //for btn template change type
                formItem[k].type = 'form';
                if (!(formItem[k].rows &&
                     formItem[k].rows.length === 1 &&
                     formItem[k].view === 'table')) {
                  formHtml.content += templates.formListItemRow(formItem[k]);
                }
              } else if (formRow.first === '') {
                formHtml.content += templates.formItemRowWithoutLabel(formRow);
                //render normal row
              } else {
                formHtml.content += templates.formItemRow(formRow);
              }
              if (formItem[k].plainhint) {
                var hLen = formItem[k].plainhint.length;
                //start from 1 because 1st elem empty
                for (var h = 1; h < hLen; h++) {
                  formItem[k].plainhint[h].name = formItem[k].name;
                  formHtml.content += templates.formPlainHintRow(formItem[k].plainhint[h]);
                }
              }
            }
          }
          formHtml.view = 'form';
          pages += templates.formPageWrapper(formHtml);
        }
        return {
          html: pages,
          model: valuesForm,
          source: sourceForm
        };
      },

      formGetTreeBranch = function(e, data) {
        var setvalues = data.setvalues,
            elem = data.elem,
            name = data.name,
            items = setvalues[name].tlist,
            html = renderTlist(items),
            id = data.id;
        elem.after(html);
        data.img.attr('src', data.src);
        elem.parent().addClass('loaded t-opened')
            .removeClass('collapsed loading');
        EventMgr.trigger('updateScroll', { id: id });
      },
      //render tree
      renderTree = function(items, tabId) {
        var elems = items.tlist, html,
            rows = items.rows * 18,
            id = items.name + '-' + tabId;
        html = renderTlist(elems, items.value);
        return '<div class="tree-wrapper ' + items.setvalue + ' ' + items.multiple + '" id="cont-' + id + '"  style="height:' + rows + 'px;">' +
          '<div id="'+ id +'" class="tree-inner" data-tabid="' + tabId + '">' +
            html +
          '<input data-type="tree" type="hidden" name="' + items.name + '" value="' +
            items.value +
            '" class="' + items.classes + '"id="' + items.name + '-' + tabId + '-value" data-tabid="' +
            tabId + '"/></div></div>' +
          '<div class="b-resizer" data-move-trigger="updateScroll" data-id="cont-' + id + '" data-tabid="' + tabId + '"></div>';
      },
      //render tree list
      renderTlist = function(items, value) {
        var len = items.length, i, html = '', child, className = '', selected;
        html = '<ul>';
        for (i = 0; i < len; i++) {
          child = items[i].child.length > 0;
          className = child ? 't-opened loaded' : items[i].collapsed ?
              'collapsed' : '';
          className += (len - 1 === i) ? ' last ' : '';
          selected = (items[i].key === value) ? ' selected ' : '';
          html += ' <li class="' + className + ' folder"> <div class="tree-hitarea bline"></div> <div class="tree-handler ' + selected + '"  data-val="' + items[i].key + '" ><div class="bline icon"><img src="' + pageInfo.commonDir + 'img/' + items[i].img + '.png" /></div><div class="tree-label bline">' + items[i].value + '</div></div>';
          if (child) {
            html += renderTlist(items[i].child, value);
          }
          html += '</li>';
        }
        html += '</ul>';
        return html;
      },

      renderInfoList = function(obj) {
        return templates.infoList({ rows: obj.rows, testMode: obj.testMode });
      },

      //render dashboard blocks
      renderDashboard = function(blocks) {
        var bLength = blocks.length,
            top = '',
            left = '',
            right = '',
            dashboard = '',
            contentBlock, title, param, classes, display, blockId, id,
            titleObject, contentObject, obj;
        storage.dashboard = {};
        for (var i = 0; i < bLength; i++) {
          blocks[i].name = String(blocks[i].name).replace(/\./g, '_');
          id = blocks[i].name;
          blockId = blocks[i].name;

          titleObject = {
            name: blocks[i].name,
            id: id,
            title: blocks[i].title,
            type: 'dashboard-block',
            blockType: blocks[i].type,
            theme: pageInfo.theme,
            collapsed: (blocks[i].display === 'min'),
            hintCollapse: pageInfo.pageCollapse,
            hintExpand: pageInfo.pageExpand,
            hintReload: blocks[i].hintReload,
            reload: false };
          if (blocks[i].type === 'toolbar') {
            contentBlock = templates.dashTaskbar({
              toolbar: blocks[i].toolbar });
          } else if (blocks[i].type === 'list') {
            /* jslint camelcase:false */
            param = {
              func: blocks[i].func,
              p_num: 1,
              dashboard: blocks[i].name };
            if (blocks[i].rows) {
              param.p_cnt = blocks[i].rows;
            }
            /* jslint camelcase:true */
            $.extend(param, blocks[i].params);
            storage.dashboard[blocks[i].name] = param;
            if (blocks[i].autoupdate) {
               setTimeout(function(block) {
                 return function() {
                   EventMgr.trigger('refreshDashBlock', { block: block });
                 };
               } (blocks[i]), blocks[i].autoupdate * 1000);
            }
            EventMgr.trigger('ajaxRequest', {
              url: pageInfo.url,
              param: param,
              invar: { blockId: 'block-' + blocks[i].name },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponseForDashboard',
              failfunc: 'failedAjaxResponseForDashboard',
              queue: 'noqueue' });
            contentBlock = '<div id="block-' + blockId +
                '" class="block-table" data-block-name="' + blocks[i].name +
                '" data-block-cnt="' + blocks[i].rows +
                '" data-block-pnum="1' +
                '" data-block-func="' + blocks[i].func + '">' +
                '<div class="dashboard-nodata">' +
                pageInfo.loading +
                '</div></div>';
            titleObject.reload = true;
          } else if (blocks[i].type === 'report') {
            param = { func: blocks[i].func, dashboard: blocks[i].name };
            $.extend(param, blocks[i].params);
            storage.dashboard[blocks[i].name] = param;
            EventMgr.trigger('ajaxRequest', {
              url: pageInfo.url,
              param: param,
              invar: { blockId: 'block-' + blocks[i].name },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponseForDashboard',
              failfunc: 'failedAjaxResponseForDashboard',
              queue: 'noqueue' });
            contentBlock = '<div id="block-' + blockId +
                '" class="block-table" data-block-name="' + blocks[i].name +
                '" data-block-func="' + blocks[i].func +
                '" data-block-param="' +
                App.Common.serializeForAttr(blocks[i].params) +
                '"><div class="dashboard-nodata">' +
                pageInfo.loading +
                '</div></div>';
            titleObject.reload = true;
          } else if (blocks[i].type === 'url') {
            var ifId = 'f-' + blocks[i].name;
            contentBlock = '<div><iframe id="' + ifId + '" width="100%" src="' +
                blocks[i].url + '"></iframe></div>';
          } else if (blocks[i].type === 'infolist') {
            param = { func: blocks[i].func, dashboard: blocks[i].name };
            storage.dashboard[blocks[i].name] = param;
            if (blocks[i].autoupdate) {
               setTimeout(function(block) {
                 return function() {
                   EventMgr.trigger('refreshDashBlock', { block: block });
                 };
               } (blocks[i]), blocks[i].autoupdate * 1000);
            }
            EventMgr.trigger('ajaxRequest', {
              url: pageInfo.url,
              param: param,
              invar: { blockId: 'block-' + blocks[i].name },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponseForDashboard',
              failfunc: 'failedAjaxResponseForDashboard',
              queue: 'noqueue' });
            titleObject.reload = true;
            contentBlock = '<div class="" id="block-' + blockId +
                '" data-block-name="' + blocks[i].name + '"></div>';
          } else if(blocks[i].type === 'isplicense' || blocks[i].type === 'ispupdate') {
            param = { func: blocks[i].func, dashboard: blocks[i].name };
            storage.dashboard[blocks[i].name] = param;
            EventMgr.trigger('ajaxRequest', {
              url: pageInfo.url,
              param: param,
              invar: { blockId: 'block-' + blocks[i].name },
              type: 'get',
              outtype: 'json',
              trfunc: 'ajaxResponseForDashboard',
              failfunc: 'failedAjaxResponseForDashboard',
              queue: 'noqueue' });
            titleObject.reload = true;
            contentBlock = '<div class="" id="block-' + blockId +
                '" data-block-name="' + blocks[i].name + '"><div class="dashboard-nodata">' +
                pageInfo.loading +
                '</div></div>';
          } else {
             EventMgr.trigger('pullMsg', { msg: 'Dashboard type "' + blocks[i].type + '" do not support.' });
             return;
          }
          //check for update
          if (blocks[i].update) {
            EventMgr.trigger('addBlockToUpdate', blocks[i]);
          }
          title = templates.formPageTitle(titleObject);

          classes = (blocks[i].display === 'min') ?
              ' b-form-page_st_collapsed ' : '';
          display = (blocks[i].display === 'min') ? 'none' : 'block';

          contentObject = {
            view: 'dblock',
            title: title,
            content: contentBlock,
            classes: classes,
            display: display,
            tabId: blocks[i].name,
            hide: [],
            show: [] };

          if (blocks[i].position === 'top' ||
              blocks[i].position === 'undefined') {
            top += templates.formPageWrapper(contentObject);
          } else if (blocks[i].position === 'left') {
            left += templates.formPageWrapper(contentObject);
          } else if (blocks[i].position === 'right') {
            right += templates.formPageWrapper(contentObject);
          }
          contentBlock = '';
          title = '';
          classes = '';
          display = '';
        }

        obj = {
          top: top,
          left: left,
          right: right,
          id: 'tab0'
        };
        return obj;
      },

      renderDashboardTable = function(e, data) {
        var resp = data,
            startTime = resp.startTime || 0,
            extraTime,
            blockId = resp.blockId.replace(/\./g, '_'),
            block, bandHTML, table, pagerList, blockHTML,
            bName, bCnt, bFunc, bPnum, tblock;
        resp.tabId = blockId;
        block = App.Dom.byId(blockId);
        //remove loading class
        tblock = App.Dom.byId('t' + blockId);
        //calc time end of animation
        extraTime = 1000 - (((new Date()).getTime() - startTime) % 1000);
        setTimeout(function() {
          if (tblock) {
            tblock.className = tblock.className.replace(/loading/g, '');
          }
        }, extraTime);
        if (block === null) { return; }
        if (resp.type === 'report') {
          bandHTML = renderBandDash(resp.bands, blockId);
          block.innerHTML = bandHTML;
          setTimeout(function() {
            EventMgr.trigger('loadGCharts', { bands: resp, tabId: blockId });
          }, 10);
        } else if (resp.type === 'infolist') {
          blockHTML = renderInfoList({ rows: resp.rows, testMode: resp.testMode });
          block.innerHTML = blockHTML;
        } else if (resp.type === 'isplicense') { 
          blockHTML = renderLicenseBlock(resp.isplicense_data);
          block.innerHTML = blockHTML;
        } else if (resp.type === 'ispupdate') {
          blockHTML = renderUpdateBlock(resp.ispupdate_data);
          block.innerHTML = blockHTML;
        } else {
          table = '';
          pagerList = '';
          if (resp.error) {
            table = resp.ermsg;
          } else {
            table = renderTable(resp);
            if (resp.pager.pager === 'true') {
              pagerList = buildPagerList(resp.pager.pageCount, resp.pager.pageNum);
            }
          }

          blockHTML = '<div id="' + blockId + '-scrollwrapper">' + table +
              '</div><div class="pager_list pager-list_type_dashboard">' +
              pagerList + '</div>';
          bName = block.getAttribute('data-block-name');
          bCnt = block.getAttribute('data-block-cnt');
          bFunc = block.getAttribute('data-block-func');
          bPnum = block.getAttribute('data-block-pnum');

          block = App.Common.replaceHtml(block, blockHTML);
          block.setAttribute('data-block-pnum', resp.pager ? resp.pager.pageNum : 1);
          block.setAttribute('data-block-name', bName);
          block.setAttribute('data-block-cnt', bCnt);
          block.setAttribute('data-block-func', bFunc);
          block.setAttribute('data-block-pnum', bPnum);
          if (!resp.error) {
            EventMgr.trigger('appendDashList', { tabId: blockId });
          }
        }
        setTimeout(function() {
          EventMgr.trigger('updateScroll', { id: 'cont-tab0' });
        }, 300);
        setTimeout(function() {
          EventMgr.trigger('updateScroll', { id: 'cont-tab0' });
        }, 7000);
        block = null;
      },
      //render bands for
      renderBandDash = function(bands, id) {
        var bandLen = bands.length - 1,
            output = '',
            i, gid, title, titleClass, fullwidth;
        if (bandLen > 0) {
          for (i = 0; i < bandLen; i++) {
            gid = id + '-' + i + bands[i].id + '0';
            title = '';
            titleClass = '';
            fullwidth = bands[i].fullwidth ? 'fullwidth-band' : '';
            if (bands[i].bigTitle !== '') {
              title = bands[i].bigTitle || '';
              titleClass = 'big-title';
            } else if (bands[i].smallTitle !== '') {
              title = bands[i].smallTitle || '';
              titleClass = 'small-title';
            }
            output += templates.reportBandDash({
              empty: bands[i].empty,
              emptymsg: pageInfo.emptyreport,
              title: title,
              titleClass: titleClass,
              id: id,
              gid: gid,
              fullwidth: fullwidth });
          }
        } else {
          output = '<div class="dashboard-nodata">' + pageInfo.nodata + '</div>';
        }
        return output;
      },
      // render license block on dashboard
      renderLicenseBlock = function(data) {
        return templates.licenseDashBlock(data)
      },
      // render update to isp6 block on dashboard
      renderUpdateBlock = function(data) {
        return templates.updateToIsp6(data);
      },
      //render tables in reports
      renderBands = function(reports, tabId) {
        //if no data return fake chart
        if (reports.emptyBand) {
          if (reports.hasDiagram) {
            return templates.emptyBandOverlay({
              emptymsg: pageInfo.emptyreport, tabId: tabId });
          } else {
            return '<div class="report-nodata">' + pageInfo.nodata + '</div>';
          }
        }
        var bandsContent = '',
            bands = reports.bands,
            len = bands.length - 1,
            id = null, fullwidth,
            i;
        //go for bands
        for (i = 0; i < len; i++) {
          id = tabId + '-' + i;
          if (bands[i].content.length === 0) {
            if (bands[i - 1] && bands[i - 1].title) {
              bandsContent += '<div class="b-report-nodata">' + pageInfo.nodata + '</div>';
            }
            continue;
          }

          //check for band like title
          if (bands[i].title !== undefined) {
            fullwidth = bands[i].fullwidth ? 'fullwidth-band' : '';
            bandsContent += '<div class="band-content b-title ' + fullwidth +
                '"><div class="band-title big-title">' + bands[i].title +
                '</div></div>';
          } else {
            $.extend(bands[i], {
              elKey: bands[i].headers[0].name,
              pager: { pageElems: 0 },
              tabId: id, oTabId: tabId });
            bands[i].func = reports.func;
            var table = '<div>' + renderTable(bands[i]),
                gid = id + bands[i].id,
                aid = tabId + '-' + bands[i].id,
                title = '', titleClass = '',
                hidden = bands[i].hidden ? 'data-table-hidden' : '',
                showMsg = bands[i].showMsg,
                hideMsg = bands[i].hideMsg,
                hiddenClass = bands[i].hidden ? 'hidden' : '',
                diagrmCount = bands[i].diagram.length;
            fullwidth = bands[i].fullwidth ? 'fullwidth-band' : '';
            if (diagrmCount === 0) {
              fullwidth += ' nodiagram';
            }
            if (bands[i].smallTitle !== '') {
              title = bands[i].smallTitle;
              titleClass = 'small-title';
            }
            bandsContent += templates.reportBand({
              title: title || '',
              titleClass: titleClass,
              table: table,
              id: id,
              aid: aid,
              gid: gid,
              fullwidth: fullwidth,
              hidden: hidden,
              showMsg: showMsg,
              hideMsg: hideMsg,
              hiddenClass: hiddenClass,
              dc: diagrmCount });
            bandsContent += createTableRow(bands[i].headers, id);
          }          // EventMgr.trigger('loadChart', {diagram :
          // bands[i].diagram, gid : gid});
        }
        return bandsContent;
      },
      //render table with one row for sum in table reports
      createTableRow = function(headers, id) {
        var table = '<table id="table_sum-' + id + '"><tr>';
        for (var i = 0; i < headers; i++) {
          table += '<td>' +
              '<span class="data-sum" id="' + headers[i].name + '"></span>' +
              '</td>';
        }
        table += '</tr></table>';
        return table;
      },
      //data for reload page
      reloadTabData = function(e, data) {
        var tabId = data.tabId,
            resetFilterOn = data.resetFilterOn,
            url = pageInfo.url,
            iType = data.softUpdate ? 'softUpdate' : 'hardUpdate',
            filter = data.filter || false,
            param, scrollTop = 0,
            //stay help chain
            help = data.help,
            selid = data.selid || true;
        if (data.reload) {
          if (!checkReload(data)) {
            return;
          }
        }
        if (tabs[tabId] === undefined) { return; }
        var defParams = tabs[tabId].paramObjAll,
            parent = tabs[tabId].parent,
            newUrl = data.newurl ? true : false;
        if (data.param) {
          param = data.param;
          //check for pager
          /* jslint camelcase:false */
          if (param.p_num !== defParams.p_num) {
            selid = false;
          }
          /* jslint camelcase:true */
          /* jslint camelcase:false */
          if (param.p_num) {
            delete defParams.p_num;
          }
          /* jslint camelcase:true */
        } else {
          param = data.addedParam || {};
          if (tabs[tabId].param.match('p_num')) {
            param = App.Common.parseParams(tabs[tabId].param);
          }
        }
        defParams = $.extend(defParams, param);

        if (newUrl) {
          url = pageInfo.url;
        }
        //if has selected elems remember it
        if (selid) {
          scrollTop = getScrollTop(tabId);
          if (selid === true) {
            selid = getSelectedElems(tabId);
          }
        }
        //save filter value
        if (filter) {
          var filterBox = App.Dom.byId(tabId + '-search');
          if (filterBox) {
            filter = filterBox.value;
          } else {
            filter = false;
          }
        }

        //reset filter on when update from menu
        if (resetFilterOn) {
          delete defParams.filter;
        }

        //if request from filter drop, remove filter=on param from list
        if (data.__src === 'filterset' || data.__src === 'buildTabOk') {
          delete defParams.filter;
        }
        EventMgr.trigger('ajaxRequest', {
          url: url,
          param: defParams,
          invar: {
            dataSaved: true,
            parent: parent,
            targetTabId: tabId,
            selid: selid,
            scrollTop: scrollTop,
            iType: iType,
            __src: 'reloadTab',
            help: help ? tabs[tabId].help : false,
            liveFilter: filter },
          type: 'get',
          outtype: 'json',
          trfunc: 'ajaxResponse',
          queue: 'reloadTab' + tabId,
          failfunc: 'failCommonAjaxResponse' });
        if (iType !== 'softUpdate') {
          EventMgr.trigger('tabLoading', { tabId: tabId });
        }
      },

      //handler for submit form
      formHandler = function(e, data) {
        var tabId = data.tabId,
            selid = data.elid ? [data.elid] : true,
            parent = '', granny = '';
        //check for modal
        if (!tabs[tabId] && tabId === 'modal1') {
          EventMgr.trigger('formInspectorResponse', data);
        }
        //progressok for wizard form
        if (data.ok || data.progressok) {
          //check for notifyUp
          if (data.notifyUp) {
            EventMgr.trigger('forceCheckNotify');
          }
          //check for late update
          if (data.progresstype === 'wait') {
            EventMgr.trigger('progressBarSaveState', data);
            return false;
          }
          //check for banners
          if (data.message && data.message.length) {
            App.Global.bannerHtml = data.message;
            App.Global.warning = data.warning;
            App.Global.targetId = '';
          }
          if (tabs[tabId] && tabs[tabId].parent) {
            parent = tabs[tabId].parent;
          }

          if (!checkReload(data) ||
              !checkNewWin(data) ||
              !checkFeatures(data) ||
              !checkDasboard(data)) {
            closeTab(e, tabId);
            return false;
          }

          if (!checkNewForm(data) ||
              !checkNewList(data)) {
//            closeTab(e, tabId);
            return false;
          }
          App.Common.checkRefreshMenu(data);

          if (data.bootTime) {
            EventMgr.trigger('startCheckRestart', { bootTime: data.bootTime });
          }
          //if has parent close self and reload parent
          if (tabs[tabId] && tabs[tabId].parent) {
            parent = tabs[tabId].parent;
            granny = tabs[tabs[tabId].parent].parent;
            closeTab(e, tabId);
            EventMgr.trigger('reloadTab', { tabId: parent, selid: selid, filter: true });
            EventMgr.trigger('tabLoading', { parent: granny });

          } else {
            closeTab(e, tabId);
          }
        } else if (data.error && !data.form) {
          showErrorOnForm(data);
        } else {
          EventMgr.trigger('ajaxResponse', data);
        }
      },

      showErrorOnForm = function(data) {
        if (data.error && data.targetTabId) {
          var ermsg = templates.banner({ message: {
            status: 'error',
            classes: '',
            id: data.targetTabId,
            text: App.Common.wordWrap(data.ermsg, 100),
            ref: false,
            refText: pageInfo.moreinfo,
            dismiss: data.msg.dismiss
          } });
          $('#cont-' + data.targetTabId).find('.error-message').html(ermsg);
          EventMgr.trigger('tabLoadingHide', { tabId: data.targetTabId });
          resetToDefaultFormButton(data.targetTabId);
          EventMgr.trigger('updateScroll', { id: 'form-scroll-' + data.targetTabId });
        }
      },

      //BuildPager
      buildPager = function(pager, tabId) {
        var slist = templates.formItemSelect({
              name: 'pager-slist',
              slist: pager.pageSlist,
              value: pager.pageNum,
              msg: pager.pageSlist[pager.pageNum - 1].value,
              depend: pager.depend,
              dependMaster: pager.dependMaster,
              dependFields: '',
              hide: '',
              show: '',
              readonly: '',
              setvalue: '',
              id: tabId,
              attrInput: '' }),
            pagerList = buildPagerList(pager.pageCount, pager.pageNum),
            pageCnt = pager.pageCnt,
            msgBegan = pager.msgPagershow,
            msgEnd = pager.msgPagerline,
            pagerHTML = templates.listPager({
              slist: slist,
              cnt: pageCnt,
              pagerList: pagerList,
              msgBegan: msgBegan,
              msgEnd: msgEnd });
        return pagerHTML;
      },
      //build list pager
      buildPagerList = function(pages, current) {
        var html = '',
            maxLen = 9,
            active = '',
            // length environment
            rl = Math.round((maxLen - 5) / 2);
        if (!current) {
          current = 1;
        }
        current = parseInt(current, 10);

        var standartPager = function(pages, current) {
          var html = '';
          for (var i = 1; i <= pages; i++) {
            if (i === current - 0) {
              active = 'pager-list__item_active';
            } else {
              active = 'pager-list__item_act';
            }
            html += '<span class="page pager-list__item ' + active + '" data-n="' + i + '">' + i + '</span>';
          }
          return html;
        },

            firstPageActive = function(maxLen, pages, current) {
              var html = '',
                  prevLast = maxLen - 1;
              for (var i = 1; i <= maxLen; i++) {
                if (i === current - 0) {
                  active = 'pager-list__item_active';
                } else {
                  active = 'pager-list__item_act';
                }
                if (i === prevLast) {
                  html += '<span class="page ellipsis">...</span>';
                } else if (i === maxLen) {
                  html += '<span class="page pager-list__item ' + active + '" data-n="' + pages + '">' + pages + '</span>';
                } else {
                  html += '<span class="page pager-list__item ' + active + '" data-n="' + i + '">' + i + '</span>';
                }
              }
              return html;
            },

            lastPageActive = function(maxLen, pages, current) {
              var html = '',
                  first = pages - maxLen;
              for (var i = 1; i <= maxLen; i++) {
                if (i + first === current - 0) {
                  active = 'pager-list__item_active';
                } else {
                  active = 'pager-list__item_act';
                }
                if (i === 2) {
                  html += '<span class="page ellipsis"> ... </span>';
                } else if (i === 1) {
                  html += '<span class="page pager-list__item ' + active + '" data-n="1">1</span>';
                } else {
                  html += '<span class="page pager-list__item ' + active + '" data-n="' + (i + first) + '">' + (i + first) + '</span>';
                }
              }
              return html;
            },

            middlePageActive = function(maxLen, pages, current, rl) {
              var html = '',
                  first = current - rl - 3,
                  prevLast = maxLen - 1;
              for (var i = 1; i <= maxLen; i++) {
                if (i + first === current) {
                  active = 'pager-list__item_active';
                } else {
                  active = '';
                }
                if (i === 1) {
                  html += '<span class="page pager-list__item pager-list__item_act' + active + '" data-n="1">1</span>';
                } else if (i === 2 || i === prevLast) {
                  html += '<span class="page ellipsis">...</span>';
                } else if (i === maxLen) {
                  html += '<span class="page pager-list__item pager-list__item_act ' + active + '"  data-n="' + pages + '">' + pages + '</span>';
                } else {
                  html += '<span class="page pager-list__item pager-list__item_act ' + active + '" data-n="' + (i + first) + '">' + (i + first) + '</span>';
                }
              }
              return html;
            };

        if (pages <= maxLen) {
          // console.log("case: standart");
          html = standartPager(pages, current);
        } else if (pages >= maxLen && (current - rl) <= 1) {
          // console.log("case: first");
          html = firstPageActive(maxLen, pages, current);
        } else if (pages >= maxLen && (current + rl) >= pages) {
          // console.log("case: last");
          html = lastPageActive(maxLen, pages, current);
        } else if (pages >= maxLen && ((current - rl) >= 1 ||
            (current + rl) <= pages)) {
          // console.log("case: middle");
          html = middlePageActive(maxLen, pages, current, rl);
        }

        return html;
      },

      addChartToTab = function(e, data) {
        var tabId = data.tabId,
            chart = data.chart;
        if (tabs[tabId] !== undefined) {
          tabs[tabId].chart = tabs[tabId].chart || [];
          tabs[tabId].chart.push(chart);
        }
      },

      getActiveHint = function(e, data) {
        var tabId = data.tabId,
            elid = data.elid,
            pName = data.pName,
            value = data.value,
            url = pageInfo.url,
            self = data.self,
            params;
        if (tabs[tabId] === undefined) { return; }
        params = App.Common.clone(tabs[tabId].paramObjAll);
        /* jslint camelcase:false */
        params.hint_field = pName;
        /* jslint camelcase:true */
        params.plid = params.elid;
        params.elid = elid;
        if (value) {
          params.value = value;
        }

        EventMgr.trigger('ajaxRequest', {
          url: url,
          param: params,
          invar: {
            hintTabId: tabId,
            hintElid: elid,
            hintValue: value,
            hintPName: pName,
            self: self },
          type: 'get',
          outtype: 'json',
          trfunc: 'ajaxResponseHint',
          queue: 'actHint' + tabId,
          failfunc: 'failCommonAjaxResponse' });
      },
      //hook for change field callbacks
      formFieldChangeHandler = function(e) {
        var tabId = this.getAttribute('data-tabid');
        //check for input contains in tab
        if (tabs[tabId]) {
          EventMgr.trigger('formFieldChanged', {
            tabObj: tabs[tabId],
            tabId: tabId,
            field: this });
        }
      },

      //  add formModel to data for setvalues
      addModelToSetvalues = function(data) {
        var tabId = data.tabId;
        if (tabs[tabId]) {
          data.__formModel = tabs[tabId].formModel;
        }
      },

      addListModel = function(data) {
        if (data.tabId) {
          var tabId = data.tabId.replace('cont-', '');
          if (tabs[tabId] && tabs[tabId].__content && tabs[tabId].__headers) {
            data.__content = tabs[tabId].__content;
            data.__headers = tabs[tabId].__headers;
          }
        }
      },

      updateModelBySetvalues = function(e, data) {
        var tabId = data.tabId;
        if (tabs[tabId]) {
          tabs[tabId].formModel[data.name] = data.value;
        }
      },

      addTabsModel = function(data) {
        if (data) {
          data.__tabs = tabs;
        }
      },
      //check form changed
      checkFormChange = function(tabId) {
        if (tabs[tabId] && tabs[tabId].formModel) {
          var formModel = tabs[tabId].formModel,
              count = 0,
              labels = '',
              isChanged = false;
          for (var keyVar in formModel) {
            if (formModel[keyVar].isChanged && formModel[keyVar].label) {
              count++;
              labels += formModel[keyVar].label + '<br/>';
              isChanged = true;
            }
          }
          return {
            isChanged: isChanged,
            count: count,
            labels: labels
          };
        } else {
          return {
            isChanged: false,
            count: 0
          };
        }
      },
      //save form page collapsed state to server
      saveFormPageState = function(e, data) {
        var tabId = data.tabId;
        if (tabs[tabId]) {
          var param = {
            page: data.name,
            action: tabs[tabId].func,
            func: 'collapse',
            collapse: data.collapsed ? 'off' : 'on'
          };
          EventMgr.trigger('ajaxRequest', {
            param: param,
            trfunc: 'DoNothing',
            queue: 'noqueue'
          });
        }
      },

      favoriteToggle = function(e) {
        e.preventDefault();
        var $self = $(this),
            tabId = $self.closest('.tab-content').attr('data-tabid'),
            favorite,
            options = {
              param: {},
              trfunc: 'favoriteMenuUpdateDone',
              outtype: 'json'
            };
        if (tabs[tabId]) {
          favorite = tabs[tabId].favorite;
          if (favorite) {
            options.param.func = 'usermenu.suspend';
            $self.addClass('b-elem_style_gracescale');
            $self.attr('data-state', 'unfavorite');
          } else {
            options.param.func = 'usermenu.resume';
            $self.removeClass('b-elem_style_gracescale');
            $self.attr('data-state', 'favorite');
          }
          options.param.elid = tabs[tabId].func;
          EventMgr.trigger('ajaxRequest', options);
          tabs[tabId].favorite = !favorite;
        }
      },

      pinToggle = function(e) {
        e.preventDefault();
        var $self = $(this),
            tabId = $self.closest('.tab-content').attr('data-tabid'),
            pin,
            $tabLi = $('#switch-' + tabId),
            options = {
              param: {},
              trfunc: 'pinTabDone',
              outtype: 'json'
            };
        if (tabs[tabId]) {
          pin = tabs[tabId].pin;
          if (pin) {
            options.param.func = 'usermenu.unpin';
            //options.param.func = 'usermenu.unpin';
            $self.addClass('b-elem_style_gracescale');
            $self.attr('data-state', 'unpin');
            $tabLi.removeClass('subtab_is_pin');
          } else {
            options.param.func = 'usermenu.pin';
            //options.param.func = 'usermenu.pin';
            $self.removeClass('b-elem_style_gracescale');
            $self.attr('data-state', 'pin');
            $tabLi.addClass('subtab_is_pin');
          }
          options.param.elid = tabs[tabId].func;
          EventMgr.trigger('ajaxRequest', options);
          tabs[tabId].pin = !pin;
          //update localstorage tabs
          EventMgr.trigger('changedTabs', { tabs: tabs });
        }

      },

      changeTabSortIndex = function(e, data) {
        if (data.s && data.t && tabs[data.s] && tabs[data.t]) {
           var sIndex = tabs[data.s].sIndex;
           tabs[data.s].sIndex = tabs[data.t].sIndex;
           tabs[data.t].sIndex = sIndex;
           EventMgr.trigger('changedTabs', { tabs: tabs });
        }
      },
      /**
       * close form & child list/report by ESC key
       * e {object} event object
       * data {object|undefined} event object data
       */
      esckeyHandler = function(e, data) {
        var $actTab = $('.tab-content_st_active'),
            type = $actTab.attr('data-tab-type'),
            tabId = $actTab.attr('data-tabid');
        if (type === 'list' || type === 'report') {
          $actTab.find('.toolbar-button__item-img.back').trigger('click');
        } else if (type === 'form') {
          $('#switch-' + tabId).find('.i-tab-close').trigger('click');
        }
      };

  return {
    init: init,
    //for dev
    tabs: tabs,
    closeTab: closeTab,
    moneyFormat: moneyFormat
  };
}(window, $, EventMgr, App, templates);