| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 | /** * RWD Table with freezing head and columns for jQuery *  * @author  Nick Tsai <myintaer@gmail.com> * @version 1.1.2 * @see     https://github.com/yidas/jquery-freeze-table */(function ($, window) {  'use strict';  /**   * Main object   *    * @param {element} element    * @param {object} options    */  var FreezeTable = function(element, options) {    // Target element initialization    this.$tableWrapper = $(element).first();    // Options    this.options = options || {};     this.namespace = this.options.namespace || 'freeze-table';    this.callback;    this.shadow;    this.fastMode;    this.backgroundColor;    // Caches    this.$table = this.$tableWrapper.children("table");    this.$headTableWrap;    this.$columnTableWrap;    this.fixedNavbarHeight;        // Static class names for clone wraps    this.headWrapClass = 'clone-head-table-wrap';    this.columnWrapClass = 'clone-column-table-wrap';    this.columnHeadWrapClass = 'clone-column-head-table-wrap';    this.scrollBarWrapClass = 'clone-scroll-bar-wrap';    this.init();    return this;  }  /**   * Initialization   */  FreezeTable.prototype.init = function() {    // Element check    if (!this.$table.length) {      throw "The element must contain a table dom";    }    /**     * Update Mode     */    if (this.options==='update') {      this.destroy();      this.options = this.$tableWrapper.data('freeze-table-data');    }    else if (this.options==='resize') {      this.options = this.$tableWrapper.data('freeze-table-data');      // Get selected FreezeTable's namespace      this.namespace = this.options.namespace || this.namespace;      this.resize();      // Skip init for better performance usage       return;    }    else {      // Save to DOM data      this.$tableWrapper.data('freeze-table-data', this.options);    }    /**     * Options Setting     */    var options = this.options;    var freezeHead = (typeof options.freezeHead !== 'undefined') ? options.freezeHead : true;    var freezeColumn = (typeof options.freezeColumn !== 'undefined') ? options.freezeColumn : true;    var freezeColumnHead = (typeof options.freezeColumnHead !== 'undefined') ? options.freezeColumnHead : true;    var scrollBar = (typeof options.scrollBar !== 'undefined') ? options.scrollBar : false;    var fixedNavbar = options.fixedNavbar || '.navbar-fixed-top';    var callback = options.callback || null;    this.namespace = this.options.namespace || this.namespace;    this.shadow = (typeof options.shadow !== 'undefined') ? options.shadow : false;    this.fastMode = (typeof options.fastMode !== 'undefined') ? options.fastMode : false;    this.backgroundColor = options.backgroundColor || 'white';    // Get navbar height for keeping fixed navbar    this.fixedNavbarHeight = (fixedNavbar) ? $(fixedNavbar).outerHeight() || 0 : 0;        // Check existence    if (this.isInit()) {      this.destroy();    }    // Release height of the table wrapper     this.$tableWrapper.css('height', '100%')      .css('min-height', '100%')      .css('max-height', '100%');    /**     * Building     */    // Switch for freezeHead    if (freezeHead) {      this.buildHeadTable();    }    // Switch for freezeColumn    if (freezeColumn) {      this.buildColumnTable();      // X scroll bar      this.$tableWrapper.css('overflow-x', 'scroll');    }    // Switch for freezeColumnHead    if (freezeColumnHead && freezeHead && freezeColumn) {      this.buildColumnHeadTable();    }    // Switch for scrollBar    if (scrollBar) {      this.buildScrollBar();    }    // Initialization    this.resize();    // Callback    if (typeof callback === 'function') {      callback();    }  }  /**   * Freeze thead table   */  FreezeTable.prototype.buildHeadTable = function() {    var that = this;        // Clone the table as Fixed thead    var $headTable = this.clone(this.$table);    // Fast Mode    if (this.fastMode) {      var $headTable = this.simplifyHead($headTable);    }        var headWrapStyles = this.options.headWrapStyles || null;    // Wrap the Fixed Column table    this.$headTableWrap = $('<div class="'+this.headWrapClass+'"></div>')      .append($headTable)      .css('position', 'fixed')      .css('overflow', 'hidden')      .css('visibility', 'hidden')      .css('top', 0 + this.fixedNavbarHeight)      .css('z-index', 2);    // Shadow option    if (this.shadow) {      this.$headTableWrap.css('box-shadow', '0px 6px 10px -5px rgba(159, 159, 160, 0.8)');    }    // Styles option    if (headWrapStyles && typeof headWrapStyles === "object") {      $.each(headWrapStyles, function(key, value) {        that.$headTableWrap.css(key, value);      });    }    // Add into target table wrap    this.$tableWrapper.append(this.$headTableWrap);    /**     * Listener - Table scroll for effecting Freeze Column     */    this.$tableWrapper.on('scroll.'+this.namespace, function() {      // this.$headTableWrap.css('left', this.$table.offset().left);      that.$headTableWrap.scrollLeft($(this).scrollLeft());    });    /**     * Listener - Window scroll for effecting freeze head table     */    $(window).on('scroll.'+this.namespace, function() {      // Current container's top position      var topPosition = $(window).scrollTop() + that.fixedNavbarHeight;            // Detect Current container's top is in the table scope      if (that.$table.offset().top - 1 <= topPosition && (that.$table.offset().top + that.$table.outerHeight() - 1) >= topPosition) {        that.$headTableWrap.css('visibility', 'visible');      } else {        that.$headTableWrap.css('visibility', 'hidden');      }    });    /**     * Listener - Window resize for effecting freeze head table     */    $(window).on('resize.'+this.namespace, function() {      that.$headTableWrap.css('width', that.$tableWrapper.width());      that.$headTableWrap.css('height', that.$table.find("thead").outerHeight());    });  }  /**   * Freeze column table   */  FreezeTable.prototype.buildColumnTable = function() {    var that = this;    /**     * Setting     */    var columnWrapStyles = this.options.columnWrapStyles || null;    var columnNum = this.options.columnNum || 1;      // Shadow option      var defaultColumnBorderWidth = (this.shadow) ? 0 : 1;      var columnBorderWidth = (typeof this.options.columnBorderWidth !== 'undefined') ? this.options.columnBorderWidth : defaultColumnBorderWidth;        // Clone the table as Fixed Column table    var $columnTable = this.clone(this.$table);        // Wrap the Fixed Column table    this.$columnTableWrap = $('<div class="'+this.columnWrapClass+'"></div>')      .append($columnTable)      .css('position', 'fixed')      .css('overflow', 'hidden')      .css('visibility', 'hidden')      .css('z-index', 1);    // Shadow option    if (this.shadow) {      this.$columnTableWrap.css('box-shadow', '6px 0px 10px -5px rgba(159, 159, 160, 0.8)');    }    // Styles option    if (columnWrapStyles && typeof columnWrapStyles === "object") {      $.each(columnWrapStyles, function(key, value) {        that.$columnTableWrap.css(key, value);      });    }    // Add into target table wrap    this.$tableWrapper.append(this.$columnTableWrap);    /**     * Align the column wrap to current top     */    var align = function () {      that.$columnTableWrap.css('top', that.$table.offset().top - $(window).scrollTop());    }    /**     * Listener - Table scroll for effecting Freeze Column     */    this.$tableWrapper.on('scroll.'+this.namespace, function() {      // Detect for horizontal scroll      if ($(this).scrollLeft() > 0) {        that.$columnTableWrap.css('visibility', 'visible');      } else {        that.$columnTableWrap.css('visibility', 'hidden');      }    });    /**     * Listener - Window resize for effecting tables     */    $(window).on('resize.'+this.namespace, function() {      // Follows origin table's width      $columnTable.width(that.$table.width());      /**       * Dynamic column calculation       */      // Get width by fixed column with number setting      var width = 0 + columnBorderWidth;      for (var i = 1; i <= columnNum; i++) {        // th/td detection        var th = that.$table.find('th:nth-child('+i+')').outerWidth();        var addWidth = (th > 0) ? th : that.$table.find('td:nth-child('+i+')').outerWidth();        width += addWidth;      }      that.$columnTableWrap.width(width);      align();    });    /**     * Listener - Window scroll for effecting freeze column table     */    $(window).on('scroll.'+this.namespace, function() {      align();    });  }  /**   * Freeze column thead table   */  FreezeTable.prototype.buildColumnHeadTable = function() {    var that = this;    // Clone head table wrap    var $columnHeadTableWrap = this.clone(this.$headTableWrap);    // Fast Mode    if (this.fastMode) {      var $columnHeadTableWrap = this.simplifyHead($columnHeadTableWrap);    }    var columnHeadWrapStyles = this.options.columnHeadWrapStyles || null;    $columnHeadTableWrap.removeClass(this.namespace)      .addClass(this.columnHeadWrapClass)      .css('z-index', 3);    // Shadow option    if (this.shadow) {      $columnHeadTableWrap.css('box-shadow', 'none');    }    // Styles option    if (columnHeadWrapStyles && typeof columnHeadWrapStyles === "object") {      $.each(columnHeadWrapStyles, function(key, value) {        $columnHeadTableWrap.css(key, value);      });    }    // Add into target table wrap    this.$tableWrapper.append($columnHeadTableWrap);    /**     * Detect column-head wrap to show or not     */    var detect = function () {      // Current container's top position      var topPosition = $(window).scrollTop() + that.fixedNavbarHeight;            // Detect Current container's top is in the table scope      // Plus tableWrapper scroll detection      if (that.$table.offset().top - 1 <= topPosition && (that.$table.offset().top + that.$table.outerHeight() - 1) >= topPosition && that.$tableWrapper.scrollLeft() > 0) {        $columnHeadTableWrap.css('visibility', 'visible');      } else {        $columnHeadTableWrap.css('visibility', 'hidden');      }    }    /**     * Listener - Window scroll for effecting Freeze column-head table     */    $(window).on('scroll.'+this.namespace, function() {      detect();    });    /**     * Listener - Table scroll for effecting Freeze column-head table     */    this.$tableWrapper.on('scroll.'+this.namespace, function() {      detect();    });    /**     * Listener - Window resize for effecting freeze column-head table     */    $(window).on('resize.'+this.namespace, function() {      // Table synchronism      $columnHeadTableWrap.find("> table").css('width', that.$table.width());      $columnHeadTableWrap.css('width', that.$columnTableWrap.width());      $columnHeadTableWrap.css('height', that.$table.find("thead").outerHeight());    });  }  /**   * Freeze scroll bar   */  FreezeTable.prototype.buildScrollBar = function() {    var that = this;    var theadHeight = this.$table.find("thead").outerHeight();    // Scroll wrap container    var $scrollBarContainer = $('<div class="'+this.scrollBarWrapClass+'"></div>')      .css('width', this.$table.width())      .css('height', 1);        // Wrap the Fixed Column table    var $scrollBarWrap = $('<div class="'+this.scrollBarWrapClass+'"></div>')      .css('position', 'fixed')      .css('overflow-x', 'scroll')      .css('visibility', 'hidden')      .css('bottom', 0)      .css('z-index', 2)      .css('width', this.$tableWrapper.width())      .css('height', 20);    // Add into target table wrap    $scrollBarWrap.append($scrollBarContainer);    this.$tableWrapper.append($scrollBarWrap);    /**     * Listener - Freeze scroll bar effected Table     */    $scrollBarWrap.on('scroll.'+this.namespace, function() {      that.$tableWrapper.scrollLeft($(this).scrollLeft());    });    /**     * Listener - Table scroll for effecting Freeze scroll bar     */    this.$tableWrapper.on('scroll.'+this.namespace, function() {      // this.$headTableWrap.css('left', $table.offset().left);      $scrollBarWrap.scrollLeft($(this).scrollLeft());    });    /**     * Listener - Window scroll for effecting scroll bar     */    $(window).on('scroll.'+this.namespace, function() {            // Current container's top position      var bottomPosition = $(window).scrollTop() + $(window).height() - theadHeight + that.fixedNavbarHeight;            // Detect Current container's top is in the table scope      if (that.$table.offset().top - 1 <= bottomPosition && (that.$table.offset().top + that.$table.outerHeight() - 1) >= bottomPosition) {        $scrollBarWrap.css('visibility', 'visible');      } else {        $scrollBarWrap.css('visibility', 'hidden');      }    });    /**     * Listener - Window resize for effecting scroll bar     */    $(window).on('resize.'+this.namespace, function() {            // Update width      $scrollBarContainer.css('width', that.$table.width())      // Update Wrap      $scrollBarWrap.css('width', that.$tableWrapper.width());    });  }  /**   * Clone element   *    * @param {element} element    */  FreezeTable.prototype.clone = function (element) {    return $(element).clone()      .removeAttr('id') // Remove ID      .css('background-color', this.backgroundColor); // Bootstrap background-color transparent problem  }  /**   * simplify cloned head table   *    * @param {element} table Table element   */  FreezeTable.prototype.simplifyHead = function (table) {    var that = this;        var $headTable = $(table);    // Remove non-display DOM    $headTable.find("> tr, > tbody, > tfoot").remove();    // Each th/td width synchronism    $.each($headTable.find("> thead > tr:nth-child(1) >"), function (key, value) {            var width = that.$table.find("> thead > tr:nth-child(1) > :nth-child("+parseInt(key+1)+")").outerWidth();      $(this).css('width', width);    });    return $headTable;  }  /**   * Detect is already initialized   */  FreezeTable.prototype.isInit = function() {        // Check existence DOM    if (this.$tableWrapper.find("."+this.headWrapClass).length)      return true;    if (this.$tableWrapper.find("."+this.columnWrapClass).length)      return true;    if (this.$tableWrapper.find("."+this.columnHeadWrapClass).length)      return true;    if (this.$tableWrapper.find("."+this.scrollBarWrapClass).length)      return true;    return false;  }  /**   * Unbind all events by same namespace   */  FreezeTable.prototype.unbind = function() {    $(window).off('resize.'+this.namespace);    $(window).off('scroll.'+this.namespace);    this.$tableWrapper.off('scroll.'+this.namespace);  }  /**   * Destroy Freeze Table by same namespace   */  FreezeTable.prototype.destroy = function() {    this.unbind();    this.$tableWrapper.find("."+this.headWrapClass).remove();    this.$tableWrapper.find("."+this.columnWrapClass).remove();    this.$tableWrapper.find("."+this.columnHeadWrapClass).remove();    this.$tableWrapper.find("."+this.scrollBarWrapClass).remove();  }  /**   * Resize trigger for current same namespace   */  FreezeTable.prototype.resize = function() {    $(window).trigger('resize.'+this.namespace);    $(window).trigger('scroll.'+this.namespace);    this.$tableWrapper.trigger('scroll.'+this.namespace);    return true;  }  /**   * Update for Dynamic Content   */  FreezeTable.prototype.update = function() {    // Same as re-new object    this.options = 'update';    this.init();    return this;  }  /**   * Interface   */  // Class for single element  window.FreezeTable = FreezeTable;  // jQuery interface  $.fn.freezeTable = function (options) {    // Single/Multiple mode    if (this.length === 1) {      return new FreezeTable(this, options)    }     else if (this.length > 1) {      var result = [];      // Multiple elements bundle      this.each(function () {        result.push(new FreezeTable(this, options));      });      return result;    }        return false;  }})(jQuery, window);
 |