bootstrap-table-multiple-sort.js 29 KB

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