// 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);