79 lines
2.8 KiB
JavaScript
79 lines
2.8 KiB
JavaScript
// export.js — CSV download of the current table view.
|
||
//
|
||
// Exports what the user sees: filter + sort applied, columns in the
|
||
// order declared by the spec. Values pass through util.formatCell so
|
||
// date / number / boolean cells match their on-screen rendering.
|
||
// RFC 4180 quoting (double-quote any cell with a comma, newline, or
|
||
// quote; escape inner quotes by doubling). UTF-8 BOM prepended so
|
||
// Excel detects the encoding without a manual import-wizard step.
|
||
|
||
(function (app) {
|
||
'use strict';
|
||
|
||
function csvEscape(value) {
|
||
if (value == null) return '';
|
||
const str = String(value);
|
||
if (/[",\r\n]/.test(str)) {
|
||
return '"' + str.replace(/"/g, '""') + '"';
|
||
}
|
||
return str;
|
||
}
|
||
|
||
function buildCsv(rows, columns, util) {
|
||
const lines = [];
|
||
lines.push(columns.map(function (c) {
|
||
return csvEscape(c.title || c.field || '');
|
||
}).join(','));
|
||
for (let i = 0; i < rows.length; i++) {
|
||
const row = rows[i];
|
||
const cells = columns.map(function (c) {
|
||
const raw = util.resolveField(row.data, c.field);
|
||
return csvEscape(util.formatCell(raw, c.format));
|
||
});
|
||
lines.push(cells.join(','));
|
||
}
|
||
return lines.join('\r\n') + '\r\n';
|
||
}
|
||
|
||
function suggestFilename() {
|
||
const titleEl = document.getElementById('table-title');
|
||
const raw = (titleEl && titleEl.textContent) ? titleEl.textContent : 'table';
|
||
const base = raw.toLowerCase()
|
||
.replace(/[^a-z0-9]+/g, '-')
|
||
.replace(/^-+|-+$/g, '') || 'table';
|
||
const stamp = new Date().toISOString().slice(0, 10);
|
||
return base + '-' + stamp + '.csv';
|
||
}
|
||
|
||
function download(csv, filename) {
|
||
const blob = new Blob(['' + csv], { type: 'text/csv;charset=utf-8' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
|
||
}
|
||
|
||
function invoke() {
|
||
const ctx = app.context || {};
|
||
const columns = Array.isArray(ctx.columns) ? ctx.columns : [];
|
||
if (columns.length === 0) {
|
||
return;
|
||
}
|
||
const state = app.state;
|
||
const util = app.modules.util;
|
||
const filtered = app.modules.filters.apply(state.rows, columns, state.filter, util.resolveField);
|
||
const sorted = app.modules.sort.apply(filtered, state.sort, columns, util);
|
||
const csv = buildCsv(sorted, columns, util);
|
||
download(csv, suggestFilename());
|
||
}
|
||
|
||
app.modules.exportCsv = {
|
||
invoke: invoke,
|
||
buildCsv: buildCsv,
|
||
csvEscape: csvEscape
|
||
};
|
||
})(window.tablesApp);
|