Source: ui/gridheadercell.js

goog.provide('pear.ui.GridHeaderCell');

goog.require('pear.fx.dom.HeaderMenuSlide');
goog.require('pear.ui.Cell');
goog.require('pear.ui.Resizable');



/**
 * HeaderCell
 *
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for
 *     document interaction.
 * @constructor
 * @extends {pear.ui.Cell}
 */
pear.ui.GridHeaderCell = function(opt_domHelper) {
  pear.ui.Cell.call(this, opt_domHelper);
};
goog.inherits(pear.ui.GridHeaderCell, pear.ui.Cell);


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.headerMenuContainer_ = null;


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.sortIndicator_ = null;


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.sortAscIndicator_ = null;


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.sortDescIndicator_ = null;


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.contentCell_ = null;


/**
 * @private
 * @type {?Element}
 */
pear.ui.GridHeaderCell.prototype.contentIndicator_ = null;


/**
 * @private
 * @type {pear.ui.Grid.SortDirection | number}
 */
pear.ui.GridHeaderCell.prototype.sortDirection_ = 0;


/**
 * [resizable_ description]
 * @type {pear.ui.Resizable}
 * @private
 */
pear.ui.GridHeaderCell.prototype.resizable_ = null;


/**
 * get Resizable Control
 * @return {pear.ui.Resizable}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getResizable = function() {
  return this.resizable_;
};


/**
 * Default CSS class to be applied to the root element of cell
 * @type {string}
 */
pear.ui.GridHeaderCell.CSS_CLASS =
    goog.getCssName('pear-grid-cell-header');


/**
 * get Sort Direction {@link pear.ui.Grid.SortDirection}
 * @return {pear.ui.Grid.SortDirection}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getSortDirection = function() {
  this.sortDirection_ = this.sortDirection_ || pear.ui.Grid.SortDirection.NONE;
  return (/** @type {pear.ui.Grid.SortDirection} */ (this.sortDirection_));
};


/**
 * setsortDirection_ of Column
 * @param  {?pear.ui.Grid.SortDirection} value
 * @private
 */
pear.ui.GridHeaderCell.prototype.setsortDirection_ = function(value) {
  this.sortDirection_ = value || pear.ui.Grid.SortDirection.NONE;

  if (value === pear.ui.Grid.SortDirection.ASC) {
    goog.style.setElementShown(this.sortAscIndicator_, true);
    goog.style.setElementShown(this.sortDescIndicator_, false);
  }else if (value === pear.ui.Grid.SortDirection.DESC) {
    goog.style.setElementShown(this.sortAscIndicator_, false);
    goog.style.setElementShown(this.sortDescIndicator_, true);
  }else {
    goog.style.setElementShown(this.sortAscIndicator_, false);
    goog.style.setElementShown(this.sortDescIndicator_, false);
  }
  this.adjustContentCellSize();
};


/**
 * Get Menu Control Container
 * @return {Element}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getMenuElement = function() {
  return this.headerMenuContainer_;
};


/**
 * set state of Sliding Menu Container
 * @param {boolean} open , true is visible
 * @public
 */
pear.ui.GridHeaderCell.prototype.setMenuState = function(open) {
  this.keepSlideMenuOpen_ = open;
};


/**
 * Returns the text caption or DOM structure displayed in the component.
 * @return {goog.ui.ControlContent} Text caption or DOM structure
 *     comprising the component's contents.
 */
pear.ui.GridHeaderCell.prototype.getContent = function() {
  return '';
};


/**
 * Get the Content Cell
 * @return {?Element}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getContentCell = function() {
  return this.contentCell_;
};


/**
 * Get Content Text - Header Text
 * @return {string}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getContentText = function() {
  return this.getDataColumn().getHeaderText();
};


/**
 * Get Column Id
 * @return {string}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getColumnId = function() {
  return this.getDataColumn().getId();
};


/**
 * Get Indicator Element Container - this suppose to hold indicators
 * for sort , filter .
 * @return {Element}
 * @public
 */
pear.ui.GridHeaderCell.prototype.getContentIndicatorElement = function() {
  return this.contentIndicator_;
};


/**
 * clear header cell content
 * @public
 *
 */
pear.ui.GridHeaderCell.prototype.clearContent = function() {
  // Header Cell Content
  this.contentCell_.innerHTML = '';
};


/**
 * Configures the component after its DOM has been rendered, and sets up event
 * handling.  Overrides {@link goog.ui.Component#enterDocument}.
 * @override
 */
pear.ui.GridHeaderCell.prototype.enterDocument = function() {
  pear.ui.GridHeaderCell.superClass_.enterDocument.call(this);

  this.splitHeaderCell_();
  this.registerEvent_(true);
};


/**
 *
 * @protected
 */
pear.ui.GridHeaderCell.prototype.decorateElementWithClasses = function() {
  goog.dom.classlist.add(this.getElement(), pear.ui.GridHeaderCell.CSS_CLASS);
  goog.dom.classlist.add(this.getElement(), 'col' + this.getCellIndex());
  goog.dom.classlist.add(this.getElement(), 'overflowhidden');
};


/**
 * [registerEvent_ description]
 * @param  {boolean} enable [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.registerEvent_ = function(enable) {
  var handler = this.getHandler();
  var element = this.getElement();
  if (enable) {
    handler.
        listen(element, goog.events.EventType.MOUSEENTER, this.handleEnter_).
        listen(element, goog.events.EventType.MOUSEDOWN, this.handleMouseDown_).
        listen(element, goog.events.EventType.MOUSELEAVE, this.handleLeave_).
        listen(this.contentCell_, [
          goog.events.EventType.MOUSEENTER,
          goog.events.EventType.MOUSELEAVE
            ], function(be) {
              be.preventDefault();
            });

  } else {
    handler.
        unlisten(element, goog.events.EventType.MOUSEENTER,
            this.handleEnter_).
        unlisten(element, goog.events.EventType.MOUSEDOWN,
            this.handleMouseDown_).
        unlisten(element, goog.events.EventType.MOUSELEAVE, this.handleLeave_).
        unlisten(this.contentCell_, [
          goog.events.EventType.MOUSEENTER,
          goog.events.EventType.MOUSELEAVE
            ], function(be) {
              be.preventDefault();
            });
  }
};


/**
 * [registerEventOnMenuContainer_ description]
 * @param  {boolean} enable [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.registerEventOnMenuContainer_ =
    function(enable) {
  var handler = this.getHandler();
  var element = this.getElement();
  if (enable) {
    handler.
        listen(element, goog.events.EventType.MOUSELEAVE, this.handleLeave_).
        listen(this.headerMenuContainer_,
        goog.events.EventType.MOUSEENTER, function(e) {
          e.preventDefault();
        });

  } else {
    handler.
        unlisten(element, goog.events.EventType.MOUSELEAVE, this.handleLeave_).
        unlisten(this.headerMenuContainer_,
        goog.events.EventType.MOUSEENTER, function(e) {
          e.preventDefault();
        });
  }
};


/**
 * Header cell is divided into 3 content , indicators and sliding menu
 * @private
 *
 */
pear.ui.GridHeaderCell.prototype.splitHeaderCell_ = function() {
  var grid = this.getGrid();
  var align = this.getDataColumn().getAlign();

  // Indicators
  this.createHeaderCellIndicatorPlaceHolder_();

  // Header Menu
  if (grid.getConfiguration().AllowColumnHeaderMenu) {
    this.createHeaderCellMenu_();
    this.registerEventOnMenuContainer_(true);
  }

  // Sort Indicators
  if (grid.getConfiguration().AllowSorting) {
    this.createSortIndicators_();
  }

  // Resize Handles
  if (grid.getConfiguration().AllowColumnResize) {
    this.createResizeHandle_();
  }

  this.createHeaderCellContent_();


  this.adjustContentCellSize();
};


/**
 * create content cell
 * @private
 */
pear.ui.GridHeaderCell.prototype.createHeaderCellContent_ = function() {
  // Header Cell Content
  var contentElem = goog.dom.createDom('div',
      goog.getCssName(pear.ui.GridHeaderCell.CSS_CLASS, 'content'),
      this.getContentText()
      );

  var align = this.getDataColumn().getAlign();
  var aligncss = (align === pear.data.Column.Align.LEFT) ?
      goog.getCssName(pear.ui.GridHeaderCell.CSS_CLASS, 'left') :
      goog.getCssName(pear.ui.GridHeaderCell.CSS_CLASS, 'right');

  goog.dom.classlist.add(contentElem, aligncss);

  if (align === pear.data.Column.Align.RIGHT) {
    this.contentCell_ = (/**@type {Element} */ (
        this.getElement().appendChild(contentElem)));
  }else if (align === pear.data.Column.Align.LEFT) {
    this.contentCell_ = (/**@type {Element} */(
        this.getElement().insertBefore(contentElem,
        this.contentIndicator_)));
  }else {
    // no-op
  }


};


/**
 * @private
 */
pear.ui.GridHeaderCell.prototype.createHeaderCellIndicatorPlaceHolder_ =
    function() {
  // Header Menu Control
  this.contentIndicator_ = goog.dom.createDom('div',
      'pear-grid-cell-header-indicators'
      );
  goog.dom.appendChild(this.getElement(), this.contentIndicator_);

};


/**
 * [createHeaderCellMenu_ description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.createHeaderCellMenu_ = function() {
  // Header Menu Control
  this.headerMenuContainer_ = this.getDomHelper().createDom(
      'div',
      'pear-grid-cell-header-slidemenu');
  this.getDomHelper().appendChild(this.getElement(), this.headerMenuContainer_);
};


/**
 * [createResizeHandle_ description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.createResizeHandle_ = function() {
  var resizeData = {};
  resizeData['handles'] = pear.ui.Resizable.Position.RIGHT;


  this.resizable_ = new pear.ui.Resizable(this.getElement(), resizeData);
  this.getHandler().
      listen(this.resizable_, pear.ui.Resizable.EventType.RESIZE,
          this.handleResize_, false).
      listen(this.resizable_, pear.ui.Resizable.EventType.END_RESIZE,
          this.handleResizeEnd_, false);
};


/**
 * create sort indicators
 * @private
 */
pear.ui.GridHeaderCell.prototype.createSortIndicators_ = function() {
  var contentIndicatorElem = this.getContentIndicatorElement();

  this.sortIndicator_ = goog.dom.createDom('div',
      'pear-grid-cell-header-sort'
      );
  goog.dom.appendChild(contentIndicatorElem, this.sortIndicator_);

  this.sortAscIndicator_ = goog.dom.createDom(
      'div', {
        'class' : 'fa fa-arrow-circle-down',
        style: 'display:none'
      });
  goog.dom.appendChild(this.sortIndicator_, this.sortAscIndicator_);
  this.sortDescIndicator_ = goog.dom.createDom(
      'div', {
        'class' : 'fa fa-arrow-circle-up' ,
        style: 'display:none'
      });
  goog.dom.appendChild(this.sortIndicator_, this.sortDescIndicator_);
};


/**
 * Adjust size of content cell.
 * @public
 */
pear.ui.GridHeaderCell.prototype.adjustContentCellSize = function() {
  this.syncContentCellOnResize_();
};


/**
 * Synchronize Cells on Resize Event
 * @private
 */
pear.ui.GridHeaderCell.prototype.syncContentCellOnResize_ = function() {
  var bound = goog.style.getBounds(this.getElement());
  var boundContent = goog.style.getContentBoxSize(this.getElement());

  var boundIndicator = goog.style.getBounds(this.getContentIndicatorElement());
  var boundSlideMenu, marginBox, paddingBox;
  var lessWidth = 0;
  var grid = this.getGrid();
  if (grid.getConfiguration().AllowColumnHeaderMenu) {
    boundSlideMenu = goog.style.getBounds(
        this.headerMenuContainer_);
    marginBox = goog.style.getMarginBox(
        this.headerMenuContainer_);
    if (marginBox.left < 0) {
      lessWidth = lessWidth + boundSlideMenu.width;
    }
  }

  if (grid.getConfiguration().AllowColumnResize) {
    var resizeHandle = goog.style.getBounds(
        this.resizable_.getHandle(pear.ui.Resizable.Position.RIGHT));
    if (resizeHandle.width > 0) {
      lessWidth = lessWidth + resizeHandle.width;
    }
    this.resizable_.setMinWidth(lessWidth + 10);
  }

  paddingBox = goog.style.getPaddingBox(this.getContentIndicatorElement());

  lessWidth = lessWidth + boundIndicator.width +
      (bound.width - boundContent.width) +
      paddingBox.right + paddingBox.left;
  goog.style.setWidth(this.contentCell_, bound.width - lessWidth);
};


/**
 * [getHeaderMenuContainerWidth description]
 * @return {number}
 */
pear.ui.GridHeaderCell.prototype.getHeaderMenuContainerWidth = function() {
  // TODO
  var bounds = goog.style.getBounds(this.headerMenuContainer_);
  return bounds.width;
};


/**
 * [slideMenuOpen description]
 * @param  {boolean} display
 */
pear.ui.GridHeaderCell.prototype.slideMenuOpen = function(display) {
  if (display && this.slideMenuOpenState) {
    this.slideMenuOpenState = true;
    return;
  }
  this.slideMenuOpenState = display;
  var marginleft = 0;
  var left = 0;
  var width = this.getHeaderMenuContainerWidth();
  if (this.headerMenuContainer_ && display) {
    marginleft = marginleft + width;
  }else {
    marginleft = marginleft + 0;
  }
  marginleft = marginleft * -1;
  this.handleMenuSlide_(this.headerMenuContainer_, [marginleft]);
  this.adjustContentCellSize();
};


/**
 * [handleMenuSlide_ description]
 * @param  {Element} el
 * @param  {Array.<number>} value
 * @private
 */
pear.ui.GridHeaderCell.prototype.handleMenuSlide_ = function(el, value) {
  var anim = new pear.fx.dom.HeaderMenuSlide(el, [0], value, 300);
  goog.events.listen(anim, goog.fx.Animation.EventType.ANIMATE,
      this.adjustContentCellSize, false, this);
  anim.play();
};


/**
 * [handleMouseDown_ description]
 * @param  {goog.events.BrowserEvent} be [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.handleMouseDown_ = function(be) {
  if (be.defaultPrevented) {return;}

  if (be.isMouseActionButton()) {
    if (this.resizable_ &&
        this.resizable_.getResizehandle(pear.ui.Resizable.Position.RIGHT) ===
        be.target) {
      // Ignore

    }else {
      if (this.getGrid().getConfiguration().AllowSorting) {
        this.dispatchEvent(goog.ui.Component.EventType.ACTION);
      }
    }
  }

  be.preventDefault();
};


/**
 * [handleEnter_ description]
 * @param  {goog.events.BrowserEvent} be [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.handleEnter_ = function(be) {
  if (this.getGrid().getConfiguration().AllowColumnHeaderMenu) {
    this.slideMenuOpen(true);
  }
};


/**
 * @private
 * @param  {goog.events.BrowserEvent} be [description]
 */
pear.ui.GridHeaderCell.prototype.handleLeave_ = function(be) {
  if (be.target === this.getElement() &&
      this.getGrid().getConfiguration().AllowColumnHeaderMenu &&
      !this.keepSlideMenuOpen_) {
    this.slideMenuOpen(false);
  }
  be.preventDefault();
};


/**
 * [handleResize_ description]
 * @param  {pear.ui.ResizableEvent} ge [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.handleResize_ = function(ge) {
  ge.preventDefault();
  var pos = this.getCellIndex();
  var grid = this.getGrid();
  grid.setColumnWidth(pos, ge.size.width);
  this.adjustContentCellSize();
  // Give more realtime - resize
  grid.refreshOnColumnResize();
};


/**
 * [handleResizeEnd_ description]
 * @param  {pear.ui.ResizableEvent} ge [description]
 * @private
 */
pear.ui.GridHeaderCell.prototype.handleResizeEnd_ = function(ge) {
  ge.preventDefault();
  var grid = this.getGrid();
  // clear style
  goog.style.setSize(this.getElement(), '', '');
  goog.style.setPosition(this.getElement(), '', '');
  grid.refreshCssStyle(true);
};


/**
 * @public
 */
pear.ui.GridHeaderCell.prototype.resetSortDirection = function() {
  this.setsortDirection_(pear.ui.Grid.SortDirection.NONE);
};


/**
 * @public
 */
pear.ui.GridHeaderCell.prototype.toggleSortDirection = function() {
  if (this.getSortDirection() === pear.ui.Grid.SortDirection.ASC) {
    this.setsortDirection_(pear.ui.Grid.SortDirection.DESC);

  }else if (this.getSortDirection() === pear.ui.Grid.SortDirection.DESC) {
    this.setsortDirection_(pear.ui.Grid.SortDirection.ASC);
  }else {
    this.setsortDirection_(pear.ui.Grid.SortDirection.DESC);
  }
};


/**
 * Dispose Events
 * @private
 */
pear.ui.GridHeaderCell.prototype.disposeEvents_ = function() {
  this.registerEvent_(false);
  this.registerEventOnMenuContainer_(false);
};


/**
 * @override
 */
pear.ui.GridHeaderCell.prototype.disposeInternal = function() {
  this.disposeEvents_();

  if (this.resizable_) {
    this.resizable_.dispose();
  }
  this.resizable_ = null;

  if (this.sortIndicator_) {
    goog.dom.removeNode(this.sortIndicator_);
  }
  this.sortIndicator_ = null;

  if (this.sortAscIndicator_) {
    goog.dom.removeNode(this.sortAscIndicator_);
  }
  this.sortAscIndicator_ = null;

  if (this.sortDescIndicator_) {
    goog.dom.removeNode(this.sortDescIndicator_);
  }
  this.sortDescIndicator_ = null;

  if (this.headerMenuContainer_) {
    goog.dom.removeNode(this.headerMenuContainer_);
  }
  this.headerMenuContainer_ = null;

  if (this.contentIndicator_) {
    goog.dom.removeNode(this.contentIndicator_);
  }
  this.contentIndicator_ = null;

  if (this.contentCell_) {
    goog.dom.removeNode(this.contentCell_);
  }
  this.contentCell_ = null;


  delete this.sortDirection_;
  pear.ui.GridHeaderCell.superClass_.disposeInternal.call(this);
};



goog.provide('pear.ui.GridHeaderCellMenuButton');
goog.require('goog.ui.MenuButton');



/**
 * [GridHeaderCellMenuButton description]
 * @param {string} content
 * @param {goog.ui.Menu=} opt_menu Menu to render under the button when clicked.
 * @param {goog.ui.ButtonRenderer=} opt_renderer Renderer used to render or
 *     decorate the menu button; defaults to {@link goog.ui.MenuButtonRenderer}.
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM hepler, used for
 *     document interaction.
 * @constructor
 * @extends {goog.ui.MenuButton}
 */
pear.ui.GridHeaderCellMenuButton = function(
    content, opt_menu, opt_renderer, opt_domHelper) {
  goog.ui.MenuButton.call(this, content, opt_menu, opt_renderer ||
      pear.ui.GridHeaderCellMenuButtonRenderer.getInstance(), opt_domHelper);
};
goog.inherits(pear.ui.GridHeaderCellMenuButton, goog.ui.MenuButton);





goog.provide('pear.ui.GridHeaderCellMenuButtonRenderer');

goog.require('goog.ui.MenuButtonRenderer');



/**
 * Toolbar-specific renderer for {@link goog.ui.MenuButton}s, based on {@link
 * goog.ui.MenuButtonRenderer}.
 * @constructor
 * @extends {goog.ui.MenuButtonRenderer}
 */
pear.ui.GridHeaderCellMenuButtonRenderer = function() {
  goog.ui.MenuButtonRenderer.call(this);
};
goog.inherits(pear.ui.GridHeaderCellMenuButtonRenderer,
    goog.ui.MenuButtonRenderer);
goog.addSingletonGetter(pear.ui.GridHeaderCellMenuButtonRenderer);


/**
 * Default CSS class to be applied to the root element of menu buttons rendered
 * by this renderer.
 * @type {string}
 */
pear.ui.GridHeaderCellMenuButtonRenderer.CSS_CLASS =
    goog.getCssName('pear-grid-cell-header-slidemenu-menubutton');


/**
 * Returns the CSS class to be applied to the root element of menu buttons
 * rendered using this renderer.
 * @return {string} Renderer-specific CSS class.
 * @override
 */
pear.ui.GridHeaderCellMenuButtonRenderer.prototype.getCssClass = function() {
  return pear.ui.GridHeaderCellMenuButtonRenderer.CSS_CLASS;
};