Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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