bootstrap-table-toolbar.js 12 KB

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