bootstrap-table-multiple-sort.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. /**
  2. * @author Nadim Basalamah <dimbslmh@gmail.com>
  3. * @version: v1.1.0
  4. * https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js
  5. * Modification: ErwannNevou <https://github.com/ErwannNevou>
  6. */
  7. let isSingleSort = false
  8. const Utils = $.fn.bootstrapTable.utils
  9. $.extend($.fn.bootstrapTable.defaults.icons, {
  10. plus: {
  11. bootstrap3: 'glyphicon-plus',
  12. bootstrap4: 'fa-plus',
  13. bootstrap5: 'bi-plus',
  14. semantic: 'fa-plus',
  15. materialize: 'plus',
  16. foundation: 'fa-plus',
  17. bulma: 'fa-plus',
  18. 'bootstrap-table': 'icon-plus'
  19. }[$.fn.bootstrapTable.theme] || 'fa-clock',
  20. minus: {
  21. bootstrap3: 'glyphicon-minus',
  22. bootstrap4: 'fa-minus',
  23. bootstrap5: 'bi-dash',
  24. semantic: 'fa-minus',
  25. materialize: 'minus',
  26. foundation: 'fa-minus',
  27. bulma: 'fa-minus',
  28. 'bootstrap-table': 'icon-minus'
  29. }[$.fn.bootstrapTable.theme] || 'fa-clock',
  30. sort: {
  31. bootstrap3: 'glyphicon-sort',
  32. bootstrap4: 'fa-sort',
  33. bootstrap5: 'bi-arrow-down-up',
  34. semantic: 'fa-sort',
  35. materialize: 'sort',
  36. foundation: 'fa-sort',
  37. bulma: 'fa-sort',
  38. 'bootstrap-table': 'icon-sort-amount-asc'
  39. }[$.fn.bootstrapTable.theme] || 'fa-clock'
  40. })
  41. const theme = {
  42. bootstrap3: {
  43. html: {
  44. multipleSortModal: `
  45. <div class="modal fade" id="%s" tabindex="-1" role="dialog" aria-labelledby="%sLabel" aria-hidden="true">
  46. <div class="modal-dialog">
  47. <div class="modal-content">
  48. <div class="modal-header">
  49. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  50. <h4 class="modal-title" id="%sLabel">%s</h4>
  51. </div>
  52. <div class="modal-body">
  53. <div class="bootstrap-table">
  54. <div class="fixed-table-toolbar">
  55. <div class="bars">
  56. <div id="toolbar">
  57. <button id="add" type="button" class="btn btn-default">%s %s</button>
  58. <button id="delete" type="button" class="btn btn-default" disabled>%s %s</button>
  59. </div>
  60. </div>
  61. </div>
  62. <div class="fixed-table-container">
  63. <table id="multi-sort" class="table">
  64. <thead>
  65. <tr>
  66. <th></th>
  67. <th><div class="th-inner">%s</div></th>
  68. <th><div class="th-inner">%s</div></th>
  69. </tr>
  70. </thead>
  71. <tbody></tbody>
  72. </table>
  73. </div>
  74. </div>
  75. </div>
  76. <div class="modal-footer">
  77. <button type="button" class="btn btn-default" data-dismiss="modal">%s</button>
  78. <button type="button" class="btn btn-primary multi-sort-order-button">%s</button>
  79. </div>
  80. </div>
  81. </div>
  82. </div>
  83. `,
  84. multipleSortButton: '<button class="multi-sort %s" type="button" data-toggle="modal" data-target="#%s" title="%s">%s</button>',
  85. multipleSortSelect: '<select class="%s %s form-control">'
  86. }
  87. },
  88. bootstrap4: {
  89. html: {
  90. multipleSortModal: `
  91. <div class="modal fade" id="%s" tabindex="-1" role="dialog" aria-labelledby="%sLabel" aria-hidden="true">
  92. <div class="modal-dialog" role="document">
  93. <div class="modal-content">
  94. <div class="modal-header">
  95. <h5 class="modal-title" id="%sLabel">%s</h5>
  96. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  97. <span aria-hidden="true">&times;</span>
  98. </button>
  99. </div>
  100. <div class="modal-body">
  101. <div class="bootstrap-table">
  102. <div class="fixed-table-toolbar">
  103. <div class="bars">
  104. <div id="toolbar" class="pb-3">
  105. <button id="add" type="button" class="btn btn-secondary">%s %s</button>
  106. <button id="delete" type="button" class="btn btn-secondary" disabled>%s %s</button>
  107. </div>
  108. </div>
  109. </div>
  110. <div class="fixed-table-container">
  111. <table id="multi-sort" class="table">
  112. <thead>
  113. <tr>
  114. <th></th>
  115. <th><div class="th-inner">%s</div></th>
  116. <th><div class="th-inner">%s</div></th>
  117. </tr>
  118. </thead>
  119. <tbody></tbody>
  120. </table>
  121. </div>
  122. </div>
  123. </div>
  124. <div class="modal-footer">
  125. <button type="button" class="btn btn-secondary" data-dismiss="modal">%s</button>
  126. <button type="button" class="btn btn-primary multi-sort-order-button">%s</button>
  127. </div>
  128. </div>
  129. </div>
  130. </div>
  131. `,
  132. multipleSortButton: '<button class="multi-sort %s" type="button" data-toggle="modal" data-target="#%s" title="%s">%s</button>',
  133. multipleSortSelect: '<select class="%s %s form-control">'
  134. }
  135. },
  136. bootstrap5: {
  137. html: {
  138. multipleSortModal: `
  139. <div class="modal fade" id="%s" tabindex="-1" role="dialog" aria-labelledby="%sLabel" aria-hidden="true">
  140. <div class="modal-dialog" role="document">
  141. <div class="modal-content">
  142. <div class="modal-header">
  143. <h5 class="modal-title" id="%sLabel">%s</h5>
  144. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
  145. </div>
  146. <div class="modal-body">
  147. <div class="bootstrap-table">
  148. <div class="fixed-table-toolbar">
  149. <div class="bars">
  150. <div id="toolbar" class="pb-3">
  151. <button id="add" type="button" class="btn btn-secondary">%s %s</button>
  152. <button id="delete" type="button" class="btn btn-secondary" disabled>%s %s</button>
  153. </div>
  154. </div>
  155. </div>
  156. <div class="fixed-table-container">
  157. <table id="multi-sort" class="table">
  158. <thead>
  159. <tr>
  160. <th></th>
  161. <th><div class="th-inner">%s</div></th>
  162. <th><div class="th-inner">%s</div></th>
  163. </tr>
  164. </thead>
  165. <tbody></tbody>
  166. </table>
  167. </div>
  168. </div>
  169. </div>
  170. <div class="modal-footer">
  171. <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">%s</button>
  172. <button type="button" class="btn btn-primary multi-sort-order-button">%s</button>
  173. </div>
  174. </div>
  175. </div>
  176. </div>
  177. `,
  178. multipleSortButton: '<button class="multi-sort %s" type="button" data-bs-toggle="modal" data-bs-target="#%s" title="%s">%s</button>',
  179. multipleSortSelect: '<select class="%s %s form-control">'
  180. }
  181. },
  182. semantic: {
  183. html: {
  184. multipleSortModal: `
  185. <div class="ui modal tiny" id="%s" aria-labelledby="%sLabel" aria-hidden="true">
  186. <i class="close icon"></i>
  187. <div class="header" id="%sLabel">
  188. %s
  189. </div>
  190. <div class="image content">
  191. <div class="bootstrap-table">
  192. <div class="fixed-table-toolbar">
  193. <div class="bars">
  194. <div id="toolbar" class="pb-3">
  195. <button id="add" type="button" class="ui button">%s %s</button>
  196. <button id="delete" type="button" class="ui button" disabled>%s %s</button>
  197. </div>
  198. </div>
  199. </div>
  200. <div class="fixed-table-container">
  201. <table id="multi-sort" class="table">
  202. <thead>
  203. <tr>
  204. <th></th>
  205. <th><div class="th-inner">%s</div></th>
  206. <th><div class="th-inner">%s</div></th>
  207. </tr>
  208. </thead>
  209. <tbody></tbody>
  210. </table>
  211. </div>
  212. </div>
  213. </div>
  214. <div class="actions">
  215. <div class="ui button deny">%s</div>
  216. <div class="ui button approve multi-sort-order-button">%s</div>
  217. </div>
  218. </div>
  219. `,
  220. multipleSortButton: '<button class="multi-sort %s" type="button" data-toggle="modal" data-target="#%s" title="%s">%s</button>',
  221. multipleSortSelect: '<select class="%s %s">'
  222. }
  223. },
  224. materialize: {
  225. html: {
  226. multipleSortModal: `
  227. <div id="%s" class="modal" aria-labelledby="%sLabel" aria-hidden="true">
  228. <div class="modal-content" id="%sLabel">
  229. <h4>%s</h4>
  230. <div class="bootstrap-table">
  231. <div class="fixed-table-toolbar">
  232. <div class="bars">
  233. <div id="toolbar" class="pb-3">
  234. <button id="add" type="button" class="waves-effect waves-light btn">%s %s</button>
  235. <button id="delete" type="button" class="waves-effect waves-light btn" disabled>%s %s</button>
  236. </div>
  237. </div>
  238. </div>
  239. <div class="fixed-table-container">
  240. <table id="multi-sort" class="table">
  241. <thead>
  242. <tr>
  243. <th></th>
  244. <th><div class="th-inner">%s</div></th>
  245. <th><div class="th-inner">%s</div></th>
  246. </tr>
  247. </thead>
  248. <tbody></tbody>
  249. </table>
  250. </div>
  251. </div>
  252. <div class="modal-footer">
  253. <a href="javascript:void(0)" class="modal-close waves-effect waves-light btn">%s</a>
  254. <a href="javascript:void(0)" class="modal-close waves-effect waves-light btn multi-sort-order-button">%s</a>
  255. </div>
  256. </div>
  257. </div>
  258. `,
  259. multipleSortButton: '<a class="multi-sort %s modal-trigger" href="#%s" type="button" data-toggle="modal" title="%s">%s</a>',
  260. multipleSortSelect: '<select class="%s %s browser-default">'
  261. }
  262. },
  263. foundation: {
  264. html: {
  265. multipleSortModal: `
  266. <div class="reveal" id="%s" data-reveal aria-labelledby="%sLabel" aria-hidden="true">
  267. <div id="%sLabel">
  268. <h1>%s</h1>
  269. <div class="bootstrap-table">
  270. <div class="fixed-table-toolbar">
  271. <div class="bars">
  272. <div id="toolbar" class="padding-bottom-2">
  273. <button id="add" type="button" class="waves-effect waves-light button">%s %s</button>
  274. <button id="delete" type="button" class="waves-effect waves-light button" disabled>%s %s</button>
  275. </div>
  276. </div>
  277. </div>
  278. <div class="fixed-table-container">
  279. <table id="multi-sort" class="table">
  280. <thead>
  281. <tr>
  282. <th></th>
  283. <th><div class="th-inner">%s</div></th>
  284. <th><div class="th-inner">%s</div></th>
  285. </tr>
  286. </thead>
  287. <tbody></tbody>
  288. </table>
  289. </div>
  290. </div>
  291. <button class="waves-effect waves-light button" data-close aria-label="Close modal" type="button">
  292. <span aria-hidden="true">%s</span>
  293. </button>
  294. <button class="waves-effect waves-light button multi-sort-order-button" data-close aria-label="Order" type="button">
  295. <span aria-hidden="true">%s</span>
  296. </button>
  297. </div>
  298. </div>
  299. `,
  300. multipleSortButton: '<button class="multi-sort %s" data-open="%s" title="%s">%s</button>',
  301. multipleSortSelect: '<select class="%s %s browser-default">'
  302. }
  303. },
  304. bulma: {
  305. html: {
  306. multipleSortModal: `
  307. <div class="modal" id="%s" aria-labelledby="%sLabel" aria-hidden="true">
  308. <div class="modal-background"></div>
  309. <div class="modal-content" id="%sLabel">
  310. <div class="box">
  311. <h2>%s</h2>
  312. <div class="bootstrap-table">
  313. <div class="fixed-table-toolbar">
  314. <div class="bars">
  315. <div id="toolbar" class="padding-bottom-2">
  316. <button id="add" type="button" class="waves-effect waves-light button">%s %s</button>
  317. <button id="delete" type="button" class="waves-effect waves-light button" disabled>%s %s</button>
  318. </div>
  319. </div>
  320. </div>
  321. <div class="fixed-table-container">
  322. <table id="multi-sort" class="table">
  323. <thead>
  324. <tr>
  325. <th></th>
  326. <th><div class="th-inner">%s</div></th>
  327. <th><div class="th-inner">%s</div></th>
  328. </tr>
  329. </thead>
  330. <tbody></tbody>
  331. </table>
  332. </div>
  333. </div>
  334. <button type="button" class="waves-effect waves-light button" data-close>%s</button>
  335. <button type="button" class="waves-effect waves-light button multi-sort-order-button" data-close>%s</button>
  336. </div>
  337. </div>
  338. </div>
  339. `,
  340. multipleSortButton: '<button class="multi-sort %s" data-target="%s" title="%s">%s</button>',
  341. multipleSortSelect: '<select class="%s %s browser-default">'
  342. }
  343. },
  344. 'bootstrap-table': {
  345. html: {
  346. multipleSortModal: `
  347. <div class="modal" id="%s" aria-labelledby="%sLabel" aria-hidden="true">
  348. <div class="modal-background"></div>
  349. <div class="modal-content" id="%sLabel">
  350. <div class="box">
  351. <h2>%s</h2>
  352. <div class="bootstrap-table">
  353. <div class="fixed-table-toolbar">
  354. <div class="bars">
  355. <div id="toolbar" class="padding-bottom-2">
  356. <button id="add" type="button" class="btn">%s %s</button>
  357. <button id="delete" type="button" class="btn" disabled>%s %s</button>
  358. </div>
  359. </div>
  360. </div>
  361. <div class="fixed-table-container">
  362. <table id="multi-sort" class="table">
  363. <thead>
  364. <tr>
  365. <th></th>
  366. <th><div class="th-inner">%s</div></th>
  367. <th><div class="th-inner">%s</div></th>
  368. </tr>
  369. </thead>
  370. <tbody></tbody>
  371. </table>
  372. </div>
  373. </div>
  374. <div class="mt-30">
  375. <button type="button" class="btn" data-close>%s</button>
  376. <button type="button" class="btn multi-sort-order-button" data-close>%s</button>
  377. </div>
  378. </div>
  379. </div>
  380. </div>
  381. `,
  382. multipleSortButton: '<button class="multi-sort %s" data-target="%s" title="%s">%s</button>',
  383. multipleSortSelect: '<select class="%s %s browser-default">'
  384. }
  385. }
  386. }[$.fn.bootstrapTable.theme]
  387. const showSortModal = that => {
  388. const _selector = that.sortModalSelector
  389. const _id = `#${_selector}`
  390. const o = that.options
  391. if (!$(_id).hasClass('modal')) {
  392. const sModal = Utils.sprintf(
  393. theme.html.multipleSortModal,
  394. _selector, _selector, _selector,
  395. that.options.formatMultipleSort(),
  396. Utils.sprintf(that.constants.html.icon, o.iconsPrefix, o.icons.plus),
  397. that.options.formatAddLevel(),
  398. Utils.sprintf(that.constants.html.icon, o.iconsPrefix, o.icons.minus),
  399. that.options.formatDeleteLevel(),
  400. that.options.formatColumn(),
  401. that.options.formatOrder(),
  402. that.options.formatCancel(),
  403. that.options.formatSort()
  404. )
  405. $('body').append($(sModal))
  406. that.$sortModal = $(_id)
  407. const $rows = that.$sortModal.find('tbody > tr')
  408. that.$sortModal.off('click', '#add').on('click', '#add', () => {
  409. const total = that.$sortModal.find('.multi-sort-name:first option').length
  410. let current = that.$sortModal.find('tbody tr').length
  411. if (current < total) {
  412. current++
  413. that.addLevel()
  414. that.setButtonStates()
  415. }
  416. })
  417. that.$sortModal.off('click', '#delete').on('click', '#delete', () => {
  418. const total = that.$sortModal.find('.multi-sort-name:first option').length
  419. let current = that.$sortModal.find('tbody tr').length
  420. if (current > 1 && current <= total) {
  421. current--
  422. that.$sortModal.find('tbody tr:last').remove()
  423. that.setButtonStates()
  424. }
  425. })
  426. that.$sortModal.off('click', '.multi-sort-order-button').on('click', '.multi-sort-order-button', () => {
  427. const $rows = that.$sortModal.find('tbody > tr')
  428. let $alert = that.$sortModal.find('div.alert')
  429. const fields = []
  430. const results = []
  431. const sortPriority = $.map($rows, row => {
  432. const $row = $(row)
  433. const name = $row.find('.multi-sort-name').val()
  434. const order = $row.find('.multi-sort-order').val()
  435. fields.push(name)
  436. return {
  437. sortName: name,
  438. sortOrder: order
  439. }
  440. })
  441. const sorted_fields = fields.sort()
  442. for (let i = 0; i < fields.length - 1; i++) {
  443. if (sorted_fields[i + 1] === sorted_fields[i]) {
  444. results.push(sorted_fields[i])
  445. }
  446. }
  447. if (results.length > 0) {
  448. if ($alert.length === 0) {
  449. $alert = `<div class="alert alert-danger" role="alert"><strong>${that.options.formatDuplicateAlertTitle()}</strong> ${that.options.formatDuplicateAlertDescription()}</div>`
  450. $($alert).insertBefore(that.$sortModal.find('.bars'))
  451. }
  452. } else {
  453. if ($alert.length === 1) {
  454. $($alert).remove()
  455. }
  456. if (['bootstrap3', 'bootstrap4', 'bootstrap5'].includes($.fn.bootstrapTable.theme)) {
  457. that.$sortModal.modal('hide')
  458. }
  459. that.multiSort(sortPriority)
  460. }
  461. })
  462. if (that.options.sortPriority === null || that.options.sortPriority.length === 0) {
  463. if (that.options.sortName) {
  464. that.options.sortPriority = [{
  465. sortName: that.options.sortName,
  466. sortOrder: that.options.sortOrder
  467. }]
  468. }
  469. }
  470. if (that.options.sortPriority !== null && that.options.sortPriority.length > 0) {
  471. if ($rows.length < that.options.sortPriority.length && typeof that.options.sortPriority === 'object') {
  472. for (let i = 0; i < that.options.sortPriority.length; i++) {
  473. that.addLevel(i, that.options.sortPriority[i])
  474. }
  475. }
  476. } else {
  477. that.addLevel(0)
  478. }
  479. that.setButtonStates()
  480. }
  481. }
  482. $.fn.bootstrapTable.methods.push('multipleSort')
  483. $.fn.bootstrapTable.methods.push('multiSort')
  484. $.extend($.fn.bootstrapTable.defaults, {
  485. showMultiSort: false,
  486. showMultiSortButton: true,
  487. multiSortStrictSort: false,
  488. sortPriority: null,
  489. onMultipleSort () {
  490. return false
  491. }
  492. })
  493. $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
  494. 'multiple-sort.bs.table': 'onMultipleSort'
  495. })
  496. $.extend($.fn.bootstrapTable.locales, {
  497. formatMultipleSort () {
  498. return 'Multiple Sort'
  499. },
  500. formatAddLevel () {
  501. return 'Add Level'
  502. },
  503. formatDeleteLevel () {
  504. return 'Delete Level'
  505. },
  506. formatColumn () {
  507. return 'Column'
  508. },
  509. formatOrder () {
  510. return 'Order'
  511. },
  512. formatSortBy () {
  513. return 'Sort by'
  514. },
  515. formatThenBy () {
  516. return 'Then by'
  517. },
  518. formatSort () {
  519. return 'Sort'
  520. },
  521. formatCancel () {
  522. return 'Cancel'
  523. },
  524. formatDuplicateAlertTitle () {
  525. return 'Duplicate(s) detected!'
  526. },
  527. formatDuplicateAlertDescription () {
  528. return 'Please remove or change any duplicate column.'
  529. },
  530. formatSortOrders () {
  531. return {
  532. asc: 'Ascending',
  533. desc: 'Descending'
  534. }
  535. }
  536. })
  537. $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
  538. const BootstrapTable = $.fn.bootstrapTable.Constructor
  539. const _initToolbar = BootstrapTable.prototype.initToolbar
  540. const _destroy = BootstrapTable.prototype.destroy
  541. BootstrapTable.prototype.initToolbar = function (...args) {
  542. this.showToolbar = this.showToolbar || this.options.showMultiSort
  543. const that = this
  544. const sortModalSelector = `sortModal_${this.$el.attr('id')}`
  545. const sortModalId = `#${sortModalSelector}`
  546. const $multiSortBtn = this.$toolbar.find('div.multi-sort')
  547. const o = this.options
  548. this.$sortModal = $(sortModalId)
  549. this.sortModalSelector = sortModalSelector
  550. if (that.options.sortPriority !== null) {
  551. that.onMultipleSort()
  552. }
  553. if (this.options.showMultiSort && this.options.showMultiSortButton) {
  554. this.buttons = Object.assign(this.buttons, {
  555. multipleSort: {
  556. html: Utils.sprintf(theme.html.multipleSortButton,
  557. that.constants.buttonsClass, that.sortModalSelector, this.options.formatMultipleSort(),
  558. Utils.sprintf(that.constants.html.icon, o.iconsPrefix, o.icons.sort))
  559. }
  560. })
  561. }
  562. _initToolbar.apply(this, Array.prototype.slice.apply(args))
  563. if (that.options.sidePagination === 'server' && !isSingleSort && that.options.sortPriority !== null) {
  564. const t = that.options.queryParams
  565. that.options.queryParams = params => {
  566. params.multiSort = that.options.sortPriority
  567. return t(params)
  568. }
  569. }
  570. if (this.options.showMultiSort) {
  571. if (!$multiSortBtn.length && this.options.showMultiSortButton) {
  572. if ($.fn.bootstrapTable.theme === 'semantic') {
  573. this.$toolbar.find('.multi-sort').on('click', () => {
  574. $(sortModalId).modal('show')
  575. })
  576. } else if ($.fn.bootstrapTable.theme === 'materialize') {
  577. this.$toolbar.find('.multi-sort').on('click', () => {
  578. $(sortModalId).modal()
  579. })
  580. } else if ($.fn.bootstrapTable.theme === 'bootstrap-table') {
  581. this.$toolbar.find('.multi-sort').on('click', () => {
  582. $(sortModalId).addClass('show')
  583. })
  584. } else if ($.fn.bootstrapTable.theme === 'foundation') {
  585. this.$toolbar.find('.multi-sort').on('click', () => {
  586. if (!this.foundationModal) {
  587. // eslint-disable-next-line no-undef
  588. this.foundationModal = new Foundation.Reveal($(sortModalId))
  589. }
  590. this.foundationModal.open()
  591. })
  592. } else if ($.fn.bootstrapTable.theme === 'bulma') {
  593. this.$toolbar.find('.multi-sort').on('click', () => {
  594. $('html').toggleClass('is-clipped')
  595. $(sortModalId).toggleClass('is-active')
  596. $('button[data-close]').one('click', () => {
  597. $('html').toggleClass('is-clipped')
  598. $(sortModalId).toggleClass('is-active')
  599. })
  600. })
  601. }
  602. showSortModal(that)
  603. }
  604. this.$el.on('sort.bs.table', () => {
  605. isSingleSort = true
  606. })
  607. this.$el.on('multiple-sort.bs.table', () => {
  608. isSingleSort = false
  609. })
  610. this.$el.on('load-success.bs.table', () => {
  611. if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object' && that.options.sidePagination !== 'server') {
  612. that.onMultipleSort()
  613. }
  614. })
  615. this.$el.on('column-switch.bs.table', (field, checked) => {
  616. if (that.options.sortPriority !== null && that.options.sortPriority.length > 0) {
  617. for (let i = 0; i < that.options.sortPriority.length; i++) {
  618. if (that.options.sortPriority[i].sortName === checked) {
  619. that.options.sortPriority.splice(i, 1)
  620. }
  621. }
  622. that.assignSortableArrows()
  623. }
  624. that.$sortModal.remove()
  625. showSortModal(that)
  626. })
  627. this.$el.on('reset-view.bs.table', () => {
  628. if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') {
  629. that.assignSortableArrows()
  630. }
  631. })
  632. }
  633. }
  634. BootstrapTable.prototype.destroy = function (...args) {
  635. _destroy.apply(this, Array.prototype.slice.apply(args))
  636. if (this.options.showMultiSort) {
  637. this.enableCustomSort = false
  638. this.$sortModal.remove()
  639. }
  640. }
  641. BootstrapTable.prototype.multipleSort = function () {
  642. const that = this
  643. if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object' && that.options.sidePagination !== 'server') {
  644. that.onMultipleSort()
  645. }
  646. }
  647. BootstrapTable.prototype.onMultipleSort = function () {
  648. const that = this
  649. const cmp = (x, y) => x > y ? 1 : x < y ? -1 : 0
  650. const arrayCmp = (a, b) => {
  651. const arr1 = []
  652. const arr2 = []
  653. for (let i = 0; i < that.options.sortPriority.length; i++) {
  654. let fieldName = that.options.sortPriority[i].sortName
  655. const fieldIndex = that.header.fields.indexOf(fieldName)
  656. const sorterName = that.header.sorters[that.header.fields.indexOf(fieldName)]
  657. if (that.header.sortNames[fieldIndex]) {
  658. fieldName = that.header.sortNames[fieldIndex]
  659. }
  660. const order = that.options.sortPriority[i].sortOrder === 'desc' ? -1 : 1
  661. let aa = Utils.getItemField(a, fieldName)
  662. let bb = Utils.getItemField(b, fieldName)
  663. const value1 = $.fn.bootstrapTable.utils.calculateObjectValue(that.header, sorterName, [aa, bb])
  664. const value2 = $.fn.bootstrapTable.utils.calculateObjectValue(that.header, sorterName, [bb, aa])
  665. if (value1 !== undefined && value2 !== undefined) {
  666. arr1.push(order * value1)
  667. arr2.push(order * value2)
  668. continue
  669. }
  670. if (aa === undefined || aa === null) aa = ''
  671. if (bb === undefined || bb === null) bb = ''
  672. if ($.isNumeric(aa) && $.isNumeric(bb)) {
  673. aa = parseFloat(aa)
  674. bb = parseFloat(bb)
  675. } else {
  676. aa = aa.toString()
  677. bb = bb.toString()
  678. if (that.options.multiSortStrictSort) {
  679. aa = aa.toLowerCase()
  680. bb = bb.toLowerCase()
  681. }
  682. }
  683. arr1.push(order * cmp(aa, bb))
  684. arr2.push(order * cmp(bb, aa))
  685. }
  686. return cmp(arr1, arr2)
  687. }
  688. this.enableCustomSort = true
  689. this.data.sort((a, b) => arrayCmp(a, b))
  690. this.initBody()
  691. this.assignSortableArrows()
  692. this.trigger('multiple-sort')
  693. }
  694. BootstrapTable.prototype.addLevel = function (index, sortPriority) {
  695. const text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy()
  696. this.$sortModal.find('tbody')
  697. .append($('<tr>')
  698. .append($('<td>').text(text))
  699. .append($('<td>').append($(Utils.sprintf(theme.html.multipleSortSelect, this.constants.classes.paginationDropdown, 'multi-sort-name'))))
  700. .append($('<td>').append($(Utils.sprintf(theme.html.multipleSortSelect, this.constants.classes.paginationDropdown, 'multi-sort-order'))))
  701. )
  702. const $multiSortName = this.$sortModal.find('.multi-sort-name').last()
  703. const $multiSortOrder = this.$sortModal.find('.multi-sort-order').last()
  704. $.each(this.columns, (i, column) => {
  705. if (column.sortable === false || column.visible === false) {
  706. return true
  707. }
  708. $multiSortName.append(`<option value="${column.field}">${column.title}</option>`)
  709. })
  710. $.each(this.options.formatSortOrders(), (value, order) => {
  711. $multiSortOrder.append(`<option value="${value}">${order}</option>`)
  712. })
  713. if (sortPriority !== undefined) {
  714. $multiSortName.find(`option[value="${sortPriority.sortName}"]`).attr('selected', true)
  715. $multiSortOrder.find(`option[value="${sortPriority.sortOrder}"]`).attr('selected', true)
  716. }
  717. }
  718. BootstrapTable.prototype.assignSortableArrows = function () {
  719. const that = this
  720. const headers = that.$header.find('th')
  721. for (let i = 0; i < headers.length; i++) {
  722. for (let c = 0; c < that.options.sortPriority.length; c++) {
  723. if ($(headers[i]).data('field') === that.options.sortPriority[c].sortName) {
  724. $(headers[i]).find('.sortable').removeClass('desc asc').addClass(that.options.sortPriority[c].sortOrder)
  725. }
  726. }
  727. }
  728. }
  729. BootstrapTable.prototype.setButtonStates = function () {
  730. const total = this.$sortModal.find('.multi-sort-name:first option').length
  731. const current = this.$sortModal.find('tbody tr').length
  732. if (current === total) {
  733. this.$sortModal.find('#add').attr('disabled', 'disabled')
  734. }
  735. if (current > 1) {
  736. this.$sortModal.find('#delete').removeAttr('disabled')
  737. }
  738. if (current < total) {
  739. this.$sortModal.find('#add').removeAttr('disabled')
  740. }
  741. if (current === 1) {
  742. this.$sortModal.find('#delete').attr('disabled', 'disabled')
  743. }
  744. }
  745. BootstrapTable.prototype.multiSort = function (sortPriority) {
  746. this.options.sortPriority = sortPriority
  747. this.options.sortName = undefined
  748. if (this.options.sidePagination === 'server') {
  749. const queryParams = this.options.queryParams
  750. this.options.queryParams = params => {
  751. params.multiSort = this.options.sortPriority
  752. return $.fn.bootstrapTable.utils.calculateObjectValue(this.options, queryParams, [params])
  753. }
  754. isSingleSort = false
  755. this.initServer(this.options.silentSort)
  756. return
  757. }
  758. this.onMultipleSort()
  759. }