bootstrap-table.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. /**
  2. * @author zhixin wen <wenzhixin2010@gmail.com>
  3. * version: 1.2.3
  4. * https://github.com/wenzhixin/bootstrap-table/
  5. */
  6. !function ($) {
  7. 'use strict';
  8. // TOOLS DEFINITION
  9. // ======================
  10. // it only does '%s', and return '' when arguments are undefined
  11. var sprintf = function(str) {
  12. var args = arguments,
  13. flag = true,
  14. i = 1;
  15. str = str.replace(/%s/g, function () {
  16. var arg = args[i++];
  17. if (typeof arg === 'undefined') {
  18. flag = false;
  19. return '';
  20. }
  21. return arg;
  22. });
  23. if (flag) {
  24. return str;
  25. }
  26. return '';
  27. };
  28. var getPropertyFromOther = function (list, from, to, value) {
  29. var result = '';
  30. $.each(list, function (i, item) {
  31. if (item[from] === value) {
  32. result = item[to];
  33. return false;
  34. }
  35. return true;
  36. });
  37. return result;
  38. };
  39. var getFiledIndex = function (columns, field) {
  40. var index = -1;
  41. $.each(columns, function (i, column) {
  42. if (column.field === field) {
  43. index = i;
  44. return false;
  45. }
  46. return true;
  47. });
  48. return index;
  49. };
  50. var getScrollBarWidth = function () {
  51. var inner = $('<p/>').addClass('fixed-table-scroll-inner'),
  52. outer = $('<div/>').addClass('fixed-table-scroll-outer'),
  53. w1, w2;
  54. outer.append(inner);
  55. $('body').append(outer);
  56. w1 = inner[0].offsetWidth;
  57. outer.css('overflow', 'scroll');
  58. w2 = inner[0].offsetWidth;
  59. if (w1 == w2) {
  60. w2 = outer[0].clientWidth;
  61. }
  62. outer.remove();
  63. return w1 - w2;
  64. };
  65. // BOOTSTRAP TABLE CLASS DEFINITION
  66. // ======================
  67. var BootstrapTable = function (el, options) {
  68. this.options = options;
  69. this.$el = $(el);
  70. this.$el_ = this.$el.clone();
  71. this.timeoutId_ = 0;
  72. this.init();
  73. };
  74. BootstrapTable.DEFAULTS = {
  75. classes: 'table table-hover',
  76. height: undefined,
  77. undefinedText: '-',
  78. sortName: undefined,
  79. sortOrder: 'asc',
  80. striped: false,
  81. columns: [],
  82. data: [],
  83. method: 'get',
  84. url: undefined,
  85. cache: true,
  86. contentType: 'application/json',
  87. queryParams: function (params) {return {};},
  88. queryParamsType: undefined,
  89. responseHandler: function (res) {return res;},
  90. pagination: false,
  91. sidePagination: 'client', // client or server
  92. totalRows: 0, // server side need to set
  93. pageNumber: 1,
  94. pageSize: 10,
  95. pageList: [10, 25, 50, 100],
  96. search: false,
  97. selectItemName: 'btSelectItem',
  98. showHeader: true,
  99. showColumns: false,
  100. showRefresh: false,
  101. showToggle: false,
  102. minimumCountColumns: 1,
  103. idField: undefined,
  104. cardView: false,
  105. clickToSelect: false,
  106. singleSelect: false,
  107. toolbar: undefined,
  108. checkboxHeader: true,
  109. sortable: true,
  110. maintainSelected: false,
  111. rowStyle: function (row, index) {return {};},
  112. formatLoadingMessage: function () {
  113. return 'Loading, please wait…';
  114. },
  115. formatRecordsPerPage: function (pageNumber) {
  116. return sprintf('%s records per page', pageNumber);
  117. },
  118. formatShowingRows: function (pageFrom, pageTo, totalRows) {
  119. return sprintf('Showing %s to %s of %s rows', pageFrom, pageTo, totalRows);
  120. },
  121. formatSearch: function () {
  122. return 'Search';
  123. },
  124. formatNoMatches: function () {
  125. return 'No matching records found';
  126. },
  127. onAll: function (name, args) {return false;},
  128. onClickRow: function (item, $element) {return false;},
  129. onDblClickRow: function (item, $element) {return false;},
  130. onSort: function (name, order) {return false;},
  131. onCheck: function (row) {return false;},
  132. onUncheck: function (row) {return false;},
  133. onCheckAll: function () {return false;},
  134. onUncheckAll: function () {return false;},
  135. onLoadSuccess: function (data) {return false;},
  136. onLoadError: function (status) {return false;}
  137. };
  138. BootstrapTable.COLUMN_DEFAULTS = {
  139. radio: false,
  140. checkbox: false,
  141. checkboxEnabled: true,
  142. field: undefined,
  143. title: undefined,
  144. 'class': undefined,
  145. align: undefined, // left, right, center
  146. halign: undefined, // left, right, center
  147. valign: undefined, // top, middle, bottom
  148. width: undefined,
  149. sortable: false,
  150. order: 'asc', // asc, desc
  151. visible: true,
  152. switchable: true,
  153. formatter: undefined,
  154. events: undefined,
  155. sorter: undefined,
  156. clickToSelect: true
  157. };
  158. BootstrapTable.EVENTS = {
  159. 'all.bs.table': 'onAll',
  160. 'click-row.bs.table': 'onClickRow',
  161. 'dbl-click-row.bs.table': 'onDblClickRow',
  162. 'sort.bs.table': 'onSort',
  163. 'check.bs.table': 'onCheck',
  164. 'uncheck.bs.table': 'onUncheck',
  165. 'check-all.bs.table': 'onCheckAll',
  166. 'uncheck-all.bs.table': 'onUncheckAll',
  167. 'load-success.bs.table': 'onLoadSuccess',
  168. 'load-error.bs.table': 'onLoadError'
  169. };
  170. BootstrapTable.prototype.init = function () {
  171. this.initContainer();
  172. this.initTable();
  173. this.initHeader();
  174. this.initData();
  175. this.initToolbar();
  176. this.initPagination();
  177. this.initBody();
  178. this.initServer();
  179. };
  180. BootstrapTable.prototype.initContainer = function () {
  181. this.$container = $([
  182. '<div class="bootstrap-table">',
  183. '<div class="fixed-table-toolbar"></div>',
  184. '<div class="fixed-table-container">',
  185. '<div class="fixed-table-header"><table></table></div>',
  186. '<div class="fixed-table-body">',
  187. '<div class="fixed-table-loading">',
  188. this.options.formatLoadingMessage(),
  189. '</div>',
  190. '</div>',
  191. '<div class="fixed-table-pagination"></div>',
  192. '</div>',
  193. '</div>'].join(''));
  194. this.$container.insertAfter(this.$el);
  195. this.$container.find('.fixed-table-body').append(this.$el);
  196. this.$container.after('<div class="clearfix"></div>');
  197. this.$loading = this.$container.find('.fixed-table-loading');
  198. this.$el.addClass(this.options.classes);
  199. if (this.options.striped) {
  200. this.$el.addClass('table-striped');
  201. }
  202. };
  203. BootstrapTable.prototype.initTable = function () {
  204. var that = this,
  205. columns = [],
  206. data = [];
  207. this.$header = this.$el.find('thead');
  208. if (!this.$header.length) {
  209. this.$header = $('<thead></thead>').appendTo(this.$el);
  210. }
  211. if (!this.$header.find('tr').length) {
  212. this.$header.append('<tr></tr>');
  213. }
  214. this.$header.find('th').each(function () {
  215. var column = $.extend({}, {
  216. title: $(this).html(),
  217. 'class': $(this).attr('class')
  218. }, $(this).data());
  219. columns.push(column);
  220. });
  221. this.options.columns = $.extend({}, columns, this.options.columns);
  222. $.each(this.options.columns, function (i, column) {
  223. that.options.columns[i] = $.extend({}, BootstrapTable.COLUMN_DEFAULTS,
  224. {field: i}, column); // when field is undefined, use index instead
  225. });
  226. // if options.data is setting, do not process tbody data
  227. if (this.options.data.length) {
  228. return;
  229. }
  230. this.$el.find('tbody tr').each(function () {
  231. var row = {};
  232. $(this).find('td').each(function (i) {
  233. row[that.options.columns[i].field] = $(this).html();
  234. });
  235. data.push(row);
  236. });
  237. this.options.data = data;
  238. };
  239. BootstrapTable.prototype.initHeader = function () {
  240. var that = this,
  241. visibleColumns = [],
  242. html = [];
  243. this.header = {
  244. fields: [],
  245. styles: [],
  246. classes: [],
  247. formatters: [],
  248. events: [],
  249. sorters: [],
  250. clickToSelects: []
  251. };
  252. $.each(this.options.columns, function (i, column) {
  253. var text = '',
  254. style = sprintf('text-align: %s; ', column.align) +
  255. sprintf('vertical-align: %s; ', column.valign),
  256. class_ = sprintf(' class="%s"', column['class']),
  257. order = that.options.sortOrder || column.order;
  258. if (!column.visible) {
  259. return;
  260. }
  261. visibleColumns.push(column);
  262. that.header.fields.push(column.field);
  263. that.header.styles.push(style);
  264. that.header.classes.push(class_);
  265. that.header.formatters.push(column.formatter);
  266. that.header.events.push(column.events);
  267. that.header.sorters.push(column.sorter);
  268. that.header.clickToSelects.push(column.clickToSelect);
  269. if (column.halign) {
  270. style = sprintf('text-align: %s; ', column.halign) +
  271. sprintf('vertical-align: %s; ', column.valign);
  272. }
  273. style += sprintf('width: %spx; ', column.checkbox || column.radio ? 36 : column.width);
  274. html.push('<th',
  275. column.checkbox || column.radio ? ' class="bs-checkbox"' :
  276. class_,
  277. sprintf(' style="%s"', style),
  278. '>');
  279. html.push(sprintf('<div class="th-inner %s">', that.options.sortable && column.sortable ?
  280. 'sortable' : ''));
  281. text = column.title;
  282. if (that.options.sortName === column.field && that.options.sortable && column.sortable) {
  283. text += that.getCaretHtml();
  284. }
  285. if (column.checkbox) {
  286. if (!that.options.singleSelect && that.options.checkboxHeader) {
  287. text = '<input name="btSelectAll" type="checkbox" />';
  288. }
  289. that.header.stateField = column.field;
  290. }
  291. if (column.radio) {
  292. text = '';
  293. that.header.stateField = column.field;
  294. that.options.singleSelect = true;
  295. }
  296. html.push(text);
  297. html.push('</div>');
  298. html.push('<div class="fht-cell"></div>');
  299. html.push('</th>');
  300. });
  301. this.$header.find('tr').html(html.join(''));
  302. this.$header.find('th').each(function (i) {
  303. $(this).data(visibleColumns[i]);
  304. if (that.options.sortable && visibleColumns[i].sortable) {
  305. $(this).off('click').on('click', $.proxy(that.onSort, that));
  306. }
  307. });
  308. if (!this.options.showHeader || this.options.cardView) {
  309. this.$header.hide();
  310. this.$container.find('.fixed-table-header').hide();
  311. this.$loading.css('top', 0);
  312. } else {
  313. this.$header.show();
  314. this.$container.find('.fixed-table-header').show();
  315. this.$loading.css('top', '37px');
  316. }
  317. this.$selectAll = this.$header.find('[name="btSelectAll"]');
  318. this.$selectAll.off('click').on('click', function () {
  319. var checked = $(this).prop('checked');
  320. that[checked ? 'checkAll' : 'uncheckAll']();
  321. });
  322. };
  323. BootstrapTable.prototype.initData = function (data, append) {
  324. if (append) {
  325. this.data = this.data.concat(data);
  326. } else {
  327. this.data = data || this.options.data;
  328. }
  329. this.options.data = this.data;
  330. this.initSort();
  331. };
  332. BootstrapTable.prototype.initSort = function () {
  333. var name = this.options.sortName,
  334. order = this.options.sortOrder === 'desc' ? -1 : 1,
  335. index = $.inArray(this.options.sortName, this.header.fields);
  336. if (index !== -1) {
  337. var sorter = this.header.sorters[index];
  338. this.data.sort(function (a, b) {
  339. if (typeof sorter === 'function') {
  340. return order * sorter(a[name], b[name]);
  341. }
  342. if (typeof sorter === 'string') {
  343. return order * eval(sorter + '(a[name], b[name])'); // eval ?
  344. }
  345. if (a[name] === b[name]) {
  346. return 0;
  347. }
  348. if (a[name] < b[name]) {
  349. return order * -1;
  350. }
  351. return order;
  352. });
  353. }
  354. };
  355. BootstrapTable.prototype.onSort = function (event) {
  356. var $this = $(event.currentTarget),
  357. $this_ = this.$header.find('th').eq($this.index());
  358. this.$header.add(this.$header_).find('span.order').remove();
  359. if (this.options.sortName === $this.data('field')) {
  360. this.options.sortOrder = this.options.sortOrder === 'asc' ? 'desc' : 'asc';
  361. } else {
  362. this.options.sortName = $this.data('field');
  363. this.options.sortOrder = $this.data('order') === 'asc' ? 'desc' : 'asc';
  364. }
  365. this.trigger('sort', this.options.sortName, this.options.sortOrder);
  366. $this.add($this_).data('order', this.options.sortOrder)
  367. .find('.th-inner').append(this.getCaretHtml());
  368. if (this.options.sidePagination === 'server') {
  369. this.initServer();
  370. return;
  371. }
  372. this.initSort();
  373. this.initBody();
  374. };
  375. BootstrapTable.prototype.initToolbar = function () {
  376. var that = this,
  377. html = [],
  378. timeoutId = 0,
  379. $keepOpen,
  380. $search;
  381. this.$toolbar = this.$container.find('.fixed-table-toolbar').html('');
  382. if (typeof this.options.toolbar === 'string') {
  383. $('<div class="bars pull-left"></div>')
  384. .appendTo(this.$toolbar)
  385. .append($(this.options.toolbar));
  386. }
  387. // showColumns, showToggle, showRefresh
  388. html = ['<div class="columns btn-group pull-right">'];
  389. if (this.options.showRefresh) {
  390. html.push('<button class="btn btn-default" type="button" name="refresh">',
  391. '<i class="glyphicon glyphicon-refresh icon-refresh"></i>',
  392. '</button>');
  393. }
  394. if (this.options.showToggle) {
  395. html.push('<button class="btn btn-default" type="button" name="toggle">',
  396. '<i class="glyphicon glyphicon glyphicon-list-alt icon-list-alt"></i>',
  397. '</button>');
  398. }
  399. if (this.options.showColumns) {
  400. html.push(sprintf('<div class="keep-open %s">',
  401. this.options.showRefresh || this.options.showToggle ? 'btn-group' : ''),
  402. '<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',
  403. '<i class="glyphicon glyphicon-th icon-th"></i>',
  404. ' <span class="caret"></span>',
  405. '</button>',
  406. '<ul class="dropdown-menu" role="menu">');
  407. $.each(this.options.columns, function (i, column) {
  408. if (column.radio || column.checkbox) {
  409. return;
  410. }
  411. var checked = column.visible ? ' checked="checked"' : '';
  412. if (column.switchable) {
  413. html.push(sprintf('<li>' +
  414. '<label><input type="checkbox" value="%s"%s> %s</label>' +
  415. '</li>', i, checked, column.title));
  416. }
  417. });
  418. html.push('</ul>',
  419. '</div>');
  420. }
  421. html.push('</div>');
  422. if (html.length > 2) {
  423. this.$toolbar.append(html.join(''));
  424. }
  425. if (this.options.showRefresh) {
  426. this.$toolbar.find('button[name="refresh"]')
  427. .off('click').on('click', $.proxy(this.refresh, this));
  428. }
  429. if (this.options.showToggle) {
  430. this.$toolbar.find('button[name="toggle"]')
  431. .off('click').on('click', function () {
  432. that.options.cardView = !that.options.cardView;
  433. that.initHeader();
  434. that.initBody();
  435. });
  436. }
  437. if (this.options.showColumns) {
  438. $keepOpen = this.$toolbar.find('.keep-open');
  439. $keepOpen.find('li').off('click').on('click', function (event) {
  440. event.stopImmediatePropagation();
  441. });
  442. $keepOpen.find('input').off('click').on('click', function () {
  443. var $this = $(this);
  444. that.toggleColumn($this.val(), $this.prop('checked'), false);
  445. });
  446. }
  447. if (this.options.search) {
  448. html = [];
  449. html.push(
  450. '<div class="pull-right search">',
  451. sprintf('<input class="form-control" type="text" placeholder="%s">',
  452. this.options.formatSearch()),
  453. '</div>');
  454. this.$toolbar.append(html.join(''));
  455. $search = this.$toolbar.find('.search input');
  456. $search.off('keyup').on('keyup', function (event) {
  457. clearTimeout(timeoutId); // doesn't matter if it's 0
  458. timeoutId = setTimeout($.proxy(that.onSearch, that), 500, event); // 500ms
  459. });
  460. }
  461. };
  462. BootstrapTable.prototype.onSearch = function (event) {
  463. var text = $.trim($(event.currentTarget).val());
  464. if (text === this.searchText) {
  465. return;
  466. }
  467. this.searchText = text;
  468. this.options.pageNumber = 1;
  469. this.initSearch();
  470. this.updatePagination();
  471. };
  472. BootstrapTable.prototype.initSearch = function () {
  473. var that = this;
  474. if (this.options.sidePagination !== 'server') {
  475. var s = this.searchText && this.searchText.toLowerCase();
  476. this.data = s ? $.grep(this.options.data, function (item) {
  477. for (var key in item) {
  478. if (that.header.fields.indexOf(key) !== -1 &&
  479. (typeof item[key] === 'string' ||
  480. typeof item[key] === 'number') &&
  481. (item[key] + '').toLowerCase().indexOf(s) !== -1) {
  482. return true;
  483. }
  484. }
  485. return false;
  486. }) : this.options.data;
  487. }
  488. };
  489. BootstrapTable.prototype.initPagination = function () {
  490. this.$pagination = this.$container.find('.fixed-table-pagination');
  491. if (!this.options.pagination) {
  492. return;
  493. }
  494. var that = this,
  495. html = [],
  496. i, from, to,
  497. $pageList,
  498. $first, $pre,
  499. $next, $last,
  500. $number,
  501. data = this.searchText ? this.data : this.options.data;
  502. if (this.options.sidePagination !== 'server') {
  503. this.options.totalRows = data.length;
  504. }
  505. this.totalPages = 0;
  506. if (this.options.totalRows) {
  507. this.totalPages = ~~((this.options.totalRows - 1) / this.options.pageSize) + 1;
  508. }
  509. if (this.totalPages > 0 && this.options.pageNumber > this.totalPages) {
  510. this.options.pageNumber = this.totalPages;
  511. }
  512. this.pageFrom = (this.options.pageNumber - 1) * this.options.pageSize + 1;
  513. this.pageTo = this.options.pageNumber * this.options.pageSize;
  514. if (this.pageTo > this.options.totalRows) {
  515. this.pageTo = this.options.totalRows;
  516. }
  517. html.push(
  518. '<div class="pull-left pagination-detail">',
  519. '<span class="pagination-info">',
  520. this.options.formatShowingRows(this.pageFrom, this.pageTo, this.options.totalRows),
  521. '</span>');
  522. html.push('<span class="page-list">');
  523. var pageNumber = [
  524. '<span class="btn-group dropup">',
  525. '<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',
  526. '<span class="page-size">',
  527. this.options.pageSize,
  528. '</span>',
  529. ' <span class="caret"></span>',
  530. '</button>',
  531. '<ul class="dropdown-menu" role="menu">'],
  532. pageList = this.options.pageList;
  533. if (typeof this.options.pageList === 'string') {
  534. pageList = eval(this.options.pageList);
  535. }
  536. $.each(pageList, function (i, page) {
  537. var active = page === that.options.pageSize ? ' class="active"' : '';
  538. pageNumber.push(sprintf('<li%s><a href="javascript:void(0)">%s</a></li>', active, page));
  539. });
  540. pageNumber.push('</ul></span>');
  541. html.push(this.options.formatRecordsPerPage(pageNumber.join('')));
  542. html.push('</span>');
  543. html.push('</div>',
  544. '<div class="pull-right pagination">',
  545. '<ul class="pagination">',
  546. '<li class="page-first"><a href="javascript:void(0)">&lt;&lt;</a></li>',
  547. '<li class="page-pre"><a href="javascript:void(0)">&lt;</a></li>');
  548. if (this.totalPages < 5) {
  549. from = 1;
  550. to = this.totalPages;
  551. } else {
  552. from = this.options.pageNumber - 2;
  553. to = from + 4;
  554. if (from < 1) {
  555. from = 1;
  556. to = 5;
  557. }
  558. if (to > this.totalPages) {
  559. to = this.totalPages;
  560. from = to - 4;
  561. }
  562. }
  563. for (i = from; i <= to; i++) {
  564. html.push('<li class="page-number' + (i === this.options.pageNumber ? ' active' : '') + '">',
  565. '<a href="javascript:void(0)">', i ,'</a>',
  566. '</li>');
  567. }
  568. html.push(
  569. '<li class="page-next"><a href="javascript:void(0)">&gt;</a></li>',
  570. '<li class="page-last"><a href="javascript:void(0)">&gt;&gt;</a></li>',
  571. '</ul>',
  572. '</div>');
  573. this.$pagination.html(html.join(''));
  574. $pageList = this.$pagination.find('.page-list a');
  575. $first = this.$pagination.find('.page-first');
  576. $pre = this.$pagination.find('.page-pre');
  577. $next = this.$pagination.find('.page-next');
  578. $last = this.$pagination.find('.page-last');
  579. $number = this.$pagination.find('.page-number');
  580. if (this.options.pageNumber <= 1) {
  581. $first.addClass('disabled');
  582. $pre.addClass('disabled');
  583. }
  584. if (this.options.pageNumber >= this.totalPages) {
  585. $next.addClass('disabled');
  586. $last.addClass('disabled');
  587. }
  588. $pageList.off('click').on('click', $.proxy(this.onPageListChange, this));
  589. $first.off('click').on('click', $.proxy(this.onPageFirst, this));
  590. $pre.off('click').on('click', $.proxy(this.onPagePre, this));
  591. $next.off('click').on('click', $.proxy(this.onPageNext, this));
  592. $last.off('click').on('click', $.proxy(this.onPageLast, this));
  593. $number.off('click').on('click', $.proxy(this.onPageNumber, this));
  594. };
  595. BootstrapTable.prototype.updatePagination = function () {
  596. if (!this.options.maintainSelected) {
  597. this.resetRows();
  598. }
  599. this.initPagination();
  600. if (this.options.sidePagination === 'server') {
  601. this.initServer();
  602. } else {
  603. this.initBody();
  604. }
  605. };
  606. BootstrapTable.prototype.onPageListChange = function (event) {
  607. var $this = $(event.currentTarget);
  608. $this.parent().addClass('active').siblings().removeClass('active');
  609. this.options.pageSize = +$this.text();
  610. this.$toolbar.find('.page-size').text(this.options.pageSize);
  611. this.updatePagination();
  612. };
  613. BootstrapTable.prototype.onPageFirst = function () {
  614. this.options.pageNumber = 1;
  615. this.updatePagination();
  616. };
  617. BootstrapTable.prototype.onPagePre = function () {
  618. this.options.pageNumber--;
  619. this.updatePagination();
  620. };
  621. BootstrapTable.prototype.onPageNext = function () {
  622. this.options.pageNumber++;
  623. this.updatePagination();
  624. };
  625. BootstrapTable.prototype.onPageLast = function () {
  626. this.options.pageNumber = this.totalPages;
  627. this.updatePagination();
  628. };
  629. BootstrapTable.prototype.onPageNumber = function (event) {
  630. if (this.options.pageNumber === +$(event.currentTarget).text()) {
  631. return;
  632. }
  633. this.options.pageNumber = +$(event.currentTarget).text();
  634. this.updatePagination();
  635. };
  636. BootstrapTable.prototype.initBody = function (fixedScroll) {
  637. var that = this,
  638. html = [],
  639. data = this.getData();
  640. this.$body = this.$el.find('tbody');
  641. if (!this.$body.length) {
  642. this.$body = $('<tbody></tbody>').appendTo(this.$el);
  643. }
  644. if (this.options.sidePagination === 'server') {
  645. data = this.data;
  646. }
  647. if (!this.options.pagination || this.options.sidePagination === 'server') {
  648. this.pageFrom = 1;
  649. this.pageTo = data.length;
  650. }
  651. for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
  652. var item = data[i],
  653. style = {},
  654. csses = [];
  655. if (typeof this.options.rowStyle === 'function') {
  656. style = this.options.rowStyle(item, i);
  657. } else if (typeof this.options.rowStyle === 'string') {
  658. style = eval(this.options.rowStyle + '(item, i)');
  659. }
  660. if (style && style.css) {
  661. for (var key in style.css) {
  662. csses.push(key + ': ' + style.css[key]);
  663. }
  664. }
  665. html.push('<tr',
  666. sprintf(' class="%s"', style.classes),
  667. sprintf(' data-index="%s"', i),
  668. '>'
  669. );
  670. if (this.options.cardView) {
  671. html.push(sprintf('<td colspan="%s">', this.header.fields.length));
  672. }
  673. $.each(this.header.fields, function (j, field) {
  674. var text = '',
  675. value = item[field],
  676. type = '',
  677. style = sprintf('style="%s"', csses.concat(that.header.styles[j]).join('; '));
  678. if (typeof that.header.formatters[j] === 'function') {
  679. value = that.header.formatters[j](value, item, i);
  680. } else if (typeof that.header.formatters[j] === 'string') {
  681. value = eval(that.header.formatters[j] + '(value, item, i)'); // eval ?
  682. }
  683. if (that.options.columns[j].checkbox || that.options.columns[j].radio) {
  684. //if card view mode bypass
  685. if (that.options.cardView) {
  686. return true;
  687. }
  688. type = that.options.columns[j].checkbox ? 'checkbox' : type;
  689. type = that.options.columns[j].radio ? 'radio' : type;
  690. text = ['<td class="bs-checkbox">',
  691. '<input' +
  692. sprintf(' data-index="%s"', i) +
  693. sprintf(' name="%s"', that.options.selectItemName) +
  694. sprintf(' type="%s"', type) +
  695. sprintf(' value="%s"', item[that.options.idField]) +
  696. sprintf(' checked="%s"', value ? 'checked' : undefined) +
  697. sprintf(' %s', that.options.columns[j].checkboxEnabled ? undefined : 'disabled') +
  698. ' />',
  699. '</td>'].join('');
  700. } else {
  701. value = typeof value === 'undefined' ? that.options.undefinedText : value;
  702. text = that.options.cardView ?
  703. ['<div class="card-view">',
  704. sprintf('<span class="title" %s>%s</span>', style,
  705. getPropertyFromOther(that.options.columns, 'field', 'title', field)),
  706. sprintf('<span class="value">%s</span>', value),
  707. '</div>'].join('') :
  708. [sprintf('<td%s %s>', that.header.classes[j], style),
  709. value,
  710. '</td>'].join('');
  711. }
  712. html.push(text);
  713. });
  714. if (this.options.cardView) {
  715. html.push('</td>');
  716. }
  717. html.push('</tr>');
  718. }
  719. // show no records
  720. if (!html.length) {
  721. html.push('<tr class="no-records-found">',
  722. sprintf('<td colspan="%s">%s</td>', this.header.fields.length, this.options.formatNoMatches()),
  723. '</tr>');
  724. }
  725. this.$body.html(html.join(''));
  726. if (!fixedScroll) {
  727. this.$container.find('.fixed-table-body').scrollTop(0);
  728. }
  729. // click to select by column
  730. this.$body.find('> tr > td').off('click').on('click', function () {
  731. var $tr = $(this).parent();
  732. that.trigger('click-row', that.data[$tr.data('index')], $tr);
  733. // if click to select - then trigger the checkbox/radio click
  734. if (that.options.clickToSelect) {
  735. if (that.header.clickToSelects[$tr.children().index($(this))]) {
  736. $tr.find(sprintf('[name="%s"]',
  737. that.options.selectItemName)).trigger('click');
  738. }
  739. }
  740. });
  741. this.$body.find('tr').off('dblclick').on('dblclick', function () {
  742. that.trigger('dbl-click-row', that.data[$(this).data('index')], $(this));
  743. });
  744. this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName));
  745. this.$selectItem.off('click').on('click', function (event) {
  746. event.stopImmediatePropagation();
  747. // radio trigger click event bug!
  748. if ($(this).is(':radio')) {
  749. $(this).prop('checked', true);
  750. }
  751. var checkAll = that.$selectItem.length === that.$selectItem.filter(':checked').length,
  752. checked = $(this).prop('checked'),
  753. row = that.data[$(this).data('index')];
  754. that.$selectAll.add(that.$selectAll_).prop('checked', checkAll);
  755. row[that.header.stateField] = checked;
  756. that.trigger(checked ? 'check' : 'uncheck', row);
  757. if (that.options.singleSelect) {
  758. that.$selectItem.not(this).each(function () {
  759. that.data[$(this).data('index')][that.header.stateField] = false;
  760. });
  761. that.$selectItem.filter(':checked').not(this).prop('checked', false);
  762. }
  763. that.updateSelected();
  764. });
  765. $.each(this.header.events, function (i, events) {
  766. if (!events) {
  767. return;
  768. }
  769. if (typeof events === 'string') {
  770. events = eval(events);
  771. }
  772. for (var key in events) {
  773. that.$body.find('tr').each(function () {
  774. var $tr = $(this),
  775. $td = $tr.find('td').eq(i),
  776. index = key.indexOf(' '),
  777. name = key.substring(0, index),
  778. el = key.substring(index + 1),
  779. func = events[key];
  780. $td.find(el).off(name).on(name, function (e) {
  781. var index = $tr.data('index'),
  782. row = that.data[index],
  783. value = row[that.header.fields[i]];
  784. func(e, value, row, index);
  785. });
  786. });
  787. }
  788. });
  789. this.updateSelected();
  790. this.resetView();
  791. };
  792. BootstrapTable.prototype.initServer = function (silent) {
  793. var that = this,
  794. data = {},
  795. params = {
  796. pageSize: this.options.pageSize,
  797. pageNumber: this.options.pageNumber,
  798. searchText: this.searchText,
  799. sortName: this.options.sortName,
  800. sortOrder: this.options.sortOrder
  801. };
  802. if (!this.options.url) {
  803. return;
  804. }
  805. if (!silent) {
  806. this.$loading.show();
  807. }
  808. if (this.options.queryParamsType === 'limit') {
  809. params = {
  810. limit: params.pageSize,
  811. offset: params.pageSize * (params.pageNumber - 1),
  812. search: params.searchText,
  813. sort: params.sortName,
  814. order: params.sortOrder
  815. };
  816. }
  817. if (typeof this.options.queryParams === 'function') {
  818. data = this.options.queryParams(params);
  819. } else if (typeof this.options.queryParams === 'string') {
  820. data = eval(this.options.queryParams + '(params)');
  821. }
  822. $.ajax({
  823. type: this.options.method,
  824. url: this.options.url,
  825. data: data,
  826. cache: this.options.cache,
  827. contentType: this.options.contentType,
  828. dataType: 'json',
  829. success: function (res) {
  830. if (typeof that.options.responseHandler === 'function') {
  831. res = that.options.responseHandler(res);
  832. } else if (typeof that.options.responseHandler === 'string') {
  833. res = eval(that.options.responseHandler + '(res)');
  834. }
  835. var data = res;
  836. if (that.options.sidePagination === 'server') {
  837. that.options.totalRows = res.total;
  838. data = res.rows;
  839. }
  840. that.load(data);
  841. that.trigger('load-success', data);
  842. },
  843. error: function (res) {
  844. that.trigger('load-error', res.status);
  845. },
  846. complete: function () {
  847. if (!silent) {
  848. that.$loading.hide();
  849. }
  850. }
  851. });
  852. };
  853. BootstrapTable.prototype.getCaretHtml = function () {
  854. return ['<span class="order' + (this.options.sortOrder === 'desc' ? '' : ' dropup') + '">',
  855. '<span class="caret" style="margin: 10px 5px;"></span>',
  856. '</span>'].join('');
  857. };
  858. BootstrapTable.prototype.updateSelected = function () {
  859. this.$selectItem.each(function () {
  860. $(this).parents('tr')[$(this).prop('checked') ? 'addClass' : 'removeClass']('selected');
  861. });
  862. };
  863. BootstrapTable.prototype.updateRows = function (checked) {
  864. var that = this;
  865. this.$selectItem.each(function () {
  866. that.data[$(this).data('index')][that.header.stateField] = checked;
  867. });
  868. };
  869. BootstrapTable.prototype.resetRows = function () {
  870. var that = this;
  871. $.each(this.data, function (i, row) {
  872. that.$selectAll.prop('checked', false);
  873. that.$selectItem.prop('checked', false);
  874. row[that.header.stateField] = false;
  875. });
  876. };
  877. BootstrapTable.prototype.trigger = function (name) {
  878. var args = Array.prototype.slice.call(arguments, 1);
  879. name += '.bs.table';
  880. this.options[BootstrapTable.EVENTS[name]].apply(this.options, args);
  881. this.$el.trigger($.Event(name), args);
  882. this.options.onAll(name, args);
  883. this.$el.trigger($.Event('all.bs.table'), [name, args]);
  884. };
  885. BootstrapTable.prototype.resetHeader = function () {
  886. var that = this,
  887. $fixedHeader = this.$container.find('.fixed-table-header'),
  888. $fixedBody = this.$container.find('.fixed-table-body'),
  889. scrollWidth = this.$el.width() > $fixedBody.width() ? getScrollBarWidth() : 0;
  890. // fix #61: the hidden table reset header bug.
  891. if (this.$el.is(':hidden')) {
  892. clearTimeout(this.timeoutId_); // doesn't matter if it's 0
  893. this.timeoutId_ = setTimeout($.proxy(this.resetHeader, this), 100); // 100ms
  894. return;
  895. }
  896. this.$header_ = this.$header.clone(true);
  897. this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');
  898. // fix bug: get $el.css('width') error sometime (height = 500)
  899. setTimeout(function () {
  900. $fixedHeader.css({
  901. 'height': '37px',
  902. 'border-bottom': '1px solid #dddddd',
  903. 'margin-right': scrollWidth
  904. }).find('table').css('width', that.$el.css('width'))
  905. .html('').attr('class', that.$el.attr('class'))
  906. .append(that.$header_);
  907. that.$el.css('margin-top', -that.$header.height());
  908. that.$body.find('tr:first-child:not(.no-records-found) > *').each(function(i) {
  909. that.$header_.find('div.fht-cell').eq(i).width($(this).innerWidth());
  910. });
  911. // horizontal scroll event
  912. $fixedBody.off('scroll').on('scroll', function () {
  913. $fixedHeader.scrollLeft($(this).scrollLeft());
  914. });
  915. });
  916. };
  917. BootstrapTable.prototype.toggleColumn = function (index, checked, needUpdate) {
  918. if (index === -1) {
  919. return;
  920. }
  921. this.options.columns[index].visible = checked;
  922. this.initHeader();
  923. this.initSearch();
  924. this.initPagination();
  925. this.initBody();
  926. if (this.options.showColumns) {
  927. var $items = this.$toolbar.find('.keep-open input').prop('disabled', false);
  928. if (needUpdate) {
  929. $items.filter(sprintf('[value="%s"]', index)).prop('checked', checked);
  930. }
  931. if ($items.filter(':checked').length <= this.options.minimumCountColumns) {
  932. $items.filter(':checked').prop('disabled', true);
  933. }
  934. }
  935. };
  936. // PUBLIC FUNCTION DEFINITION
  937. // =======================
  938. BootstrapTable.prototype.resetView = function (params) {
  939. var that = this,
  940. header = this.header;
  941. if (params && params.height) {
  942. this.options.height = params.height;
  943. }
  944. this.$selectAll.prop('checked', this.$selectItem.length > 0 &&
  945. this.$selectItem.length === this.$selectItem.filter(':checked').length);
  946. if (this.options.height) {
  947. var toolbarHeight = +this.$toolbar.children().outerHeight(true),
  948. paginationHeight = +this.$pagination.children().outerHeight(true),
  949. height = this.options.height - toolbarHeight - paginationHeight;
  950. this.$container.find('.fixed-table-container').css('height', height + 'px');
  951. }
  952. if (this.options.cardView) {
  953. // remove the element css
  954. that.$el.css('margin-top', '0');
  955. that.$container.find('.fixed-table-container').css('padding-bottom', '0');
  956. return;
  957. }
  958. if (this.options.showHeader && this.options.height) {
  959. this.resetHeader();
  960. }
  961. if (this.options.height && this.options.showHeader) {
  962. this.$container.find('.fixed-table-container').css('padding-bottom', '37px');
  963. }
  964. };
  965. BootstrapTable.prototype.getData = function () {
  966. return this.searchText ? this.data : this.options.data;
  967. };
  968. BootstrapTable.prototype.load = function (data) {
  969. this.initData(data);
  970. this.initSearch();
  971. this.initPagination();
  972. this.initBody();
  973. };
  974. BootstrapTable.prototype.append = function (data) {
  975. this.initData(data, true);
  976. this.initSearch();
  977. this.initPagination();
  978. this.initBody(true);
  979. };
  980. BootstrapTable.prototype.remove = function (params) {
  981. var len = this.options.data.length,
  982. i, row;
  983. if (!params.hasOwnProperty('field') || !params.hasOwnProperty('values')) {
  984. return;
  985. }
  986. for (i = len - 1; i >= 0; i--) {
  987. row = this.options.data[i];
  988. if (!row.hasOwnProperty(params.field)) {
  989. return;
  990. }
  991. if (params.values.indexOf(row[params.field]) !== -1) {
  992. this.options.data.splice(i, 1);
  993. }
  994. }
  995. if (len === this.options.data.length) {
  996. return;
  997. }
  998. this.initSearch();
  999. this.initPagination();
  1000. this.initBody(true);
  1001. };
  1002. BootstrapTable.prototype.updateRow = function (params) {
  1003. if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) {
  1004. return;
  1005. }
  1006. $.extend(this.data[params.index], params.row);
  1007. this.initBody();
  1008. };
  1009. BootstrapTable.prototype.mergeCells = function (options) {
  1010. var row = options.index,
  1011. col = $.inArray(options.field, this.header.fields),
  1012. rowspan = options.rowspan || 1,
  1013. colspan = options.colspan || 1,
  1014. i, j,
  1015. $tr = this.$body.find('tr'),
  1016. $td = $tr.eq(row).find('td').eq(col);
  1017. if (row < 0 || col < 0 || row >= this.data.length) {
  1018. return;
  1019. }
  1020. for (i = row; i < row + rowspan; i++) {
  1021. for (j = col; j < col + colspan; j++) {
  1022. $tr.eq(i).find('td').eq(j).hide();
  1023. }
  1024. }
  1025. $td.attr('rowspan', rowspan).attr('colspan', colspan)
  1026. .show(10, $.proxy(this.resetView, this));
  1027. };
  1028. BootstrapTable.prototype.getSelections = function () {
  1029. var that = this;
  1030. return $.grep(this.data, function (row) {
  1031. return row[that.header.stateField];
  1032. });
  1033. };
  1034. BootstrapTable.prototype.checkAll = function () {
  1035. this.$selectAll.add(this.$selectAll_).prop('checked', true);
  1036. this.$selectItem.prop('checked', true);
  1037. this.updateRows(true);
  1038. this.updateSelected();
  1039. this.trigger('check-all');
  1040. };
  1041. BootstrapTable.prototype.uncheckAll = function () {
  1042. this.$selectAll.add(this.$selectAll_).prop('checked', false);
  1043. this.$selectItem.prop('checked', false);
  1044. this.updateRows(false);
  1045. this.updateSelected();
  1046. this.trigger('uncheck-all');
  1047. };
  1048. BootstrapTable.prototype.destroy = function () {
  1049. this.$el.insertBefore(this.$container);
  1050. $(this.options.toolbar).insertBefore(this.$el);
  1051. this.$container.next().remove();
  1052. this.$container.remove();
  1053. this.$el.html(this.$el_.html())
  1054. .attr('class', this.$el_.attr('class') || ''); // reset the class
  1055. };
  1056. BootstrapTable.prototype.showLoading = function () {
  1057. this.$loading.show();
  1058. };
  1059. BootstrapTable.prototype.hideLoading = function () {
  1060. this.$loading.hide();
  1061. };
  1062. BootstrapTable.prototype.refresh = function (params) {
  1063. if (params && params.url) {
  1064. this.options.url = params.url;
  1065. }
  1066. this.initServer(params && params.silent);
  1067. };
  1068. BootstrapTable.prototype.showColumn = function (field) {
  1069. this.toggleColumn(getFiledIndex(this.options.columns, field), true, true);
  1070. };
  1071. BootstrapTable.prototype.hideColumn = function (field) {
  1072. this.toggleColumn(getFiledIndex(this.options.columns, field), false, true);
  1073. };
  1074. // BOOTSTRAP TABLE PLUGIN DEFINITION
  1075. // =======================
  1076. $.fn.bootstrapTable = function (option, _relatedTarget) {
  1077. var allowedMethods = [
  1078. 'getSelections', 'getData',
  1079. 'load', 'append', 'remove',
  1080. 'updateRow',
  1081. 'mergeCells',
  1082. 'checkAll', 'uncheckAll',
  1083. 'refresh',
  1084. 'resetView',
  1085. 'destroy',
  1086. 'showLoading', 'hideLoading',
  1087. 'showColumn', 'hideColumn'
  1088. ],
  1089. value;
  1090. this.each(function () {
  1091. var $this = $(this),
  1092. data = $this.data('bootstrap.table'),
  1093. options = $.extend({}, BootstrapTable.DEFAULTS, $this.data(),
  1094. typeof option === 'object' && option);
  1095. if (typeof option === 'string') {
  1096. if ($.inArray(option, allowedMethods) < 0) {
  1097. throw "Unknown method: " + option;
  1098. }
  1099. if (!data) {
  1100. return;
  1101. }
  1102. value = data[option](_relatedTarget);
  1103. if (option === 'destroy') {
  1104. $this.removeData('bootstrap.table');
  1105. }
  1106. }
  1107. if (!data) {
  1108. $this.data('bootstrap.table', (data = new BootstrapTable(this, options)));
  1109. }
  1110. });
  1111. return typeof value === 'undefined' ? this : value;
  1112. };
  1113. $.fn.bootstrapTable.Constructor = BootstrapTable;
  1114. $.fn.bootstrapTable.defaults = BootstrapTable.DEFAULTS;
  1115. $.fn.bootstrapTable.columnDefaults = BootstrapTable.COLUMN_DEFAULTS;
  1116. // BOOTSTRAP TABLE INIT
  1117. // =======================
  1118. $(function () {
  1119. $('[data-toggle="table"]').bootstrapTable();
  1120. });
  1121. }(jQuery);