bootstrap-table-multiple-sort.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. (function (global, factory) {
  2. if (typeof define === "function" && define.amd) {
  3. define([], factory);
  4. } else if (typeof exports !== "undefined") {
  5. factory();
  6. } else {
  7. var mod = {
  8. exports: {}
  9. };
  10. factory();
  11. global.bootstrapTableMultipleSort = mod.exports;
  12. }
  13. })(this, function () {
  14. 'use strict';
  15. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  16. return typeof obj;
  17. } : function (obj) {
  18. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  19. };
  20. /**
  21. * @author Nadim Basalamah <dimbslmh@gmail.com>
  22. * @version: v1.1.0
  23. * https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js
  24. * Modification: ErwannNevou <https://github.com/ErwannNevou>
  25. */
  26. (function ($) {
  27. 'use strict';
  28. var isSingleSort = false;
  29. var showSortModal = function showSortModal(that) {
  30. var _selector = that.sortModalSelector,
  31. _id = '#' + _selector;
  32. if (!$(_id).hasClass("modal")) {
  33. var sModal = ' <div class="modal fade" id="' + _selector + '" tabindex="-1" role="dialog" aria-labelledby="' + _selector + 'Label" aria-hidden="true">';
  34. sModal += ' <div class="modal-dialog">';
  35. sModal += ' <div class="modal-content">';
  36. sModal += ' <div class="modal-header">';
  37. sModal += ' <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
  38. sModal += ' <h4 class="modal-title" id="' + _selector + 'Label">' + that.options.formatMultipleSort() + '</h4>';
  39. sModal += ' </div>';
  40. sModal += ' <div class="modal-body">';
  41. sModal += ' <div class="bootstrap-table">';
  42. sModal += ' <div class="fixed-table-toolbar">';
  43. sModal += ' <div class="bars">';
  44. sModal += ' <div id="toolbar">';
  45. sModal += ' <button id="add" type="button" class="btn btn-default"><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.plus + '"></i> ' + that.options.formatAddLevel() + '</button>';
  46. sModal += ' <button id="delete" type="button" class="btn btn-default" disabled><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.minus + '"></i> ' + that.options.formatDeleteLevel() + '</button>';
  47. sModal += ' </div>';
  48. sModal += ' </div>';
  49. sModal += ' </div>';
  50. sModal += ' <div class="fixed-table-container">';
  51. sModal += ' <table id="multi-sort" class="table">';
  52. sModal += ' <thead>';
  53. sModal += ' <tr>';
  54. sModal += ' <th></th>';
  55. sModal += ' <th><div class="th-inner">' + that.options.formatColumn() + '</div></th>';
  56. sModal += ' <th><div class="th-inner">' + that.options.formatOrder() + '</div></th>';
  57. sModal += ' </tr>';
  58. sModal += ' </thead>';
  59. sModal += ' <tbody></tbody>';
  60. sModal += ' </table>';
  61. sModal += ' </div>';
  62. sModal += ' </div>';
  63. sModal += ' </div>';
  64. sModal += ' <div class="modal-footer">';
  65. sModal += ' <button type="button" class="btn btn-default" data-dismiss="modal">' + that.options.formatCancel() + '</button>';
  66. sModal += ' <button type="button" class="btn btn-primary">' + that.options.formatSort() + '</button>';
  67. sModal += ' </div>';
  68. sModal += ' </div>';
  69. sModal += ' </div>';
  70. sModal += ' </div>';
  71. $('body').append($(sModal));
  72. that.$sortModal = $(_id);
  73. var $rows = that.$sortModal.find('tbody > tr');
  74. that.$sortModal.off('click', '#add').on('click', '#add', function () {
  75. var total = that.$sortModal.find('.multi-sort-name:first option').length,
  76. current = that.$sortModal.find('tbody tr').length;
  77. if (current < total) {
  78. current++;
  79. that.addLevel();
  80. that.setButtonStates();
  81. }
  82. });
  83. that.$sortModal.off('click', '#delete').on('click', '#delete', function () {
  84. var total = that.$sortModal.find('.multi-sort-name:first option').length,
  85. current = that.$sortModal.find('tbody tr').length;
  86. if (current > 1 && current <= total) {
  87. current--;
  88. that.$sortModal.find('tbody tr:last').remove();
  89. that.setButtonStates();
  90. }
  91. });
  92. that.$sortModal.off('click', '.btn-primary').on('click', '.btn-primary', function () {
  93. var $rows = that.$sortModal.find('tbody > tr'),
  94. $alert = that.$sortModal.find('div.alert'),
  95. fields = [],
  96. results = [];
  97. that.options.sortPriority = $.map($rows, function (row) {
  98. var $row = $(row),
  99. name = $row.find('.multi-sort-name').val(),
  100. order = $row.find('.multi-sort-order').val();
  101. fields.push(name);
  102. return {
  103. sortName: name,
  104. sortOrder: order
  105. };
  106. });
  107. var sorted_fields = fields.sort();
  108. for (var i = 0; i < fields.length - 1; i++) {
  109. if (sorted_fields[i + 1] == sorted_fields[i]) {
  110. results.push(sorted_fields[i]);
  111. }
  112. }
  113. if (results.length > 0) {
  114. if ($alert.length === 0) {
  115. $alert = '<div class="alert alert-danger" role="alert"><strong>' + that.options.formatDuplicateAlertTitle() + '</strong> ' + that.options.formatDuplicateAlertDescription() + '</div>';
  116. $($alert).insertBefore(that.$sortModal.find('.bars'));
  117. }
  118. } else {
  119. if ($alert.length === 1) {
  120. $($alert).remove();
  121. }
  122. that.$sortModal.modal('hide');
  123. that.options.sortName = '';
  124. if (that.options.sidePagination === 'server') {
  125. var t = that.options.queryParams;
  126. that.options.queryParams = function (params) {
  127. params.multiSort = that.options.sortPriority;
  128. return t(params);
  129. };
  130. isSingleSort = false;
  131. that.initServer(that.options.silentSort);
  132. return;
  133. }
  134. that.onMultipleSort();
  135. }
  136. });
  137. if (that.options.sortPriority === null || that.options.sortPriority.length === 0) {
  138. if (that.options.sortName) {
  139. that.options.sortPriority = [{
  140. sortName: that.options.sortName,
  141. sortOrder: that.options.sortOrder
  142. }];
  143. }
  144. }
  145. if (that.options.sortPriority !== null && that.options.sortPriority.length > 0) {
  146. if ($rows.length < that.options.sortPriority.length && _typeof(that.options.sortPriority) === 'object') {
  147. for (var i = 0; i < that.options.sortPriority.length; i++) {
  148. that.addLevel(i, that.options.sortPriority[i]);
  149. }
  150. }
  151. } else {
  152. that.addLevel(0);
  153. }
  154. that.setButtonStates();
  155. }
  156. };
  157. $.fn.bootstrapTable.methods.push('multipleSort');
  158. $.extend($.fn.bootstrapTable.defaults, {
  159. showMultiSort: false,
  160. showMultiSortButton: true,
  161. sortPriority: null,
  162. onMultipleSort: function onMultipleSort() {
  163. return false;
  164. }
  165. });
  166. $.extend($.fn.bootstrapTable.defaults.icons, {
  167. sort: 'glyphicon-sort',
  168. plus: 'glyphicon-plus',
  169. minus: 'glyphicon-minus'
  170. });
  171. $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
  172. 'multiple-sort.bs.table': 'onMultipleSort'
  173. });
  174. $.extend($.fn.bootstrapTable.locales, {
  175. formatMultipleSort: function formatMultipleSort() {
  176. return 'Multiple Sort';
  177. },
  178. formatAddLevel: function formatAddLevel() {
  179. return 'Add Level';
  180. },
  181. formatDeleteLevel: function formatDeleteLevel() {
  182. return 'Delete Level';
  183. },
  184. formatColumn: function formatColumn() {
  185. return 'Column';
  186. },
  187. formatOrder: function formatOrder() {
  188. return 'Order';
  189. },
  190. formatSortBy: function formatSortBy() {
  191. return 'Sort by';
  192. },
  193. formatThenBy: function formatThenBy() {
  194. return 'Then by';
  195. },
  196. formatSort: function formatSort() {
  197. return 'Sort';
  198. },
  199. formatCancel: function formatCancel() {
  200. return 'Cancel';
  201. },
  202. formatDuplicateAlertTitle: function formatDuplicateAlertTitle() {
  203. return 'Duplicate(s) detected!';
  204. },
  205. formatDuplicateAlertDescription: function formatDuplicateAlertDescription() {
  206. return 'Please remove or change any duplicate column.';
  207. },
  208. formatSortOrders: function formatSortOrders() {
  209. return {
  210. asc: 'Ascending',
  211. desc: 'Descending'
  212. };
  213. }
  214. });
  215. $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
  216. var BootstrapTable = $.fn.bootstrapTable.Constructor,
  217. _initToolbar = BootstrapTable.prototype.initToolbar;
  218. BootstrapTable.prototype.initToolbar = function () {
  219. this.showToolbar = this.showToolbar || this.options.showMultiSort;
  220. var that = this,
  221. sortModalSelector = 'sortModal_' + this.$el.attr('id'),
  222. sortModalId = '#' + sortModalSelector;
  223. this.$sortModal = $(sortModalId);
  224. this.sortModalSelector = sortModalSelector;
  225. _initToolbar.apply(this, Array.prototype.slice.apply(arguments));
  226. if (that.options.sidePagination === 'server' && !isSingleSort && that.options.sortPriority !== null) {
  227. var t = that.options.queryParams;
  228. that.options.queryParams = function (params) {
  229. params.multiSort = that.options.sortPriority;
  230. return t(params);
  231. };
  232. }
  233. if (this.options.showMultiSort) {
  234. var $btnGroup = this.$toolbar.find('>.btn-group').first(),
  235. $multiSortBtn = this.$toolbar.find('div.multi-sort');
  236. if (!$multiSortBtn.length && this.options.showMultiSortButton) {
  237. $multiSortBtn = ' <button class="multi-sort btn btn-default' + (this.options.iconSize === undefined ? '' : ' btn-' + this.options.iconSize) + '" type="button" data-toggle="modal" data-target="' + sortModalId + '" title="' + this.options.formatMultipleSort() + '">';
  238. $multiSortBtn += ' <i class="' + this.options.iconsPrefix + ' ' + this.options.icons.sort + '"></i>';
  239. $multiSortBtn += '</button>';
  240. $btnGroup.append($multiSortBtn);
  241. showSortModal(that);
  242. }
  243. this.$el.on('sort.bs.table', function () {
  244. isSingleSort = true;
  245. });
  246. this.$el.on('multiple-sort.bs.table', function () {
  247. isSingleSort = false;
  248. });
  249. this.$el.on('load-success.bs.table', function () {
  250. if (!isSingleSort && that.options.sortPriority !== null && _typeof(that.options.sortPriority) === 'object' && that.options.sidePagination !== 'server') {
  251. that.onMultipleSort();
  252. }
  253. });
  254. this.$el.on('column-switch.bs.table', function (field, checked) {
  255. for (var i = 0; i < that.options.sortPriority.length; i++) {
  256. if (that.options.sortPriority[i].sortName === checked) {
  257. that.options.sortPriority.splice(i, 1);
  258. }
  259. }
  260. that.assignSortableArrows();
  261. that.$sortModal.remove();
  262. showSortModal(that);
  263. });
  264. this.$el.on('reset-view.bs.table', function () {
  265. if (!isSingleSort && that.options.sortPriority !== null && _typeof(that.options.sortPriority) === 'object') {
  266. that.assignSortableArrows();
  267. }
  268. });
  269. }
  270. };
  271. BootstrapTable.prototype.multipleSort = function () {
  272. var that = this;
  273. if (!isSingleSort && that.options.sortPriority !== null && _typeof(that.options.sortPriority) === 'object' && that.options.sidePagination !== 'server') {
  274. that.onMultipleSort();
  275. }
  276. };
  277. BootstrapTable.prototype.onMultipleSort = function () {
  278. var that = this;
  279. var cmp = function cmp(x, y) {
  280. return x > y ? 1 : x < y ? -1 : 0;
  281. };
  282. var arrayCmp = function arrayCmp(a, b) {
  283. var arr1 = [],
  284. arr2 = [];
  285. for (var i = 0; i < that.options.sortPriority.length; i++) {
  286. var order = that.options.sortPriority[i].sortOrder === 'desc' ? -1 : 1,
  287. aa = a[that.options.sortPriority[i].sortName],
  288. bb = b[that.options.sortPriority[i].sortName];
  289. if (aa === undefined || aa === null) {
  290. aa = '';
  291. }
  292. if (bb === undefined || bb === null) {
  293. bb = '';
  294. }
  295. if ($.isNumeric(aa) && $.isNumeric(bb)) {
  296. aa = parseFloat(aa);
  297. bb = parseFloat(bb);
  298. }
  299. if (typeof aa !== 'string') {
  300. aa = aa.toString();
  301. }
  302. arr1.push(order * cmp(aa, bb));
  303. arr2.push(order * cmp(bb, aa));
  304. }
  305. return cmp(arr1, arr2);
  306. };
  307. this.data.sort(function (a, b) {
  308. return arrayCmp(a, b);
  309. });
  310. this.initBody();
  311. this.assignSortableArrows();
  312. this.trigger('multiple-sort');
  313. };
  314. BootstrapTable.prototype.addLevel = function (index, sortPriority) {
  315. var text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();
  316. this.$sortModal.find('tbody').append($('<tr>').append($('<td>').text(text)).append($('<td>').append($('<select class="form-control multi-sort-name">'))).append($('<td>').append($('<select class="form-control multi-sort-order">'))));
  317. var $multiSortName = this.$sortModal.find('.multi-sort-name').last(),
  318. $multiSortOrder = this.$sortModal.find('.multi-sort-order').last();
  319. $.each(this.columns, function (i, column) {
  320. if (column.sortable === false || column.visible === false) {
  321. return true;
  322. }
  323. $multiSortName.append('<option value="' + column.field + '">' + column.title + '</option>');
  324. });
  325. $.each(this.options.formatSortOrders(), function (value, order) {
  326. $multiSortOrder.append('<option value="' + value + '">' + order + '</option>');
  327. });
  328. if (sortPriority !== undefined) {
  329. $multiSortName.find('option[value="' + sortPriority.sortName + '"]').attr("selected", true);
  330. $multiSortOrder.find('option[value="' + sortPriority.sortOrder + '"]').attr("selected", true);
  331. }
  332. };
  333. BootstrapTable.prototype.assignSortableArrows = function () {
  334. var that = this,
  335. headers = that.$header.find('th');
  336. for (var i = 0; i < headers.length; i++) {
  337. for (var c = 0; c < that.options.sortPriority.length; c++) {
  338. if ($(headers[i]).data('field') === that.options.sortPriority[c].sortName) {
  339. $(headers[i]).find('.sortable').removeClass('desc asc').addClass(that.options.sortPriority[c].sortOrder);
  340. }
  341. }
  342. }
  343. };
  344. BootstrapTable.prototype.setButtonStates = function () {
  345. var total = this.$sortModal.find('.multi-sort-name:first option').length,
  346. current = this.$sortModal.find('tbody tr').length;
  347. if (current == total) {
  348. this.$sortModal.find('#add').attr('disabled', 'disabled');
  349. }
  350. if (current > 1) {
  351. this.$sortModal.find('#delete').removeAttr('disabled');
  352. }
  353. if (current < total) {
  354. this.$sortModal.find('#add').removeAttr('disabled');
  355. }
  356. if (current == 1) {
  357. this.$sortModal.find('#delete').attr('disabled', 'disabled');
  358. }
  359. };
  360. })(jQuery);
  361. });