UNPKG

11.5 kBJavaScriptView Raw
1/**
2 * @author zhixin wen <wenzhixin2010@gmail.com>
3 */
4
5const Utils = $.fn.bootstrapTable.utils
6
7// Reasonable defaults
8const PIXEL_STEP = 10
9const LINE_HEIGHT = 40
10const PAGE_HEIGHT = 800
11
12function normalizeWheel (event) {
13 let sX = 0 // spinX
14 let sY = 0 // spinY
15 let pX = 0 // pixelX
16 let pY = 0 // pixelY
17
18 // Legacy
19 if ('detail' in event) { sY = event.detail }
20 if ('wheelDelta' in event) { sY = -event.wheelDelta / 120 }
21 if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120 }
22 if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120 }
23
24 // side scrolling on FF with DOMMouseScroll
25 if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
26 sX = sY
27 sY = 0
28 }
29
30 pX = sX * PIXEL_STEP
31 pY = sY * PIXEL_STEP
32
33 if ('deltaY' in event) { pY = event.deltaY }
34 if ('deltaX' in event) { pX = event.deltaX }
35
36 if ((pX || pY) && event.deltaMode) {
37 if (event.deltaMode === 1) { // delta in LINE units
38 pX *= LINE_HEIGHT
39 pY *= LINE_HEIGHT
40 } else { // delta in PAGE units
41 pX *= PAGE_HEIGHT
42 pY *= PAGE_HEIGHT
43 }
44 }
45
46 // Fall-back if spin cannot be determined
47 if (pX && !sX) { sX = (pX < 1) ? -1 : 1 }
48 if (pY && !sY) { sY = (pY < 1) ? -1 : 1 }
49
50 return {
51 spinX: sX,
52 spinY: sY,
53 pixelX: pX,
54 pixelY: pY
55 }
56}
57
58$.extend($.fn.bootstrapTable.defaults, {
59 fixedColumns: false,
60 fixedNumber: 0,
61 fixedRightNumber: 0
62})
63
64$.BootstrapTable = class extends $.BootstrapTable {
65
66 fixedColumnsSupported () {
67 return this.options.fixedColumns &&
68 !this.options.detailView &&
69 !this.options.cardView
70 }
71
72 initContainer () {
73 super.initContainer()
74
75 if (!this.fixedColumnsSupported()) {
76 return
77 }
78
79 if (this.options.fixedNumber) {
80 this.$tableContainer.append('<div class="fixed-columns"></div>')
81 this.$fixedColumns = this.$tableContainer.find('.fixed-columns')
82 }
83
84 if (this.options.fixedRightNumber) {
85 this.$tableContainer.append('<div class="fixed-columns-right"></div>')
86 this.$fixedColumnsRight = this.$tableContainer.find('.fixed-columns-right')
87 }
88 }
89
90 initBody (...args) {
91 super.initBody(...args)
92
93 if (this.$fixedColumns && this.$fixedColumns.length) {
94 this.$fixedColumns.toggle(this.fixedColumnsSupported())
95 }
96 if (this.$fixedColumnsRight && this.$fixedColumnsRight.length) {
97 this.$fixedColumnsRight.toggle(this.fixedColumnsSupported())
98 }
99
100 if (!this.fixedColumnsSupported()) {
101 return
102 }
103
104 if (this.options.showHeader && this.options.height) {
105 return
106 }
107
108 this.initFixedColumnsBody()
109 this.initFixedColumnsEvents()
110 }
111
112 trigger (...args) {
113 super.trigger(...args)
114
115 if (!this.fixedColumnsSupported()) {
116 return
117 }
118
119 if (args[0] === 'post-header') {
120 this.initFixedColumnsHeader()
121 } else if (args[0] === 'scroll-body') {
122 if (this.needFixedColumns && this.options.fixedNumber) {
123 this.$fixedBody.scrollTop(this.$tableBody.scrollTop())
124 }
125
126 if (this.needFixedColumns && this.options.fixedRightNumber) {
127 this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop())
128 }
129 }
130 }
131
132 updateSelected () {
133 super.updateSelected()
134
135 if (!this.fixedColumnsSupported()) {
136 return
137 }
138
139 this.$tableBody.find('tr').each((i, el) => {
140 const $el = $(el)
141 const index = $el.data('index')
142 const classes = $el.attr('class')
143
144 const inputSelector = `[name="${this.options.selectItemName}"]`
145 const $input = $el.find(inputSelector)
146
147 if (typeof index === undefined) {
148 return
149 }
150
151 const updateFixedBody = ($fixedHeader, $fixedBody) => {
152 const $tr = $fixedBody.find(`tr[data-index="${index}"]`)
153
154 $tr.attr('class', classes)
155
156 if ($input.length) {
157 $tr.find(inputSelector).prop('checked', $input.prop('checked'))
158 }
159
160 if (this.$selectAll.length) {
161 $fixedHeader.add($fixedBody)
162 .find('[name="btSelectAll"]')
163 .prop('checked', this.$selectAll.prop('checked'))
164 }
165 }
166
167 if (this.$fixedBody && this.options.fixedNumber) {
168 updateFixedBody(this.$fixedHeader, this.$fixedBody)
169 }
170
171 if (this.$fixedBodyRight && this.options.fixedRightNumber) {
172 updateFixedBody(this.$fixedHeaderRight, this.$fixedBodyRight)
173 }
174 })
175 }
176
177 hideLoading () {
178 super.hideLoading()
179
180 if (this.needFixedColumns && this.options.fixedNumber) {
181 this.$fixedColumns.find('.fixed-table-loading').hide()
182 }
183
184 if (this.needFixedColumns && this.options.fixedRightNumber) {
185 this.$fixedColumnsRight.find('.fixed-table-loading').hide()
186 }
187 }
188
189 initFixedColumnsHeader () {
190 if (this.options.height) {
191 this.needFixedColumns = this.$tableHeader.outerWidth(true) < this.$tableHeader.find('table').outerWidth(true)
192 } else {
193 this.needFixedColumns = this.$tableBody.outerWidth(true) < this.$tableBody.find('table').outerWidth(true)
194 }
195
196 const initFixedHeader = ($fixedColumns, isRight) => {
197 $fixedColumns.find('.fixed-table-header').remove()
198 $fixedColumns.append(this.$tableHeader.clone(true))
199
200 $fixedColumns.css({
201 width: this.getFixedColumnsWidth(isRight)
202 })
203 return $fixedColumns.find('.fixed-table-header')
204 }
205
206 if (this.needFixedColumns && this.options.fixedNumber) {
207 this.$fixedHeader = initFixedHeader(this.$fixedColumns)
208 this.$fixedHeader.css('margin-right', '')
209 } else if (this.$fixedColumns) {
210 this.$fixedColumns.html('').css('width', '')
211 }
212
213 if (this.needFixedColumns && this.options.fixedRightNumber) {
214 this.$fixedHeaderRight = initFixedHeader(this.$fixedColumnsRight, true)
215 this.$fixedHeaderRight.scrollLeft(this.$fixedHeaderRight.find('table').width())
216 } else if (this.$fixedColumnsRight) {
217 this.$fixedColumnsRight.html('').css('width', '')
218 }
219
220 this.initFixedColumnsBody()
221 this.initFixedColumnsEvents()
222 }
223
224 initFixedColumnsBody () {
225 const initFixedBody = ($fixedColumns, $fixedHeader) => {
226 $fixedColumns.find('.fixed-table-body').remove()
227 $fixedColumns.append(this.$tableBody.clone(true))
228 $fixedColumns.find('.fixed-table-body table').removeAttr('id')
229
230 const $fixedBody = $fixedColumns.find('.fixed-table-body')
231
232 const tableBody = this.$tableBody.get(0)
233 const scrollHeight = tableBody.scrollWidth > tableBody.clientWidth ?
234 Utils.getScrollBarWidth() : 0
235 const height = this.$tableContainer.outerHeight(true) - scrollHeight - 1
236
237 $fixedColumns.css({
238 height
239 })
240
241 $fixedBody.css({
242 height: height - $fixedHeader.height()
243 })
244
245 return $fixedBody
246 }
247
248 if (this.needFixedColumns && this.options.fixedNumber) {
249 this.$fixedBody = initFixedBody(this.$fixedColumns, this.$fixedHeader)
250 }
251
252 if (this.needFixedColumns && this.options.fixedRightNumber) {
253 this.$fixedBodyRight = initFixedBody(this.$fixedColumnsRight, this.$fixedHeaderRight)
254 this.$fixedBodyRight.scrollLeft(this.$fixedBodyRight.find('table').width())
255 this.$fixedBodyRight.css('overflow-y', this.options.height ? 'auto' : 'hidden')
256 }
257 }
258
259 getFixedColumnsWidth (isRight) {
260 let visibleFields = this.getVisibleFields()
261 let width = 0
262 let fixedNumber = this.options.fixedNumber
263 let marginRight = 0
264
265 if (isRight) {
266 visibleFields = visibleFields.reverse()
267 fixedNumber = this.options.fixedRightNumber
268 marginRight = parseInt(this.$tableHeader.css('margin-right'), 10)
269 }
270
271 for (let i = 0; i < fixedNumber; i++) {
272 width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
273 }
274
275 return width + marginRight + 1
276 }
277
278 initFixedColumnsEvents () {
279 const toggleHover = (e, toggle) => {
280 const tr = `tr[data-index="${$(e.currentTarget).data('index')}"]`
281 let $trs = this.$tableBody.find(tr)
282
283 if (this.$fixedBody) {
284 $trs = $trs.add(this.$fixedBody.find(tr))
285 }
286 if (this.$fixedBodyRight) {
287 $trs = $trs.add(this.$fixedBodyRight.find(tr))
288 }
289
290 $trs.css('background-color', toggle ? $(e.currentTarget).css('background-color') : '')
291 }
292
293 this.$tableBody.find('tr').hover(e => {
294 toggleHover(e, true)
295 }, e => {
296 toggleHover(e, false)
297 })
298
299 const isFirefox = typeof navigator !== 'undefined' &&
300 navigator.userAgent.toLowerCase().indexOf('firefox') > -1
301 const mousewheel = isFirefox ? 'DOMMouseScroll' : 'mousewheel'
302 const updateScroll = (e, fixedBody) => {
303 const normalized = normalizeWheel(e)
304 const deltaY = Math.ceil(normalized.pixelY)
305 const top = this.$tableBody.scrollTop() + deltaY
306
307 if (
308 deltaY < 0 && top > 0 ||
309 deltaY > 0 && top < fixedBody.scrollHeight - fixedBody.clientHeight
310 ) {
311 e.preventDefault()
312 }
313
314 this.$tableBody.scrollTop(top)
315 if (this.$fixedBody) {
316 this.$fixedBody.scrollTop(top)
317 }
318 if (this.$fixedBodyRight) {
319 this.$fixedBodyRight.scrollTop(top)
320 }
321 }
322
323 if (this.needFixedColumns && this.options.fixedNumber) {
324 this.$fixedBody.find('tr').hover(e => {
325 toggleHover(e, true)
326 }, e => {
327 toggleHover(e, false)
328 })
329
330 this.$fixedBody[0].addEventListener(mousewheel, e => {
331 updateScroll(e, this.$fixedBody[0])
332 })
333 }
334
335 if (this.needFixedColumns && this.options.fixedRightNumber) {
336 this.$fixedBodyRight.find('tr').hover(e => {
337 toggleHover(e, true)
338 }, e => {
339 toggleHover(e, false)
340 })
341
342 this.$fixedBodyRight.off('scroll').on('scroll', () => {
343 const top = this.$fixedBodyRight.scrollTop()
344
345 this.$tableBody.scrollTop(top)
346 if (this.$fixedBody) {
347 this.$fixedBody.scrollTop(top)
348 }
349 })
350 }
351
352 if (this.options.filterControl) {
353 $(this.$fixedColumns).off('keyup change').on('keyup change', e => {
354 const $target = $(e.target)
355 const value = $target.val()
356 const field = $target.parents('th').data('field')
357 const $coreTh = this.$header.find(`th[data-field="${field}"]`)
358
359 if ($target.is('input')) {
360 $coreTh.find('input').val(value)
361 } else if ($target.is('select')) {
362 const $select = $coreTh.find('select')
363
364 $select.find('option[selected]').removeAttr('selected')
365 $select.find(`option[value="${value}"]`).attr('selected', true)
366 }
367
368 this.triggerSearch()
369 })
370 }
371 }
372
373 renderStickyHeader () {
374 if (!this.options.stickyHeader) {
375 return
376 }
377
378 this.$stickyContainer = this.$container.find('.sticky-header-container')
379 super.renderStickyHeader()
380
381 if (this.needFixedColumns && this.options.fixedNumber) {
382 this.$fixedColumns.css('z-index', 101)
383 .find('.sticky-header-container')
384 .css('right', '')
385 .width(this.$fixedColumns.outerWidth())
386 }
387
388 if (this.needFixedColumns && this.options.fixedRightNumber) {
389 const $stickyHeaderContainerRight = this.$fixedColumnsRight.find('.sticky-header-container')
390
391 this.$fixedColumnsRight.css('z-index', 101)
392 $stickyHeaderContainerRight.css('left', '')
393 .scrollLeft($stickyHeaderContainerRight.find('.table').outerWidth())
394 .width(this.$fixedColumnsRight.outerWidth())
395 }
396 }
397
398 matchPositionX () {
399 if (!this.options.stickyHeader) {
400 return
401 }
402
403 this.$stickyContainer.eq(0).scrollLeft(this.$tableBody.scrollLeft())
404 }
405}