corrade-nucleus-nucleons – Blame information for rev 24

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