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.Hint.js

/**
 * Модуль отвечает за отображение хинтов
 * @param {object} window global object
 * @param {object|function} $ jQuery
 * @param {object} EventMgr Event manager
 * @param {object} App Application
 */
/*global App:true*/
App.Hint = function(window, $, EventMgr, App) {
  'use strict';
  var init = function() {
    EventMgr.on($mainWrapper(), hintItemSelector,
        'mouseover', hintShowHandler);
    EventMgr.on($mainWrapper(), '.i-text-content',
        'mouseover', hintInListShowHandler);
    EventMgr.on($mainWrapper(), hintActiveItemSelector,
        'mouseover', hintActiveShowHandler);
    EventMgr.bind('hintActiveShowHandler', hintActiveShowHandler);
    EventMgr.on($mainWrapper(), hintMenuItemSelector,
        'mouseover', hintShowHandler);
    EventMgr.on($mainWrapper(), hintItemSelector,
        'mouseout', hintHideHandler);
    EventMgr.on($mainWrapper(), '.i-text-content',
        'mouseout', hintHideHandler);
    EventMgr.on($mainWrapper(), previewItemSelector,
        'mouseover', previewShowHandler);
    EventMgr.on($mainWrapper(), previewItemSelector,
        'mouseout', hintHideHandler);
    EventMgr.on($mainWrapper(), hintActiveItemSelector,
        'mouseout', hintHideHandler);
    EventMgr.on($mainWrapper(), hintMenuItemSelector,
        'mouseout', hintHideHandler);
    EventMgr.on($mainWrapper(), hintBoxSelector, 'mouseover', hintShow);
    EventMgr.on($mainWrapper(), hintBoxSelector, 'mouseout', hintHide);
    EventMgr.on($body(), tipCloseSelector, 'click', closeTipByCross);
    //EventMgr.on($body(), tipCloseCrossSelector, 'click', closeTipByCross);
    EventMgr.bind('showHintMap', showHintMap);
    EventMgr.bind('forceShowHint', forceShowHint);
    EventMgr.bind('hideHint', hintHide);
    EventMgr.bind('stopShowHint', stopShowHint);
    EventMgr.bind('tabLoading', hintHide);
    EventMgr.bind('closeTabEvent', hintHide);
    EventMgr.bind('ajaxResponseHint', updateHint);
    EventMgr.on('.force-hint-flag', '.force-hint', 'focus', showForceHint);
    EventMgr.on('.force-hint-flag', '.force-hint', 'blur', forcehintHide);
    EventMgr.bind('verticalScroll', checkPosition);
    EventMgr.bind('showTips', showTips);
    EventMgr.bind('loadPage', checkTipsForDesktop);
    EventMgr.bind('updateTipPosition', updateTipPosition);
  },
      $mainWrapper = function() {
        return App.u.selectorCache('#main-wrapper');
      },

      $body = function() {
        return App.u.selectorCache('#main-wrapper');
      },

      hintItemSelector = '.hint',

      tipCloseSelector = '.b-tip',

      tipCloseCrossSelector = '.b-tip__close',

      pageInfo = window.pageInfo,

      previewItemSelector = '#modal1-img li',

      hintActiveItemSelector = '.acthint',

      $hintBoxFn = function() {
        return $('#hint');
      },

      $hintBoxInnerFn = function() {
        return $('#hint-inner');
      },

      hintBoxSelector = '#hint',
      //$ elem inner hint
      $$hintBoxInner,
      $$hintBox,

      hintMenuItemSelector = '.overwidth',

      timer,
      hideTimer,

      lastSelf,
      /**
       * Force show hint when form elem in focus
       * @param {object} e
       * @this HTML Node
       */
      showForceHint = function(e) {
        clearTimeout(hideTimer);
        var $srcElem = $(this),
            hintField = $srcElem.parents('.i-form__item').find('.field-help'),
            self = hintField;
        if (hintField.length > 0 && hintGetContent(self, false)) {
          setTimeout(function() {
            setHintPosition(self, true);
            hintShow(undefined, true);
          }, 1);
        }
        lastSelf = $srcElem;
      },

      forcehintHide = function() {
        $$hintBox = $$hintBox || $hintBoxFn();
        $$hintBox.css('visibility', '').removeClass('active');
      },

      checkPosition = function() {
        if ($$hintBox.hasClass('active')) {
          if (lastSelf && lastSelf.hasClass('force-hint')) {
            var hintField = lastSelf.parents('.l-form__row').find('.field-help');
            if (hintField.offset().top < 142) {
              forcehintHide();
            } else {
              setHintPosition(hintField, true);
            }
          }
        }
      },

      //prevent show hint
      stopShowHint = function() {
        clearTimeout(timer);
      },
      /**
       * Hint handler for DCMap
       * get props of element and show it as list
       * @param {object} e
       */
      showHintMap = function(e) {
        var data = e.originalEvent.detail.props,
            self = $(e.originalEvent.detail.elem),
            hint = '<ul>',
            msg = data.msg,
            key,
            $$hintBoxInner = $$hintBoxInner || $hintBoxInnerFn();
        for (key in data) {
          if (msg[key]) {
            hint += '<li>' +
                '<label class="b-hint-line__label">' + msg[key] + ':</label>' +
                ' ' + data[key] + '</li>';
          }
        }
        hint += '</ul>';
        $$hintBoxInner.html(hint);

        //@todo least 200ms mouseover don't show hint

        timer = setTimeout(function() { hintShow(self); }, 500);
        lastSelf = null;
      },
      /**
       * Show hint like preview for development mode
       * @param {object} e
       * @this {object} HTML Node
       */
      previewShowHandler = function(e) {
        var self = $(this),
            imgName = this.getAttribute('data-val'),
            text, style, src;
        $$hintBoxInner = $$hintBoxInner || $hintBoxInnerFn();
        if (!imgName) {
          return;
        }
        src = 'src="/manimg/common/img/' + imgName + '.png"';
        style = 'style="min-height: 16px; min-width: 16px;"';
        text = '<img class="preview-icon" ' + style + ' ' + src + ' ></img>';
        $$hintBoxInner.html(text);
        //check for shadow

        setHintPosition(self, false);

        //@todo least 200ms mouseover don't show hint
        timer = setTimeout(function() { hintShow(); }, 500);
      },
      /**
       * show hint for element with custom hint
       * @param {object} e
       * @param {object} data
       */
      forceShowHint = function(e, data) {
        var elem = data.elem,
            hint = data.hint,
            self = $(elem);
        $$hintBoxInner = $$hintBoxInner || $hintBoxInnerFn();
        $$hintBoxInner.html(hint);
        setHintPosition(self, false);
        hintShow();
        lastSelf = null;
      },
      /**
       * Get hint content for view
       * find out hint content in elem attribute
       * @param {object} self jQuery object of element
       * @param {boolean} active Flag for active hint
       * @return {boolean}
       */
      hintGetContent = function(self, active) {
        var state, text, shadow, row, mn,
            overwidth = false;
        $$hintBoxInner = $$hintBoxInner || $hintBoxInnerFn();
        //get hint content
        state = self[0].getAttribute('data-state');
        if (state) {
          text = self[0].getAttribute('data-hint-' + state);
          if (!text) {
            text = self[0].getAttribute('data-hint');
          }
        } else {
          text = self[0].getAttribute('data-hint');
        }
        mn = self[0].getAttribute('data-hint-mn');
        if (active) {
          text = pageInfo.loading;
        }
        if (!text) {
          if (self.hasClass('overwidth')) {
            text = self[0].innerText || self[0].firstChild.nodeValue || self.html();
            overwidth = true;
          } else {
            return false;
          }
        }
        //filtred text
        text = window.filterXSS(text);
        shadow = self.hasClass('shadow');
        if (shadow) {
          row = self.parents('tr.row-shadow');
          if (!row.length) {
            text = text.replace(/<span class=['"]hint-.*/g , '');
          }
        }

        $$hintBoxInner.html(text);
        if (mn) {
          if (!String(mn).match('hint')) {
            mn = 'hint_' + mn;
          }
          $$hintBoxInner.attr('data-mn', mn);
        } else {
          $$hintBoxInner.attr('data-mn', null);
        }
        lastSelf = null;
        return true;
      },
      /**
       * Show hint handler
       * call function for show hint
       * @param {object} e
       * @param {boolean} active Flag for active hint
       * @this HTML Node
       */
      hintShowHandler = function(e, active) {
        var self = $(this);
        if (hintGetContent(self, active)) {
          setHintPosition(self, false);
          //@todo least 200ms mouseover don't show hint
          timer = setTimeout(function() { hintShow(); }, 500);
        }
        lastSelf = null;
        //if hint on parent
        if (e.stopPropagation) {
          e.stopPropagation();
        }
      },

      hintInListShowHandler = function(e) {
        if (this.className.match(/overwidth/)) {
          hintShowHandler.apply(this, [e]);
        } else {
          var width = this.offsetWidth,
              scrollWidth = this.scrollWidth - 1;
          if (width < scrollWidth) {
            this.className += ' overwidth';
            hintShowHandler.apply(this, [e]);
          }
        }
      },

      /**
       * Set position for hint
       * detect best position for view hint
       * @param {object} self jQuery object of element
       * @param {boolean} fixed flag for fixed position of hint (for form items)
       */
      setHintPosition = function(self, fixed, box, boxInner, forceRight, forceBottom) {
        var PADDING = 15,
            heightTail = 10,
            marginElem = 3,
            N3 = 7,
            N4 = 30,
            $hintBoxInner,
            $hintBox;
        if (box && boxInner) {
          $hintBoxInner = boxInner;
          $hintBox = box;
        } else {
          if (!$$hintBox || !$$hintBoxInner) {
            $$hintBoxInner = $hintBoxInnerFn();
            $$hintBox = $hintBoxFn();
          }
          $hintBoxInner = $$hintBoxInner;
          $hintBox = $$hintBox;
        }
        //calculate hint position
        var heightHintBox = $hintBoxInner[0].offsetHeight,
            widthElem = self.width(),
            heightElem,
            selfOffset = self.offset(),
            //top position of element
            topElem = selfOffset.top,
            //left position of element
            leftElem = selfOffset.left,
            docWidth = $('body').width(),
            left, top,
            topFlag = false,
            rightFlag = false,
            LEFT_BORDER;
        //check for svg elem
        if (widthElem === 0 && self && self[0]) {
          widthElem = self[0].getBoundingClientRect().width;
        }
        $hintBoxInner
            .removeClass('b-hint__inner_right_fixed' +
                ' b-hint__inner_right' +
                ' b-hint__inner_top' +
                ' b-hint__inner_top_right' +
                ' b-hint__inner_left');
        //top of element hinting
        if (!fixed) {
          top = topElem - heightHintBox - heightTail - marginElem - PADDING;
          left = leftElem + (widthElem / 2) - N3;
          LEFT_BORDER = 300;
        } else {
          top = topElem - PADDING;
          left = leftElem + widthElem + marginElem + heightTail;
          LEFT_BORDER = 250;
        }
        //check for left border
        if ((docWidth - left) < LEFT_BORDER || forceRight) {
          $hintBoxInner.addClass('b-hint__inner_right');
          var right = docWidth - leftElem - N4;
          rightFlag = true;
          $hintBox.css('right', right + 'px');
          $hintBox.css('left', '');
          if (fixed) {
            top = topElem - heightHintBox - heightTail - marginElem - PADDING;
          }
        } else {
          if (fixed) {
            $hintBoxInner.addClass('b-hint__inner_right_fixed');
          }
          $hintBoxInner.addClass('b-hint__inner_left');
          $hintBox.css('left', left + 'px');
          $hintBox.css('right', '');
        }
        //check for top border
        if (heightHintBox > top || forceBottom) {
          heightElem = self.outerHeight();
          //check for svg elem
          if (heightElem === 0 && self && self[0]) {
            heightElem = self[0].getBoundingClientRect().height;
          }
          top = self.offset().top + heightElem + heightTail - PADDING;
          if (rightFlag) {
            $hintBoxInner.addClass('b-hint__inner_top_right');
          } else {
            $hintBoxInner.addClass('b-hint__inner_top');
          }
        }
        $hintBox.css('top', top + 'px');
      },

      currentHintId,
      /**
       * Active hint handler
       * get request for content hint
       * @param {object} e
       * @this {object}
       */
      hintActiveShowHandler = function(e) {
        var _this = this;
        if (e.originalEvent.detail.elem) {
          _this = e.originalEvent.detail.elem;
        }
        var self = $(_this),
            tabId = $('.tab-content_st_active').attr('data-tabid'),
            elid = self.parents('tr').attr('data-elid') ||
                _this.getAttribute('data-elid'),
            pName = _this.getAttribute('data-name'),
            value = _this.getAttribute('data-value'),
            hintfunc = _this.getAttribute('data-hintfunc');
        //for acthint in col
        if (!pName) {
          var index = self.closest('td').index(),
              th = self.closest('table').find('th')[index],
              pName = th.getAttribute('data-colname');
        }
        if (hintfunc) {
          currentHintId = tabId + value + elid + pName;
          var params = {
            func: hintfunc,
            elid: elid,
            type: pName
          };
          EventMgr.trigger('ajaxRequest', {
            url: pageInfo.url,
            param: params,
            invar: {
              hintTabId: tabId,
              hintElid: elid,
              hintPName: pName,
              hintValue: value,
              self: self },
            type: 'get',
            outtype: 'json',
            trfunc: 'ajaxResponseHint',
            queue: 'actHint' + tabId,
            failfunc: 'failCommonAjaxResponse' });

        } else {
          currentHintId = tabId + value + elid + pName;
          EventMgr.trigger('getActiveHint', {
            tabId: tabId,
            elid: elid,
            pName: pName,
            value: value,
            self: self });
        }

        hintShowHandler.apply(_this, [{}, true]);
        e.preventDefault();
        e.stopPropagation();
      },
      /**
       * Update hint content when got response of active hint
       * @param {object} e
       * @param {object} data
       */
      updateHint = function(e, data) {
        var elid = data.hintElid,
            tabId = data.hintTabId,
            pName = data.hintPName,
            value = data.hintValue,
            self = data.self,
            id = tabId + value + elid + pName,
            textValue;
        if (currentHintId === id) {
          if (!data.hint || data.hint === '') {
            textValue = 'Oops..';
          } else {
            textValue = window.htmlDecode(data.hint);
          }
          textValue = window.filterXSS(textValue);
          $$hintBoxInner.html(textValue);
          setHintPosition(self, false);
        }
      },
      /**
       * Show HTML Node of hint
       * @param {object} self jQuery object of element
       * @param {boolean} force Force show hint flag
       */
      hintShow = function(self, force) {
        $$hintBoxInner = $$hintBoxInner || $hintBoxInnerFn();
        $$hintBox = $$hintBox || $hintBoxFn();
        //check for hint show by self
        if (self !== undefined && typeof self.width === 'function') {
          setHintPosition(self, false);
        }
        $$hintBox.addClass('active');
        if (force) {
          $$hintBox.css('visibility', 'visible');
        } else {
          $$hintBox.css('visibility', '');
        }
        clearTimeout(timer);
      },

      hintHideHandler = function(e) {
        hintHide();
        clearTimeout(timer);
      },
      /**
       * Hide HTML Node of hint
       */
      hintHide = function() {
        $$hintBox = $$hintBox || $hintBoxFn();
        $$hintBox.removeClass('active');
        $$hintBox.find('.hint-cont').html();
        currentHintId = '';
        clearTimeout(timer);
      },

      renderTip = function(tipObject, inTab) {
        var html = templates.tip(tipObject);
        if (inTab) {
          $('.tab-content_st_active').append(html);
        } else {
          $body().append(html);
        }
        return $('.b-tip_name_' + tipObject.name);
      },
      actTip,
      /**
       * show Tips
       * @param {object} e
       * @param {object} data
       *
       * find target element by classname i-tip-target_st_NAME
       * */
      showTips = function(e, data) {
        actTip = data;
        var tips = data.tips,
            inTab = data.inTab,
            tabId = data.tabId,
            l = tips.length,
            sameModule = data.sameModule,
            $target, $tip,
            TABMARGINTOP = 69,
            TABMARGINLEFT = 205,
            forceRight = false,
            forceBottom = false;
        //show only one tip
        if ($('.b-tip').length) {
          return;
        }
        while (l--) {
          //check for exist this tip
          if ($('.b-tip_name_' + tips[l].name).length) {
            continue;
          }
          //check for sameModule load form menu
          if (tips[l].name === 'title_reload' && !sameModule) {
            continue;
          }
          if (tips[l].name === 'mbar_pin') {
            inTab = false;
          }
          if (tips[l].name === 'tabs_close') {
            if ($('.tab-group').length < 9) {
              continue;
            }
            inTab = false;
          }
          //show inside tab
          if (inTab) {
            $target = $('#cont-' + tabId + ' .i-tip-target_st_' + tips[l].name);
          } else {
            $target = $('.i-tip-target_st_' + tips[l].name);
          }
          //show textarea only when it focused
          if (tips[l].name === 'textarea_resize' && !data.textareaTip) {
            $('.b-textarea').bind('focus', showTipsForTextarea);
            textareaTip = [tips[l]];
            continue;
          } else if (data.textareaTip) {
            var $textarea = $('.b-textarea');
            if ($target.length) {
              var $targetTextarea = $target.prev();
                if ($targetTextarea.length) {
                var height = $targetTextarea[0].offsetHeight,
                    scrollHeight = $targetTextarea[0].scrollHeight - 1;
                if (height < scrollHeight) {
                  $textarea.off('focus', showTipsForTextarea);
                  forceBottom = true;
                } else {
                  continue;
                }
              }
            }
          }

          //force bottom position for new_btn tip
          if (tips[l].name === 'btn_new') {
            forceBottom = true;
          }
          if ($target.length) {
            //check for visibility
            if ($target[0].offsetWidth === 0 || $target[0].offsetHeight === 0) {
              continue;
            }
            $tip = renderTip(tips[l], inTab);
            setHintPosition($target, false, $tip, $tip.find('.b-tip__inner'), forceRight, forceBottom);
            //correct position inside tab
            if (inTab) {
              $tip.css('top', parseFloat($tip.css('top')) - TABMARGINTOP);
              var left;
              if ($tip.length) {
                left = $tip[0].style.left;
              }
              if (left) {
                $tip.css('left', parseFloat(left) - TABMARGINLEFT);
              }
            }
            $target.on('click', $.proxy(closeTipByCross, {
              elem: $tip.find('.b-tip__close') }));
          }
        }
      },

      textareaTip = [],

      showTipsForTextarea = function(e) {
        var tabId = this.getAttribute('data-tabid'),
            tips = textareaTip;
        EventMgr.trigger('showTips', {
              tips: tips,
              inTab: true,
              textareaTip: true,
              tabId: tabId });
      },

      closeTipByCross = function(e) {
        var self = this,
            $self = $(this);
        if (this.elem && this.elem[0]) {
          this.elem.trigger('click');
          return;
        }
        var id = self.getAttribute('data-name');
        if (!id) {
          id = $self.find('.b-tip__close').attr('data-name');
        } else {
          $self = $self.closest('.b-tip');
        }
        var param = {
          func: 'tip',
          elid: id
        };
        EventMgr.trigger('ajaxRequest', {
          param: param,
          type: 'get',
          outtype: 'json',
          trfunc: 'DoNothing',
          queue: 'noqueue' });
        //$('.i-tip-target_st_' + id).off('click');

        actTip = null;
        $self.remove();
      },

      closeTip = function(e) {
        $(this).remove();
        actTip = null;
      },

      checkTipsForDesktop = function(e, data) {
        if (pageInfo && pageInfo.tips) {
          //timeout for make all objects in theme
          setTimeout(function() {
            showTips.apply(window, [{}, { tips: pageInfo.tips }]);
          }, 1500);
        }
      },
      /**
       * update position for Tip
       * @param {object} e
       * @param {object} data
       */
      updateTipPosition = function(e, data) {
        if (actTip) {
          $('.b-tip').remove();
          showTips.apply(window, [{}, actTip]);
        }
      };

  return {
    init: init
  };
}(window, $, EventMgr, App);