/**
 * Blocks fabric - main object for whole blocks manipulations
 */
function ptsBlockFabric() {
  this._blocks = [];
  this._isSorting = false;
  this._animationSpeed = g_ptsAnimationSpeed;
}
ptsBlockFabric.prototype.addFromHtml = function (blockData, jqueryHtml) {
  var block = this.add(blockData);
  block.setRaw(jqueryHtml);
};
ptsBlockFabric.prototype.add = function (blockData) {
  var blockData = jQuery.extend({}, blockData);
  if (!blockData.original_id) {
    blockData.original_id = blockData.id;
    blockData.id = 0;
  }
  var blockClass = window['ptsBlock_' + blockData.cat_code];
  if (blockClass) {
    var block = new blockClass(blockData);
    var blockIter = this._blocks.push(block);
    block.setIter(blockIter - 1);
    return block;
  } else {
    // console.log('Block Class For ' + blockData.cat_code + ' Not Found!!!');
  }
};
ptsBlockFabric.prototype.getByViewId = function (viewId) {
  if (this._blocks && this._blocks.length) {
    for (var i = 0; i < this._blocks.length; i++) {
      if (this._blocks[i].get('view_id') == viewId) {
        return this._blocks[i];
      }
    }
  }
  return false;
};
/**
 * Base block object - for extending
 * @param {object} blockData all block data from database (block database row)
 */
function ptsBlockBase(blockData) {
  this._data = blockData;
  this._$ = null;
  this._original$ = null;
  this._id = 0;
  this._iter = 0;
  this._elements = [];
  this._animationSpeed = 300;
  this._disableContentChange = false;
  //this._oneTimeElementsInited = false;
}
ptsBlockBase.prototype.get = function (key) {
  return this._data[key];
};
ptsBlockBase.prototype.getParam = function (key) {
  return this._data.params[key] ? this._data.params[key].val : false;
};
ptsBlockBase.prototype.setParam = function (key, value) {
  if (!this._data.params[key]) this._data.params[key] = {};
  this._data.params[key].val = value;
};
ptsBlockBase.prototype.getRaw = function () {
  return this._$;
};
/**
 * Alias for getRaw method
 */
ptsBlockBase.prototype.$ = function () {
  return this.getRaw();
};
ptsBlockBase.prototype.setRaw = function (jqueryHtml) {
  this._$ = jqueryHtml;
  this._resetElements();
  this._initHtml();
  if (this.getParam('font_family')) {
    this._setFont(this.getParam('font_family'));
  }
};
ptsBlockBase.prototype._initElements = function () {
  this._initElementsForArea(this._$);
};
ptsBlockBase.prototype._initElementsForArea = function (area) {
  var block = this,
    addedElements = [];
  var initElement = function (htmlEl) {
    var elementCode = jQuery(htmlEl).data('el'),
      elementClass = window['ptsElement_' + elementCode];
    if (elementClass) {
      var newElement = new elementClass(jQuery(htmlEl), block);
      newElement._setCode(elementCode);
      var newIterNum = block._elements.push(newElement);
      addedElements.push(newElement);
      newElement.setIterNum(newIterNum - 1); // newIterNum == new length of _elements array, iterator number for element - is new length - 1
    } else {
      // if (g_ptsEdit)
      // console.log('Undefined Element [' + elementCode + '] !!!');
    }
  };
  jQuery(area)
    .find('.ptsEl')
    .each(function () {
      initElement(this);
    });
  if (jQuery(area).hasClass('ptsEl')) {
    initElement(area);
  }
  this._afterInitElements();
  return addedElements;
};
ptsBlockBase.prototype._afterInitElements = function () {};
ptsBlockBase.prototype._resetElements = function () {
  this._clearElements();
  this._initElements();
};
ptsBlockBase.prototype._clearElements = function () {
  if (this._elements && this._elements.length) {
    for (var i = 0; i < this._elements.length; i++) {
      this._elements[i].destroy();
    }
    this._elements = [];
  }
};
ptsBlockBase.prototype.getElements = function () {
  return this._elements;
};
ptsBlockBase.prototype._initHtml = function () {};
/**
 * ID number in list of canvas elements
 * @param {numeric} iter Iterator - number in all blocks array - for this element
 */
ptsBlockBase.prototype.setIter = function (iter) {
  this._iter = iter;
};
ptsBlockBase.prototype.showLoader = function (txt) {
  var loaderHtml = jQuery('#ptsBlockLoader');
  txt = txt ? txt : loaderHtml.data('base-txt');
  loaderHtml.find('.ptsBlockLoaderTxt').html(txt);
  loaderHtml
    .css({
      height: this._$.height(),
      top: this._$.offset().top,
    })
    .addClass('active');
};
ptsBlockBase.prototype.hideLoader = function () {
  var loaderHtml = jQuery('#ptsBlockLoader');
  loaderHtml.removeClass('active');
};
ptsBlockBase.prototype._setFont = function (fontFamily) {
  var $fontLink = this._getFontLink();
  // If this is not standard font - it should be Google font, so - load it from Google Fonts server here

  if (toeInArrayPts(fontFamily, ptsBuildConst.standardFonts) === false) {
    $fontLink.attr({
      href: 'https://fonts.googleapis.com/css?family=' + encodeURIComponent(fontFamily),
      //,	'data-font-family': fontFamily
    });
  }
  this._$.css({
    'font-family': fontFamily,
  });
  this.setParam('font_family', fontFamily);
};
ptsBlockBase.prototype._getFontLink = function () {
  var $link = this._$.find('link.ptsFont');
  if (!$link.length) {
    $link = jQuery('<link class="ptsFont" rel="stylesheet" type="text/css"/>').appendTo(this._$);
  }
  return $link;
};
ptsBlockBase.prototype.getElementByIterNum = function (iterNum) {
  return this._elements[iterNum];
};
ptsBlockBase.prototype.removeElementByIterNum = function (iterNum) {
  this._elements.splice(iterNum, 1);
  if (this._elements && this._elements.length) {
    for (var i = 0; i < this._elements.length; i++) {
      this._elements[i].setIterNum(i);
    }
  }
};
// ptsBlockBase.prototype.destroyElementByIterNum = function(iterNum, clb) {
// 	this.getElementByIterNum( iterNum ).destroy( clb );	// It will call removeElementByIterNum() inside element destroy method
// };
ptsBlockBase.prototype.destroyElementByIterNum = function (iterNum, clb) {
  var element = this.getElementByIterNum(iterNum);
  if (element) {
    element.destroy(clb); // Pass the callback to destroy
  } else if (clb && typeof clb === 'function') {
    clb(); // If no element, still call callback
  }
};
/**
 * Price table block base class
 */
function ptsBlock_price_table(blockData) {
  this._increaseHoverFontPerc = 20; // Increase font on hover effect, %
  this._$lastHoveredCol = null;
  this._refreshColsBinded = false;
  this._onloadHandle = false;
  this._isAlreadyShowed = false;
  this._isResponsiveDescInit = false;
  ptsBlock_price_table.superclass.constructor.apply(this, arguments);
}
extendPts(ptsBlock_price_table, ptsBlockBase);
ptsBlock_price_table.prototype._getColsContainer = function () {
  return this._$.find('.ptsColsWrapper:first');
};
ptsBlock_price_table.prototype._getCols = function (includeDescCol) {
  return this._getColsContainer().find('.ptsCol' + (includeDescCol ? '' : ':not(.ptsTableDescCol)'));
};
ptsBlock_price_table.prototype._initTooltipsForCells = function () {
  if (this.getParam('disable_custom_tooltip_style') != '1') {
    var $tooltipstedCells = this._$.find('.ptsCell[title], .ptsColFooter[title], .ptsColHeader[title], .ptsColDesc[title]');
    if ($tooltipstedCells && $tooltipstedCells.length) {
      // TODO: Move this to Options and make this part more flexible
      var tooltipsterSettings = {
        contentAsHTML: true,
        interactive: true,
        speed: 250,
        delay: 0,
        animation: 'swing',
        maxWidth: 450,
        position: 'top',
      };
      $tooltipstedCells.tooltipster(tooltipsterSettings);

      $tooltipstedCells.each(function () {
        var el = jQuery(this);
        el.attr('data-title', el.attr('title')).removeAttr('title');
      });
    }
  }
};
ptsBlock_price_table.prototype._afterInitElements = function () {
  ptsBlock_price_table.superclass._afterInitElements.apply(this, arguments);
  if (parseInt(this.getParam('enb_hover_animation')) == 1) {
    this._initHoverEffect();
  }
  if (this.getParam('table_align')) this._$.addClass('ptsTableAlign_' + this.getParam('table_align'));
  if (this.getParam('text_align')) this._$.addClass('ptsAlign_' + this.getParam('text_align'));
  if (this.getParam('ajax')) this._$.addClass('ptsAjax_' + this.getParam('ajax'));
  if (!this._disableContentChange) {
    this._refreshCellsHeight();
  }
  if (!this._refreshColsBinded) {
    this._$.bind(
      'ptsBlockContentChanged',
      jQuery.proxy(function () {
        this._refreshCellsHeight();
      }, this)
    );
    this._refreshColsBinded = true;
  }
  if (!_ptsIsEditMode()) {
    // Not for edit mode unfortunatelly ....
    this._initTooltipsForCells();
    /*var $tooltipstedCells = this._$.find('.ptsCell[title], .ptsColFooter[title], .ptsColHeader[title], .ptsColDesc[title]');

    if(this.getParam('disable_custom_tooltip_style') != '1') {
      if($tooltipstedCells && $tooltipstedCells.length) {
        // TODO: Move this to Options and make this part more flexible
        var tooltipsterSettings = {
          contentAsHTML: true
          ,	interactive: true
          ,	speed: 250
          ,	delay: 0
          ,	animation: 'swing'
          ,	maxWidth: 450
          ,	position: 'top'
        };
        $tooltipstedCells.tooltipster( tooltipsterSettings );
      }
    }*/
    var self = this,
      PTS_VISIBLE_SET_HEIGHT_KEY = 'PTS-VISIBLE-SET-HEIGHT-KEY';

    this._fixResponsive();

    jQuery(window).resize(function () {
      if (!self._$.is(':visible')) {
        self._$.data(PTS_VISIBLE_SET_HEIGHT_KEY, false);
      } else {
        self._fixResponsive();
        self._refreshCellsHeight();
      }
    });
    jQuery('.ptsTableFrontedShell .ptsPreDisplayStyle').remove();
    jQuery('.ptsBlock').css({
      opacity: '1',
      visibility: 'visible',
    });
    jQuery(window).on('toggleChangeCellHeight', function () {
      self._refreshCellsHeight();
    });
    jQuery(function () {
      var isEnableLazyLoad = function () {
          return self._$.find('img[data-lazy-src]:not(.lazyloaded)').length > 0;
        },
        checkedLazyLoadLib = false;

      if (isEnableLazyLoad()) {
        checkedLazyLoadLib = true;
      }

      var observer = new MutationObserver(function (mutationsList) {
        for (var mutation of mutationsList) {
          if (mutation.type === 'childList') {
            jQuery(mutation.addedNodes).each(function () {
              if (this.nodeType === 1 && this.nodeName === 'IMG' && self._$ && self._$.get(0) && jQuery.contains(self._$.get(0), this)) {
                if (checkedLazyLoadLib) {
                  var isLoadedImages = true;

                  self._$.find('img[data-lazy-src]').each(function () {
                    var $this = jQuery(this);

                    if (!$this.hasClass('lazyloaded') && !$this.hasClass('lazyload')) {
                      isLoadedImages = false;
                    }
                  });

                  if (isLoadedImages) {
                    checkedLazyLoadLib = false;

                    self._$.find('img[data-lazy-src]').on('load', function () {
                      self._fixResponsive();
                      self._refreshCellsHeight();
                    });
                  }
                }
              }
            });
          }
        }

        if (self._isAlreadyShowed || !self._$) return;

        if (self._$.visible()) {
          self._isAlreadyShowed = true;
          self._fixResponsive();
          self._refreshCellsHeight();
        }
      });

      observer.observe(document.body, {
        childList: true,
        subtree: true,
      });

      self.setCalcWidth();
    });
  } else {
    this.columnChidrensWidthCalc();
  }

  var self = this;

  if (!this._onloadHandle) {
    this._onloadHandle = true;
    jQuery(window).on('load', function () {
      self._refreshCellsHeight();
    });
  }
};
ptsBlock_price_table.prototype._initHoverEffect = function () {
  // if(_ptsIsEditMode()) {
  // 	this.setParam('enb_hover_animation', 1);
  // 	return;
  // }

  if (parseInt(this.getParam('enb_hover_animation')) == 1) {
    var $cols = this._getCols(),
      self = this;
    $cols
      .mouseenter((e) => {
        self._increaseHoverFont(jQuery(e.currentTarget));
      })
      .mouseleave((e) => {
        self._backHoverFont(jQuery(e.currentTarget));
      })
      .mouseover((e) => {
        self._increaseHoverFont(jQuery(e.currentTarget));
      })
      .mouseout((e) => {
        self._backHoverFont(jQuery(e.currentTarget));
      });
  }
};
ptsBlock_price_table.prototype._increaseHoverFont = function ($col) {
  var self = this;
  if (_ptsIsEditMode()) return; // Not for edit mode unfortunatelly ....
  var $descCell = $col.find('.ptsColDesc');
  $col.height($col.height()); // Reset height on frontend.tables.js (listeners: window resize)
  $descCell.find('span').each(function () {
    var newFontSize = jQuery(this).data('new-font-size');
    if (!newFontSize) {
      var prevFontSize = jQuery(this).css('font-size'),
        fontUnits = prevFontSize.replace(/\d+/, ''),
        fontSize = parseInt(str_replace(prevFontSize, fontUnits, ''));
      if (fontSize && fontUnits) {
        newFontSize = Math.ceil(fontSize + (self._increaseHoverFontPerc * fontSize) / 100);
        jQuery(this).data('prev-font-size', prevFontSize).data('font-units', fontUnits).data('new-font-size', newFontSize);
      }
    }
    if (newFontSize) {
      jQuery(this).css('font-size', newFontSize + jQuery(this).data('font-units'));
    }
  });

  if (this.getParam('is_horisontal_row_type') != '1') {
    if (!$descCell.attr('data-prev-height')) {
      var descHeight = $descCell.outerHeight();
      $descCell.attr('data-prev-height', descHeight);
    } else {
      descHeight = $descCell.attr('data-prev-height');
    }
    $descCell.css({
      'min-height': descHeight,
      height: 'auto',
    });
  }

  $col.addClass('hover');
  if (_ptsIsEditMode()) {
    setTimeout(function () {
      var colElement = self.getElementByIterNum($col.data('iter-num'));
      if (colElement) {
        colElement.repositeMenu();
      }
    }, g_ptsHoverAnim); // 300 - standard animation speed
  }
};
ptsBlock_price_table.prototype._backHoverFont = function ($col) {
  if (_ptsIsEditMode()) return; // Not for edit mode unfortunatelly ....
  $col.removeClass('hover');
  var $descCell = $col.find('.ptsColDesc');
  $descCell.find('span').each(function () {
    var prevFontSize = jQuery(this).data('prev-font-size');
    if (prevFontSize) {
      jQuery(this).css('font-size', prevFontSize);
    }
  });
  setTimeout(function () {
    $descCell.outerHeight($descCell.data('prev-height'));
  }, 300); // time is set in css styles, but it always is something around 300ms
};
ptsBlock_price_table.prototype._disableHoverEffect = function ($cols) {
  if (_ptsIsEditMode()) return; // Not for edit mode unfortunatelly ....
  $cols = $cols ? $cols : this._getCols();
  //$cols.unbind('hover.animation');
};
ptsBlock_price_table.prototype.getColSelectors = function () {
  return {
    header: { sel: '.ptsColHeader' },
    desc: { sel: '.ptsColDesc' },
    rows: { sel: '.ptsRows' },
    cells: { sel: '.ptsCell' },
    footer: { sel: '.ptsColFooter' },
  };
};
ptsBlock_price_table.prototype.getMaxColsSizes = function (widthDesc) {
  var $cols = this._getCols(widthDesc),
    sizes = this.getColSelectors();

  $cols.each(function () {
    //fix effects from bug with large min-height in frontend #266
    jQuery(this).css({ 'min-height': 'auto' });
    for (var key in sizes) {
      if (key == 'rows') continue;
      var $entity = jQuery(this).find(sizes[key].sel);
      if ($entity && $entity.length) {
        if (key == 'cells') {
          if (!sizes[key].height) sizes[key].height = [];
          var cellNum = 0;
          $entity.each(function () {
            var prevHeight = jQuery(this).outerHeight();

            jQuery(this).css('height', 'auto');
            var height = jQuery(this).outerHeight();

            if (!sizes[key].height[cellNum] || sizes[key].height[cellNum] < height) {
              sizes[key].height[cellNum] = height;
            }
            //jQuery(this).outerHeight( prevHeight );
            cellNum++;
          });
        } else {
          var prevHeight = $entity.outerHeight();

          $entity.css('height', 'auto');
          var height = $entity.outerHeight();

          if (!sizes[key].height || sizes[key].height < height) {
            sizes[key].height = height;
          }
          $entity.outerHeight(prevHeight);
        }
      }
    }
  });
  return sizes;
};
ptsBlock_price_table.prototype.getColumnWithInfo = function (strWidthAttr) {
  var trimAttr = strWidthAttr.trim();
  var number = trimAttr.match('\\d+');
  var isPerc = trimAttr.match('%');
  var isPx = trimAttr.match('\\d+');
  if (number === null || (isPerc === null && isPx === null)) {
    return null;
  }
  return new Object({
    num: number.length && number.length > 0 && !isNaN(parseInt(number[0])) ? parseInt(number[0]) : null,
    isPerc: isPerc === null ? false : true,
  });
};
ptsBlock_price_table.prototype.setColsWidth = function (width, perc) {
  var thatObj = this;
  if (thatObj.getParam('is_horisontal_row_type') != '1') {
    if (this.getParam('dsbl_responsive') === '1') {
      var tableWidth = this._$.width(),
        fixedValueTableWidth = this._$.width(),
        $cols = this._getCols(true),
        notSettedColumnWidthArr = new Array();
      $cols.each(function () {
        var col1 = jQuery(this);
        if (col1.length > 0 && col1[0].style && col1[0].style.width) {
          var colWidthObj = thatObj.getColumnWithInfo(col1[0].style.width);
          if (colWidthObj && 'num' in colWidthObj && 'isPerc' in colWidthObj) {
            var calcColWidth = 0;
            if (colWidthObj.isPerc) {
              calcColWidth = (fixedValueTableWidth * colWidthObj.num) / 100;
            } else {
              calcColWidth = colWidthObj.num;
            }
            var colPdL = parseFloat(col1.css('padding-left')),
              colPdR = parseFloat(col1.css('padding-right')),
              colMgL = parseFloat(col1.css('margin-left')),
              colMgR = parseFloat(col1.css('margin-right')),
              colSumMarginPadding = 0;
            if (!isNaN(colPdL)) {
              colSumMarginPadding += colPdL;
            }
            if (!isNaN(colPdR)) {
              colSumMarginPadding += colPdR;
            }
            if (!isNaN(colMgL)) {
              colSumMarginPadding += colMgL;
            }
            if (!isNaN(colMgR)) {
              colSumMarginPadding += colMgR;
            }
            tableWidth -= calcColWidth;
            calcColWidth = Math.floor(calcColWidth - colSumMarginPadding);
            if (calcColWidth < 0) {
              calcColWidth = 0;
            }
            col1.width(calcColWidth);
          } else {
            notSettedColumnWidthArr[notSettedColumnWidthArr.length] = col1;
          }
        } else {
          notSettedColumnWidthArr[notSettedColumnWidthArr.length] = col1;
        }
      });
      if (tableWidth > 0 && notSettedColumnWidthArr.length > 0) {
        var calcWidthForNsCol = Math.round(tableWidth / notSettedColumnWidthArr.length);
        for (var oneNsColumn in notSettedColumnWidthArr) {
          // set width for Other columns
          notSettedColumnWidthArr[oneNsColumn].width(calcWidthForNsCol);
        }
      }
    } else {
      width = parseFloat(width);
      if (width) {
        if (!perc) {
          this.setParam('col_width', width);
        }
        var $cols = this._getCols(true);
        if (perc) {
          width += '%';
        } else {
          width += 'px';
        }
        $cols.css({
          width: width,
        });
      }
    }
  } else {
    this.columnChidrensWidthCalc();
  }
};
ptsBlock_price_table.prototype.columnChidrensWidthCalc = function () {
  if (this.getParam('is_horisontal_row_type') != '1') {
    return;
  }
  // only for HORIZONTAL ROW
  var $cols = this._getCols(true);
  $cols.each(function (ind, oneCol) {
    var currColumn = jQuery(oneCol),
      emptyChilds = currColumn.find('.ptsTableElementContent').children(':not(:has(">div")):not(".ptsColBadge")'),
      level1Childs = currColumn.find('.ptsTableElementContent').children(':has(">div"):not(".ptsColBadge")'),
      level1ChildRows = currColumn.find('.ptsTableElementContent').children('.ptsRows'),
      level2ChildRows = level1ChildRows.children(),
      allChildCount = level1Childs.length,
      level2ChildCount = 1;

    if (level1ChildRows.length > 0 && level2ChildRows.length > 0) {
      allChildCount += level2ChildRows.length - 1;
      level2ChildCount = level2ChildRows.length;
    }
    //
    emptyChilds.css({
      width: '0%',
      margin: '0',
      padding: '0',
    });
    var oneChildWidth = Math.floor(95 / allChildCount);

    level1Childs.css('width', oneChildWidth + '%');
    var widthInPixel = level1Childs.css('width');
    level1ChildRows.css('width', level2ChildCount * oneChildWidth + 2 + '%');
    level2ChildRows.css('width', widthInPixel);
  });
};
ptsBlock_price_table.prototype.checkColWidthPerc = function () {
  if (this.getParam('calc_width') === 'table') {
    this.setColWidthPerc();
  }
};
ptsBlock_price_table.prototype.setColWidthPerc = function () {
  var $cols = this._getCols(parseInt(this.getParam('enb_desc_col')));
  this.setColsWidth(100 / $cols.length, true);
};
ptsBlock_price_table.prototype.setTableWidth = function (width, measure) {
  if (width && parseInt(width)) {
    width = parseInt(width);
    this.setParam('table_width', width);
  } else {
    width = this.getParam('table_width');
  }
  if (measure) {
    this.setParam('table_width_measure', measure);
  } else {
    measure = this.getParam('table_width_measure');
  }
  this._$.width(width + measure);
};
ptsBlock_price_table.prototype.setTableVertPadding = function (padding, measure) {
  if (padding && parseInt(padding)) {
    padding = parseInt(padding);
    this.setParam('vert_padding', padding);
  } else {
    padding = this.getParam('vert_padding');
  }
  if (measure) {
    this.setParam('vert_padding_measure', measure);
  } else {
    measure = this.getParam('vert_padding_measure');
  }
  this._$.find('.ptsCol').css('paddingBottom', padding + 'px');
};
ptsBlock_price_table.prototype.setCalcWidth = function (type) {
  if (type) {
    this.setParam('calc_width', type);
  } else {
    type = this.getParam('calc_width');
  }
  switch (type) {
    case 'table':
      this.setTableWidth();
      this.setColWidthPerc();
      break;
    case 'col':
      var enb_desc_col = this.getParam('enb_desc_col') != 0 ? true : false;
      this._$.width(this._getCols(enb_desc_col).length * this.getParam('col_width'));
      this.setColsWidth(this.getParam('col_width'));
      break;
  }
};
ptsBlock_price_table.prototype._fixResponsive = function () {
  if (this.getParam('is_horisontal_row_type') == '1') {
    var $parent = this._$.parents('.ptsTableFrontedShell:first').parent(),
      parentWidth = $parent.width();

    if (jQuery(window).width() < 600) {
      $parent.addClass('ptsResponcive');
    } else {
      $parent.removeClass('ptsResponcive');
    }
    return;
  }
  var $parent = this._$.parents('.ptsTableFrontedShell:first').parent(),
    parentWidth = $parent.width(),
    widthMeasure = this.getParam('table_width_measure'),
    calcWidth = this.getParam('calc_width'),
    includeDesc = parseInt(this.getParam('enb_desc_col')),
    $cols = this._getCols(includeDesc),
    actualTblWidth = this._$.width(),
    criticalColWidth = isNaN(parseInt(this.getParam('resp_min_col_width'))) ? 150 : parseInt(this.getParam('resp_min_col_width')),
    dsblResponsive = parseInt(this.getParam('dsbl_responsive'));
  this._$.removeClass('ptsBlockMobile');
  switch (calcWidth) {
    case 'table':
      switch (widthMeasure) {
        case '%':
          var self = this,
            removeOtherDescCol = function () {
              if (!dsblResponsive && !_ptsIsEditMode() && self._$.find('.ptsTableDescCol').length > 1 && includeDesc) {
                var $descCols = self._$.find('.ptsTableDescCol'),
                  firstCol = false;

                $descCols.each(function () {
                  var $this = jQuery(this);
                  if (!firstCol) {
                    firstCol = true;
                    return;
                  }
                  $this.remove();
                });
              }
            };

          //removeOtherDescCol();

          $cols = this._getCols(includeDesc);
          // There can be several desc cols - exclude those invalid numbers
          var descColNum = $cols.filter('.ptsTableDescCol').length;

          var colsNum = $cols.length - (descColNum > 1 ? descColNum - 1 : 0),
            currWidth = actualTblWidth / colsNum;

          if (currWidth <= criticalColWidth && !dsblResponsive) {
            $cols.css('width', '100%');

            if (!_ptsIsEditMode() && includeDesc) {
              var $descColumn = this._$.find('.ptsTableDescCol').first(),
                $columns = this._$.find('.ptsCol:not(.ptsTableDescCol)'),
                firstCol = false;
              removeOtherDescCol();

              var i = 0;
              $columns.each(function () {
                var $this = jQuery(this);

                if (!firstCol) {
                  firstCol = true;
                  return;
                }

                i++;
                var $descClone = $descColumn.clone();
                $descClone
                  .find('.tooltipstered[data-title]')
                  .removeClass('tooltipstered')
                  .each(function () {
                    var el = jQuery(this);
                    el.attr('title', el.attr('data-title')).removeAttr('data-title');
                  });
                $descClone.insertBefore($this);
              });
              this._initTooltipsForCells();

              this._isResponsiveDescInit = true;
              this._$.find('.ptsCol').css('width', '50%');
            }

            this._$.addClass('ptsBlockMobile');
            this.setParam('went_to_responsive', 1);
          } else {
            removeOtherDescCol();
            if (this.getParam('went_to_responsive')) {
              this.setColWidthPerc();
              this.setParam('went_to_responsive', 0);
            }
          }
          break;
        case 'px':
          if (actualTblWidth > parentWidth) {
            this.setParam('went_to_responsive', this.getParam('table_width'));
            this.setTableWidth(100, '%'); // make it 100% in this case
            this._fixResponsive(); // Repeat - to check case '%':
          } else if (this.getParam('went_to_responsive')) {
            this.setTableWidth(this.getParam('went_to_responsive'), 'px'); // Back to px width
            this.setParam('went_to_responsive', 0);
          }
          break;
      }
      break;
    case 'col':
      var colsNum = $cols.length,
        currWidth = parseFloat(this.getParam('col_width'));
      if (currWidth * colsNum >= parentWidth) {
        this.setParam('went_to_responsive', currWidth);
        this.setParam('table_width', 100); // Set table width to 100%
        this.setParam('table_width_measure', '%');
        this.setCalcWidth('table');
        this._fixResponsive(); // Repeat - to check case '%':
      } else if (this.getParam('went_to_responsive')) {
        this.setCalcWidth('col');
        this.setParam('col_width', this.getParam('went_to_responsive')); // Back to px width
        this.setParam('went_to_responsive', 0);
      }
      break;
  }
};
ptsBlock_price_table.prototype._refreshCellsHeight = function () {
  // Really important  - keep all this functionality as light as possible, as it can slow down whole builder work
  var $cols = this._getCols(true),
    self = this,
    sizes = this.getMaxColsSizes(true);

  $cols.each(function () {
    for (var key in sizes) {
      var $entity = jQuery(this).find(sizes[key].sel);
      if (self.getParam('is_horisontal_row_type') == '1') {
        $entity.css({ height: 'auto' });
      } else {
        if (key == 'rows') {
          $entity.css({ height: 'auto' });
          continue;
        }
        if ($entity && $entity.length) {
          if (key == 'cells') {
            var cellNum = 0;
            $entity.each(function () {
              jQuery(this).css('height', sizes[key].height[cellNum]);
              cellNum++;
            });
          } else {
            $entity.outerHeight(sizes[key].height);

            if ($entity.outerHeight() != sizes[key].height) {
              $entity.css('height', sizes[key].height);
            }
          }
        }
      }
    }
  });
};

// ELEMENTS BASE JS

function ptsElementBase(jqueryHtml, block) {
  this._iterNum = 0;
  this._id = 'el_' + mtRand(1, 999999);
  this._animationSpeed = g_ptsAnimationSpeed;
  this._$ = jqueryHtml;
  this._block = block;
  if (typeof this._menuOriginalId === 'undefined') {
    this._menuOriginalId = '';
  }
  this._innerImgsCount = 0;
  this._innerImgsLoaded = 0;
  //this._$menu = null;
  this._menu = null;
  this._menuClbs = {};
  if (typeof this._menuClass === 'undefined') {
    this._menuClass = 'ptsElementMenu';
  }
  this._menuOnBottom = false;
  this._code = 'base';

  this._initedComplete = false;
  this._editArea = null;
  if (typeof this._isMovable === 'undefined') {
    this._isMovable = false;
  }
  this._moveHandler = null;
  this._sortInProgress = false;
  if (typeof this._showMenuEvent === 'undefined') {
    this._showMenuEvent = 'click';
  }
  if (typeof this._changeable === 'undefined') {
    this._changeable = false;
  }
  if (g_ptsEdit) {
    this._init();
    this._initMenuClbs();
    this._initMenu();

    var images = this._$.find('img');
    if (images && (this._innerImgsCount = images.length)) {
      this._innerImgsLoaded = 0;
      var self = this;
      images.load(function () {
        self._innerImgsLoaded++;
        if (self._$.find('img').length == self._innerImgsLoaded) {
          self._afterFullContentLoad();
        }
      });
    }
  }
  this._onlyFirstHtmlInit();
  this._initedComplete = true;
}
ptsElementBase.prototype.getId = function () {
  return this._id;
};
ptsElementBase.prototype.getBlock = function () {
  return this._block;
};
ptsElementBase.prototype._onlyFirstHtmlInit = function () {
  if (this._$ && !this._$.data('first-inited')) {
    this._$.data('first-inited', 1);
    return true;
  }
  return false;
};
ptsElementBase.prototype.setIterNum = function (num) {
  this._iterNum = num;
  this._$.data('iter-num', num);
};
ptsElementBase.prototype.getIterNum = function () {
  return this._iterNum;
};
ptsElementBase.prototype.$ = function () {
  return this._$;
};
ptsElementBase.prototype.getCode = function () {
  return this._code;
};
ptsElementBase.prototype._setCode = function (code) {
  this._code = code;
};
ptsElementBase.prototype._init = function () {
  this._beforeInit();
};
ptsElementBase.prototype._beforeInit = function () {};
ptsElementBase.prototype.destroy = function () {};
ptsElementBase.prototype.get = function (opt) {
  return jQuery('<div/>')
    .html(this._$.attr('data-' + opt))
    .text(); // not .data() - as it should be saved even after page reload, .data() will not create element attribute
};
ptsElementBase.prototype.set = function (opt, val) {
  this._$.attr('data-' + opt, jQuery('<div/>').text(val).html()); // not .data() - as it should be saved even after page reload, .data() will not create element attribute
};
ptsElementBase.prototype._getEditArea = function () {
  if (!this._editArea || this._$.attr('data-reset') == '1') {
    this._editArea = this._$.children('.ptsElArea');
    if (!this._editArea.length) {
      this._editArea = this._$.find('.ptsInputShell');
      this._$.removeAttr('data-reset');
    }
  }
  return this._editArea;
};
ptsElementBase.prototype._getOverlay = function () {
  return this._$.find('.ptsElOverlay');
};
/**
 * Standart button item
 */
function ptsElement_btn(jqueryHtml, block) {
  if (typeof this._menuOriginalId === 'undefined') {
    this._menuOriginalId = 'ptsElMenuBtnExl';
  }
  this._menuClass = 'ptsElementMenu_btn';
  this._haveAdditionBgEl = null;
  this._changeable = true;
  this.includePostLinks = true;
  ptsElement_btn.superclass.constructor.apply(this, arguments);
}
extendPts(ptsElement_btn, ptsElementBase);
ptsElement_btn.prototype._onlyFirstHtmlInit = function () {
  if (ptsElement_btn.superclass._onlyFirstHtmlInit.apply(this, arguments)) {
    if (this.get('customhover-clb')) {
      var clbName = this.get('customhover-clb');
      if (typeof this[clbName] === 'function') {
        var self = this;
        this._getEditArea().hover(
          function () {
            self[clbName](true, this);
          },
          function () {
            self[clbName](false, this);
          }
        );
      }
    }
  }
};
ptsElement_btn.prototype._hoverChangeFontColor = function (hover, element) {
  if (hover) {
    jQuery(element).data('original-color', this._getEditArea().css('color')).css('color', jQuery(element).parents('.ptsEl:first').attr('data-bgcolor')); // Ugly, but only one way to get this value in dynamic way for now
  } else {
    jQuery(element).css('color', jQuery(element).data('original-color'));
  }
};
ptsElement_btn.prototype._hoverChangeBgColor = function (hover, element) {
  var parentElement = jQuery(element).parents('.ptsEl:first'); // Actual element html
  if (hover) {
    parentElement.data('original-color', parentElement.css('background-color')).css('background-color', parentElement.attr('data-bgcolor')); // Ugly, but only one way to get this value in dynamic way for now
  } else {
    parentElement.css('background-color', parentElement.data('original-color'));
  }
};
ptsElement_btn.prototype._hoverBorderColor = function (hover, element) {
  //var parentElement = jQuery(element).parents('.ptsEl:first');	// Actual element html
  if (hover) {
    jQuery(element).data('original-color', jQuery(element).css('border-color')).css('border-color', jQuery(element).parents('.ptsEl:first').attr('data-bgcolor')); // Ugly, but only one way to get this value in dynamic way for now
  } else {
    jQuery(element).css('border-color', jQuery(element).data('original-color'));
  }
};
/**
 * Table column element
 */
function ptsElement_table_col(jqueryHtml, block) {
  if (typeof this._menuOriginalId === 'undefined') {
    this._menuOriginalId = 'ptsElMenuTableColExl';
  }
  if (typeof this._menuClass === 'undefined') {
    this._menuClass = 'ptsElementMenu_table_col';
  }
  if (typeof this._isMovable === 'undefined') {
    this._isMovable = true;
  }
  this._showMenuEvent = 'click';
  this._colNum = 0;
  ptsElement_table_col.superclass.constructor.apply(this, arguments);
  /*if(parseInt(this.get('enb-schedule'))) {
    console.log(this.getIterNum());
  }*/
}
extendPts(ptsElement_table_col, ptsElementBase);
ptsElement_table_col.prototype.setIterNum = function () {
  ptsElement_table_col.superclass.setIterNum.apply(this, arguments);
  if (!g_ptsEdit && typeof ptsScheduleCheck !== 'undefined') {
    ptsScheduleCheck(this);
  }
};
/**
 * Table description column element
 */
function ptsElement_table_col_desc(jqueryHtml, block) {
  this._isMovable = false;
  ptsElement_table_col_desc.superclass.constructor.apply(this, arguments);
  //this.refreshHeight();
  //var self = this;
  /*this.getBlock().$().bind('ptsBlockContentChanged', function(){
    self.refreshHeight();
  });*/
}
extendPts(ptsElement_table_col_desc, ptsElement_table_col);
/*ptsElement_table_col_desc.prototype.refreshHeight = function() {
  var sizes = this.getBlock().getMaxColsSizes();
  for(var key in sizes) {
    var $entity = this._$.find(sizes[ key ].sel);
    if($entity && $entity.length) {
      if(key == 'cells' &&  sizes[ key ].height) {
        var cellNum = 0;
        $entity.each(function(){
          if(typeof(sizes[ key ].height[ cellNum ]) !== 'undefined') {
            jQuery(this).css('height', sizes[ key ].height[ cellNum ]);
          }
          cellNum++;
        });
      } else {
        $entity.css('height', sizes[ key ].height);
      }
    }
  }
};*/

/**
 * Text element
 */
function ptsElement_table_cell_txt(jqueryHtml, block) {
  if (block.getParam('responsive_text')) {
    jqueryHtml.find('span, p').responsiveText({ minFontSize: 14 });
  }
  this.includePostLinks = true;
  ptsElement_table_cell_txt.superclass.constructor.apply(this, arguments);
}
extendPts(ptsElement_table_cell_txt, ptsElementBase);

// RESPONSIVE TEXT

(function ($) {
  $.fn.responsiveText = function (options) {
    // Setup options
    var settings = $.extend(
      {
        minFontSize: Number.NEGATIVE_INFINITY,
        maxFontSize: Number.POSITIVE_INFINITY,
      },
      options
    );

    return this.each(function () {
      // Store the object
      var $this = $(this),
        text = $this.get(0);

      if (!text) return;

      $this.data('original-font-size', parseFloat(window.getComputedStyle(text).fontSize), 10);

      // Resizer() resizes items based on the object width divided by the compressor * 10
      var resizer = function () {
        var ratio = null,
          originalWidth = window.screen.availWidth,
          currentWidth = window.innerWidth,
          size = $this.data('original-font-size');

        if (originalWidth == currentWidth || !size) return;

        if (currentWidth != originalWidth) ratio = originalWidth / currentWidth;

        if (currentWidth > originalWidth) size *= ratio;
        else size /= ratio;

        size = Math.max(Math.min(size, settings.maxFontSize), settings.minFontSize);

        $this.css('font-size', size + 'px');
      };

      resizer();

      // Call on resize. Opera debounces their resize by default.
      $(window).on('resize.responsiveText orientationchange.responsiveText', resizer);
    });
  };
})(jQuery);
// TABLES BASE
var g_ptsEdit = false,
  g_ptsBlockFabric = null,
  g_ptsHoverAnim = 300, // Table hover animation lenght, ms - hardcoded for now
  g_ptsHoverMargin = 20; // Table hover margin displace, px - hardcoded for now

//array with unique_id template that without enabled options header row
//overlap toggle elements
var g_ptsUniqueIdArray = ['wnOq3v2K', 'sa0DHT4h', 'B1gpCofW', 'ptmJ4YnA', 'r0OL4vCy'];

jQuery(document).ready(function () {
  _ptsInitFabric();
  if (typeof ptsTables !== 'undefined' && ptsTables && ptsTables.length) {
    for (var i = 0; i < ptsTables.length; i++) {
      g_ptsBlockFabric.addFromHtml(ptsTables[i], jQuery('#' + ptsTables[i].view_id));

      jQuery('body').trigger('set_default_position');
      //for fix horizontal element size bugs frontend.pro.tables.js
      if (ptsTables[i].unique_id === '7m6k5X0i') {
        jQuery('#' + ptsTables[i].view_id).attr('data-unique_id', ptsTables[i].unique_id);
      }

      // fix overlap toggle elements
      if (g_ptsUniqueIdArray.indexOf(ptsTables[i].unique_id) != -1) {
        jQuery('#' + ptsTables[i].view_id).attr('data-unique_id', ptsTables[i].unique_id);
        //if undefined that means options is enabled by default.

        var enableHeader = '1';
        if (typeof ptsTables[i].params.enb_head_row !== 'undefined') {
          enableHeader = typeof ptsTables[i].params.enb_head_row.val !== 'undefined' ? '0' : '1';
        }
        jQuery(document.body).trigger('overlay_toggle', [ptsTables[i].unique_id, enableHeader]);
      }
      //jQuery(".ptsTableFrontedShell .tooltipstered").removeAttr("title");
    }
    jQuery(window).bind('load', function () {
      if (typeof g_ptsAllowAddUndo !== 'undefined') {
        setTimeout(function () {
          g_ptsAllowAddUndo = true;
          _ptsAddUndoBuffer();
        }, 200);
      }
    });
  }
});
jQuery(window).on('load', function () {
  setTimeout(function () {
    jQuery('body').trigger('resize');
  }, 500);
});
//in case images are loading dynamically
jQuery('.ptsEl.ptsCol[data-el="table_col"] img').on('load', function () {
  jQuery('body').trigger('resize');
});
function _ptsInitFabric() {
  g_ptsBlockFabric = new ptsBlockFabric();
}
function ptsGetFabric() {
  return g_ptsBlockFabric;
}
function _ptsIsEditMode() {
  return typeof g_ptsEditMode !== 'undefined' && g_ptsEditMode;
}
//TABLES BASE END
//MODAL
(function ($) {
  'use strict';

  $.fn.sModal = function (options) {
    var self = this,
      settings = $.extend(
        {
          width: 640,
          height: 480,
          buttons: [],
        },
        options
      ),
      $modalOverlay,
      $modalContainer,
      $closeModalButton,
      $modalContent,
      $modalButtons,
      modalOverlayStyle = {
        position: 'fixed',
        top: 0,
        left: 0,
        background: 'rgba(0,0,0,.75)',
        width: '100%',
        height: '100%',
        'z-index': '100000',
        display: 'none',
        'overflow-y': 'auto',
      },
      modalContainerStyle = {
        width: settings.width,
        position: 'absolute',
        top: '50%',
        left: '50%',
        'max-width': 'calc(100% - 1.5em)',
        'margin-right': '-50%',
        'margin-bottom': '20px',
        transform: 'translate(-50%, -50%)',
        background: '#fff',
        padding: '1em',
      },
      modalContentStyle = {
        height: 'calc(100% - 3.6em)',
        'overflow-y': 'auto',
        'overflow-x': 'hidden',
        padding: '1em',
      },
      closeButtonStyle = {
        position: 'absolute',
        right: '10px',
        top: '10px',
        'font-size': '35px',
        color: '#fff',
        cursor: 'pointer',
      },
      modalButtonsStyle = {
        position: 'relative',
        width: '100%',
        'text-align': 'right',
        'margin-top': '1em',
      };

    function closeModal() {
      self.trigger('close.before');
      if (jQuery('.sModal:visible').length < 2) {
        jQuery('body').css('overflow', 'auto');
      }
      $modalOverlay.fadeOut();
      self.trigger('close.after');
    }

    function openModal() {
      jQuery('body').css('overflow', 'hidden');
      $modalOverlay.show(0, function () {
        resizeModal();
        $modalOverlay.hide().fadeIn();
      });

      if (parseInt(jQuery('.sc-modal-container').css('top')) > jQuery(window).height()) {
        var offset = jQuery(window).height() / 2 + 40;
        jQuery('.sc-modal-container').css('top', offset);
      }
    }

    function resizeModal() {
      var offset = '50%';
      if ($modalContainer.height() > jQuery(window).height()) {
        offset = $modalContainer.height() / 2 + 40;
      }
      $modalContainer.css('top', offset);
    }

    function createInstance($modalTemplate) {
      $modalOverlay = jQuery('<div class="sc-modal-overlay" tabindex="0">').css(modalOverlayStyle);

      $modalContainer = jQuery('<div class="sc-modal-container">').css(modalContainerStyle);

      $closeModalButton = jQuery('<div class="sc-modal-close-button">&times;</div>').css(closeButtonStyle);
      $closeModalButton.appendTo($modalOverlay);

      $modalContent = jQuery('<div class="sc-modal-content">').css(modalContentStyle);
      $modalContent.appendTo($modalContainer);

      $modalTemplate.appendTo($modalContent).show();

      $modalContainer.appendTo($modalOverlay);

      $modalOverlay.appendTo('body');
      $modalOverlay.add($closeModalButton).on('click', function (event) {
        if (jQuery(this).is(jQuery(event.target))) {
          closeModal();
        }
      });

      jQuery(document).on('keyup', function (event) {
        if (event.which == 27 && $modalOverlay.is(':visible')) {
          closeModal();
        }
      });

      var resizeTimer;

      jQuery(window).on('resize', function (event) {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(function () {
          resizeModal();
        }, 250);
      });

      if (settings.buttons.length > 0) {
        $modalButtons = jQuery('<div class="sc-modal-action-buttons">').css(modalButtonsStyle);

        for (var i = 0; i < settings.buttons.length; i++) {
          jQuery('<button>')
            .attr('class', settings.buttons[i].class || null)
            .html(settings.buttons[i].content || null)
            .on('click', $.proxy(settings.buttons[i].event, $modalTemplate))
            .appendTo($modalButtons);
        }

        self.$buttons = $modalButtons;

        $modalButtons.appendTo($modalContainer);
      }
    }

    createInstance(this);

    $.extend(this, {
      open: function () {
        this.trigger('open.before');
        openModal();
        this.trigger('open.after');
        return this;
      },
      close: function () {
        this.trigger('close.before');
        closeModal();
        this.trigger('close.after');
        return this;
      },
    });

    return this;
  };
})(jQuery);
//MODAL
