bootstrap-table-multiple-sort.js 30 KB

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