Skip to content

Commit

Permalink
Rewrited sticky-header extension to ES6.
Browse files Browse the repository at this point in the history
  • Loading branch information
wenzhixin committed Feb 1, 2019
1 parent 04872ab commit 2766e00
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 121 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ ChangeLog

### 1.13.4

- **New(sticky-header extension):** Rewrited sticky-header extension to ES6.
- **New(sticky-header extension):** Added to support bootstrap v4 and `theadClasses` option.
- **New(auto-refresh extension):** Icons update to font-awesome 5.
- **Update(js):** Fixed `theadClasses` is not set when a `thead` exists.
- **Update(cookie extension):** Fixed cookie extension broken bug.
Expand Down
9 changes: 4 additions & 5 deletions site/docs/extensions/sticky-header.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ group: extensions
toc: true
---

This is an extension for [Bootstrap table](http://github.com/wenzhixin/bootstrap-table) module which provides a sticky header for the table when scrolling. </br>
You must include the bootstrap-table-sticky-header.css file in order to get the appropriate style
This is an extension which provides a sticky header for the table when scrolling.

## Usage

Expand All @@ -29,10 +28,10 @@ You must include the bootstrap-table-sticky-header.css file in order to get the

### stickyHeaderOffsetY

- **type:** `String`
- **type:** `Number`

- **Detail:**

Set the Y offset from the top of the window to pin the sticky header. If there is a fixed navigation bar with a height of 60px, this value would be `60px`.
Set the Y offset from the top of the window to pin the sticky header. If there is a fixed navigation bar with a height of 60px, this value would be `60`.

- **Default:** `undefined`
- **Default:** `0`
26 changes: 13 additions & 13 deletions src/extensions/sticky-header/bootstrap-table-sticky-header.css
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
/**
* @author vincent loh <[email protected]>
* @version: v1.0.0
* https://github.com/vinzloh/bootstrap-table/
* Sticky header for bootstrap-table
* @update zhixin wen <[email protected]>
*/

.fix-sticky {
position: fixed;
z-index: 100;
position: fixed !important;
overflow: hidden;
z-index: 100;
}
.fix-sticky thead {
background: #fff;

.fix-sticky table thead {
background: #fff;
}

.fix-sticky table thead.thead-light {
background: #e9ecef;
}

.fix-sticky thead th,
.fix-sticky thead th:first-child {
border-left: 0;
border-right: 0;
border-bottom: 1px solid #eee;
border-radius: 0;
.fix-sticky table thead.thead-light {
background: #212529;
}
164 changes: 61 additions & 103 deletions src/extensions/sticky-header/bootstrap-table-sticky-header.js
Original file line number Diff line number Diff line change
@@ -1,118 +1,76 @@
/**
* @author vincent loh <[email protected]>
* @version: v1.1.0
* https://github.com/vinzloh/bootstrap-table/
* Sticky header for bootstrap-table
* @update J Manuel Corona <[email protected]>
* @update zhixin wen <[email protected]>
*/

(function ($) {
'use strict';
($ => {
const Utils = $.fn.bootstrapTable.utils

var sprintf = $.fn.bootstrapTable.utils.sprintf;
$.extend($.fn.bootstrapTable.defaults, {
stickyHeader: false
});

var bootstrapVersion = 3;
try {
bootstrapVersion = parseInt($.fn.dropdown.Constructor.VERSION, 10);
} catch (e) { }
var hidden_class = bootstrapVersion > 3 ? 'd-none' : 'hidden';
$.extend($.fn.bootstrapTable.defaults, {
stickyHeader: false,
stickyHeaderOffsetY: 0
})

var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initHeader = BootstrapTable.prototype.initHeader;
const hiddenClass = Utils.bootstrapVersion === 4 ? 'd-none' : 'hidden'

BootstrapTable.prototype.initHeader = function () {
var that = this;
_initHeader.apply(this, Array.prototype.slice.apply(arguments));
$.BootstrapTable = class extends $.BootstrapTable {
initHeader (...args) {
super.initHeader(...args)

if (!this.options.stickyHeader) {
return;
}
if (!this.options.stickyHeader) {
return
}

var table = this.$tableBody.find('table'),
table_id = table.attr('id'),
header_id = table.attr('id') + '-sticky-header',
sticky_header_container_id = header_id +'-sticky-header-container',
anchor_begin_id = header_id +'_sticky_anchor_begin',
anchor_end_id = header_id +'_sticky_anchor_end';
// add begin and end anchors to track table position
this.$el.before('<div class="sticky-header-container"></div>')
this.$el.before('<div class="sticky_anchor_begin"></div>')
this.$el.after('<div class="sticky_anchor_end"></div>')
this.$header.addClass('sticky-header')

table.before(sprintf('<div id="%s" class="%s"></div>', sticky_header_container_id, hidden_class));
table.before(sprintf('<div id="%s"></div>', anchor_begin_id));
table.after(sprintf('<div id="%s"></div>', anchor_end_id));
// clone header just once, to be used as sticky header
// deep clone header, using source header affects tbody>td width
this.$stickyContainer = this.$tableBody.find('.sticky-header-container')
this.$stickyBegin = this.$tableBody.find('.sticky_anchor_begin')
this.$stickyEnd = this.$tableBody.find('.sticky_anchor_end')
this.$stickyHeader = this.$header.clone(true, true)

table.find('thead').attr('id', header_id);
// render sticky on window scroll or resize
$(window).on('resize.sticky-header-table', () => this.renderStickyHeader())
$(window).on('scroll.sticky-header-table', () => this.renderStickyHeader())
this.$tableBody.off('scroll').on('scroll', () => this.matchPositionX())
}

// clone header just once, to be used as sticky header
// deep clone header. using source header affects tbody>td width
this.$stickyHeader = $($('#'+header_id).clone(true, true));
// avoid id conflict
this.$stickyHeader.removeAttr('id');
renderStickyHeader () {
const top = $(window).scrollTop()
// top anchor scroll position, minus header height
const start = this.$stickyBegin.offset().top - this.options.stickyHeaderOffsetY
// bottom anchor scroll position, minus header height, minus sticky height
const end = this.$stickyEnd.offset().top - this.options.stickyHeaderOffsetY - this.$header.height()
// show sticky when top anchor touches header, and when bottom anchor not exceeded
if (top > start && top <= end) {
// ensure clone and source column widths are the same
this.$stickyHeader.find('tr:eq(0)').find('th').each((index, el) => {
$(el).css('min-width', this.$header.find('tr:eq(0)').find('th').eq(index).css('width'))
})
// match bootstrap table style
this.$stickyContainer.removeClass(hiddenClass).addClass('fix-sticky fixed-table-container')
// stick it in position
this.$stickyContainer.css('top', `${this.options.stickyHeaderOffsetY}px`)
// create scrollable container for header
this.$stickyTable = $('<table/>')
this.$stickyTable.addClass(this.options.classes)
// append cloned header to dom
this.$stickyContainer.html(this.$stickyTable.append(this.$stickyHeader))
// match clone and source header positions when left-right scroll
this.matchPositionX()
} else {
this.$stickyContainer.removeClass('fix-sticky').addClass(hiddenClass)
}
}

// render sticky on window scroll or resize
$(window).on('resize.'+table_id, table, render_sticky_header);
$(window).on('scroll.'+table_id, table, render_sticky_header);
// render sticky when table scroll left-right
table.closest('.fixed-table-container').find('.fixed-table-body').on('scroll.'+table_id, table, match_position_x);
matchPositionX () {
this.$stickyContainer.scrollLeft(this.$tableBody.scrollLeft())
}
}

this.$el.on('all.bs.table', function (e) {
that.$stickyHeader = $($('#'+header_id).clone(true, true));
that.$stickyHeader.removeAttr('id');
});

function render_sticky_header(event) {
var table = event.data;
var table_header_id = table.find('thead').attr('id');
// console.log('render_sticky_header for > '+table_header_id);
if (table.length < 1 || $('#'+table_id).length < 1){
// turn off window listeners
$(window).off('resize.'+table_id);
$(window).off('scroll.'+table_id);
table.closest('.fixed-table-container').find('.fixed-table-body').off('scroll.'+table_id);
return;
}
// get header height
var header_height = '0';
if (that.options.stickyHeaderOffsetY) header_height = that.options.stickyHeaderOffsetY.replace('px','');
// window scroll top
var t = $(window).scrollTop();
// top anchor scroll position, minus header height
var e = $("#"+anchor_begin_id).offset().top - header_height;
// bottom anchor scroll position, minus header height, minus sticky height
var e_end = $("#"+anchor_end_id).offset().top - header_height - $('#'+table_header_id).css('height').replace('px','');
// show sticky when top anchor touches header, and when bottom anchor not exceeded
if (t > e && t <= e_end) {
// ensure clone and source column widths are the same
$.each( that.$stickyHeader.find('tr').eq(0).find('th'), function (index, item) {
$(item).css('min-width', $('#'+table_header_id+' tr').eq(0).find('th').eq(index).css('width'));
});
// match bootstrap table style
$("#"+sticky_header_container_id).removeClass(hidden_class).addClass("fix-sticky fixed-table-container") ;
// stick it in position
$("#"+sticky_header_container_id).css('top', header_height + 'px');
// create scrollable container for header
var scrollable_div = $('<div style="position:absolute;width:100%;overflow-x:hidden;" />');
// append cloned header to dom
$("#"+sticky_header_container_id).html(scrollable_div.append(that.$stickyHeader));
// match clone and source header positions when left-right scroll
match_position_x(event);
} else {
// hide sticky
$("#"+sticky_header_container_id).removeClass("fix-sticky").addClass(hidden_class);
}

}
function match_position_x(event){
var table = event.data;
var table_header_id = table.find('thead').attr('id');
// match clone and source header positions when left-right scroll
$("#"+sticky_header_container_id).css(
'width', +table.closest('.fixed-table-body').css('width').replace('px', '') + 1
);
$("#"+sticky_header_container_id+" thead").parent().scrollLeft(Math.abs($('#'+table_header_id).position().left));
}
};

})(jQuery);
})(jQuery)

0 comments on commit 2766e00

Please sign in to comment.