Skip to content

Commit 9f5f22f

Browse files
committed
merged footer changes
2 parents a037d25 + 0dd5e0a commit 9f5f22f

File tree

2 files changed

+154
-60
lines changed

2 files changed

+154
-60
lines changed

src/bootstrap-table.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
-moz-border-radius: 4px;
2121
}
2222

23+
.fixed-table-footer,
2324
.fixed-table-header {
25+
height: 37px; /*cellHeight*/
26+
border-bottom: 1px solid #dddddd;
2427
overflow: hidden;
2528
border-radius: 4px 4px 0 0;
2629
-webkit-border-radius: 4px 4px 0 0;

src/bootstrap-table.js

Lines changed: 151 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
*/
66

77
!function ($) {
8-
98
'use strict';
109

10+
var cellHeight = 37; // update css if changed
1111
// TOOLS DEFINITION
1212
// ======================
1313

@@ -54,24 +54,28 @@
5454
return index;
5555
};
5656

57+
var cachedWidth = null;
5758
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;
6163

62-
outer.append(inner);
63-
$('body').append(outer);
64+
outer.append(inner);
65+
$('body').append(outer);
6466

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;
6870

69-
if (w1 === w2) {
70-
w2 = outer[0].clientWidth;
71-
}
71+
if (w1 === w2) {
72+
w2 = outer[0].clientWidth;
73+
}
7274

73-
outer.remove();
74-
return w1 - w2;
75+
outer.remove();
76+
cachedWidth = w1 - w2;
77+
}
78+
return cachedWidth;
7579
};
7680

7781
var calculateObjectValue = function (self, name, args, defaultValue) {
@@ -117,6 +121,7 @@
117121
this.$el = $(el);
118122
this.$el_ = this.$el.clone();
119123
this.timeoutId_ = 0;
124+
this.timeoutFooter_ = 0;
120125

121126
this.init();
122127
};
@@ -153,6 +158,7 @@
153158
searchAlign: 'right',
154159
selectItemName: 'btSelectItem',
155160
showHeader: true,
161+
showFooter: false,
156162
showColumns: false,
157163
showPaginationSwitch: false,
158164
showRefresh: false,
@@ -282,6 +288,7 @@
282288
'class': undefined,
283289
align: undefined, // left, right, center
284290
halign: undefined, // left, right, center
291+
falign: undefined, // left, right, center
285292
valign: undefined, // top, middle, bottom
286293
width: undefined,
287294
sortable: false,
@@ -290,6 +297,7 @@
290297
switchable: true,
291298
clickToSelect: true,
292299
formatter: undefined,
300+
footerFormatter: undefined,
293301
events: undefined,
294302
sorter: undefined,
295303
cellStyle: undefined,
@@ -320,6 +328,7 @@
320328
this.initTable();
321329
this.initHeader();
322330
this.initData();
331+
this.initFooter();
323332
this.initToolbar();
324333
this.initPagination();
325334
this.initBody();
@@ -337,6 +346,7 @@
337346
this.options.formatLoadingMessage(),
338347
'</div>',
339348
'</div>',
349+
'<div class="fixed-table-footer"><table><tr></tr></table></div>',
340350
'<div class="fixed-table-pagination"></div>',
341351
'</div>',
342352
'</div>'].join(''));
@@ -498,7 +508,7 @@
498508
} else {
499509
this.$header.show();
500510
this.$container.find('.fixed-table-header').show();
501-
this.$loading.css('top', '37px');
511+
this.$loading.css('top', cellHeight + 'px');
502512
}
503513

504514
this.$selectAll = this.$header.find('[name="btSelectAll"]');
@@ -509,6 +519,78 @@
509519
});
510520
};
511521

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], '&nbsp;') || '&nbsp;');
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+
512594
/**
513595
* @param data
514596
* @param type: append / prepend
@@ -1027,7 +1109,8 @@
10271109
}
10281110

10291111
for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
1030-
var item = data[i],
1112+
var key,
1113+
item = data[i],
10311114
style = {},
10321115
csses = [],
10331116
attributes = {},
@@ -1036,7 +1119,7 @@
10361119
style = calculateObjectValue(this.options, this.options.rowStyle, [item, i], style);
10371120

10381121
if (style && style.css) {
1039-
for (var key in style.css) {
1122+
for (key in style.css) {
10401123
csses.push(key + ': ' + style.css[key]);
10411124
}
10421125
}
@@ -1045,7 +1128,7 @@
10451128
this.options.rowAttributes, [item, i], attributes);
10461129

10471130
if (attributes) {
1048-
for (var key in attributes) {
1131+
for (key in attributes) {
10491132
htmlAttributes.push(sprintf('%s="%s"', key, escapeHTML(attributes[key])));
10501133
}
10511134
}
@@ -1348,49 +1431,50 @@
13481431
};
13491432

13501433
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());
13561435
// 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-
13661436
// 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+
};
13841441

1385-
that.$el.css('margin-top', -that.$header.height());
1442+
BootstrapTable.prototype.fitHeader = function () {
1443+
var bt = this,
1444+
$fixedHeader,
1445+
$fixedBody,
1446+
scrollWidth;
13861447

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+
});
13911468

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());
13931471
});
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');
13941478
};
13951479

13961480
BootstrapTable.prototype.toggleColumn = function (index, checked, needUpdate) {
@@ -1421,7 +1505,8 @@
14211505

14221506
BootstrapTable.prototype.resetView = function (params) {
14231507
var that = this,
1424-
header = this.header;
1508+
padding = 0,
1509+
$tableContainer = that.$container.find('.fixed-table-container');
14251510

14261511
if (params && params.height) {
14271512
this.options.height = params.height;
@@ -1435,25 +1520,31 @@
14351520
paginationHeight = +this.$pagination.children().outerHeight(true),
14361521
height = this.options.height - toolbarHeight - paginationHeight;
14371522

1438-
this.$container.find('.fixed-table-container').css('height', height + 'px');
1523+
$tableContainer.css('height', height + 'px');
14391524
}
14401525

14411526
if (this.options.cardView) {
14421527
// remove the element css
14431528
that.$el.css('margin-top', '0');
1444-
that.$container.find('.fixed-table-container').css('padding-bottom', '0');
1529+
$tableContainer.css('padding-bottom', '0');
14451530
return;
14461531
}
14471532

14481533
if (this.options.showHeader && this.options.height) {
14491534
this.resetHeader();
1535+
padding += cellHeight;
14501536
} else {
14511537
this.trigger('post-header');
14521538
}
14531539

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+
}
14561545
}
1546+
1547+
$tableContainer.css('padding-bottom', padding + 'px');
14571548
};
14581549

14591550
BootstrapTable.prototype.getData = function () {

0 commit comments

Comments
 (0)