UNPKG

5.63 kBJavaScriptView Raw
1/**
2 * @author vincent loh <vincent.ml@gmail.com>
3 * @update J Manuel Corona <jmcg92@gmail.com>
4 * @update zhixin wen <wenzhixin2010@gmail.com>
5 */
6
7const Utils = $.fn.bootstrapTable.utils
8
9Object.assign($.fn.bootstrapTable.defaults, {
10 stickyHeader: false,
11 stickyHeaderOffsetY: 0,
12 stickyHeaderOffsetLeft: 0,
13 stickyHeaderOffsetRight: 0
14})
15
16$.BootstrapTable = class extends $.BootstrapTable {
17 initHeader (...args) {
18 super.initHeader(...args)
19
20 if (!this.options.stickyHeader) {
21 return
22 }
23
24 this.$tableBody.find('.sticky-header-container,.sticky_anchor_begin,.sticky_anchor_end').remove()
25
26 this.$el.before('<div class="sticky-header-container"></div>')
27 this.$el.before('<div class="sticky_anchor_begin"></div>')
28 this.$el.after('<div class="sticky_anchor_end"></div>')
29 this.$header.addClass('sticky-header')
30
31 // clone header just once, to be used as sticky header
32 // deep clone header, using source header affects tbody>td width
33 this.$stickyContainer = this.$tableBody.find('.sticky-header-container')
34 this.$stickyBegin = this.$tableBody.find('.sticky_anchor_begin')
35 this.$stickyEnd = this.$tableBody.find('.sticky_anchor_end')
36 this.$stickyHeader = this.$header.clone(true, true)
37
38 // render sticky on window scroll or resize
39 const resizeEvent = Utils.getEventName('resize.sticky-header-table', this.$el.attr('id'))
40 const scrollEvent = Utils.getEventName('scroll.sticky-header-table', this.$el.attr('id'))
41
42 $(window).off(resizeEvent).on(resizeEvent, () => this.renderStickyHeader())
43 $(window).off(scrollEvent).on(scrollEvent, () => this.renderStickyHeader())
44 this.$tableBody.off('scroll').on('scroll', () => this.matchPositionX())
45 }
46
47 onColumnSearch ({ currentTarget, keyCode }) {
48 super.onColumnSearch({ currentTarget, keyCode })
49 this.renderStickyHeader()
50 }
51
52 resetView (...args) {
53 super.resetView(...args)
54
55 $('.bootstrap-table.fullscreen').off('scroll')
56 .on('scroll', () => this.renderStickyHeader())
57 }
58
59 getCaret (...args) {
60 super.getCaret(...args)
61
62 if (this.$stickyHeader) {
63 const $ths = this.$stickyHeader.find('th')
64
65 this.$header.find('th').each((i, th) => {
66 $ths.eq(i).find('.sortable').attr('class', $(th).find('.sortable').attr('class'))
67 })
68 }
69 }
70
71 horizontalScroll () {
72 super.horizontalScroll()
73 this.$tableBody.on('scroll', () => this.matchPositionX())
74 }
75
76 renderStickyHeader () {
77 const that = this
78
79 this.$stickyHeader = this.$header.clone(true, true)
80
81 if (this.options.filterControl) {
82 $(this.$stickyHeader).off('keyup change mouseup').on('keyup change mouse', function (e) {
83 const $target = $(e.target)
84 const value = $target.val()
85 const field = $target.parents('th').data('field')
86 const $coreTh = that.$header.find(`th[data-field="${field}"]`)
87
88 if ($target.is('input')) {
89 $coreTh.find('input').val(value)
90 } else if ($target.is('select')) {
91 const $select = $coreTh.find('select')
92
93 $select.find('option[selected]').removeAttr('selected')
94 $select.find(`option[value="${value}"]`).attr('selected', true)
95 }
96
97 that.triggerSearch()
98 })
99 }
100
101 const top = $(window).scrollTop()
102 // top anchor scroll position, minus header height
103 const start = this.$stickyBegin.offset().top - this.options.stickyHeaderOffsetY
104 // bottom anchor scroll position, minus header height, minus sticky height
105 const end = this.$stickyEnd.offset().top - this.options.stickyHeaderOffsetY - this.$header.height()
106
107 // show sticky when top anchor touches header, and when bottom anchor not exceeded
108 if (top > start && top <= end) {
109 // ensure clone and source column widths are the same
110 this.$stickyHeader.find('tr').each((indexRows, rows) => {
111 const columns = $(rows).find('th')
112
113 columns.each((indexColumns, celd) => {
114 $(celd).css('min-width', this.$header.find(`tr:eq(${indexRows})`).find(`th:eq(${indexColumns})`).css('width'))
115 })
116 })
117 // match bootstrap table style
118 this.$stickyContainer.show().addClass('fix-sticky fixed-table-container')
119 // stick it in position
120 const coords = this.$tableBody[0].getBoundingClientRect()
121 let width = '100%'
122 let stickyHeaderOffsetLeft = this.options.stickyHeaderOffsetLeft
123 let stickyHeaderOffsetRight = this.options.stickyHeaderOffsetRight
124
125 if (!stickyHeaderOffsetLeft) {
126 stickyHeaderOffsetLeft = coords.left
127 }
128 if (!stickyHeaderOffsetRight) {
129 width = `${coords.width}px`
130 }
131 if (this.$el.closest('.bootstrap-table').hasClass('fullscreen')) {
132 stickyHeaderOffsetLeft = 0
133 stickyHeaderOffsetRight = 0
134 width = '100%'
135 }
136 this.$stickyContainer.css('top', `${this.options.stickyHeaderOffsetY}px`)
137 this.$stickyContainer.css('left', `${stickyHeaderOffsetLeft}px`)
138 this.$stickyContainer.css('right', `${stickyHeaderOffsetRight}px`)
139 this.$stickyContainer.css('width', `${width}`)
140 // create scrollable container for header
141 this.$stickyTable = $('<table/>')
142 this.$stickyTable.addClass(this.options.classes)
143 // append cloned header to dom
144 this.$stickyContainer.html(this.$stickyTable.append(this.$stickyHeader))
145 // match clone and source header positions when left-right scroll
146 this.matchPositionX()
147 } else {
148 this.$stickyContainer.removeClass('fix-sticky').hide()
149 }
150 }
151
152 matchPositionX () {
153 this.$stickyContainer.scrollLeft(this.$tableBody.scrollLeft())
154 }
155}