1 |
|
2 |
|
3 |
|
4 |
|
5 | const Utils = $.fn.bootstrapTable.utils
|
6 |
|
7 |
|
8 | const PIXEL_STEP = 10
|
9 | const LINE_HEIGHT = 40
|
10 | const PAGE_HEIGHT = 800
|
11 |
|
12 | function normalizeWheel (event) {
|
13 | let sX = 0
|
14 | let sY = 0
|
15 | let pX = 0
|
16 | let pY = 0
|
17 |
|
18 |
|
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 |
|
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) {
|
38 | pX *= LINE_HEIGHT
|
39 | pY *= LINE_HEIGHT
|
40 | } else {
|
41 | pX *= PAGE_HEIGHT
|
42 | pY *= PAGE_HEIGHT
|
43 | }
|
44 | }
|
45 |
|
46 |
|
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 | }
|