bootstrap-table-print.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /**
  2. * @update zhixin wen <wenzhixin2010@gmail.com>
  3. */
  4. const Utils = $.fn.bootstrapTable.utils
  5. function printPageBuilderDefault (table) {
  6. return `
  7. <html>
  8. <head>
  9. <style type="text/css" media="print">
  10. @page {
  11. size: auto;
  12. margin: 25px 0 25px 0;
  13. }
  14. </style>
  15. <style type="text/css" media="all">
  16. table {
  17. border-collapse: collapse;
  18. font-size: 12px;
  19. }
  20. table, th, td {
  21. border: 1px solid grey;
  22. }
  23. th, td {
  24. text-align: center;
  25. vertical-align: middle;
  26. }
  27. p {
  28. font-weight: bold;
  29. margin-left:20px;
  30. }
  31. table {
  32. width:94%;
  33. margin-left:3%;
  34. margin-right:3%;
  35. }
  36. div.bs-table-print {
  37. text-align:center;
  38. }
  39. </style>
  40. </head>
  41. <title>Print Table</title>
  42. <body>
  43. <p>Printed on: ${new Date} </p>
  44. <div class="bs-table-print">${table}</div>
  45. </body>
  46. </html>`
  47. }
  48. $.extend($.fn.bootstrapTable.locales, {
  49. formatPrint () {
  50. return 'Print'
  51. }
  52. })
  53. $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
  54. $.extend($.fn.bootstrapTable.defaults, {
  55. showPrint: false,
  56. printAsFilteredAndSortedOnUI: true,
  57. printSortColumn: undefined,
  58. printSortOrder: 'asc',
  59. printPageBuilder (table) {
  60. return printPageBuilderDefault(table)
  61. }
  62. })
  63. $.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
  64. printFilter: undefined,
  65. printIgnore: false,
  66. printFormatter: undefined
  67. })
  68. $.extend($.fn.bootstrapTable.defaults.icons, {
  69. print: {
  70. bootstrap3: 'glyphicon-print icon-share',
  71. 'bootstrap-table': 'icon-printer'
  72. }[$.fn.bootstrapTable.theme] || 'fa-print'
  73. })
  74. $.BootstrapTable = class extends $.BootstrapTable {
  75. init (...args) {
  76. super.init(...args)
  77. if (!this.options.showPrint) {
  78. return
  79. }
  80. this.mergedCells = []
  81. }
  82. initToolbar (...args) {
  83. this.showToolbar = this.showToolbar || this.options.showPrint
  84. if (this.options.showPrint) {
  85. this.buttons = Object.assign(this.buttons, {
  86. print: {
  87. text: this.options.formatPrint(),
  88. icon: this.options.icons.print,
  89. event: () => {
  90. this.doPrint(this.options.printAsFilteredAndSortedOnUI ? this.getData() : this.options.data.slice(0))
  91. },
  92. attributes: {
  93. 'aria-label': this.options.formatPrint(),
  94. title: this.options.formatPrint()
  95. }
  96. }
  97. })
  98. }
  99. super.initToolbar(...args)
  100. }
  101. mergeCells (options) {
  102. super.mergeCells(options)
  103. if (!this.options.showPrint) {
  104. return
  105. }
  106. let col = this.getVisibleFields().indexOf(options.field)
  107. if (Utils.hasDetailViewIcon(this.options)) {
  108. col += 1
  109. }
  110. this.mergedCells.push({
  111. row: options.index,
  112. col,
  113. rowspan: options.rowspan || 1,
  114. colspan: options.colspan || 1
  115. })
  116. }
  117. doPrint (data) {
  118. const formatValue = (row, i, column) => {
  119. const value = Utils.calculateObjectValue(column, column.printFormatter,
  120. [row[column.field], row, i], row[column.field])
  121. return typeof value === 'undefined' || value === null ?
  122. this.options.undefinedText : value
  123. }
  124. const buildTable = (data, columnsArray) => {
  125. const dir = this.$el.attr('dir') || 'ltr'
  126. const html = [`<table dir="${dir}"><thead>`]
  127. for (const columns of columnsArray) {
  128. html.push('<tr>')
  129. for (let h = 0; h < columns.length; h++) {
  130. if (!columns[h].printIgnore) {
  131. html.push(
  132. `<th
  133. ${Utils.sprintf(' rowspan="%s"', columns[h].rowspan)}
  134. ${Utils.sprintf(' colspan="%s"', columns[h].colspan)}
  135. >${columns[h].title}</th>`)
  136. }
  137. }
  138. html.push('</tr>')
  139. }
  140. html.push('</thead><tbody>')
  141. const dontRender = []
  142. if (this.mergedCells) {
  143. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  144. const currentMergedCell = this.mergedCells[mc]
  145. for (let rs = 0; rs < currentMergedCell.rowspan; rs++) {
  146. const row = currentMergedCell.row + rs
  147. for (let cs = 0; cs < currentMergedCell.colspan; cs++) {
  148. const col = currentMergedCell.col + cs
  149. dontRender.push(`${row },${ col}`)
  150. }
  151. }
  152. }
  153. }
  154. for (let i = 0; i < data.length; i++) {
  155. html.push('<tr>')
  156. const columns = columnsArray.flat(1)
  157. columns.sort((c1, c2) => {
  158. return c1.colspanIndex - c2.colspanIndex
  159. })
  160. for (let j = 0; j < columns.length; j++) {
  161. if (columns[j].colspanGroup > 0) continue
  162. let rowspan = 0
  163. let colspan = 0
  164. if (this.mergedCells) {
  165. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  166. const currentMergedCell = this.mergedCells[mc]
  167. if (currentMergedCell.col === j && currentMergedCell.row === i) {
  168. rowspan = currentMergedCell.rowspan
  169. colspan = currentMergedCell.colspan
  170. }
  171. }
  172. }
  173. if (
  174. !columns[j].printIgnore && columns[j].field &&
  175. (
  176. !dontRender.includes(`${i },${ j}`) ||
  177. (rowspan > 0 && colspan > 0)
  178. )
  179. ) {
  180. if (rowspan > 0 && colspan > 0) {
  181. html.push(`<td ${Utils.sprintf(' rowspan="%s"', rowspan)} ${Utils.sprintf(' colspan="%s"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>')
  182. } else {
  183. html.push('<td>', formatValue(data[i], i, columns[j]), '</td>')
  184. }
  185. }
  186. }
  187. html.push('</tr>')
  188. }
  189. html.push('</tbody>')
  190. if (this.options.showFooter) {
  191. html.push('<footer><tr>')
  192. for (const columns of columnsArray) {
  193. for (let h = 0; h < columns.length; h++) {
  194. if (!columns[h].printIgnore) {
  195. const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))
  196. const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')
  197. html.push(`<th>${footerValue}</th>`)
  198. }
  199. }
  200. }
  201. html.push('</tr></footer>')
  202. }
  203. html.push('</table>')
  204. return html.join('')
  205. }
  206. const sortRows = (data, colName, sortOrder) => {
  207. if (!colName) {
  208. return data
  209. }
  210. let reverse = sortOrder !== 'asc'
  211. reverse = -((+reverse) || -1)
  212. return data.sort((a, b) => reverse * (a[colName].localeCompare(b[colName])))
  213. }
  214. const filterRow = (row, filters) => {
  215. for (let index = 0; index < filters.length; ++index) {
  216. if (row[filters[index].colName] !== filters[index].value) {
  217. return false
  218. }
  219. }
  220. return true
  221. }
  222. const filterRows = (data, filters) => data.filter(row => filterRow(row, filters))
  223. const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({
  224. colName: col.field,
  225. value: col.printFilter
  226. }))
  227. data = filterRows(data, getColumnFilters(this.options.columns))
  228. data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder)
  229. const table = buildTable(data, this.options.columns)
  230. const newWin = window.open('')
  231. newWin.document.write(this.options.printPageBuilder.call(this, table))
  232. newWin.document.close()
  233. newWin.focus()
  234. newWin.print()
  235. newWin.close()
  236. }
  237. }