|
5 | 5 | */
|
6 | 6 |
|
7 | 7 | !function ($) {
|
8 |
| - |
9 | 8 | 'use strict';
|
10 | 9 |
|
| 10 | + var cellHeight = 37; // update css if changed |
11 | 11 | // TOOLS DEFINITION
|
12 | 12 | // ======================
|
13 | 13 |
|
|
54 | 54 | return index;
|
55 | 55 | };
|
56 | 56 |
|
| 57 | + var cachedWidth = null; |
57 | 58 | var getScrollBarWidth = function () {
|
58 |
| - var inner = $('<p/>').addClass('fixed-table-scroll-inner'), |
59 |
| - outer = $('<div/>').addClass('fixed-table-scroll-outer'), |
60 |
| - w1, w2; |
| 59 | + if (cachedWidth === null) { |
| 60 | + var inner = $('<p/>').addClass('fixed-table-scroll-inner'), |
| 61 | + outer = $('<div/>').addClass('fixed-table-scroll-outer'), |
| 62 | + w1, w2; |
61 | 63 |
|
62 |
| - outer.append(inner); |
63 |
| - $('body').append(outer); |
| 64 | + outer.append(inner); |
| 65 | + $('body').append(outer); |
64 | 66 |
|
65 |
| - w1 = inner[0].offsetWidth; |
66 |
| - outer.css('overflow', 'scroll'); |
67 |
| - w2 = inner[0].offsetWidth; |
| 67 | + w1 = inner[0].offsetWidth; |
| 68 | + outer.css('overflow', 'scroll'); |
| 69 | + w2 = inner[0].offsetWidth; |
68 | 70 |
|
69 |
| - if (w1 === w2) { |
70 |
| - w2 = outer[0].clientWidth; |
71 |
| - } |
| 71 | + if (w1 === w2) { |
| 72 | + w2 = outer[0].clientWidth; |
| 73 | + } |
72 | 74 |
|
73 |
| - outer.remove(); |
74 |
| - return w1 - w2; |
| 75 | + outer.remove(); |
| 76 | + cachedWidth = w1 - w2; |
| 77 | + } |
| 78 | + return cachedWidth; |
75 | 79 | };
|
76 | 80 |
|
77 | 81 | var calculateObjectValue = function (self, name, args, defaultValue) {
|
|
117 | 121 | this.$el = $(el);
|
118 | 122 | this.$el_ = this.$el.clone();
|
119 | 123 | this.timeoutId_ = 0;
|
| 124 | + this.timeoutFooter_ = 0; |
120 | 125 |
|
121 | 126 | this.init();
|
122 | 127 | };
|
|
153 | 158 | searchAlign: 'right',
|
154 | 159 | selectItemName: 'btSelectItem',
|
155 | 160 | showHeader: true,
|
| 161 | + showFooter: false, |
156 | 162 | showColumns: false,
|
157 | 163 | showPaginationSwitch: false,
|
158 | 164 | showRefresh: false,
|
|
282 | 288 | 'class': undefined,
|
283 | 289 | align: undefined, // left, right, center
|
284 | 290 | halign: undefined, // left, right, center
|
| 291 | + falign: undefined, // left, right, center |
285 | 292 | valign: undefined, // top, middle, bottom
|
286 | 293 | width: undefined,
|
287 | 294 | sortable: false,
|
|
290 | 297 | switchable: true,
|
291 | 298 | clickToSelect: true,
|
292 | 299 | formatter: undefined,
|
| 300 | + footerFormatter: undefined, |
293 | 301 | events: undefined,
|
294 | 302 | sorter: undefined,
|
295 | 303 | cellStyle: undefined,
|
|
320 | 328 | this.initTable();
|
321 | 329 | this.initHeader();
|
322 | 330 | this.initData();
|
| 331 | + this.initFooter(); |
323 | 332 | this.initToolbar();
|
324 | 333 | this.initPagination();
|
325 | 334 | this.initBody();
|
|
337 | 346 | this.options.formatLoadingMessage(),
|
338 | 347 | '</div>',
|
339 | 348 | '</div>',
|
| 349 | + '<div class="fixed-table-footer"><table><tr></tr></table></div>', |
340 | 350 | '<div class="fixed-table-pagination"></div>',
|
341 | 351 | '</div>',
|
342 | 352 | '</div>'].join(''));
|
|
498 | 508 | } else {
|
499 | 509 | this.$header.show();
|
500 | 510 | this.$container.find('.fixed-table-header').show();
|
501 |
| - this.$loading.css('top', '37px'); |
| 511 | + this.$loading.css('top', cellHeight + 'px'); |
502 | 512 | }
|
503 | 513 |
|
504 | 514 | this.$selectAll = this.$header.find('[name="btSelectAll"]');
|
|
509 | 519 | });
|
510 | 520 | };
|
511 | 521 |
|
| 522 | + BootstrapTable.prototype.initFooter = function () { |
| 523 | + this.$footer = this.$container.find('.fixed-table-footer'); |
| 524 | + if (!this.options.showFooter || this.options.cardView) { |
| 525 | + this.$footer.hide(); |
| 526 | + } else { |
| 527 | + this.$footer.show(); |
| 528 | + } |
| 529 | + }; |
| 530 | + |
| 531 | + BootstrapTable.prototype.resetFooter = function () { |
| 532 | + var bt = this, |
| 533 | + data = bt.getData(), |
| 534 | + html = []; |
| 535 | + |
| 536 | + if (!this.options.showFooter || this.options.cardView) { //do nothing |
| 537 | + return; |
| 538 | + } |
| 539 | + |
| 540 | + $.each(bt.options.columns, function (i, column) { |
| 541 | + var falign = '', // footer align style |
| 542 | + style = '', |
| 543 | + class_ = sprintf(' class="%s"', column['class']); |
| 544 | + |
| 545 | + if (!column.visible) { |
| 546 | + return; |
| 547 | + } |
| 548 | + |
| 549 | + falign = sprintf('text-align: %s; ', column.falign ? column.falign : column.align); |
| 550 | + style = sprintf('vertical-align: %s; ', column.valign); |
| 551 | + |
| 552 | + html.push('<td', class_, sprintf(' style="%s"', falign + style), '>'); |
| 553 | + |
| 554 | + |
| 555 | + html.push(calculateObjectValue(column, column.footerFormatter, [data], ' ') || ' '); |
| 556 | + html.push('</td>'); |
| 557 | + }); |
| 558 | + |
| 559 | + bt.$footer.find('tr').html(html.join('')); |
| 560 | + clearTimeout(bt.timeoutFooter_); |
| 561 | + bt.timeoutFooter_ = setTimeout($.proxy(bt.fitFooter, bt), bt.$el.is(':hidden') ? 100: 0); |
| 562 | + return; |
| 563 | + }; |
| 564 | + |
| 565 | + BootstrapTable.prototype.fitFooter = function () { |
| 566 | + var bt = this, |
| 567 | + $fixedBody, |
| 568 | + $footerTd, |
| 569 | + elWidth, |
| 570 | + scrollWidth; |
| 571 | + clearTimeout(bt.timeoutFooter_); |
| 572 | + if (bt.$el.is(':hidden')) { |
| 573 | + bt.timeoutFooter_ = setTimeout($.proxy(bt.fitFooter, bt), 100); |
| 574 | + return; |
| 575 | + } |
| 576 | + |
| 577 | + $fixedBody = bt.$container.find('.fixed-table-body'); |
| 578 | + elWidth = bt.$el.css('width'); |
| 579 | + scrollWidth = elWidth > $fixedBody.width() ? getScrollBarWidth() : 0; |
| 580 | + |
| 581 | + bt.$footer.css({ |
| 582 | + 'margin-right': scrollWidth |
| 583 | + }).find('table').css('width', elWidth) |
| 584 | + .attr('class', bt.$el.attr('class')); |
| 585 | + |
| 586 | + $footerTd = bt.$footer.find('td'); |
| 587 | + |
| 588 | + $fixedBody.find('tbody tr:first-child:not(.no-records-found) > td').each(function(i) { |
| 589 | + $footerTd.eq(i).outerWidth($(this).outerWidth()); |
| 590 | + }); |
| 591 | + }; |
| 592 | + |
| 593 | + |
512 | 594 | /**
|
513 | 595 | * @param data
|
514 | 596 | * @param type: append / prepend
|
|
1027 | 1109 | }
|
1028 | 1110 |
|
1029 | 1111 | for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
|
1030 |
| - var item = data[i], |
| 1112 | + var key, |
| 1113 | + item = data[i], |
1031 | 1114 | style = {},
|
1032 | 1115 | csses = [],
|
1033 | 1116 | attributes = {},
|
|
1036 | 1119 | style = calculateObjectValue(this.options, this.options.rowStyle, [item, i], style);
|
1037 | 1120 |
|
1038 | 1121 | if (style && style.css) {
|
1039 |
| - for (var key in style.css) { |
| 1122 | + for (key in style.css) { |
1040 | 1123 | csses.push(key + ': ' + style.css[key]);
|
1041 | 1124 | }
|
1042 | 1125 | }
|
|
1045 | 1128 | this.options.rowAttributes, [item, i], attributes);
|
1046 | 1129 |
|
1047 | 1130 | if (attributes) {
|
1048 |
| - for (var key in attributes) { |
| 1131 | + for (key in attributes) { |
1049 | 1132 | htmlAttributes.push(sprintf('%s="%s"', key, escapeHTML(attributes[key])));
|
1050 | 1133 | }
|
1051 | 1134 | }
|
|
1348 | 1431 | };
|
1349 | 1432 |
|
1350 | 1433 | BootstrapTable.prototype.resetHeader = function () {
|
1351 |
| - var that = this, |
1352 |
| - $fixedHeader = this.$container.find('.fixed-table-header'), |
1353 |
| - $fixedBody = this.$container.find('.fixed-table-body'), |
1354 |
| - scrollWidth = this.$el.width() > $fixedBody.width() ? getScrollBarWidth() : 0; |
1355 |
| - |
| 1434 | + this.$el.css('margin-top', -this.$header.height()); |
1356 | 1435 | // fix #61: the hidden table reset header bug.
|
1357 |
| - if (this.$el.is(':hidden')) { |
1358 |
| - clearTimeout(this.timeoutId_); // doesn't matter if it's 0 |
1359 |
| - this.timeoutId_ = setTimeout($.proxy(this.resetHeader, this), 100); // 100ms |
1360 |
| - return; |
1361 |
| - } |
1362 |
| - |
1363 |
| - this.$header_ = this.$header.clone(true, true); |
1364 |
| - this.$selectAll_ = this.$header_.find('[name="btSelectAll"]'); |
1365 |
| - |
1366 | 1436 | // fix bug: get $el.css('width') error sometime (height = 500)
|
1367 |
| - setTimeout(function () { |
1368 |
| - $fixedHeader.css({ |
1369 |
| - 'height': '37px', |
1370 |
| - 'border-bottom': '1px solid #dddddd', |
1371 |
| - 'margin-right': scrollWidth |
1372 |
| - }).find('table').css('width', that.$el.css('width')) |
1373 |
| - .html('').attr('class', that.$el.attr('class')) |
1374 |
| - .append(that.$header_); |
1375 |
| - |
1376 |
| - // fix bug: $.data() is not working as expected after $.append() |
1377 |
| - that.$header.find('th').each(function (i) { |
1378 |
| - that.$header_.find('th').eq(i).data($(this).data()); |
1379 |
| - }); |
1380 |
| - |
1381 |
| - that.$body.find('tr:first-child:not(.no-records-found) > *').each(function (i) { |
1382 |
| - that.$header_.find('div.fht-cell').eq(i).width($(this).innerWidth()); |
1383 |
| - }); |
| 1437 | + clearTimeout(this.timeoutId_); |
| 1438 | + this.timeoutId_ = setTimeout($.proxy(this.fitHeader, this), this.$el.is(':hidden') ? 100 : 0); |
| 1439 | + return; |
| 1440 | + }; |
1384 | 1441 |
|
1385 |
| - that.$el.css('margin-top', -that.$header.height()); |
| 1442 | + BootstrapTable.prototype.fitHeader = function () { |
| 1443 | + var bt = this, |
| 1444 | + $fixedHeader, |
| 1445 | + $fixedBody, |
| 1446 | + scrollWidth; |
1386 | 1447 |
|
1387 |
| - // horizontal scroll event |
1388 |
| - $fixedBody.off('scroll').on('scroll', function () { |
1389 |
| - $fixedHeader.scrollLeft($(this).scrollLeft()); |
1390 |
| - }); |
| 1448 | + if (bt.$el.is(':hidden')) { |
| 1449 | + bt.timeoutFooter_ = setTimeout($.proxy(bt.fitHeader, bt), 100); |
| 1450 | + return; |
| 1451 | + } |
| 1452 | + $fixedHeader = bt.$container.find('.fixed-table-header'), |
| 1453 | + $fixedBody = bt.$container.find('.fixed-table-body'), |
| 1454 | + scrollWidth = bt.$el.width() > $fixedBody.width() ? getScrollBarWidth() : 0; |
| 1455 | + |
| 1456 | + bt.$header_ = bt.$header.clone(true, true); |
| 1457 | + bt.$selectAll_ = bt.$header_.find('[name="btSelectAll"]'); |
| 1458 | + $fixedHeader.css({ |
| 1459 | + 'margin-right': scrollWidth |
| 1460 | + }).find('table').css('width', bt.$el.css('width')) |
| 1461 | + .html('').attr('class', bt.$el.attr('class')) |
| 1462 | + .append(bt.$header_); |
| 1463 | + |
| 1464 | + // fix bug: $.data() is not working as expected after $.append() |
| 1465 | + bt.$header.find('th').each(function (i) { |
| 1466 | + bt.$header_.find('th').eq(i).data($(this).data()); |
| 1467 | + }); |
1391 | 1468 |
|
1392 |
| - that.trigger('post-header'); |
| 1469 | + bt.$body.find('tr:first-child:not(.no-records-found) > *').each(function (i) { |
| 1470 | + bt.$header_.find('div.fht-cell').eq(i).width($(this).innerWidth()); |
1393 | 1471 | });
|
| 1472 | + // horizontal scroll event |
| 1473 | + // TODO: it's probably better improving the layout than binding to scroll event |
| 1474 | + $fixedBody.off('scroll').on('scroll', function () { |
| 1475 | + $fixedHeader.scrollLeft($(this).scrollLeft()); |
| 1476 | + }); |
| 1477 | + bt.trigger('post-header'); |
1394 | 1478 | };
|
1395 | 1479 |
|
1396 | 1480 | BootstrapTable.prototype.toggleColumn = function (index, checked, needUpdate) {
|
|
1421 | 1505 |
|
1422 | 1506 | BootstrapTable.prototype.resetView = function (params) {
|
1423 | 1507 | var that = this,
|
1424 |
| - header = this.header; |
| 1508 | + padding = 0, |
| 1509 | + $tableContainer = that.$container.find('.fixed-table-container'); |
1425 | 1510 |
|
1426 | 1511 | if (params && params.height) {
|
1427 | 1512 | this.options.height = params.height;
|
|
1435 | 1520 | paginationHeight = +this.$pagination.children().outerHeight(true),
|
1436 | 1521 | height = this.options.height - toolbarHeight - paginationHeight;
|
1437 | 1522 |
|
1438 |
| - this.$container.find('.fixed-table-container').css('height', height + 'px'); |
| 1523 | + $tableContainer.css('height', height + 'px'); |
1439 | 1524 | }
|
1440 | 1525 |
|
1441 | 1526 | if (this.options.cardView) {
|
1442 | 1527 | // remove the element css
|
1443 | 1528 | that.$el.css('margin-top', '0');
|
1444 |
| - that.$container.find('.fixed-table-container').css('padding-bottom', '0'); |
| 1529 | + $tableContainer.css('padding-bottom', '0'); |
1445 | 1530 | return;
|
1446 | 1531 | }
|
1447 | 1532 |
|
1448 | 1533 | if (this.options.showHeader && this.options.height) {
|
1449 | 1534 | this.resetHeader();
|
| 1535 | + padding += cellHeight; |
1450 | 1536 | } else {
|
1451 | 1537 | this.trigger('post-header');
|
1452 | 1538 | }
|
1453 | 1539 |
|
1454 |
| - if (this.options.height && this.options.showHeader) { |
1455 |
| - this.$container.find('.fixed-table-container').css('padding-bottom', '37px'); |
| 1540 | + if (this.options.showFooter) { |
| 1541 | + this.resetFooter(); |
| 1542 | + if (this.options.height) { |
| 1543 | + padding += cellHeight; |
| 1544 | + } |
1456 | 1545 | }
|
| 1546 | + |
| 1547 | + $tableContainer.css('padding-bottom', padding + 'px'); |
1457 | 1548 | };
|
1458 | 1549 |
|
1459 | 1550 | BootstrapTable.prototype.getData = function () {
|
|
0 commit comments