bootstrap-table-toolbar.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /**
  2. * @author: aperez <aperez@datadec.es>
  3. * @version: v2.0.0
  4. *
  5. * @update Dennis Hernández
  6. * @update zhixin wen <wenzhixin2010@gmail.com>
  7. */
  8. const Utils = $.fn.bootstrapTable.utils
  9. const theme = {
  10. bootstrap3: {
  11. icons: {
  12. advancedSearchIcon: 'glyphicon-chevron-down'
  13. },
  14. classes: {},
  15. html: {
  16. modal: `
  17. <div id="avdSearchModal_%s" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
  18. <div class="modal-dialog modal-xs">
  19. <div class="modal-content">
  20. <div class="modal-header">
  21. <button class="close toolbar-modal-close" data-dismiss="modal" aria-label="Close">
  22. <span aria-hidden="true">&times;</span>
  23. </button>
  24. <h4 class="modal-title toolbar-modal-title"></h4>
  25. </div>
  26. <div class="modal-body toolbar-modal-body"></div>
  27. <div class="modal-footer toolbar-modal-footer">
  28. <button class="btn btn-%s toolbar-modal-close"></button>
  29. </div>
  30. </div>
  31. </div>
  32. </div>
  33. `
  34. }
  35. },
  36. bootstrap4: {
  37. icons: {
  38. advancedSearchIcon: 'fa-chevron-down'
  39. },
  40. classes: {},
  41. html: {
  42. modal: `
  43. <div id="avdSearchModal_%s" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
  44. <div class="modal-dialog modal-xs">
  45. <div class="modal-content">
  46. <div class="modal-header">
  47. <h4 class="modal-title toolbar-modal-title"></h4>
  48. <button class="close toolbar-modal-close" data-dismiss="modal" aria-label="Close">
  49. <span aria-hidden="true">&times;</span>
  50. </button>
  51. </div>
  52. <div class="modal-body toolbar-modal-body"></div>
  53. <div class="modal-footer toolbar-modal-footer">
  54. <button class="btn btn-%s toolbar-modal-close"></button>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. `
  60. }
  61. },
  62. bootstrap5: {
  63. icons: {
  64. advancedSearchIcon: 'bi-chevron-down'
  65. },
  66. classes: {
  67. formGroup: 'mb-3'
  68. },
  69. html: {
  70. modal: `
  71. <div id="avdSearchModal_%s" class="modal fade" tabindex="-1" aria-hidden="true">
  72. <div class="modal-dialog modal-xs">
  73. <div class="modal-content">
  74. <div class="modal-header">
  75. <h5 class="modal-title toolbar-modal-title"></h5>
  76. <button class="btn-close toolbar-modal-close" data-bs-dismiss="modal" aria-label="Close"></button>
  77. </div>
  78. <div class="modal-body toolbar-modal-body"></div>
  79. <div class="modal-footer toolbar-modal-footer">
  80. <button class="btn btn-%s toolbar-modal-close"></button>
  81. </div>
  82. </div>
  83. </div>
  84. </div>
  85. `
  86. }
  87. },
  88. bulma: {
  89. icons: {
  90. advancedSearchIcon: 'fa-chevron-down'
  91. },
  92. classes: {},
  93. html: {
  94. modal: `
  95. <div class="modal" id="avdSearchModal_%s">
  96. <div class="modal-background"></div>
  97. <div class="modal-card">
  98. <header class="modal-card-head">
  99. <p class="modal-card-title toolbar-modal-title"></p>
  100. <button class="delete toolbar-modal-close"></button>
  101. </header>
  102. <section class="modal-card-body toolbar-modal-body"></section>
  103. <footer class="modal-card-foot toolbar-modal-footer">
  104. <button class="button button-%s toolbar-modal-close"></button>
  105. </footer>
  106. </div>
  107. </div>
  108. `
  109. }
  110. },
  111. foundation: {
  112. icons: {
  113. advancedSearchIcon: 'fa-chevron-down'
  114. },
  115. classes: {},
  116. html: {
  117. modal: `
  118. <div class="reveal" id="avdSearchModal_%s" data-reveal>
  119. <h1 class="toolbar-modal-title"></h1>
  120. <div class="toolbar-modal-body"></div>
  121. <button class="close-button toolbar-modal-close" data-close aria-label="Close modal">
  122. <span aria-hidden="true">&times;</span>
  123. </button>
  124. <div class="toolbar-modal-footer">
  125. <button class="button button-%s toolbar-modal-close"></button>
  126. </div>
  127. </div>
  128. `
  129. }
  130. },
  131. materialize: {
  132. icons: {
  133. advancedSearchIcon: 'expand_more'
  134. },
  135. classes: {},
  136. html: {
  137. modal: `
  138. <div id="avdSearchModal_%s" class="modal">
  139. <div class="modal-content">
  140. <h4 class="toolbar-modal-title"></h4>
  141. <div class="toolbar-modal-body"></div>
  142. </div>
  143. <div class="modal-footer toolbar-modal-footer">
  144. <a href="javascript:void(0)" class="modal-close waves-effect waves-green btn-flat btn-%s toolbar-modal-close"></a>
  145. </div>
  146. </div>
  147. `
  148. }
  149. },
  150. semantic: {
  151. icons: {
  152. advancedSearchIcon: 'fa-chevron-down'
  153. },
  154. classes: {},
  155. html: {
  156. modal: `
  157. <div class="ui modal" id="avdSearchModal_%s">
  158. <i class="close icon toolbar-modal-close"></i>
  159. <div class="header toolbar-modal-title""></div>
  160. <div class="image content ui form toolbar-modal-body"></div>
  161. <div class="actions toolbar-modal-footer">
  162. <div class="ui black deny button button-%s toolbar-modal-close"></div>
  163. </div>
  164. </div>
  165. `
  166. }
  167. }
  168. }[$.fn.bootstrapTable.theme]
  169. Object.assign($.fn.bootstrapTable.defaults, {
  170. advancedSearch: false,
  171. idForm: 'advancedSearch',
  172. actionForm: '',
  173. idTable: undefined,
  174. // eslint-disable-next-line no-unused-vars
  175. onColumnAdvancedSearch (field, text) {
  176. return false
  177. }
  178. })
  179. Object.assign($.fn.bootstrapTable.defaults.icons, {
  180. advancedSearchIcon: theme.icons.advancedSearchIcon
  181. })
  182. Object.assign($.fn.bootstrapTable.events, {
  183. 'column-advanced-search.bs.table': 'onColumnAdvancedSearch'
  184. })
  185. Object.assign($.fn.bootstrapTable.locales, {
  186. formatAdvancedSearch () {
  187. return 'Advanced search'
  188. },
  189. formatAdvancedCloseButton () {
  190. return 'Close'
  191. }
  192. })
  193. Object.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
  194. $.BootstrapTable = class extends $.BootstrapTable {
  195. initToolbar () {
  196. this.showToolbar = this.showToolbar ||
  197. this.options.search &&
  198. this.options.advancedSearch &&
  199. this.options.idTable
  200. if (this.showToolbar) {
  201. this.buttons = Object.assign(this.buttons, {
  202. advancedSearch: {
  203. text: this.options.formatAdvancedSearch(),
  204. icon: this.options.icons.advancedSearchIcon,
  205. event: this.showAdvancedSearch,
  206. attributes: {
  207. 'aria-label': this.options.formatAdvancedSearch(),
  208. title: this.options.formatAdvancedSearch()
  209. }
  210. }
  211. })
  212. if (Utils.isEmptyObject(this.filterColumnsPartial)) {
  213. this.filterColumnsPartial = {}
  214. }
  215. }
  216. super.initToolbar()
  217. }
  218. showAdvancedSearch () {
  219. this.$toolbarModal = $(`#avdSearchModal_${this.options.idTable}`)
  220. if (this.$toolbarModal.length <= 0) {
  221. $('body').append(Utils.sprintf(theme.html.modal,
  222. this.options.idTable, this.options.buttonsClass))
  223. this.$toolbarModal = $(`#avdSearchModal_${this.options.idTable}`)
  224. this.$toolbarModal.find('.toolbar-modal-close')
  225. .off('click')
  226. .on('click', () => this.hideToolbarModal())
  227. }
  228. this.initToolbarModalBody()
  229. this.showToolbarModal()
  230. }
  231. initToolbarModalBody () {
  232. this.$toolbarModal.find('.toolbar-modal-title')
  233. .html(this.options.formatAdvancedSearch())
  234. this.$toolbarModal.find('.toolbar-modal-footer .toolbar-modal-close')
  235. .html(this.options.formatAdvancedCloseButton())
  236. this.$toolbarModal.find('.toolbar-modal-body')
  237. .html(this.createToolbarForm())
  238. .off('keyup blur', 'input').on('keyup blur', 'input', e => {
  239. this.onColumnAdvancedSearch(e)
  240. })
  241. }
  242. showToolbarModal () {
  243. const theme = $.fn.bootstrapTable.theme
  244. if (['bootstrap3', 'bootstrap4'].includes(theme)) {
  245. this.$toolbarModal.modal()
  246. } else if (theme === 'bootstrap5') {
  247. if (!this.toolbarModal) {
  248. this.toolbarModal = new window.bootstrap.Modal(this.$toolbarModal[0], {})
  249. }
  250. this.toolbarModal.show()
  251. } else if (theme === 'bulma') {
  252. this.$toolbarModal.toggleClass('is-active')
  253. } else if (theme === 'foundation') {
  254. if (!this.toolbarModal) {
  255. this.toolbarModal = new window.Foundation.Reveal(this.$toolbarModal)
  256. }
  257. this.toolbarModal.open()
  258. } else if (theme === 'materialize') {
  259. this.$toolbarModal.modal().modal('open')
  260. } else if (theme === 'semantic') {
  261. this.$toolbarModal.modal('show')
  262. }
  263. }
  264. hideToolbarModal () {
  265. const theme = $.fn.bootstrapTable.theme
  266. if (['bootstrap3', 'bootstrap4'].includes(theme)) {
  267. this.$toolbarModal.modal('hide')
  268. } else if (theme === 'bootstrap5') {
  269. this.toolbarModal.hide()
  270. } else if (theme === 'bulma') {
  271. $('html').toggleClass('is-clipped')
  272. this.$toolbarModal.toggleClass('is-active')
  273. } else if (theme === 'foundation') {
  274. this.toolbarModal.close()
  275. } else if (theme === 'materialize') {
  276. this.$toolbarModal.modal('open')
  277. } else if (theme === 'semantic') {
  278. this.$toolbarModal.modal('close')
  279. }
  280. if (this.options.sidePagination === 'server') {
  281. this.options.pageNumber = 1
  282. this.updatePagination()
  283. this.trigger('column-advanced-search', this.filterColumnsPartial)
  284. }
  285. }
  286. createToolbarForm () {
  287. const html = [
  288. `<form class="form-horizontal toolbar-model-form" action="${this.options.actionForm}">`
  289. ]
  290. for (const column of this.columns) {
  291. if (!column.checkbox && column.visible && column.searchable) {
  292. const title = $('<div/>').html(column.title).text().trim()
  293. const value = this.filterColumnsPartial[column.field] || ''
  294. html.push(`
  295. <div class="form-group row ${theme.classes.formGroup || ''}">
  296. <label class="col-sm-4 control-label">${title}</label>
  297. <div class="col-sm-6">
  298. <input type="text" class="form-control ${this.constants.classes.input}"
  299. name="${column.field}" placeholder="${title}" value="${value}">
  300. </div>
  301. </div>
  302. `)
  303. }
  304. }
  305. html.push('</form>')
  306. return html.join('')
  307. }
  308. initSearch () {
  309. super.initSearch()
  310. if (!this.options.advancedSearch || this.options.sidePagination === 'server') {
  311. return
  312. }
  313. const fp = Utils.isEmptyObject(this.filterColumnsPartial) ? null : this.filterColumnsPartial
  314. this.data = fp ? this.data.filter((item, i) => {
  315. for (const [key, v] of Object.entries(fp)) {
  316. const val = v.toLowerCase()
  317. let value = item[key]
  318. const index = this.header.fields.indexOf(key)
  319. value = Utils.calculateObjectValue(this.header,
  320. this.header.formatters[index], [value, item, i], value)
  321. if (
  322. !(index !== -1 &&
  323. (typeof value === 'string' || typeof value === 'number') &&
  324. `${value}`.toLowerCase().includes(val))
  325. ) {
  326. return false
  327. }
  328. }
  329. return true
  330. }) : this.data
  331. this.unsortedData = [...this.data]
  332. }
  333. onColumnAdvancedSearch (e) {
  334. const text = $(e.currentTarget).val().trim()
  335. const field = $(e.currentTarget).attr('name')
  336. if (text) {
  337. this.filterColumnsPartial[field] = text
  338. } else {
  339. delete this.filterColumnsPartial[field]
  340. }
  341. if (this.options.sidePagination !== 'server') {
  342. this.options.pageNumber = 1
  343. this.initSearch()
  344. this.updatePagination()
  345. this.trigger('column-advanced-search', field, text)
  346. }
  347. }
  348. }