-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Fix issues table export.jquery.plugin deprecated #8070 #8071
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||
| * @author zhixin wen <wenzhixin2010@gmail.com> | ||||||||||||||||||||||||||||||||||||||||||
| * extensions: https://github.com/hhurz/tableExport.jquery.plugin | ||||||||||||||||||||||||||||||||||||||||||
| * Built-in export implementation (replacing deprecated tableExport.jquery.plugin) | ||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const Utils = $.fn.bootstrapTable.utils | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -179,10 +179,165 @@ $.BootstrapTable = class extends $.BootstrapTable { | |||||||||||||||||||||||||||||||||||||||||
| const stateField = this.header.stateField | ||||||||||||||||||||||||||||||||||||||||||
| const isCardView = o.cardView | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Helper: escape CSV field | ||||||||||||||||||||||||||||||||||||||||||
| const csvEscape = (value, delimiter) => { | ||||||||||||||||||||||||||||||||||||||||||
| const d = delimiter || ',' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (value === null || value === undefined) return '' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const str = String(value) | ||||||||||||||||||||||||||||||||||||||||||
| const mustQuote = str.includes(d) || str.includes('"') || str.includes('\n') || str.includes('\r') | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (!mustQuote) return str | ||||||||||||||||||||||||||||||||||||||||||
| return `"${str.replace(/"/g, '""')}"` | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Helper: build a 2D array of visible table content from DOM | ||||||||||||||||||||||||||||||||||||||||||
| const collectTableMatrix = ignoreColumnIdxs => { | ||||||||||||||||||||||||||||||||||||||||||
| const ignore = new Set((ignoreColumnIdxs ? ignoreColumnIdxs.map(Number) : [])) | ||||||||||||||||||||||||||||||||||||||||||
| const headerRow = [] | ||||||||||||||||||||||||||||||||||||||||||
| const headerTr = this.$el.find('thead tr').last() | ||||||||||||||||||||||||||||||||||||||||||
| const $ths = headerTr.children() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| $ths.each((idx, th) => { | ||||||||||||||||||||||||||||||||||||||||||
| if ($(th).is(':visible') && !ignore.has(idx)) { | ||||||||||||||||||||||||||||||||||||||||||
| headerRow.push($(th).text().trim()) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const rows = [] | ||||||||||||||||||||||||||||||||||||||||||
| const $trs = this.$el.find('tbody > tr:visible') | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| $trs.each((_, tr) => { | ||||||||||||||||||||||||||||||||||||||||||
| // skip detail view rows or non-data rows | ||||||||||||||||||||||||||||||||||||||||||
| const $tr = $(tr) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if ($tr.hasClass('detail-view') || $tr.hasClass('no-records-found')) return | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const row = [] | ||||||||||||||||||||||||||||||||||||||||||
| $tr.children().each((idx, td) => { | ||||||||||||||||||||||||||||||||||||||||||
| if ($(td).is(':visible') && !ignore.has(idx)) { | ||||||||||||||||||||||||||||||||||||||||||
| row.push($(td).text().trim()) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (row.length) { | ||||||||||||||||||||||||||||||||||||||||||
| rows.push(row) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return { headerRow, rows } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Helper: convert to content by type | ||||||||||||||||||||||||||||||||||||||||||
| const buildFile = (type, matrix, exportOptions) => { | ||||||||||||||||||||||||||||||||||||||||||
| const delimiter = exportOptions && exportOptions.csvDelimiter ? exportOptions.csvDelimiter : ',' | ||||||||||||||||||||||||||||||||||||||||||
| const tableName = exportOptions && exportOptions.tableName || 'table' | ||||||||||||||||||||||||||||||||||||||||||
| const { headerRow, rows } = matrix | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| switch (type) { | ||||||||||||||||||||||||||||||||||||||||||
| case 'csv': { | ||||||||||||||||||||||||||||||||||||||||||
| const lines = [] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (headerRow.length) { | ||||||||||||||||||||||||||||||||||||||||||
| lines.push(headerRow.map(h => csvEscape(h, delimiter)).join(delimiter)) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| rows.forEach(r => lines.push(r.map(v => csvEscape(v, delimiter)).join(delimiter))) | ||||||||||||||||||||||||||||||||||||||||||
| return { mime: 'text/csv;charset=utf-8', ext: 'csv', content: lines.join('\r\n') } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| case 'txt': { | ||||||||||||||||||||||||||||||||||||||||||
| const d = '\t' | ||||||||||||||||||||||||||||||||||||||||||
| const lines = [] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (headerRow.length) { | ||||||||||||||||||||||||||||||||||||||||||
| lines.push(headerRow.join(d)) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| rows.forEach(r => lines.push(r.join(d))) | ||||||||||||||||||||||||||||||||||||||||||
| return { mime: 'text/plain;charset=utf-8', ext: 'txt', content: lines.join('\r\n') } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| case 'json': { | ||||||||||||||||||||||||||||||||||||||||||
| const objs = [] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (headerRow.length) { | ||||||||||||||||||||||||||||||||||||||||||
| rows.forEach(r => { | ||||||||||||||||||||||||||||||||||||||||||
| const obj = {} | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| headerRow.forEach((h, i) => { | ||||||||||||||||||||||||||||||||||||||||||
| obj[h || `col${i + 1}`] = r[i] | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| objs.push(obj) | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| rows.forEach(r => objs.push(r)) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return { mime: 'application/json;charset=utf-8', ext: 'json', content: JSON.stringify(objs, null, 2) } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| case 'xml': { | ||||||||||||||||||||||||||||||||||||||||||
| const esc = s => String(s === null || s === undefined ? '' : s) | ||||||||||||||||||||||||||||||||||||||||||
| .replace(/&/g, '&') | ||||||||||||||||||||||||||||||||||||||||||
| .replace(/</g, '<') | ||||||||||||||||||||||||||||||||||||||||||
| .replace(/>/g, '>') | ||||||||||||||||||||||||||||||||||||||||||
| .replace(/"/g, '"') | ||||||||||||||||||||||||||||||||||||||||||
| .replace(/'/g, ''') | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const lines = ['<?xml version="1.0" encoding="UTF-8"?>', `<${tableName}>`] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+287
to
+288
|
||||||||||||||||||||||||||||||||||||||||||
| rows.forEach(r => { | ||||||||||||||||||||||||||||||||||||||||||
| lines.push(' <row>') | ||||||||||||||||||||||||||||||||||||||||||
| r.forEach((v, i) => { | ||||||||||||||||||||||||||||||||||||||||||
| const key = headerRow[i] || `col${i + 1}` | ||||||||||||||||||||||||||||||||||||||||||
| lines.push(` <${key}>${esc(v)}</${key}>`) | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+291
to
+294
|
||||||||||||||||||||||||||||||||||||||||||
| lines.push(' </row>') | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| lines.push(`</${tableName}>`) | ||||||||||||||||||||||||||||||||||||||||||
| return { mime: 'application/xml;charset=utf-8', ext: 'xml', content: lines.join('\n') } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| case 'sql': { | ||||||||||||||||||||||||||||||||||||||||||
| const cols = headerRow.map(h => (h || '').replace(/`/g, '``') || null).map((c, i) => c || `col${i + 1}`) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const values = rows.map(r => `(${r.map(v => { | ||||||||||||||||||||||||||||||||||||||||||
| if (v === null || v === undefined || v === '') return 'NULL' | ||||||||||||||||||||||||||||||||||||||||||
| const s = String(v).replace(/'/g, '\'\'' ) | ||||||||||||||||||||||||||||||||||||||||||
| return `'${s}'` | ||||||||||||||||||||||||||||||||||||||||||
| }).join(', ')})`) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const sql = `INSERT INTO \`${tableName}\` (\`${cols.join('`, `')}\`) VALUES\n${values.join(',\n')};` | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+304
to
+310
|
||||||||||||||||||||||||||||||||||||||||||
| const values = rows.map(r => `(${r.map(v => { | |
| if (v === null || v === undefined || v === '') return 'NULL' | |
| const s = String(v).replace(/'/g, '\'\'' ) | |
| return `'${s}'` | |
| }).join(', ')})`) | |
| const sql = `INSERT INTO \`${tableName}\` (\`${cols.join('`, `')}\`) VALUES\n${values.join(',\n')};` | |
| // If there are no rows, avoid generating an invalid INSERT statement. | |
| if (!rows.length) { | |
| return { mime: 'application/sql;charset=utf-8', ext: 'sql', content: '' } | |
| } | |
| const values = rows.map(r => `(${r.map(v => { | |
| if (v === null || v === undefined || v === '') return 'NULL' | |
| const s = String(v).replace(/'/g, '\'\'' ) | |
| return `'${s}'` | |
| }).join(', ')})`) | |
| const safeTableName = String(tableName).replace(/`/g, '``') | |
| const sql = `INSERT INTO \`${safeTableName}\` (\`${cols.join('`, `')}\`) VALUES\n${values.join(',\n')};` |
Copilot
AI
Feb 17, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the export type is unsupported, doExport silently no-ops and restores state, but the caller still fires the export-saved event, which is misleading because no file was produced. Please have doExport return a success/failure flag (or throw/trigger an error event) so unsupported types can avoid emitting export-saved and optionally notify the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The added helper code introduces trailing whitespace on blank lines (e.g., around this block). ESLint is configured with
no-trailing-spaces: 'error'(eslint.config.js:85), so this will fail lint. Please remove the trailing spaces (or run the project formatter/linter autofix) in the new code.