· 8 years ago · Dec 20, 2017, 03:00 PM
1/**
2 * @author zhixin wen <wenzhixin2010@gmail.com>
3 * version: 1.11.1
4 * https://github.com/wenzhixin/bootstrap-table/
5 */
6
7(function ($) {
8 'use strict';
9
10 // TOOLS DEFINITION
11 // ======================
12
13 var bootstrapVersion = 3;
14 try {
15 bootstrapVersion = parseInt($.fn.dropdown.Constructor.VERSION, 10);
16 } catch (e) {}
17 var bs = {
18 3: {
19 buttonsClass: 'default',
20 iconsPrefix: 'glyphicon',
21 icons: {
22 paginationSwitchDown: 'glyphicon-collapse-down icon-chevron-down',
23 paginationSwitchUp: 'glyphicon-collapse-up icon-chevron-up',
24 refresh: 'glyphicon-refresh icon-refresh',
25 toggle: 'glyphicon-list-alt icon-list-alt',
26 columns: 'glyphicon-th icon-th',
27 detailOpen: 'glyphicon-plus icon-plus',
28 detailClose: 'glyphicon-minus icon-minus',
29 fullscreen: 'glyphicon-fullscreen'
30 },
31 pullClass: 'pull',
32 toobarDropdowHtml: ['<ul class="dropdown-menu" role="menu">', '</ul>'],
33 toobarDropdowItemHtml: '<li role="menuitem"><label>%s</label></li>',
34 pageDropdownHtml: ['<ul class="dropdown-menu" role="menu">', '</ul>'],
35 pageDropdownItemHtml: '<li role="menuitem" class="%s"><a href="#">%s</a></li>'
36 },
37 4: {
38 buttonsClass: 'secondary',
39 iconsPrefix: 'fa',
40 icons: {
41 paginationSwitchDown: 'fa-toggle-down',
42 paginationSwitchUp: 'fa-toggle-up',
43 refresh: 'fa-refresh',
44 toggle: 'fa-toggle-on',
45 columns: 'fa-th-list',
46 detailOpen: 'fa-plus',
47 detailClose: 'fa-minus',
48 fullscreen: 'fa-arrows-alt'
49 },
50 pullClass: 'float',
51 toobarDropdowHtml: ['<div class="dropdown-menu dropdown-menu-right">', '</div>'],
52 toobarDropdowItemHtml: '<label class="dropdown-item">%s</label>',
53 pageDropdownHtml: ['<div class="dropdown-menu">', '</div>'],
54 pageDropdownItemHtml: '<a class="dropdown-item %s" href="#">%s</a>'
55 }
56 }[bootstrapVersion];
57
58 var cachedWidth = null;
59
60 // it only does '%s', and return '' when arguments are undefined
61 var sprintf = function (str) {
62 var args = arguments,
63 flag = true,
64 i = 1;
65
66 str = str.replace(/%s/g, function () {
67 var arg = args[i++];
68
69 if (typeof arg === 'undefined') {
70 flag = false;
71 return '';
72 }
73 return arg;
74 });
75 return flag ? str : '';
76 };
77
78 var getPropertyFromOther = function (list, from, to, value) {
79 var result = '';
80 $.each(list, function (i, item) {
81 if (item[from] === value) {
82 result = item[to];
83 return false;
84 }
85 return true;
86 });
87 return result;
88 };
89
90 // http://jsfiddle.net/wenyi/47nz7ez9/3/
91 var setFieldIndex = function (columns) {
92 var i, j, k,
93 totalCol = 0,
94 flag = [];
95
96 for (i = 0; i < columns[0].length; i++) {
97 totalCol += columns[0][i].colspan || 1;
98 }
99
100 for (i = 0; i < columns.length; i++) {
101 flag[i] = [];
102 for (j = 0; j < totalCol; j++) {
103 flag[i][j] = false;
104 }
105 }
106
107 for (i = 0; i < columns.length; i++) {
108 for (j = 0; j < columns[i].length; j++) {
109 var r = columns[i][j],
110 rowspan = r.rowspan || 1,
111 colspan = r.colspan || 1,
112 index = $.inArray(false, flag[i]);
113
114 if (colspan === 1) {
115 r.fieldIndex = index;
116 // when field is undefined, use index instead
117 if (typeof r.field === 'undefined') {
118 r.field = index;
119 }
120 }
121
122 for (k = 0; k < rowspan; k++) {
123 flag[i + k][index] = true;
124 }
125 for (k = 0; k < colspan; k++) {
126 flag[i][index + k] = true;
127 }
128 }
129 }
130 };
131
132 var getScrollBarWidth = function () {
133 if (cachedWidth === null) {
134 var inner = $('<p/>').addClass('fixed-table-scroll-inner'),
135 outer = $('<div/>').addClass('fixed-table-scroll-outer'),
136 w1, w2;
137
138 outer.append(inner);
139 $('body').append(outer);
140
141 w1 = inner[0].offsetWidth;
142 outer.css('overflow', 'scroll');
143 w2 = inner[0].offsetWidth;
144
145 if (w1 === w2) {
146 w2 = outer[0].clientWidth;
147 }
148
149 outer.remove();
150 cachedWidth = w1 - w2;
151 }
152 return cachedWidth;
153 };
154
155 var calculateObjectValue = function (self, name, args, defaultValue) {
156 var func = name;
157
158 if (typeof name === 'string') {
159 // support obj.func1.func2
160 var names = name.split('.');
161
162 if (names.length > 1) {
163 func = window;
164 $.each(names, function (i, f) {
165 func = func[f];
166 });
167 } else {
168 func = window[name];
169 }
170 }
171 if (typeof func === 'object') {
172 return func;
173 }
174 if (typeof func === 'function') {
175 return func.apply(self, args || []);
176 }
177 if (!func && typeof name === 'string' && sprintf.apply(this, [name].concat(args))) {
178 return sprintf.apply(this, [name].concat(args));
179 }
180 return defaultValue;
181 };
182
183 var compareObjects = function (objectA, objectB, compareLength) {
184 // Create arrays of property names
185 var objectAProperties = Object.getOwnPropertyNames(objectA),
186 objectBProperties = Object.getOwnPropertyNames(objectB),
187 propName = '';
188
189 if (compareLength) {
190 // If number of properties is different, objects are not equivalent
191 if (objectAProperties.length !== objectBProperties.length) {
192 return false;
193 }
194 }
195
196 for (var i = 0; i < objectAProperties.length; i++) {
197 propName = objectAProperties[i];
198
199 // If the property is not in the object B properties, continue with the next property
200 if ($.inArray(propName, objectBProperties) > -1) {
201 // If values of same property are not equal, objects are not equivalent
202 if (objectA[propName] !== objectB[propName]) {
203 return false;
204 }
205 }
206 }
207
208 // If we made it this far, objects are considered equivalent
209 return true;
210 };
211
212 var escapeHTML = function (text) {
213 if (typeof text === 'string') {
214 return text
215 .replace(/&/g, '&')
216 .replace(/</g, '<')
217 .replace(/>/g, '>')
218 .replace(/"/g, '"')
219 .replace(/'/g, ''')
220 .replace(/`/g, '`');
221 }
222 return text;
223 };
224
225 var getRealDataAttr = function (dataAttr) {
226 for (var attr in dataAttr) {
227 var auxAttr = attr.split(/(?=[A-Z])/).join('-').toLowerCase();
228 if (auxAttr !== attr) {
229 dataAttr[auxAttr] = dataAttr[attr];
230 delete dataAttr[attr];
231 }
232 }
233
234 return dataAttr;
235 };
236
237 var getItemField = function (item, field, escape) {
238 var value = item;
239
240 if (typeof field !== 'string' || item.hasOwnProperty(field)) {
241 return escape ? escapeHTML(item[field]) : item[field];
242 }
243 var props = field.split('.');
244 for (var p in props) {
245 if (props.hasOwnProperty(p)) {
246 value = value && value[props[p]];
247 }
248 }
249 return escape ? escapeHTML(value) : value;
250 };
251
252 var isIEBrowser = function () {
253 return !!(navigator.userAgent.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./));
254 };
255
256 var objectKeys = function () {
257 // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
258 if (!Object.keys) {
259 Object.keys = (function() {
260 var hasOwnProperty = Object.prototype.hasOwnProperty,
261 hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
262 dontEnums = [
263 'toString',
264 'toLocaleString',
265 'valueOf',
266 'hasOwnProperty',
267 'isPrototypeOf',
268 'propertyIsEnumerable',
269 'constructor'
270 ],
271 dontEnumsLength = dontEnums.length;
272
273 return function(obj) {
274 if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
275 throw new TypeError('Object.keys called on non-object');
276 }
277
278 var result = [], prop, i;
279
280 for (prop in obj) {
281 if (hasOwnProperty.call(obj, prop)) {
282 result.push(prop);
283 }
284 }
285
286 if (hasDontEnumBug) {
287 for (i = 0; i < dontEnumsLength; i++) {
288 if (hasOwnProperty.call(obj, dontEnums[i])) {
289 result.push(dontEnums[i]);
290 }
291 }
292 }
293 return result;
294 };
295 }());
296 }
297 };
298
299 // BOOTSTRAP TABLE CLASS DEFINITION
300 // ======================
301
302 var BootstrapTable = function (el, options) {
303 this.options = options;
304 this.$el = $(el);
305 this.$el_ = this.$el.clone();
306 this.timeoutId_ = 0;
307 this.timeoutFooter_ = 0;
308
309 this.init();
310 };
311
312 BootstrapTable.DEFAULTS = {
313 classes: 'table table-hover',
314 sortClass: undefined,
315 locale: undefined,
316 height: undefined,
317 undefinedText: '-',
318 sortName: undefined,
319 sortOrder: 'asc',
320 sortStable: false,
321 rememberOrder: false,
322 striped: false,
323 columns: [[]],
324 data: [],
325 totalField: 'total',
326 dataField: 'rows',
327 method: 'get',
328 url: undefined,
329 ajax: undefined,
330 cache: true,
331 contentType: 'application/json',
332 dataType: 'json',
333 ajaxOptions: {},
334 queryParams: function (params) {
335 return params;
336 },
337 queryParamsType: 'limit', // undefined
338 responseHandler: function (res) {
339 return res;
340 },
341 pagination: false,
342 onlyInfoPagination: false,
343 paginationLoop: true,
344 sidePagination: 'client', // client or server
345 totalRows: 0, // server side need to set
346 pageNumber: 1,
347 pageSize: 10,
348 pageList: [10, 25, 50, 100],
349 paginationHAlign: 'right', //right, left
350 paginationVAlign: 'bottom', //bottom, top, both
351 paginationDetailHAlign: 'left', //right, left
352 paginationPreText: '‹',
353 paginationNextText: '›',
354 search: false,
355 searchOnEnterKey: false,
356 strictSearch: false,
357 searchAlign: 'right',
358 selectItemName: 'btSelectItem',
359 showHeader: true,
360 showFooter: false,
361 showColumns: false,
362 showPaginationSwitch: false,
363 showRefresh: false,
364 showToggle: false,
365 showFullscreen: false,
366 buttonsAlign: 'right',
367 smartDisplay: true,
368 escape: false,
369 minimumCountColumns: 1,
370 idField: undefined,
371 uniqueId: undefined,
372 cardView: false,
373 detailView: false,
374 detailFormatter: function (index, row) {
375 return '';
376 },
377 detailFilter: function (index, row) {
378 return true;
379 },
380 trimOnSearch: true,
381 clickToSelect: false,
382 singleSelect: false,
383 toolbar: undefined,
384 toolbarAlign: 'left',
385 customToolbar: undefined,
386 checkboxHeader: true,
387 sortable: true,
388 silentSort: true,
389 maintainSelected: false,
390 searchTimeOut: 500,
391 searchText: '',
392 iconSize: undefined,
393 buttonsClass: bs.buttonsClass,
394 iconsPrefix: bs.iconsPrefix, // glyphicon or fa (font awesome)
395 icons: bs.icons,
396
397 customSearch: $.noop,
398
399 customSort: $.noop,
400
401 ignoreClickToSelectOn: function (element) {
402 return $.inArray(element.tagName, ['A', 'BUTTON']);
403 },
404
405 rowStyle: function (row, index) {
406 return {};
407 },
408
409 rowAttributes: function (row, index) {
410 return {};
411 },
412
413 footerStyle: function (row, index) {
414 return {};
415 },
416
417 onAll: function (name, args) {
418 return false;
419 },
420 onClickCell: function (field, value, row, $element) {
421 return false;
422 },
423 onDblClickCell: function (field, value, row, $element) {
424 return false;
425 },
426 onClickRow: function (item, $element) {
427 return false;
428 },
429 onDblClickRow: function (item, $element) {
430 return false;
431 },
432 onSort: function (name, order) {
433 return false;
434 },
435 onCheck: function (row) {
436 return false;
437 },
438 onUncheck: function (row) {
439 return false;
440 },
441 onCheckAll: function (rows) {
442 return false;
443 },
444 onUncheckAll: function (rows) {
445 return false;
446 },
447 onCheckSome: function (rows) {
448 return false;
449 },
450 onUncheckSome: function (rows) {
451 return false;
452 },
453 onLoadSuccess: function (data) {
454 return false;
455 },
456 onLoadError: function (status) {
457 return false;
458 },
459 onColumnSwitch: function (field, checked) {
460 return false;
461 },
462 onPageChange: function (number, size) {
463 return false;
464 },
465 onSearch: function (text) {
466 return false;
467 },
468 onToggle: function (cardView) {
469 return false;
470 },
471 onPreBody: function (data) {
472 return false;
473 },
474 onPostBody: function () {
475 return false;
476 },
477 onPostHeader: function () {
478 return false;
479 },
480 onExpandRow: function (index, row, $detail) {
481 return false;
482 },
483 onCollapseRow: function (index, row) {
484 return false;
485 },
486 onRefreshOptions: function (options) {
487 return false;
488 },
489 onRefresh: function (params) {
490 return false;
491 },
492 onResetView: function () {
493 return false;
494 },
495 onScrollBody: function () {
496 return false;
497 }
498 };
499
500 BootstrapTable.LOCALES = {};
501
502 BootstrapTable.LOCALES['en-US'] = BootstrapTable.LOCALES.en = {
503 formatLoadingMessage: function () {
504 return 'Loading, please wait...';
505 },
506 formatRecordsPerPage: function (pageNumber) {
507 return sprintf('%s rows per page', pageNumber);
508 },
509 formatShowingRows: function (pageFrom, pageTo, totalRows) {
510 return sprintf('Showing %s to %s of %s rows', pageFrom, pageTo, totalRows);
511 },
512 formatDetailPagination: function (totalRows) {
513 return sprintf('Showing %s rows', totalRows);
514 },
515 formatSearch: function () {
516 return 'Search';
517 },
518 formatNoMatches: function () {
519 return 'No matching records found';
520 },
521 formatPaginationSwitch: function () {
522 return 'Hide/Show pagination';
523 },
524 formatRefresh: function () {
525 return 'Refresh';
526 },
527 formatToggle: function () {
528 return 'Toggle';
529 },
530 formatFullscreen: function () {
531 return 'Fullscreen';
532 },
533 formatColumns: function () {
534 return 'Columns';
535 },
536 formatAllRows: function () {
537 return 'All';
538 }
539 };
540
541 $.extend(BootstrapTable.DEFAULTS, BootstrapTable.LOCALES['en-US']);
542
543 BootstrapTable.COLUMN_DEFAULTS = {
544 radio: false,
545 checkbox: false,
546 checkboxEnabled: true,
547 field: undefined,
548 title: undefined,
549 titleTooltip: undefined,
550 'class': undefined,
551 align: undefined, // left, right, center
552 halign: undefined, // left, right, center
553 falign: undefined, // left, right, center
554 valign: undefined, // top, middle, bottom
555 width: undefined,
556 sortable: false,
557 order: 'asc', // asc, desc
558 visible: true,
559 switchable: true,
560 clickToSelect: true,
561 formatter: undefined,
562 footerFormatter: undefined,
563 events: undefined,
564 sorter: undefined,
565 sortName: undefined,
566 cellStyle: undefined,
567 searchable: true,
568 searchFormatter: true,
569 cardVisible: true,
570 escape : false
571 };
572
573 BootstrapTable.EVENTS = {
574 'all.bs.table': 'onAll',
575 'click-cell.bs.table': 'onClickCell',
576 'dbl-click-cell.bs.table': 'onDblClickCell',
577 'click-row.bs.table': 'onClickRow',
578 'dbl-click-row.bs.table': 'onDblClickRow',
579 'sort.bs.table': 'onSort',
580 'check.bs.table': 'onCheck',
581 'uncheck.bs.table': 'onUncheck',
582 'check-all.bs.table': 'onCheckAll',
583 'uncheck-all.bs.table': 'onUncheckAll',
584 'check-some.bs.table': 'onCheckSome',
585 'uncheck-some.bs.table': 'onUncheckSome',
586 'load-success.bs.table': 'onLoadSuccess',
587 'load-error.bs.table': 'onLoadError',
588 'column-switch.bs.table': 'onColumnSwitch',
589 'page-change.bs.table': 'onPageChange',
590 'search.bs.table': 'onSearch',
591 'toggle.bs.table': 'onToggle',
592 'pre-body.bs.table': 'onPreBody',
593 'post-body.bs.table': 'onPostBody',
594 'post-header.bs.table': 'onPostHeader',
595 'expand-row.bs.table': 'onExpandRow',
596 'collapse-row.bs.table': 'onCollapseRow',
597 'refresh-options.bs.table': 'onRefreshOptions',
598 'reset-view.bs.table': 'onResetView',
599 'refresh.bs.table': 'onRefresh',
600 'scroll-body.bs.table': 'onScrollBody'
601 };
602
603 BootstrapTable.prototype.init = function () {
604 this.initLocale();
605 this.initContainer();
606 this.initTable();
607 this.initHeader();
608 this.initData();
609 this.initHiddenRows();
610 this.initFooter();
611 this.initToolbar();
612 this.initPagination();
613 this.initBody();
614 this.initSearchText();
615 this.initServer();
616 };
617
618 BootstrapTable.prototype.initLocale = function () {
619 if (this.options.locale) {
620 var parts = this.options.locale.split(/-|_/);
621 parts[0].toLowerCase();
622 if (parts[1]) {
623 parts[1].toUpperCase();
624 }
625 if ($.fn.bootstrapTable.locales[this.options.locale]) {
626 // locale as requested
627 $.extend(this.options, $.fn.bootstrapTable.locales[this.options.locale]);
628 } else if ($.fn.bootstrapTable.locales[parts.join('-')]) {
629 // locale with sep set to - (in case original was specified with _)
630 $.extend(this.options, $.fn.bootstrapTable.locales[parts.join('-')]);
631 } else if ($.fn.bootstrapTable.locales[parts[0]]) {
632 // short locale language code (i.e. 'en')
633 $.extend(this.options, $.fn.bootstrapTable.locales[parts[0]]);
634 }
635 }
636 };
637
638 BootstrapTable.prototype.initContainer = function () {
639 this.$container = $([
640 '<div class="bootstrap-table">',
641 '<div class="fixed-table-toolbar"></div>',
642 this.options.paginationVAlign === 'top' || this.options.paginationVAlign === 'both' ?
643 '<div class="fixed-table-pagination" style="clear: both;"></div>' :
644 '',
645 '<div class="fixed-table-container">',
646 '<div class="fixed-table-header"><table></table></div>',
647 '<div class="fixed-table-body">',
648 '<div class="fixed-table-loading">',
649 this.options.formatLoadingMessage(),
650 '</div>',
651 '</div>',
652 '<div class="fixed-table-footer"><table><tr></tr></table></div>',
653 this.options.paginationVAlign === 'bottom' || this.options.paginationVAlign === 'both' ?
654 '<div class="fixed-table-pagination"></div>' :
655 '',
656 '</div>',
657 '</div>'
658 ].join(''));
659
660 this.$container.insertAfter(this.$el);
661 this.$tableContainer = this.$container.find('.fixed-table-container');
662 this.$tableHeader = this.$container.find('.fixed-table-header');
663 this.$tableBody = this.$container.find('.fixed-table-body');
664 this.$tableLoading = this.$container.find('.fixed-table-loading');
665 this.$tableFooter = this.$container.find('.fixed-table-footer');
666 // checking if custom table-toolbar exists or not
667 if (this.options.customToolbar) {
668 this.$toolbar = $('body').find(this.options.customToolbar);
669 } else {
670 this.$toolbar = this.$container.find('.fixed-table-toolbar');
671 }
672 this.$pagination = this.$container.find('.fixed-table-pagination');
673
674 this.$tableBody.append(this.$el);
675 this.$container.after('<div class="clearfix"></div>');
676
677 this.$el.addClass(this.options.classes);
678 if (this.options.striped) {
679 this.$el.addClass('table-striped');
680 }
681 if ($.inArray('table-no-bordered', this.options.classes.split(' ')) !== -1) {
682 this.$tableContainer.addClass('table-no-bordered');
683 }
684 };
685
686 BootstrapTable.prototype.initTable = function () {
687 var that = this,
688 columns = [],
689 data = [];
690
691 this.$header = this.$el.find('>thead');
692 if (!this.$header.length) {
693 this.$header = $('<thead></thead>').appendTo(this.$el);
694 }
695 this.$header.find('tr').each(function () {
696 var column = [];
697
698 $(this).find('th').each(function () {
699 // Fix #2014 - getFieldIndex and elsewhere assume this is string, causes issues if not
700 if (typeof $(this).data('field') !== 'undefined') {
701 $(this).data('field', $(this).data('field') + '');
702 }
703 column.push($.extend({}, {
704 title: $(this).html(),
705 'class': $(this).attr('class'),
706 titleTooltip: $(this).attr('title'),
707 rowspan: $(this).attr('rowspan') ? +$(this).attr('rowspan') : undefined,
708 colspan: $(this).attr('colspan') ? +$(this).attr('colspan') : undefined
709 }, $(this).data()));
710 });
711 columns.push(column);
712 });
713 if (!$.isArray(this.options.columns[0])) {
714 this.options.columns = [this.options.columns];
715 }
716 this.options.columns = $.extend(true, [], columns, this.options.columns);
717 this.columns = [];
718 this.fieldsColumnsIndex = [];
719
720 setFieldIndex(this.options.columns);
721 $.each(this.options.columns, function (i, columns) {
722 $.each(columns, function (j, column) {
723 column = $.extend({}, BootstrapTable.COLUMN_DEFAULTS, column);
724
725 if (typeof column.fieldIndex !== 'undefined') {
726 that.columns[column.fieldIndex] = column;
727 that.fieldsColumnsIndex[column.field] = column.fieldIndex;
728 }
729
730 that.options.columns[i][j] = column;
731 });
732 });
733
734 // if options.data is setting, do not process tbody data
735 if (this.options.data.length) {
736 return;
737 }
738
739 var m = [];
740 this.$el.find('>tbody>tr').each(function (y) {
741 var row = {};
742
743 // save tr's id, class and data-* attributes
744 row._id = $(this).attr('id');
745 row._class = $(this).attr('class');
746 row._data = getRealDataAttr($(this).data());
747
748 $(this).find('>td').each(function (x) {
749 var $this = $(this),
750 cspan = +$this.attr('colspan') || 1,
751 rspan = +$this.attr('rowspan') || 1,
752 tx,
753 ty;
754
755 // skip already occupied cells in current row
756 for (; m[y] && m[y][x]; x++);
757
758 for (tx = x; tx < x + cspan; tx++) { //mark matrix elements occupied by current cell with true
759 for (ty = y; ty < y + rspan; ty++) {
760 if (!m[ty]) { //fill missing rows
761 m[ty] = [];
762 }
763 m[ty][tx] = true;
764 }
765 }
766
767 var field = that.columns[x].field;
768
769 row[field] = $(this).html();
770 // save td's id, class and data-* attributes
771 row['_' + field + '_id'] = $(this).attr('id');
772 row['_' + field + '_class'] = $(this).attr('class');
773 row['_' + field + '_rowspan'] = $(this).attr('rowspan');
774 row['_' + field + '_colspan'] = $(this).attr('colspan');
775 row['_' + field + '_title'] = $(this).attr('title');
776 row['_' + field + '_data'] = getRealDataAttr($(this).data());
777 });
778 data.push(row);
779 });
780 this.options.data = data;
781 if (data.length) this.fromHtml = true;
782 };
783
784 BootstrapTable.prototype.initHeader = function () {
785 var that = this,
786 visibleColumns = {},
787 html = [];
788
789 this.header = {
790 fields: [],
791 styles: [],
792 classes: [],
793 formatters: [],
794 events: [],
795 sorters: [],
796 sortNames: [],
797 cellStyles: [],
798 searchables: []
799 };
800
801 $.each(this.options.columns, function (i, columns) {
802 html.push('<tr>');
803
804 if (i === 0 && !that.options.cardView && that.options.detailView) {
805 html.push(sprintf('<th class="detail" rowspan="%s"><div class="fht-cell"></div></th>',
806 that.options.columns.length));
807 }
808
809 $.each(columns, function (j, column) {
810 var text = '',
811 halign = '', // header align style
812 align = '', // body align style
813 style = '',
814 class_ = sprintf(' class="%s"', column['class']),
815 order = that.options.sortOrder || column.order,
816 unitWidth = 'px',
817 width = column.width;
818
819 if (column.width !== undefined && (!that.options.cardView)) {
820 if (typeof column.width === 'string') {
821 if (column.width.indexOf('%') !== -1) {
822 unitWidth = '%';
823 }
824 }
825 }
826 if (column.width && typeof column.width === 'string') {
827 width = column.width.replace('%', '').replace('px', '');
828 }
829
830 halign = sprintf('text-align: %s; ', column.halign ? column.halign : column.align);
831 align = sprintf('text-align: %s; ', column.align);
832 style = sprintf('vertical-align: %s; ', column.valign);
833 style += sprintf('width: %s; ', (column.checkbox || column.radio) && !width ?
834 '36px' : (width ? width + unitWidth : undefined));
835
836 if (typeof column.fieldIndex !== 'undefined') {
837 that.header.fields[column.fieldIndex] = column.field;
838 that.header.styles[column.fieldIndex] = align + style;
839 that.header.classes[column.fieldIndex] = class_;
840 that.header.formatters[column.fieldIndex] = column.formatter;
841 that.header.events[column.fieldIndex] = column.events;
842 that.header.sorters[column.fieldIndex] = column.sorter;
843 that.header.sortNames[column.fieldIndex] = column.sortName;
844 that.header.cellStyles[column.fieldIndex] = column.cellStyle;
845 that.header.searchables[column.fieldIndex] = column.searchable;
846
847 if (!column.visible) {
848 return;
849 }
850
851 if (that.options.cardView && (!column.cardVisible)) {
852 return;
853 }
854
855 visibleColumns[column.field] = column;
856 }
857
858 html.push('<th' + sprintf(' title="%s"', column.titleTooltip),
859 column.checkbox || column.radio ?
860 sprintf(' class="bs-checkbox %s"', column['class'] || '') :
861 class_,
862 sprintf(' style="%s"', halign + style),
863 sprintf(' rowspan="%s"', column.rowspan),
864 sprintf(' colspan="%s"', column.colspan),
865 sprintf(' data-field="%s"', column.field),
866 j === 0 && column.fieldIndex ? ' data-not-first-th' : '',
867 '>');
868
869 html.push(sprintf('<div class="th-inner %s">', that.options.sortable && column.sortable ?
870 'sortable both' : ''));
871
872 text = that.options.escape ? escapeHTML(column.title) : column.title;
873
874 if (column.checkbox) {
875 if (!that.options.singleSelect && that.options.checkboxHeader) {
876 text = '<input name="btSelectAll" type="checkbox" />';
877 }
878 that.header.stateField = column.field;
879 }
880 if (column.radio) {
881 text = '';
882 that.header.stateField = column.field;
883 that.options.singleSelect = true;
884 }
885
886 html.push(text);
887 html.push('</div>');
888 html.push('<div class="fht-cell"></div>');
889 html.push('</div>');
890 html.push('</th>');
891 });
892 html.push('</tr>');
893 });
894
895 this.$header.html(html.join(''));
896 this.$header.find('th[data-field]').each(function (i) {
897 $(this).data(visibleColumns[$(this).data('field')]);
898 });
899 this.$container.off('click', '.th-inner').on('click', '.th-inner', function (event) {
900 var $this = $(this);
901
902 if (that.options.detailView && !$this.parent().hasClass('bs-checkbox')) {
903 if ($this.closest('.bootstrap-table')[0] !== that.$container[0]) {
904 return false;
905 }
906 }
907
908 if (that.options.sortable && $this.parent().data().sortable) {
909 that.onSort(event);
910 }
911 });
912
913 this.$header.children().children().off('keypress').on('keypress', function (event) {
914 if (that.options.sortable && $(this).data().sortable) {
915 var code = event.keyCode || event.which;
916 if (code == 13) { //Enter keycode
917 that.onSort(event);
918 }
919 }
920 });
921
922 $(window).off('resize.bootstrap-table');
923 if (!this.options.showHeader || this.options.cardView) {
924 this.$header.hide();
925 this.$tableHeader.hide();
926 this.$tableLoading.css('top', 0);
927 } else {
928 this.$header.show();
929 this.$tableHeader.show();
930 this.$tableLoading.css('top', this.$header.outerHeight() + 1);
931 // Assign the correct sortable arrow
932 this.getCaret();
933 $(window).on('resize.bootstrap-table', $.proxy(this.resetWidth, this));
934 }
935
936 this.$selectAll = this.$header.find('[name="btSelectAll"]');
937 this.$selectAll.off('click').on('click', function () {
938 var checked = $(this).prop('checked');
939 that[checked ? 'checkAll' : 'uncheckAll']();
940 that.updateSelected();
941 });
942 };
943
944 BootstrapTable.prototype.initFooter = function () {
945 if (!this.options.showFooter || this.options.cardView) {
946 this.$tableFooter.hide();
947 } else {
948 this.$tableFooter.show();
949 }
950 };
951
952 /**
953 * @param data
954 * @param type: append / prepend
955 */
956 BootstrapTable.prototype.initData = function (data, type) {
957 if (type === 'append') {
958 this.options.data = this.options.data.concat(data);
959 } else if (type === 'prepend') {
960 this.options.data = [].concat(data).concat(this.options.data);
961 } else {
962 this.options.data = data || this.options.data;
963 }
964
965 this.data = this.options.data;
966
967 if (this.options.sidePagination === 'server') {
968 return;
969 }
970 this.initSort();
971 };
972
973 BootstrapTable.prototype.initSort = function () {
974 var that = this,
975 name = this.options.sortName,
976 order = this.options.sortOrder === 'desc' ? -1 : 1,
977 index = $.inArray(this.options.sortName, this.header.fields),
978 timeoutId = 0;
979
980 if (this.options.customSort !== $.noop) {
981 this.options.customSort.apply(this, [this.options.sortName, this.options.sortOrder]);
982 return;
983 }
984
985 if (index !== -1) {
986 if (this.options.sortStable) {
987 $.each(this.data, function (i, row) {
988 row._position = i;
989 });
990 }
991
992 this.data.sort(function (a, b) {
993 if (that.header.sortNames[index]) {
994 name = that.header.sortNames[index];
995 }
996 var aa = getItemField(a, name, that.options.escape),
997 bb = getItemField(b, name, that.options.escape),
998 value = calculateObjectValue(that.header, that.header.sorters[index], [aa, bb, a, b]);
999
1000 if (value !== undefined) {
1001 if (that.options.sortStable && value === 0) {
1002 return a._position - b._position;
1003 }
1004 return order * value;
1005 }
1006
1007 // Fix #161: undefined or null string sort bug.
1008 if (aa === undefined || aa === null) {
1009 aa = '';
1010 }
1011 if (bb === undefined || bb === null) {
1012 bb = '';
1013 }
1014
1015 if (that.options.sortStable && aa === bb) {
1016 aa = a._position;
1017 bb = b._position;
1018 return a._position - b._position;
1019 }
1020
1021 // IF both values are numeric, do a numeric comparison
1022 if ($.isNumeric(aa) && $.isNumeric(bb)) {
1023 // Convert numerical values form string to float.
1024 aa = parseFloat(aa);
1025 bb = parseFloat(bb);
1026 if (aa < bb) {
1027 return order * -1;
1028 }
1029 return order;
1030 }
1031
1032 if (aa === bb) {
1033 return 0;
1034 }
1035
1036 // If value is not a string, convert to string
1037 if (typeof aa !== 'string') {
1038 aa = aa.toString();
1039 }
1040
1041 if (aa.localeCompare(bb) === -1) {
1042 return order * -1;
1043 }
1044
1045 return order;
1046 });
1047
1048 if (this.options.sortClass !== undefined) {
1049 clearTimeout(timeoutId);
1050 timeoutId = setTimeout(function () {
1051 that.$el.removeClass(that.options.sortClass);
1052 var index = that.$header.find(sprintf('[data-field="%s"]',
1053 that.options.sortName).index() + 1);
1054 that.$el.find(sprintf('tr td:nth-child(%s)', index))
1055 .addClass(that.options.sortClass);
1056 }, 250);
1057 }
1058 }
1059 };
1060
1061 BootstrapTable.prototype.onSort = function (event) {
1062 var $this = event.type === "keypress" ? $(event.currentTarget) : $(event.currentTarget).parent(),
1063 $this_ = this.$header.find('th').eq($this.index());
1064
1065 this.$header.add(this.$header_).find('span.order').remove();
1066
1067 if (this.options.sortName === $this.data('field')) {
1068 this.options.sortOrder = this.options.sortOrder === 'asc' ? 'desc' : 'asc';
1069 } else {
1070 this.options.sortName = $this.data('field');
1071 if (this.options.rememberOrder) {
1072 this.options.sortOrder = $this.data('order') === 'asc' ? 'desc' : 'asc';
1073 } else {
1074 this.options.sortOrder = this.options.columns[0].filter(function(option) {
1075 return option.field === $this.data('field');
1076 })[0].order;
1077 }
1078 }
1079 this.trigger('sort', this.options.sortName, this.options.sortOrder);
1080
1081 $this.add($this_).data('order', this.options.sortOrder);
1082
1083 // Assign the correct sortable arrow
1084 this.getCaret();
1085
1086 if (this.options.sidePagination === 'server') {
1087 this.initServer(this.options.silentSort);
1088 return;
1089 }
1090
1091 this.initSort();
1092 this.initBody();
1093 };
1094
1095 BootstrapTable.prototype.initToolbar = function () {
1096 var that = this,
1097 html = [],
1098 timeoutId = 0,
1099 $keepOpen,
1100 $search,
1101 switchableCount = 0;
1102
1103 if (this.$toolbar.find('.bs-bars').children().length) {
1104 $('body').append($(this.options.toolbar));
1105 }
1106 this.$toolbar.html('');
1107
1108 if (typeof this.options.toolbar === 'string' || typeof this.options.toolbar === 'object') {
1109 $(sprintf('<div class="bs-bars %s-%s"></div>', bs.pullClass, this.options.toolbarAlign))
1110 .appendTo(this.$toolbar)
1111 .append($(this.options.toolbar));
1112 }
1113
1114 // showColumns, showToggle, showRefresh
1115 html = [sprintf('<div class="columns columns-%s btn-group %s-%s">',
1116 this.options.buttonsAlign, bs.pullClass, this.options.buttonsAlign)];
1117
1118 if (typeof this.options.icons === 'string') {
1119 this.options.icons = calculateObjectValue(null, this.options.icons);
1120 }
1121
1122 if (this.options.showPaginationSwitch) {
1123 html.push(sprintf('<button class="btn' +
1124 sprintf(' btn-%s', this.options.buttonsClass) +
1125 sprintf(' btn-%s', this.options.iconSize) +
1126 '" type="button" name="paginationSwitch" aria-label="pagination Switch" title="%s">',
1127 this.options.formatPaginationSwitch()),
1128 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.paginationSwitchDown),
1129 '</button>');
1130 }
1131
1132 if (this.options.showFullscreen) {
1133 this.$toolbar.find('button[name="fullscreen"]')
1134 .off('click').on('click', $.proxy(this.toggleFullscreen, this));
1135 }
1136
1137 if (this.options.showRefresh) {
1138 html.push(sprintf('<button class="btn' +
1139 sprintf(' btn-%s', this.options.buttonsClass) +
1140 sprintf(' btn-%s', this.options.iconSize) +
1141 '" type="button" name="refresh" aria-label="refresh" title="%s">',
1142 this.options.formatRefresh()),
1143 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.refresh),
1144 '</button>');
1145 }
1146
1147 if (this.options.showToggle) {
1148 html.push(sprintf('<button class="btn' +
1149 sprintf(' btn-%s', this.options.buttonsClass) +
1150 sprintf(' btn-%s', this.options.iconSize) +
1151 '" type="button" name="toggle" aria-label="toggle" title="%s">',
1152 this.options.formatToggle()),
1153 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.toggle),
1154 '</button>');
1155 }
1156
1157 if (this.options.showFullscreen) {
1158 html.push(sprintf('<button class="btn' +
1159 sprintf(' btn-%s', this.options.buttonsClass) +
1160 sprintf(' btn-%s', this.options.iconSize) +
1161 '" type="button" name="fullscreen" aria-label="fullscreen" title="%s">',
1162 this.options.formatFullscreen()),
1163 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.fullscreen),
1164 '</button>');
1165 }
1166
1167 if (this.options.showColumns) {
1168 html.push(sprintf('<div class="keep-open btn-group" title="%s">',
1169 this.options.formatColumns()),
1170 '<button type="button" aria-label="columns" class="btn' +
1171 sprintf(' btn-%s', this.options.buttonsClass) +
1172 sprintf(' btn-%s', this.options.iconSize) +
1173 ' dropdown-toggle" data-toggle="dropdown">',
1174 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.columns),
1175 ' <span class="caret"></span>',
1176 '</button>',
1177 bs.toobarDropdowHtml[0]);
1178
1179 $.each(this.columns, function (i, column) {
1180 if (column.radio || column.checkbox) {
1181 return;
1182 }
1183
1184 if (that.options.cardView && !column.cardVisible) {
1185 return;
1186 }
1187
1188 var checked = column.visible ? ' checked="checked"' : '';
1189
1190 if (column.switchable) {
1191 html.push(sprintf(bs.toobarDropdowItemHtml,
1192 sprintf('<input type="checkbox" data-field="%s" value="%s"%s> %s',
1193 column.field, i, checked, column.title)));
1194 switchableCount++;
1195 }
1196 });
1197 html.push(bs.toobarDropdowHtml[1], '</div>');
1198 }
1199
1200 html.push('</div>');
1201
1202 // Fix #188: this.showToolbar is for extensions
1203 if (this.showToolbar || html.length > 2) {
1204 this.$toolbar.append(html.join(''));
1205 }
1206
1207 if (this.options.showPaginationSwitch) {
1208 this.$toolbar.find('button[name="paginationSwitch"]')
1209 .off('click').on('click', $.proxy(this.togglePagination, this));
1210 }
1211
1212 if (this.options.showRefresh) {
1213 this.$toolbar.find('button[name="refresh"]')
1214 .off('click').on('click', $.proxy(this.refresh, this));
1215 }
1216
1217 if (this.options.showToggle) {
1218 this.$toolbar.find('button[name="toggle"]')
1219 .off('click').on('click', function () {
1220 that.toggleView();
1221 });
1222 }
1223
1224 if (this.options.showColumns) {
1225 $keepOpen = this.$toolbar.find('.keep-open');
1226
1227 if (switchableCount <= this.options.minimumCountColumns) {
1228 $keepOpen.find('input').prop('disabled', true);
1229 }
1230
1231 $keepOpen.find('li').off('click').on('click', function (event) {
1232 event.stopImmediatePropagation();
1233 });
1234 $keepOpen.find('input').off('click').on('click', function () {
1235 var $this = $(this);
1236
1237 that.toggleColumn($(this).val(), $this.prop('checked'), false);
1238 that.trigger('column-switch', $(this).data('field'), $this.prop('checked'));
1239 });
1240 }
1241
1242 if (this.options.search) {
1243 html = [];
1244 html.push(
1245 sprintf('<div class="%s-%s search">', bs.pullClass, this.options.searchAlign),
1246 sprintf('<input class="form-control' +
1247 sprintf(' input-%s', this.options.iconSize) +
1248 '" type="text" placeholder="%s">',
1249 this.options.formatSearch()),
1250 '</div>');
1251
1252 this.$toolbar.append(html.join(''));
1253 $search = this.$toolbar.find('.search input');
1254 $search.off('keyup drop blur').on('keyup drop blur', function (event) {
1255 if (that.options.searchOnEnterKey && event.keyCode !== 13) {
1256 return;
1257 }
1258
1259 if ($.inArray(event.keyCode, [37, 38, 39, 40]) > -1) {
1260 return;
1261 }
1262
1263 clearTimeout(timeoutId); // doesn't matter if it's 0
1264 timeoutId = setTimeout(function () {
1265 that.onSearch(event);
1266 }, that.options.searchTimeOut);
1267 });
1268
1269 if (isIEBrowser()) {
1270 $search.off('mouseup').on('mouseup', function (event) {
1271 clearTimeout(timeoutId); // doesn't matter if it's 0
1272 timeoutId = setTimeout(function () {
1273 that.onSearch(event);
1274 }, that.options.searchTimeOut);
1275 });
1276 }
1277 }
1278 };
1279
1280 BootstrapTable.prototype.onSearch = function (event) {
1281 var text = $.trim($(event.currentTarget).val());
1282
1283 // trim search input
1284 if (this.options.trimOnSearch && $(event.currentTarget).val() !== text) {
1285 $(event.currentTarget).val(text);
1286 }
1287
1288 if (text === this.searchText) {
1289 return;
1290 }
1291 this.searchText = text;
1292 this.options.searchText = text;
1293
1294 this.options.pageNumber = 1;
1295 this.initSearch();
1296 if (event.firedByInitSearchText) {
1297 if (this.options.sidePagination === 'client') {
1298 this.updatePagination();
1299 }
1300 } else {
1301 this.updatePagination();
1302 }
1303 this.trigger('search', text);
1304 };
1305
1306 BootstrapTable.prototype.initSearch = function () {
1307 var that = this;
1308
1309 if (this.options.sidePagination !== 'server') {
1310 if (this.options.customSearch !== $.noop) {
1311 window[this.options.customSearch].apply(this, [this.searchText]);
1312 return;
1313 }
1314
1315 var s = this.searchText && (this.options.escape ?
1316 escapeHTML(this.searchText) : this.searchText).toLowerCase();
1317 var f = $.isEmptyObject(this.filterColumns) ? null : this.filterColumns;
1318
1319 // Check filter
1320 this.data = f ? $.grep(this.options.data, function (item, i) {
1321 for (var key in f) {
1322 if ($.isArray(f[key]) && $.inArray(item[key], f[key]) === -1 ||
1323 !$.isArray(f[key]) && item[key] !== f[key]) {
1324 return false;
1325 }
1326 }
1327 return true;
1328 }) : this.options.data;
1329
1330 this.data = s ? $.grep(this.data, function (item, i) {
1331 for (var j = 0; j < that.header.fields.length; j++) {
1332
1333 if (!that.header.searchables[j]) {
1334 continue;
1335 }
1336
1337 var key = $.isNumeric(that.header.fields[j]) ? parseInt(that.header.fields[j], 10) : that.header.fields[j];
1338 var column = that.columns[that.fieldsColumnsIndex[key]];
1339 var value;
1340
1341 if (typeof key === 'string') {
1342 value = item;
1343 var props = key.split('.');
1344 for (var prop_index = 0; prop_index < props.length; prop_index++) {
1345 value = value[props[prop_index]];
1346 }
1347
1348 // Fix #142: respect searchForamtter boolean
1349 if (column && column.searchFormatter) {
1350 value = calculateObjectValue(column,
1351 that.header.formatters[j], [value, item, i], value);
1352 }
1353 } else {
1354 value = item[key];
1355 }
1356
1357 if (typeof value === 'string' || typeof value === 'number') {
1358 if (that.options.strictSearch) {
1359 if ((value + '').toLowerCase() === s) {
1360 return true;
1361 }
1362 } else {
1363 if ((value + '').toLowerCase().indexOf(s) !== -1) {
1364 return true;
1365 }
1366 }
1367 }
1368 }
1369 return false;
1370 }) : this.data;
1371 }
1372 };
1373
1374 BootstrapTable.prototype.initPagination = function () {
1375 if (!this.options.pagination) {
1376 this.$pagination.hide();
1377 return;
1378 } else {
1379 this.$pagination.show();
1380 }
1381
1382 var that = this,
1383 html = [],
1384 $allSelected = false,
1385 i, from, to,
1386 $pageList,
1387 $pre,
1388 $next,
1389 $number,
1390 data = this.getData(),
1391 pageList = this.options.pageList;
1392
1393 if (this.options.sidePagination !== 'server') {
1394 this.options.totalRows = data.length;
1395 }
1396
1397 this.totalPages = 0;
1398 if (this.options.totalRows) {
1399 if (this.options.pageSize === this.options.formatAllRows()) {
1400 this.options.pageSize = this.options.totalRows;
1401 $allSelected = true;
1402 } else if (this.options.pageSize === this.options.totalRows) {
1403 // Fix #667 Table with pagination,
1404 // multiple pages and a search that matches to one page throws exception
1405 var pageLst = typeof this.options.pageList === 'string' ?
1406 this.options.pageList.replace('[', '').replace(']', '')
1407 .replace(/ /g, '').toLowerCase().split(',') : this.options.pageList;
1408 if ($.inArray(this.options.formatAllRows().toLowerCase(), pageLst) > -1) {
1409 $allSelected = true;
1410 }
1411 }
1412
1413 this.totalPages = ~~((this.options.totalRows - 1) / this.options.pageSize) + 1;
1414
1415 this.options.totalPages = this.totalPages;
1416 }
1417 if (this.totalPages > 0 && this.options.pageNumber > this.totalPages) {
1418 this.options.pageNumber = this.totalPages;
1419 }
1420
1421 this.pageFrom = (this.options.pageNumber - 1) * this.options.pageSize + 1;
1422 this.pageTo = this.options.pageNumber * this.options.pageSize;
1423 if (this.pageTo > this.options.totalRows) {
1424 this.pageTo = this.options.totalRows;
1425 }
1426
1427 html.push(
1428 sprintf('<div class="%s-%s pagination-detail">', bs.pullClass, this.options.paginationDetailHAlign),
1429 '<span class="pagination-info">',
1430 this.options.onlyInfoPagination ? this.options.formatDetailPagination(this.options.totalRows) :
1431 this.options.formatShowingRows(this.pageFrom, this.pageTo, this.options.totalRows),
1432 '</span>');
1433
1434 if (!this.options.onlyInfoPagination) {
1435 html.push('<span class="page-list">');
1436
1437 var pageNumber = [
1438 sprintf('<span class="btn-group %s">',
1439 this.options.paginationVAlign === 'top' || this.options.paginationVAlign === 'both' ?
1440 'dropdown' : 'dropup'),
1441 '<button type="button" class="btn' +
1442 sprintf(' btn-%s', this.options.buttonsClass) +
1443 sprintf(' btn-%s', this.options.iconSize) +
1444 ' dropdown-toggle" data-toggle="dropdown">',
1445 '<span class="page-size">',
1446 $allSelected ? this.options.formatAllRows() : this.options.pageSize,
1447 '</span>',
1448 ' <span class="caret"></span>',
1449 '</button>',
1450 bs.pageDropdownHtml[0]
1451 ];
1452
1453 if (typeof this.options.pageList === 'string') {
1454 var list = this.options.pageList.replace('[', '').replace(']', '')
1455 .replace(/ /g, '').split(',');
1456
1457 pageList = [];
1458 $.each(list, function (i, value) {
1459 pageList.push((value.toUpperCase() === that.options.formatAllRows().toUpperCase() || value.toUpperCase() === "UNLIMITED") ?
1460 that.options.formatAllRows() : +value);
1461 });
1462 }
1463
1464 $.each(pageList, function (i, page) {
1465 if (!that.options.smartDisplay || i === 0 || pageList[i - 1] < that.options.totalRows) {
1466 var active;
1467 if ($allSelected) {
1468 active = page === that.options.formatAllRows() ? 'active' : '';
1469 } else {
1470 active = page === that.options.pageSize ? 'active' : '';
1471 }
1472 pageNumber.push(sprintf(bs.pageDropdownItemHtml, active, page));
1473 }
1474 });
1475 pageNumber.push(bs.pageDropdownHtml[1] + '</span>');
1476
1477 html.push(this.options.formatRecordsPerPage(pageNumber.join('')));
1478 html.push('</span>');
1479
1480 html.push('</div>',
1481 sprintf('<div class="%s-%s pagination">', bs.pullClass, this.options.paginationHAlign),
1482 '<ul class="pagination' + sprintf(' pagination-%s', this.options.iconSize) + '">',
1483 sprintf('<li class="page-item page-pre"><a class="page-link" href="#">%s</a></li>',
1484 this.options.paginationPreText));
1485
1486 if (this.totalPages < 5) {
1487 from = 1;
1488 to = this.totalPages;
1489 } else {
1490 from = this.options.pageNumber - 2;
1491 to = from + 4;
1492 if (from < 1) {
1493 from = 1;
1494 to = 5;
1495 }
1496 if (to > this.totalPages) {
1497 to = this.totalPages;
1498 from = to - 4;
1499 }
1500 }
1501
1502 if (this.totalPages >= 6) {
1503 if (this.options.pageNumber >= 3) {
1504 html.push(
1505 sprintf('<li class="page-item page-first%s">',
1506 1 === this.options.pageNumber ? ' active' : ''),
1507 '<a class="page-link" href="#">', 1, '</a>',
1508 '</li>');
1509
1510 from++;
1511 }
1512
1513 if (this.options.pageNumber >= 4) {
1514 if (this.options.pageNumber == 4 || this.totalPages == 6 || this.totalPages == 7) {
1515 from--;
1516 } else {
1517 html.push('<li class="page-item page-first-separator disabled">',
1518 '<a class="page-link" href="#">...</a>',
1519 '</li>');
1520 }
1521
1522 to--;
1523 }
1524 }
1525
1526 if (this.totalPages >= 7) {
1527 if (this.options.pageNumber >= (this.totalPages - 2)) {
1528 from--;
1529 }
1530 }
1531
1532 if (this.totalPages == 6) {
1533 if (this.options.pageNumber >= (this.totalPages - 2)) {
1534 to++;
1535 }
1536 } else if (this.totalPages >= 7) {
1537 if (this.totalPages == 7 || this.options.pageNumber >= (this.totalPages - 3)) {
1538 to++;
1539 }
1540 }
1541
1542 for (i = from; i <= to; i++) {
1543 html.push(sprintf('<li class="page-item%s">',
1544 i === this.options.pageNumber ? ' active' : ''),
1545 '<a class="page-link" href="#">', i, '</a>',
1546 '</li>');
1547 }
1548
1549 if (this.totalPages >= 8) {
1550 if (this.options.pageNumber <= (this.totalPages - 4)) {
1551 html.push('<li class="page-item page-last-separator disabled">',
1552 '<a class="page-link" href="#">...</a>',
1553 '</li>');
1554 }
1555 }
1556
1557 if (this.totalPages >= 6) {
1558 if (this.options.pageNumber <= (this.totalPages - 3)) {
1559 html.push(sprintf('<li class="page-item page-last%s">',
1560 this.totalPages === this.options.pageNumber ? ' active' : ''),
1561 '<a class="page-link" href="#">', this.totalPages, '</a>',
1562 '</li>');
1563 }
1564 }
1565
1566 html.push(
1567 sprintf('<li class="page-item page-next"><a class="page-link" href="#">%s</a></li>',
1568 this.options.paginationNextText),
1569 '</ul>',
1570 '</div>');
1571 }
1572 this.$pagination.html(html.join(''));
1573
1574 if (!this.options.onlyInfoPagination) {
1575 $pageList = this.$pagination.find('.page-list a');
1576 $pre = this.$pagination.find('.page-pre');
1577 $next = this.$pagination.find('.page-next');
1578 $number = this.$pagination.find('.page-item').not('.page-next, .page-pre');
1579
1580 if (this.options.smartDisplay) {
1581 if (this.totalPages <= 1) {
1582 this.$pagination.find('div.pagination').hide();
1583 }
1584 if (pageList.length < 2 || this.options.totalRows <= pageList[0]) {
1585 this.$pagination.find('span.page-list').hide();
1586 }
1587
1588 // when data is empty, hide the pagination
1589 this.$pagination[this.getData().length ? 'show' : 'hide']();
1590 }
1591
1592 if (!this.options.paginationLoop) {
1593 if (this.options.pageNumber === 1) {
1594 $pre.addClass('disabled');
1595 }
1596 if (this.options.pageNumber === this.totalPages) {
1597 $next.addClass('disabled');
1598 }
1599 }
1600
1601 if ($allSelected) {
1602 this.options.pageSize = this.options.formatAllRows();
1603 }
1604 // removed the events for last and first, onPageNumber executeds the same logic
1605 $pageList.off('click').on('click', $.proxy(this.onPageListChange, this));
1606 $pre.off('click').on('click', $.proxy(this.onPagePre, this));
1607 $next.off('click').on('click', $.proxy(this.onPageNext, this));
1608 $number.off('click').on('click', $.proxy(this.onPageNumber, this));
1609 }
1610 };
1611
1612 BootstrapTable.prototype.updatePagination = function (event) {
1613 // Fix #171: IE disabled button can be clicked bug.
1614 if (event && $(event.currentTarget).hasClass('disabled')) {
1615 return;
1616 }
1617
1618 if (!this.options.maintainSelected) {
1619 this.resetRows();
1620 }
1621
1622 this.initPagination();
1623 if (this.options.sidePagination === 'server') {
1624 this.initServer();
1625 } else {
1626 this.initBody();
1627 }
1628
1629 this.trigger('page-change', this.options.pageNumber, this.options.pageSize);
1630 };
1631
1632 BootstrapTable.prototype.onPageListChange = function (event) {
1633 event.preventDefault();
1634 var $this = $(event.currentTarget);
1635
1636 $this.parent().addClass('active').siblings().removeClass('active');
1637 this.options.pageSize = $this.text().toUpperCase() === this.options.formatAllRows().toUpperCase() ?
1638 this.options.formatAllRows() : +$this.text();
1639 this.$toolbar.find('.page-size').text(this.options.pageSize);
1640
1641 this.updatePagination(event);
1642 return false;
1643 };
1644
1645 BootstrapTable.prototype.onPagePre = function (event) {
1646 event.preventDefault();
1647 if ((this.options.pageNumber - 1) === 0) {
1648 this.options.pageNumber = this.options.totalPages;
1649 } else {
1650 this.options.pageNumber--;
1651 }
1652 this.updatePagination(event);
1653 return false;
1654 };
1655
1656 BootstrapTable.prototype.onPageNext = function (event) {
1657 event.preventDefault();
1658 if ((this.options.pageNumber + 1) > this.options.totalPages) {
1659 this.options.pageNumber = 1;
1660 } else {
1661 this.options.pageNumber++;
1662 }
1663 this.updatePagination(event);
1664 return false;
1665 };
1666
1667 BootstrapTable.prototype.onPageNumber = function (event) {
1668 event.preventDefault();
1669 if (this.options.pageNumber === +$(event.currentTarget).text()) {
1670 return;
1671 }
1672 this.options.pageNumber = +$(event.currentTarget).text();
1673 this.updatePagination(event);
1674 return false;
1675 };
1676
1677 BootstrapTable.prototype.initRow = function(item, i, data, parentDom) {
1678 var that=this,
1679 key,
1680 html = [],
1681 style = {},
1682 csses = [],
1683 data_ = '',
1684 attributes = {},
1685 htmlAttributes = [];
1686
1687 if ($.inArray(item, this.hiddenRows) > -1) {
1688 return;
1689 }
1690
1691 style = calculateObjectValue(this.options, this.options.rowStyle, [item, i], style);
1692
1693 if (style && style.css) {
1694 for (key in style.css) {
1695 csses.push(key + ': ' + style.css[key]);
1696 }
1697 }
1698
1699 attributes = calculateObjectValue(this.options,
1700 this.options.rowAttributes, [item, i], attributes);
1701
1702 if (attributes) {
1703 for (key in attributes) {
1704 htmlAttributes.push(sprintf('%s="%s"', key, escapeHTML(attributes[key])));
1705 }
1706 }
1707
1708 if (item._data && !$.isEmptyObject(item._data)) {
1709 $.each(item._data, function(k, v) {
1710 // ignore data-index
1711 if (k === 'index') {
1712 return;
1713 }
1714 data_ += sprintf(' data-%s="%s"', k, v);
1715 });
1716 }
1717
1718 html.push('<tr',
1719 sprintf(' %s', htmlAttributes.join(' ')),
1720 sprintf(' id="%s"', $.isArray(item) ? undefined : item._id),
1721 sprintf(' class="%s"', style.classes || ($.isArray(item) ? undefined : item._class)),
1722 sprintf(' data-index="%s"', i),
1723 sprintf(' data-uniqueid="%s"', item[this.options.uniqueId]),
1724 sprintf('%s', data_),
1725 '>'
1726 );
1727
1728 if (this.options.cardView) {
1729 html.push(sprintf('<td colspan="%s"><div class="card-views">', this.header.fields.length));
1730 }
1731
1732 if (!this.options.cardView && this.options.detailView) {
1733 html.push('<td>');
1734
1735 if (calculateObjectValue(null, this.options.detailFilter, [i, item])) {
1736 html.push('<a class="detail-icon" href="#">',
1737 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.detailOpen),
1738 '</a>');
1739 }
1740
1741 html.push('</td>');
1742 }
1743
1744 $.each(this.header.fields, function(j, field) {
1745 var text = '',
1746 value_ = getItemField(item, field, that.options.escape),
1747 value = '',
1748 type = '',
1749 cellStyle = {},
1750 id_ = '',
1751 class_ = that.header.classes[j],
1752 data_ = '',
1753 rowspan_ = '',
1754 colspan_ = '',
1755 title_ = '',
1756 column = that.columns[j];
1757
1758 if (that.fromHtml && typeof value_ === 'undefined') {
1759 if((!column.checkbox) && (!column.radio)) {
1760 return;
1761 }
1762 }
1763
1764 if (!column.visible) {
1765 return;
1766 }
1767
1768 if (that.options.cardView && (!column.cardVisible)) {
1769 return;
1770 }
1771
1772 if (column.escape) {
1773 value_ = escapeHTML(value_);
1774 }
1775
1776 style = sprintf('style="%s"', csses.concat(that.header.styles[j]).join('; '));
1777
1778 // handle td's id and class
1779 if (item['_' + field + '_id']) {
1780 id_ = sprintf(' id="%s"', item['_' + field + '_id']);
1781 }
1782 if (item['_' + field + '_class']) {
1783 class_ = sprintf(' class="%s"', item['_' + field + '_class']);
1784 }
1785 if (item['_' + field + '_rowspan']) {
1786 rowspan_ = sprintf(' rowspan="%s"', item['_' + field + '_rowspan']);
1787 }
1788 if (item['_' + field + '_colspan']) {
1789 colspan_ = sprintf(' colspan="%s"', item['_' + field + '_colspan']);
1790 }
1791 if (item['_' + field + '_title']) {
1792 title_ = sprintf(' title="%s"', item['_' + field + '_title']);
1793 }
1794 cellStyle = calculateObjectValue(that.header,
1795 that.header.cellStyles[j], [value_, item, i, field], cellStyle);
1796 if (cellStyle.classes) {
1797 class_ = sprintf(' class="%s"', cellStyle.classes);
1798 }
1799 if (cellStyle.css) {
1800 var csses_ = [];
1801 for (var key in cellStyle.css) {
1802 csses_.push(key + ': ' + cellStyle.css[key]);
1803 }
1804 style = sprintf('style="%s"', csses_.concat(that.header.styles[j]).join('; '));
1805 }
1806
1807 value = calculateObjectValue(column,
1808 that.header.formatters[j], [value_, item, i, field], value_);
1809
1810 if (item['_' + field + '_data'] && !$.isEmptyObject(item['_' + field + '_data'])) {
1811 $.each(item['_' + field + '_data'], function(k, v) {
1812 // ignore data-index
1813 if (k === 'index') {
1814 return;
1815 }
1816 data_ += sprintf(' data-%s="%s"', k, v);
1817 });
1818 }
1819
1820 if (column.checkbox || column.radio) {
1821 type = column.checkbox ? 'checkbox' : type;
1822 type = column.radio ? 'radio' : type;
1823
1824 text = [sprintf(that.options.cardView ?
1825 '<div class="card-view %s">' : '<td class="bs-checkbox %s">', column['class'] || ''),
1826 '<input' +
1827 sprintf(' data-index="%s"', i) +
1828 sprintf(' name="%s"', that.options.selectItemName) +
1829 sprintf(' type="%s"', type) +
1830 sprintf(' value="%s"', item[that.options.idField]) +
1831 sprintf(' checked="%s"', value === true ||
1832 (value_ || value && value.checked) ? 'checked' : undefined) +
1833 sprintf(' disabled="%s"', !column.checkboxEnabled ||
1834 (value && value.disabled) ? 'disabled' : undefined) +
1835 ' />',
1836 that.header.formatters[j] && typeof value === 'string' ? value : '',
1837 that.options.cardView ? '</div>' : '</td>'
1838 ].join('');
1839
1840 item[that.header.stateField] = value === true || (value && value.checked);
1841 } else {
1842 value = typeof value === 'undefined' || value === null ?
1843 that.options.undefinedText : value;
1844
1845 text = that.options.cardView ? ['<div class="card-view">',
1846 that.options.showHeader ? sprintf('<span class="title" %s>%s</span>', style,
1847 getPropertyFromOther(that.columns, 'field', 'title', field)) : '',
1848 sprintf('<span class="value">%s</span>', value),
1849 '</div>'
1850 ].join('') : [sprintf('<td%s %s %s %s %s %s %s>',
1851 id_, class_, style, data_, rowspan_, colspan_, title_),
1852 value,
1853 '</td>'
1854 ].join('');
1855
1856 // Hide empty data on Card view when smartDisplay is set to true.
1857 if (that.options.cardView && that.options.smartDisplay && value === '') {
1858 // Should set a placeholder for event binding correct fieldIndex
1859 text = '<div class="card-view"></div>';
1860 }
1861 }
1862
1863 html.push(text);
1864 });
1865
1866 if (this.options.cardView) {
1867 html.push('</div></td>');
1868 }
1869 html.push('</tr>');
1870
1871 return html.join(' ');
1872 };
1873
1874 BootstrapTable.prototype.initBody = function (fixedScroll) {
1875 var that = this,
1876 html = [],
1877 data = this.getData();
1878
1879 this.trigger('pre-body', data);
1880
1881 this.$body = this.$el.find('>tbody');
1882 if (!this.$body.length) {
1883 this.$body = $('<tbody></tbody>').appendTo(this.$el);
1884 }
1885
1886 //Fix #389 Bootstrap-table-flatJSON is not working
1887
1888 if (!this.options.pagination || this.options.sidePagination === 'server') {
1889 this.pageFrom = 1;
1890 this.pageTo = data.length;
1891 }
1892
1893 var trFragments = $(document.createDocumentFragment());
1894 var hasTr;
1895
1896 for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
1897 var item = data[i];
1898 var tr = this.initRow(item, i, data, trFragments);
1899 hasTr = hasTr || !!tr;
1900 if (tr&&tr!==true) {
1901 trFragments.append(tr);
1902 }
1903 }
1904
1905 // show no records
1906 if (!hasTr) {
1907 trFragments.append('<tr class="no-records-found">' +
1908 sprintf('<td colspan="%s">%s</td>',
1909 this.$header.find('th').length,
1910 this.options.formatNoMatches()) +
1911 '</tr>');
1912 }
1913
1914 this.$body.html(trFragments);
1915
1916 if (!fixedScroll) {
1917 this.scrollTo(0);
1918 }
1919
1920 // click to select by column
1921 this.$body.find('> tr[data-index] > td').off('click dblclick').on('click dblclick', function (e) {
1922 var $td = $(this),
1923 $tr = $td.parent(),
1924 item = that.data[$tr.data('index')],
1925 index = $td[0].cellIndex,
1926 fields = that.getVisibleFields(),
1927 field = fields[that.options.detailView && !that.options.cardView ? index - 1 : index],
1928 column = that.columns[that.fieldsColumnsIndex[field]],
1929 value = getItemField(item, field, that.options.escape);
1930
1931 if ($td.find('.detail-icon').length) {
1932 return;
1933 }
1934
1935 that.trigger(e.type === 'click' ? 'click-cell' : 'dbl-click-cell', field, value, item, $td);
1936 that.trigger(e.type === 'click' ? 'click-row' : 'dbl-click-row', item, $tr, field);
1937
1938 // if click to select - then trigger the checkbox/radio click
1939 if (e.type === 'click' && that.options.clickToSelect && column.clickToSelect && that.options.ignoreClickToSelectOn(e.target)) {
1940 var $selectItem = $tr.find(sprintf('[name="%s"]', that.options.selectItemName));
1941 if ($selectItem.length) {
1942 $selectItem[0].click(); // #144: .trigger('click') bug
1943 }
1944 }
1945 });
1946
1947 this.$body.find('> tr[data-index] > td > .detail-icon').off('click').on('click', function (e) {
1948 e.preventDefault();
1949
1950 var $this = $(this),
1951 $tr = $this.parent().parent(),
1952 index = $tr.data('index'),
1953 row = data[index]; // Fix #980 Detail view, when searching, returns wrong row
1954
1955 // remove and update
1956 if ($tr.next().is('tr.detail-view')) {
1957 $this.find('i').attr('class', sprintf('%s %s', that.options.iconsPrefix, that.options.icons.detailOpen));
1958 that.trigger('collapse-row', index, row);
1959 $tr.next().remove();
1960 } else {
1961 $this.find('i').attr('class', sprintf('%s %s', that.options.iconsPrefix, that.options.icons.detailClose));
1962 $tr.after(sprintf('<tr class="detail-view"><td colspan="%s"></td></tr>', $tr.find('td').length));
1963 var $element = $tr.next().find('td');
1964 var content = calculateObjectValue(that.options, that.options.detailFormatter, [index, row, $element], '');
1965 if($element.length === 1) {
1966 $element.append(content);
1967 }
1968 that.trigger('expand-row', index, row, $element);
1969 }
1970 that.resetView();
1971 return false;
1972 });
1973
1974 this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName));
1975 this.$selectItem.off('click').on('click', function (event) {
1976 event.stopImmediatePropagation();
1977
1978 var $this = $(this),
1979 checked = $this.prop('checked'),
1980 row = that.data[$this.data('index')];
1981
1982 if ($(this).is(':radio') || that.options.singleSelect) {
1983 $.each(that.options.data, function (i, row) {
1984 row[that.header.stateField] = false;
1985 });
1986 }
1987
1988 row[that.header.stateField] = checked;
1989
1990 if (that.options.singleSelect) {
1991 that.$selectItem.not(this).each(function () {
1992 that.data[$(this).data('index')][that.header.stateField] = false;
1993 });
1994 that.$selectItem.filter(':checked').not(this).prop('checked', false);
1995 }
1996
1997 that.updateSelected();
1998 that.trigger(checked ? 'check' : 'uncheck', row, $this);
1999 });
2000
2001 $.each(this.header.events, function (i, events) {
2002 if (!events) {
2003 return;
2004 }
2005 // fix bug, if events is defined with namespace
2006 if (typeof events === 'string') {
2007 events = calculateObjectValue(null, events);
2008 }
2009
2010 var field = that.header.fields[i],
2011 fieldIndex = $.inArray(field, that.getVisibleFields());
2012
2013 if (fieldIndex === -1) {
2014 return;
2015 }
2016
2017 if (that.options.detailView && !that.options.cardView) {
2018 fieldIndex += 1;
2019 }
2020
2021 for (var key in events) {
2022 that.$body.find('>tr:not(.no-records-found)').each(function () {
2023 var $tr = $(this),
2024 $td = $tr.find(that.options.cardView ? '.card-view' : 'td').eq(fieldIndex),
2025 index = key.indexOf(' '),
2026 name = key.substring(0, index),
2027 el = key.substring(index + 1),
2028 func = events[key];
2029
2030 $td.find(el).off(name).on(name, function (e) {
2031 var index = $tr.data('index'),
2032 row = that.data[index],
2033 value = row[field];
2034
2035 func.apply(this, [e, value, row, index]);
2036 });
2037 });
2038 }
2039 });
2040
2041 this.updateSelected();
2042 this.resetView();
2043
2044 this.trigger('post-body', data);
2045 };
2046
2047 BootstrapTable.prototype.initServer = function (silent, query, url) {
2048 var that = this,
2049 data = {},
2050 params = {
2051 searchText: this.searchText,
2052 sortName: this.options.sortName,
2053 sortOrder: this.options.sortOrder
2054 },
2055 request;
2056
2057 if (this.options.pagination) {
2058 params.pageSize = this.options.pageSize === this.options.formatAllRows() ?
2059 this.options.totalRows : this.options.pageSize;
2060 params.pageNumber = this.options.pageNumber;
2061 }
2062
2063 if (!(url || this.options.url) && !this.options.ajax) {
2064 return;
2065 }
2066
2067 if (this.options.queryParamsType === 'limit') {
2068 params = {
2069 search: params.searchText,
2070 sort: params.sortName,
2071 order: params.sortOrder
2072 };
2073
2074 if (this.options.pagination) {
2075 params.offset = this.options.pageSize === this.options.formatAllRows() ?
2076 0 : this.options.pageSize * (this.options.pageNumber - 1);
2077 params.limit = this.options.pageSize === this.options.formatAllRows() ?
2078 this.options.totalRows : this.options.pageSize;
2079 if (params.limit === 0) {
2080 delete params.limit;
2081 }
2082 }
2083 }
2084
2085 if (!($.isEmptyObject(this.filterColumnsPartial))) {
2086 params.filter = JSON.stringify(this.filterColumnsPartial, null);
2087 }
2088
2089 data = calculateObjectValue(this.options, this.options.queryParams, [params], data);
2090
2091 $.extend(data, query || {});
2092
2093 // false to stop request
2094 if (data === false) {
2095 return;
2096 }
2097
2098 if (!silent) {
2099 this.$tableLoading.show();
2100 }
2101 request = $.extend({}, calculateObjectValue(null, this.options.ajaxOptions), {
2102 type: this.options.method,
2103 url: url || this.options.url,
2104 data: this.options.contentType === 'application/json' && this.options.method === 'post' ?
2105 JSON.stringify(data) : data,
2106 cache: this.options.cache,
2107 contentType: this.options.contentType,
2108 dataType: this.options.dataType,
2109 success: function (res) {
2110 res = calculateObjectValue(that.options, that.options.responseHandler, [res], res);
2111
2112 that.load(res);
2113 that.trigger('load-success', res);
2114 if (!silent) that.$tableLoading.hide();
2115 },
2116 error: function (res) {
2117 var data = [];
2118 if (that.options.sidePagination === 'server') {
2119 data = {};
2120 data[that.options.totalField] = 0;
2121 data[that.options.dataField] = [];
2122 }
2123 that.load(data);
2124 that.trigger('load-error', res.status, res);
2125 if (!silent) that.$tableLoading.hide();
2126 }
2127 });
2128
2129 if (this.options.ajax) {
2130 calculateObjectValue(this, this.options.ajax, [request], null);
2131 } else {
2132 if (this._xhr && this._xhr.readyState !== 4) {
2133 this._xhr.abort();
2134 }
2135 this._xhr = $.ajax(request);
2136 }
2137 };
2138
2139 BootstrapTable.prototype.initSearchText = function () {
2140 if (this.options.search) {
2141 this.searchText = '';
2142 if (this.options.searchText !== '') {
2143 var $search = this.$toolbar.find('.search input');
2144 $search.val(this.options.searchText);
2145 this.onSearch({currentTarget: $search, firedByInitSearchText: true});
2146 }
2147 }
2148 };
2149
2150 BootstrapTable.prototype.getCaret = function () {
2151 var that = this;
2152
2153 $.each(this.$header.find('th'), function (i, th) {
2154 $(th).find('.sortable').removeClass('desc asc').addClass($(th).data('field') === that.options.sortName ? that.options.sortOrder : 'both');
2155 });
2156 };
2157
2158 BootstrapTable.prototype.updateSelected = function () {
2159 var checkAll = this.$selectItem.filter(':enabled').length &&
2160 this.$selectItem.filter(':enabled').length ===
2161 this.$selectItem.filter(':enabled').filter(':checked').length;
2162
2163 this.$selectAll.add(this.$selectAll_).prop('checked', checkAll);
2164
2165 this.$selectItem.each(function () {
2166 $(this).closest('tr')[$(this).prop('checked') ? 'addClass' : 'removeClass']('selected');
2167 });
2168 };
2169
2170 BootstrapTable.prototype.updateRows = function () {
2171 var that = this;
2172
2173 this.$selectItem.each(function () {
2174 that.data[$(this).data('index')][that.header.stateField] = $(this).prop('checked');
2175 });
2176 };
2177
2178 BootstrapTable.prototype.resetRows = function () {
2179 var that = this;
2180
2181 $.each(this.data, function (i, row) {
2182 that.$selectAll.prop('checked', false);
2183 that.$selectItem.prop('checked', false);
2184 if (that.header.stateField) {
2185 row[that.header.stateField] = false;
2186 }
2187 });
2188 this.initHiddenRows();
2189 };
2190
2191 BootstrapTable.prototype.trigger = function (name) {
2192 var args = Array.prototype.slice.call(arguments, 1);
2193
2194 name += '.bs.table';
2195 this.options[BootstrapTable.EVENTS[name]].apply(this.options, args);
2196 this.$el.trigger($.Event(name), args);
2197
2198 this.options.onAll(name, args);
2199 this.$el.trigger($.Event('all.bs.table'), [name, args]);
2200 };
2201
2202 BootstrapTable.prototype.resetHeader = function () {
2203 // fix #61: the hidden table reset header bug.
2204 // fix bug: get $el.css('width') error sometime (height = 500)
2205 clearTimeout(this.timeoutId_);
2206 this.timeoutId_ = setTimeout($.proxy(this.fitHeader, this), this.$el.is(':hidden') ? 100 : 0);
2207 };
2208
2209 BootstrapTable.prototype.fitHeader = function () {
2210 var that = this,
2211 fixedBody,
2212 scrollWidth,
2213 focused,
2214 focusedTemp;
2215
2216 if (that.$el.is(':hidden')) {
2217 that.timeoutId_ = setTimeout($.proxy(that.fitHeader, that), 100);
2218 return;
2219 }
2220 fixedBody = this.$tableBody.get(0);
2221
2222 scrollWidth = fixedBody.scrollWidth > fixedBody.clientWidth &&
2223 fixedBody.scrollHeight > fixedBody.clientHeight + this.$header.outerHeight() ?
2224 getScrollBarWidth() : 0;
2225
2226 this.$el.css('margin-top', -this.$header.outerHeight());
2227
2228 focused = $(':focus');
2229 if (focused.length > 0) {
2230 var $th = focused.parents('th');
2231 if ($th.length > 0) {
2232 var dataField = $th.attr('data-field');
2233 if (dataField !== undefined) {
2234 var $headerTh = this.$header.find("[data-field='" + dataField + "']");
2235 if ($headerTh.length > 0) {
2236 $headerTh.find(":input").addClass("focus-temp");
2237 }
2238 }
2239 }
2240 }
2241
2242 this.$header_ = this.$header.clone(true, true);
2243 this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');
2244 this.$tableHeader.css({
2245 'margin-right': scrollWidth
2246 }).find('table').css('width', this.$el.outerWidth())
2247 .html('').attr('class', this.$el.attr('class'))
2248 .append(this.$header_);
2249
2250 focusedTemp = $('.focus-temp:visible:eq(0)');
2251 if (focusedTemp.length > 0) {
2252 focusedTemp.focus();
2253 this.$header.find('.focus-temp').removeClass('focus-temp');
2254 }
2255
2256 // fix bug: $.data() is not working as expected after $.append()
2257 this.$header.find('th[data-field]').each(function (i) {
2258 that.$header_.find(sprintf('th[data-field="%s"]', $(this).data('field'))).data($(this).data());
2259 });
2260
2261 var visibleFields = this.getVisibleFields(),
2262 $ths = this.$header_.find('th');
2263
2264 this.$body.find('>tr:first-child:not(.no-records-found) > *').each(function (i) {
2265 var $this = $(this),
2266 index = i;
2267
2268 if (that.options.detailView && !that.options.cardView) {
2269 if (i === 0) {
2270 that.$header_.find('th.detail').find('.fht-cell').width($this.innerWidth());
2271 }
2272 index = i - 1;
2273 }
2274
2275 if (index === -1) {
2276 return;
2277 }
2278
2279 var $th = that.$header_.find(sprintf('th[data-field="%s"]', visibleFields[index]));
2280 if ($th.length > 1) {
2281 $th = $($ths[$this[0].cellIndex]);
2282 }
2283
2284 var zoomWidth = $th.width() - $th.find('.fht-cell').width();
2285 $th.find('.fht-cell').width($this.innerWidth() - zoomWidth);
2286 });
2287
2288 this.horizontalScroll();
2289 this.trigger('post-header');
2290 };
2291
2292 BootstrapTable.prototype.resetFooter = function () {
2293 var that = this,
2294 data = that.getData(),
2295 html = [];
2296
2297 if (!this.options.showFooter || this.options.cardView) { //do nothing
2298 return;
2299 }
2300
2301 if (!this.options.cardView && this.options.detailView) {
2302 html.push('<td><div class="th-inner"> </div><div class="fht-cell"></div></td>');
2303 }
2304
2305 $.each(this.columns, function (i, column) {
2306 var key,
2307 falign = '', // footer align style
2308 valign = '',
2309 csses = [],
2310 style = {},
2311 class_ = sprintf(' class="%s"', column['class']);
2312
2313 if (!column.visible) {
2314 return;
2315 }
2316
2317 if (that.options.cardView && (!column.cardVisible)) {
2318 return;
2319 }
2320
2321 falign = sprintf('text-align: %s; ', column.falign ? column.falign : column.align);
2322 valign = sprintf('vertical-align: %s; ', column.valign);
2323
2324 style = calculateObjectValue(null, that.options.footerStyle);
2325
2326 if (style && style.css) {
2327 for (key in style.css) {
2328 csses.push(key + ': ' + style.css[key]);
2329 }
2330 }
2331
2332 html.push('<td', class_, sprintf(' style="%s"', falign + valign + csses.concat().join('; ')), '>');
2333 html.push('<div class="th-inner">');
2334
2335 html.push(calculateObjectValue(column, column.footerFormatter, [data], ' ') || ' ');
2336
2337 html.push('</div>');
2338 html.push('<div class="fht-cell"></div>');
2339 html.push('</div>');
2340 html.push('</td>');
2341 });
2342
2343 this.$tableFooter.find('tr').html(html.join(''));
2344 this.$tableFooter.show();
2345 clearTimeout(this.timeoutFooter_);
2346 this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this),
2347 this.$el.is(':hidden') ? 100 : 0);
2348 };
2349
2350 BootstrapTable.prototype.fitFooter = function () {
2351 var that = this,
2352 $footerTd,
2353 elWidth,
2354 scrollWidth;
2355
2356 clearTimeout(this.timeoutFooter_);
2357 if (this.$el.is(':hidden')) {
2358 this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this), 100);
2359 return;
2360 }
2361
2362 elWidth = this.$el.css('width');
2363 scrollWidth = elWidth > this.$tableBody.width() ? getScrollBarWidth() : 0;
2364
2365 this.$tableFooter.css({
2366 'margin-right': scrollWidth
2367 }).find('table').css('width', elWidth)
2368 .attr('class', this.$el.attr('class'));
2369
2370 $footerTd = this.$tableFooter.find('td');
2371
2372 this.$body.find('>tr:first-child:not(.no-records-found) > *').each(function (i) {
2373 var $this = $(this);
2374
2375 $footerTd.eq(i).find('.fht-cell').width($this.innerWidth());
2376 });
2377
2378 this.horizontalScroll();
2379 };
2380
2381 BootstrapTable.prototype.horizontalScroll = function () {
2382 var that = this;
2383 // horizontal scroll event
2384 // TODO: it's probably better improving the layout than binding to scroll event
2385
2386 that.trigger('scroll-body');
2387 this.$tableBody.off('scroll').on('scroll', function () {
2388 if (that.options.showHeader && that.options.height) {
2389 that.$tableHeader.scrollLeft($(this).scrollLeft());
2390 }
2391
2392 if (that.options.showFooter && !that.options.cardView) {
2393 that.$tableFooter.scrollLeft($(this).scrollLeft());
2394 }
2395 });
2396 };
2397
2398 BootstrapTable.prototype.toggleColumn = function (index, checked, needUpdate) {
2399 if (index === -1) {
2400 return;
2401 }
2402 this.columns[index].visible = checked;
2403 this.initHeader();
2404 this.initSearch();
2405 this.initPagination();
2406 this.initBody();
2407
2408 if (this.options.showColumns) {
2409 var $items = this.$toolbar.find('.keep-open input').prop('disabled', false);
2410
2411 if (needUpdate) {
2412 $items.filter(sprintf('[value="%s"]', index)).prop('checked', checked);
2413 }
2414
2415 if ($items.filter(':checked').length <= this.options.minimumCountColumns) {
2416 $items.filter(':checked').prop('disabled', true);
2417 }
2418 }
2419 };
2420
2421 BootstrapTable.prototype.getVisibleFields = function () {
2422 var that = this,
2423 visibleFields = [];
2424
2425 $.each(this.header.fields, function (j, field) {
2426 var column = that.columns[that.fieldsColumnsIndex[field]];
2427
2428 if (!column.visible) {
2429 return;
2430 }
2431 visibleFields.push(field);
2432 });
2433 return visibleFields;
2434 };
2435
2436 // PUBLIC FUNCTION DEFINITION
2437 // =======================
2438
2439 BootstrapTable.prototype.resetView = function (params) {
2440 var padding = 0;
2441
2442 if (params && params.height) {
2443 this.options.height = params.height;
2444 }
2445
2446 this.$selectAll.prop('checked', this.$selectItem.length > 0 &&
2447 this.$selectItem.length === this.$selectItem.filter(':checked').length);
2448
2449 if (this.options.height) {
2450 var toolbarHeight = this.$toolbar.outerHeight(true),
2451 paginationHeight = this.$pagination.outerHeight(true),
2452 height = this.options.height - toolbarHeight - paginationHeight;
2453
2454 this.$tableContainer.css('height', height + 'px');
2455 }
2456
2457 if (this.options.cardView) {
2458 // remove the element css
2459 this.$el.css('margin-top', '0');
2460 this.$tableContainer.css('padding-bottom', '0');
2461 this.$tableFooter.hide();
2462 return;
2463 }
2464
2465 if (this.options.showHeader && this.options.height) {
2466 this.$tableHeader.show();
2467 this.resetHeader();
2468 padding += this.$header.outerHeight();
2469 } else {
2470 this.$tableHeader.hide();
2471 this.trigger('post-header');
2472 }
2473
2474 if (this.options.showFooter) {
2475 this.resetFooter();
2476 if (this.options.height) {
2477 padding += this.$tableFooter.outerHeight() + 1;
2478 }
2479 }
2480
2481 // Assign the correct sortable arrow
2482 this.getCaret();
2483 this.$tableContainer.css('padding-bottom', padding + 'px');
2484 this.trigger('reset-view');
2485 };
2486
2487 BootstrapTable.prototype.getData = function (useCurrentPage) {
2488 var data = this.options.data;
2489 if (this.searchText || this.options.sortName || !$.isEmptyObject(this.filterColumns) || !$.isEmptyObject(this.filterColumnsPartial)) {
2490 data = this.data;
2491 }
2492
2493 if (useCurrentPage) {
2494 return data.slice(this.pageFrom - 1, this.pageTo);
2495 }
2496
2497 return data;
2498 };
2499
2500 BootstrapTable.prototype.load = function (data) {
2501 var fixedScroll = false;
2502
2503 // #431: support pagination
2504 if (this.options.pagination && this.options.sidePagination === 'server') {
2505 this.options.totalRows = data[this.options.totalField];
2506 fixedScroll = data.fixedScroll;
2507 data = data[this.options.dataField];
2508 } else if (!$.isArray(data)) { // support fixedScroll
2509 fixedScroll = data.fixedScroll;
2510 data = data.data;
2511 }
2512
2513 this.initData(data);
2514 this.initSearch();
2515 this.initPagination();
2516 this.initBody(fixedScroll);
2517 };
2518
2519 BootstrapTable.prototype.append = function (data) {
2520 this.initData(data, 'append');
2521 this.initSearch();
2522 this.initPagination();
2523 this.initSort();
2524 this.initBody(true);
2525 };
2526
2527 BootstrapTable.prototype.prepend = function (data) {
2528 this.initData(data, 'prepend');
2529 this.initSearch();
2530 this.initPagination();
2531 this.initSort();
2532 this.initBody(true);
2533 };
2534
2535 BootstrapTable.prototype.remove = function (params) {
2536 var len = this.options.data.length,
2537 i, row;
2538
2539 if (!params.hasOwnProperty('field') || !params.hasOwnProperty('values')) {
2540 return;
2541 }
2542
2543 for (i = len - 1; i >= 0; i--) {
2544 row = this.options.data[i];
2545
2546 if (!row.hasOwnProperty(params.field)) {
2547 continue;
2548 }
2549 if ($.inArray(row[params.field], params.values) !== -1) {
2550 this.options.data.splice(i, 1);
2551 if (this.options.sidePagination === 'server') {
2552 this.options.totalRows -= 1;
2553 }
2554 }
2555 }
2556
2557 if (len === this.options.data.length) {
2558 return;
2559 }
2560
2561 this.initSearch();
2562 this.initPagination();
2563 this.initSort();
2564 this.initBody(true);
2565 };
2566
2567 BootstrapTable.prototype.removeAll = function () {
2568 if (this.options.data.length > 0) {
2569 this.options.data.splice(0, this.options.data.length);
2570 this.initSearch();
2571 this.initPagination();
2572 this.initBody(true);
2573 }
2574 };
2575
2576 BootstrapTable.prototype.getRowByUniqueId = function (id) {
2577 var uniqueId = this.options.uniqueId,
2578 len = this.options.data.length,
2579 dataRow = null,
2580 i, row, rowUniqueId;
2581
2582 for (i = len - 1; i >= 0; i--) {
2583 row = this.options.data[i];
2584
2585 if (row.hasOwnProperty(uniqueId)) { // uniqueId is a column
2586 rowUniqueId = row[uniqueId];
2587 } else if(row._data.hasOwnProperty(uniqueId)) { // uniqueId is a row data property
2588 rowUniqueId = row._data[uniqueId];
2589 } else {
2590 continue;
2591 }
2592
2593 if (typeof rowUniqueId === 'string') {
2594 id = id.toString();
2595 } else if (typeof rowUniqueId === 'number') {
2596 if ((Number(rowUniqueId) === rowUniqueId) && (rowUniqueId % 1 === 0)) {
2597 id = parseInt(id);
2598 } else if ((rowUniqueId === Number(rowUniqueId)) && (rowUniqueId !== 0)) {
2599 id = parseFloat(id);
2600 }
2601 }
2602
2603 if (rowUniqueId === id) {
2604 dataRow = row;
2605 break;
2606 }
2607 }
2608
2609 return dataRow;
2610 };
2611
2612 BootstrapTable.prototype.removeByUniqueId = function (id) {
2613 var len = this.options.data.length,
2614 row = this.getRowByUniqueId(id);
2615
2616 if (row) {
2617 this.options.data.splice(this.options.data.indexOf(row), 1);
2618 }
2619
2620 if (len === this.options.data.length) {
2621 return;
2622 }
2623
2624 this.initSearch();
2625 this.initPagination();
2626 this.initBody(true);
2627 };
2628
2629 BootstrapTable.prototype.updateByUniqueId = function (params) {
2630 var that = this;
2631 var allParams = $.isArray(params) ? params : [ params ];
2632
2633 $.each(allParams, function(i, params) {
2634 var rowId;
2635
2636 if (!params.hasOwnProperty('id') || !params.hasOwnProperty('row')) {
2637 return;
2638 }
2639
2640 rowId = $.inArray(that.getRowByUniqueId(params.id), that.options.data);
2641
2642 if (rowId === -1) {
2643 return;
2644 }
2645 $.extend(that.options.data[rowId], params.row);
2646 });
2647
2648 this.initSearch();
2649 this.initPagination();
2650 this.initSort();
2651 this.initBody(true);
2652 };
2653
2654 BootstrapTable.prototype.refreshColumnTitle = function (params) {
2655 if (!params.hasOwnProperty('field') || !params.hasOwnProperty('title')) {
2656 return;
2657 }
2658
2659 this.columns[this.fieldsColumnsIndex[params.field]].title =
2660 this.options.escape ? escapeHTML(params.title) : params.title;
2661
2662 if (this.columns[this.fieldsColumnsIndex[params.field]].visible) {
2663 var header = this.options.height !== undefined ? this.$tableHeader : this.$header;
2664 header.find('th[data-field]').each(function (i) {
2665 if ($(this).data('field') === params.field) {
2666 $($(this).find(".th-inner")[0]).text(params.title);
2667 return false;
2668 }
2669 });
2670 }
2671 };
2672
2673 BootstrapTable.prototype.insertRow = function (params) {
2674 if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) {
2675 return;
2676 }
2677 this.options.data.splice(params.index, 0, params.row);
2678 this.initSearch();
2679 this.initPagination();
2680 this.initSort();
2681 this.initBody(true);
2682 };
2683
2684 BootstrapTable.prototype.updateRow = function (params) {
2685 var that = this;
2686 var allParams = $.isArray(params) ? params : [ params ];
2687
2688 $.each(allParams, function(i, params) {
2689 if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) {
2690 return;
2691 }
2692 $.extend(that.options.data[params.index], params.row);
2693 });
2694
2695 this.initSearch();
2696 this.initPagination();
2697 this.initSort();
2698 this.initBody(true);
2699 };
2700
2701 BootstrapTable.prototype.initHiddenRows = function () {
2702 this.hiddenRows = [];
2703 };
2704
2705 BootstrapTable.prototype.showRow = function (params) {
2706 this.toggleRow(params, true);
2707 };
2708
2709 BootstrapTable.prototype.hideRow = function (params) {
2710 this.toggleRow(params, false);
2711 };
2712
2713 BootstrapTable.prototype.toggleRow = function (params, visible) {
2714 var row, index;
2715
2716 if (params.hasOwnProperty('index')) {
2717 row = this.getData()[params.index];
2718 } else if (params.hasOwnProperty('uniqueId')) {
2719 row = this.getRowByUniqueId(params.uniqueId);
2720 }
2721
2722 if (!row) {
2723 return;
2724 }
2725
2726 index = $.inArray(row, this.hiddenRows);
2727
2728 if (!visible && index === -1) {
2729 this.hiddenRows.push(row);
2730 } else if (visible && index > -1) {
2731 this.hiddenRows.splice(index, 1);
2732 }
2733 this.initBody(true);
2734 };
2735
2736 BootstrapTable.prototype.getHiddenRows = function (show) {
2737 var that = this,
2738 data = this.getData(),
2739 rows = [];
2740
2741 $.each(data, function (i, row) {
2742 if ($.inArray(row, that.hiddenRows) > -1) {
2743 rows.push(row);
2744 }
2745 });
2746 this.hiddenRows = rows;
2747 return rows;
2748 };
2749
2750 BootstrapTable.prototype.mergeCells = function (options) {
2751 var row = options.index,
2752 col = $.inArray(options.field, this.getVisibleFields()),
2753 rowspan = options.rowspan || 1,
2754 colspan = options.colspan || 1,
2755 i, j,
2756 $tr = this.$body.find('>tr'),
2757 $td;
2758
2759 if (this.options.detailView && !this.options.cardView) {
2760 col += 1;
2761 }
2762
2763 $td = $tr.eq(row).find('>td').eq(col);
2764
2765 if (row < 0 || col < 0 || row >= this.data.length) {
2766 return;
2767 }
2768
2769 for (i = row; i < row + rowspan; i++) {
2770 for (j = col; j < col + colspan; j++) {
2771 $tr.eq(i).find('>td').eq(j).hide();
2772 }
2773 }
2774
2775 $td.attr('rowspan', rowspan).attr('colspan', colspan).show();
2776 };
2777
2778 BootstrapTable.prototype.updateCell = function (params) {
2779 if (!params.hasOwnProperty('index') ||
2780 !params.hasOwnProperty('field') ||
2781 !params.hasOwnProperty('value')) {
2782 return;
2783 }
2784 this.data[params.index][params.field] = params.value;
2785
2786 if (params.reinit === false) {
2787 return;
2788 }
2789 this.initSort();
2790 this.initBody(true);
2791 };
2792
2793 BootstrapTable.prototype.updateCellById = function (params) {
2794 var that = this;
2795 if (!params.hasOwnProperty('id') ||
2796 !params.hasOwnProperty('field') ||
2797 !params.hasOwnProperty('value')) {
2798 return;
2799 }
2800 var allParams = $.isArray(params) ? params : [ params ];
2801
2802 $.each(allParams, function(i, params) {
2803 var rowId;
2804
2805 rowId = $.inArray(that.getRowByUniqueId(params.id), that.options.data);
2806
2807 if (rowId === -1) {
2808 return;
2809 }
2810 that.data[rowId][params.field] = params.value;
2811 });
2812
2813 if (params.reinit === false) {
2814 return;
2815 }
2816 this.initSort();
2817 this.initBody(true);
2818 };
2819
2820 BootstrapTable.prototype.getOptions = function () {
2821 //Deep copy
2822 return $.extend(true, {}, this.options);
2823 };
2824
2825 BootstrapTable.prototype.getSelections = function () {
2826 var that = this;
2827
2828 return $.grep(this.options.data, function (row) {
2829 // fix #2424: from html with checkbox
2830 return row[that.header.stateField] === true;
2831 });
2832 };
2833
2834 BootstrapTable.prototype.getAllSelections = function () {
2835 var that = this;
2836
2837 return $.grep(this.options.data, function (row) {
2838 return row[that.header.stateField];
2839 });
2840 };
2841
2842 BootstrapTable.prototype.checkAll = function () {
2843 this.checkAll_(true);
2844 };
2845
2846 BootstrapTable.prototype.uncheckAll = function () {
2847 this.checkAll_(false);
2848 };
2849
2850 BootstrapTable.prototype.checkInvert = function () {
2851 var that = this;
2852 var rows = that.$selectItem.filter(':enabled');
2853 var checked = rows.filter(':checked');
2854 rows.each(function() {
2855 $(this).prop('checked', !$(this).prop('checked'));
2856 });
2857 that.updateRows();
2858 that.updateSelected();
2859 that.trigger('uncheck-some', checked);
2860 checked = that.getSelections();
2861 that.trigger('check-some', checked);
2862 };
2863
2864 BootstrapTable.prototype.checkAll_ = function (checked) {
2865 var rows;
2866 if (!checked) {
2867 rows = this.getSelections();
2868 }
2869 this.$selectAll.add(this.$selectAll_).prop('checked', checked);
2870 this.$selectItem.filter(':enabled').prop('checked', checked);
2871 this.updateRows();
2872 if (checked) {
2873 rows = this.getSelections();
2874 }
2875 this.trigger(checked ? 'check-all' : 'uncheck-all', rows);
2876 };
2877
2878 BootstrapTable.prototype.check = function (index) {
2879 this.check_(true, index);
2880 };
2881
2882 BootstrapTable.prototype.uncheck = function (index) {
2883 this.check_(false, index);
2884 };
2885
2886 BootstrapTable.prototype.check_ = function (checked, index) {
2887 var $el = this.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);
2888 this.data[index][this.header.stateField] = checked;
2889 this.updateSelected();
2890 this.trigger(checked ? 'check' : 'uncheck', this.data[index], $el);
2891 };
2892
2893 BootstrapTable.prototype.checkBy = function (obj) {
2894 this.checkBy_(true, obj);
2895 };
2896
2897 BootstrapTable.prototype.uncheckBy = function (obj) {
2898 this.checkBy_(false, obj);
2899 };
2900
2901 BootstrapTable.prototype.checkBy_ = function (checked, obj) {
2902 if (!obj.hasOwnProperty('field') || !obj.hasOwnProperty('values')) {
2903 return;
2904 }
2905
2906 var that = this,
2907 rows = [];
2908 $.each(this.options.data, function (index, row) {
2909 if (!row.hasOwnProperty(obj.field)) {
2910 return false;
2911 }
2912 if ($.inArray(row[obj.field], obj.values) !== -1) {
2913 var $el = that.$selectItem.filter(':enabled')
2914 .filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);
2915 row[that.header.stateField] = checked;
2916 rows.push(row);
2917 that.trigger(checked ? 'check' : 'uncheck', row, $el);
2918 }
2919 });
2920 this.updateSelected();
2921 this.trigger(checked ? 'check-some' : 'uncheck-some', rows);
2922 };
2923
2924 BootstrapTable.prototype.destroy = function () {
2925 this.$el.insertBefore(this.$container);
2926 $(this.options.toolbar).insertBefore(this.$el);
2927 this.$container.next().remove();
2928 this.$container.remove();
2929 this.$el.html(this.$el_.html())
2930 .css('margin-top', '0')
2931 .attr('class', this.$el_.attr('class') || ''); // reset the class
2932 };
2933
2934 BootstrapTable.prototype.showLoading = function () {
2935 this.$tableLoading.show();
2936 };
2937
2938 BootstrapTable.prototype.hideLoading = function () {
2939 this.$tableLoading.hide();
2940 };
2941
2942 BootstrapTable.prototype.togglePagination = function () {
2943 this.options.pagination = !this.options.pagination;
2944 var button = this.$toolbar.find('button[name="paginationSwitch"] i');
2945 if (this.options.pagination) {
2946 button.attr("class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchDown);
2947 } else {
2948 button.attr("class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchUp);
2949 }
2950 this.updatePagination();
2951 };
2952
2953 BootstrapTable.prototype.toggleFullscreen = function () {
2954 this.$el.closest('.bootstrap-table').toggleClass('fullscreen');
2955 };
2956
2957 BootstrapTable.prototype.refresh = function (params) {
2958 if (params && params.url) {
2959 this.options.url = params.url;
2960 }
2961 if (params && params.pageNumber) {
2962 this.options.pageNumber = params.pageNumber;
2963 }
2964 if (params && params.pageSize) {
2965 this.options.pageSize = params.pageSize;
2966 }
2967 this.initServer(params && params.silent,
2968 params && params.query, params && params.url);
2969 this.trigger('refresh', params);
2970 };
2971
2972 BootstrapTable.prototype.resetWidth = function () {
2973 if (this.options.showHeader && this.options.height) {
2974 this.fitHeader();
2975 }
2976 if (this.options.showFooter && !this.options.cardView) {
2977 this.fitFooter();
2978 }
2979 };
2980
2981 BootstrapTable.prototype.showColumn = function (field) {
2982 this.toggleColumn(this.fieldsColumnsIndex[field], true, true);
2983 };
2984
2985 BootstrapTable.prototype.hideColumn = function (field) {
2986 this.toggleColumn(this.fieldsColumnsIndex[field], false, true);
2987 };
2988
2989 BootstrapTable.prototype.getHiddenColumns = function () {
2990 return $.grep(this.columns, function (column) {
2991 return !column.visible;
2992 });
2993 };
2994
2995 BootstrapTable.prototype.getVisibleColumns = function () {
2996 return $.grep(this.columns, function (column) {
2997 return column.visible;
2998 });
2999 };
3000
3001 BootstrapTable.prototype.toggleAllColumns = function (visible) {
3002 var that = this;
3003 $.each(this.columns, function (i, column) {
3004 that.columns[i].visible = visible;
3005 });
3006
3007 this.initHeader();
3008 this.initSearch();
3009 this.initPagination();
3010 this.initBody();
3011 if (this.options.showColumns) {
3012 var $items = this.$toolbar.find('.keep-open input').prop('disabled', false);
3013
3014 if ($items.filter(':checked').length <= this.options.minimumCountColumns) {
3015 $items.filter(':checked').prop('disabled', true);
3016 }
3017 }
3018 };
3019
3020 BootstrapTable.prototype.showAllColumns = function () {
3021 this.toggleAllColumns(true);
3022 };
3023
3024 BootstrapTable.prototype.hideAllColumns = function () {
3025 this.toggleAllColumns(false);
3026 };
3027
3028 BootstrapTable.prototype.filterBy = function (columns) {
3029 this.filterColumns = $.isEmptyObject(columns) ? {} : columns;
3030 this.options.pageNumber = 1;
3031 this.initSearch();
3032 this.updatePagination();
3033 };
3034
3035 BootstrapTable.prototype.scrollTo = function (value) {
3036 if (typeof value === 'string') {
3037 value = value === 'bottom' ? this.$tableBody[0].scrollHeight : 0;
3038 }
3039 if (typeof value === 'number') {
3040 this.$tableBody.scrollTop(value);
3041 }
3042 if (typeof value === 'undefined') {
3043 return this.$tableBody.scrollTop();
3044 }
3045 };
3046
3047 BootstrapTable.prototype.getScrollPosition = function () {
3048 return this.scrollTo();
3049 };
3050
3051 BootstrapTable.prototype.selectPage = function (page) {
3052 if (page > 0 && page <= this.options.totalPages) {
3053 this.options.pageNumber = page;
3054 this.updatePagination();
3055 }
3056 };
3057
3058 BootstrapTable.prototype.prevPage = function () {
3059 if (this.options.pageNumber > 1) {
3060 this.options.pageNumber--;
3061 this.updatePagination();
3062 }
3063 };
3064
3065 BootstrapTable.prototype.nextPage = function () {
3066 if (this.options.pageNumber < this.options.totalPages) {
3067 this.options.pageNumber++;
3068 this.updatePagination();
3069 }
3070 };
3071
3072 BootstrapTable.prototype.toggleView = function () {
3073 this.options.cardView = !this.options.cardView;
3074 this.initHeader();
3075 // Fixed remove toolbar when click cardView button.
3076 //that.initToolbar();
3077 this.initBody();
3078 this.trigger('toggle', this.options.cardView);
3079 };
3080
3081 BootstrapTable.prototype.refreshOptions = function (options) {
3082 //If the objects are equivalent then avoid the call of destroy / init methods
3083 if (compareObjects(this.options, options, true)) {
3084 return;
3085 }
3086 this.options = $.extend(this.options, options);
3087 this.trigger('refresh-options', this.options);
3088 this.destroy();
3089 this.init();
3090 };
3091
3092 BootstrapTable.prototype.resetSearch = function (text) {
3093 var $search = this.$toolbar.find('.search input');
3094 $search.val(text || '');
3095 this.onSearch({currentTarget: $search});
3096 };
3097
3098 BootstrapTable.prototype.expandRow_ = function (expand, index) {
3099 var $tr = this.$body.find(sprintf('> tr[data-index="%s"]', index));
3100 if ($tr.next().is('tr.detail-view') === (expand ? false : true)) {
3101 $tr.find('> td > .detail-icon').click();
3102 }
3103 };
3104
3105 BootstrapTable.prototype.expandRow = function (index) {
3106 this.expandRow_(true, index);
3107 };
3108
3109 BootstrapTable.prototype.collapseRow = function (index) {
3110 this.expandRow_(false, index);
3111 };
3112
3113 BootstrapTable.prototype.expandAllRows = function (isSubTable) {
3114 if (isSubTable) {
3115 var $tr = this.$body.find(sprintf('> tr[data-index="%s"]', 0)),
3116 that = this,
3117 detailIcon = null,
3118 executeInterval = false,
3119 idInterval = -1;
3120
3121 if (!$tr.next().is('tr.detail-view')) {
3122 $tr.find('> td > .detail-icon').click();
3123 executeInterval = true;
3124 } else if (!$tr.next().next().is('tr.detail-view')) {
3125 $tr.next().find(".detail-icon").click();
3126 executeInterval = true;
3127 }
3128
3129 if (executeInterval) {
3130 try {
3131 idInterval = setInterval(function () {
3132 detailIcon = that.$body.find("tr.detail-view").last().find(".detail-icon");
3133 if (detailIcon.length > 0) {
3134 detailIcon.click();
3135 } else {
3136 clearInterval(idInterval);
3137 }
3138 }, 1);
3139 } catch (ex) {
3140 clearInterval(idInterval);
3141 }
3142 }
3143 } else {
3144 var trs = this.$body.children();
3145 for (var i = 0; i < trs.length; i++) {
3146 this.expandRow_(true, $(trs[i]).data("index"));
3147 }
3148 }
3149 };
3150
3151 BootstrapTable.prototype.collapseAllRows = function (isSubTable) {
3152 if (isSubTable) {
3153 this.expandRow_(false, 0);
3154 } else {
3155 var trs = this.$body.children();
3156 for (var i = 0; i < trs.length; i++) {
3157 this.expandRow_(false, $(trs[i]).data("index"));
3158 }
3159 }
3160 };
3161
3162 BootstrapTable.prototype.updateFormatText = function (name, text) {
3163 if (this.options[sprintf('format%s', name)]) {
3164 if (typeof text === 'string') {
3165 this.options[sprintf('format%s', name)] = function () {
3166 return text;
3167 };
3168 } else if (typeof text === 'function') {
3169 this.options[sprintf('format%s', name)] = text;
3170 }
3171 }
3172 this.initToolbar();
3173 this.initPagination();
3174 this.initBody();
3175 };
3176
3177 // BOOTSTRAP TABLE PLUGIN DEFINITION
3178 // =======================
3179
3180 var allowedMethods = [
3181 'getOptions',
3182 'getSelections', 'getAllSelections', 'getData',
3183 'load', 'append', 'prepend', 'remove', 'removeAll',
3184 'insertRow', 'updateRow', 'updateCell', 'updateByUniqueId', 'removeByUniqueId',
3185 'getRowByUniqueId', 'showRow', 'hideRow', 'getHiddenRows',
3186 'mergeCells', 'refreshColumnTitle',
3187 'checkAll', 'uncheckAll', 'checkInvert',
3188 'check', 'uncheck',
3189 'checkBy', 'uncheckBy',
3190 'refresh',
3191 'resetView',
3192 'resetWidth',
3193 'destroy',
3194 'showLoading', 'hideLoading',
3195 'showColumn', 'hideColumn', 'getHiddenColumns', 'getVisibleColumns',
3196 'showAllColumns', 'hideAllColumns',
3197 'filterBy',
3198 'scrollTo',
3199 'getScrollPosition',
3200 'selectPage', 'prevPage', 'nextPage',
3201 'togglePagination',
3202 'toggleView',
3203 'refreshOptions',
3204 'resetSearch',
3205 'expandRow', 'collapseRow', 'expandAllRows', 'collapseAllRows',
3206 'updateFormatText', 'updateCellById'
3207 ];
3208
3209 $.fn.bootstrapTable = function (option) {
3210 var value,
3211 args = Array.prototype.slice.call(arguments, 1);
3212
3213 this.each(function () {
3214 var $this = $(this),
3215 data = $this.data('bootstrap.table'),
3216 options = $.extend({}, BootstrapTable.DEFAULTS, $this.data(),
3217 typeof option === 'object' && option);
3218
3219 if (typeof option === 'string') {
3220 if ($.inArray(option, allowedMethods) < 0) {
3221 throw new Error("Unknown method: " + option);
3222 }
3223
3224 if (!data) {
3225 return;
3226 }
3227
3228 value = data[option].apply(data, args);
3229
3230 if (option === 'destroy') {
3231 $this.removeData('bootstrap.table');
3232 }
3233 }
3234
3235 if (!data) {
3236 $this.data('bootstrap.table', (data = new BootstrapTable(this, options)));
3237 }
3238 });
3239
3240 return typeof value === 'undefined' ? this : value;
3241 };
3242
3243 $.fn.bootstrapTable.Constructor = BootstrapTable;
3244 $.fn.bootstrapTable.defaults = BootstrapTable.DEFAULTS;
3245 $.fn.bootstrapTable.columnDefaults = BootstrapTable.COLUMN_DEFAULTS;
3246 $.fn.bootstrapTable.locales = BootstrapTable.LOCALES;
3247 $.fn.bootstrapTable.methods = allowedMethods;
3248 $.fn.bootstrapTable.utils = {
3249 bootstrapVersion: bootstrapVersion,
3250 sprintf: sprintf,
3251 compareObjects: compareObjects,
3252 calculateObjectValue: calculateObjectValue,
3253 getItemField: getItemField,
3254 objectKeys: objectKeys,
3255 isIEBrowser: isIEBrowser
3256 };
3257
3258 // BOOTSTRAP TABLE INIT
3259 // =======================
3260
3261 $(function () {
3262 $('[data-toggle="table"]').bootstrapTable();
3263 });
3264})(jQuery);