UNPKG

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