@3mo/data-grid
Version:
A data grid web component
77 lines (76 loc) • 3.08 kB
JavaScript
import { Downloader } from '@3mo/downloader';
import { NotificationComponent } from '@a11d/lit-application';
export class DataGridCsvController {
static sanitize(value) {
if (typeof value !== 'string') {
value = String(value);
}
if (value.includes(',')) {
value = `"${value.replaceAll('"', '""')}"`;
}
return value;
}
static async download(data) {
const fileName = [
document.title.split(' | ')[0],
new Date().toISOString().replace(/[-:.T]/g, '').slice(0, 14),
].filter(Boolean).join('_');
Downloader.download(`data:text/csv;charset=utf-8,${encodeURIComponent(data)}`, `${fileName}.csv`);
await new Promise(r => setTimeout(r, 1000));
}
constructor(host) {
this.host = host;
}
get generationProgress() { return this._progress; }
set generationProgress(value) {
this._progress = value;
this.host.requestUpdate();
}
get isGenerating() { return this._progress !== undefined; }
async generateCsv() {
if (this.isGenerating) {
return;
}
this.generationProgress = 0;
try {
const dataRecords = new Array();
const asyncIterator = this.host.getCsvData();
while (true) {
const { done, value } = await asyncIterator.next();
if (done) {
dataRecords.push(...value);
break;
}
this.generationProgress = value;
}
const maxLevel = Math.max(...dataRecords.map(d => d.level));
const [firstHeading, ...otherHeadings] = this.host.visibleColumns.flatMap(c => [...c.generateCsvHeading?.() ?? []].map(DataGridCsvController.sanitize));
const rows = [
[firstHeading, ...Array.from({ length: maxLevel }).fill(firstHeading), ...otherHeadings],
...dataRecords.map(d => {
const nestedPadding = Array.from({ length: d.level }).fill('');
const childrenPadding = Array.from({ length: maxLevel - d.level }).fill('');
const [first, ...rest] = this.host.visibleColumns
.flatMap(column => {
const value = KeyPath.get(d.data, column.dataSelector);
return [...column.generateCsvValue?.(value, d.data) ?? []].map(DataGridCsvController.sanitize);
});
return [
...nestedPadding,
first,
...childrenPadding,
...rest
];
})
];
const csvContent = rows.map(row => row.join(',')).join('\n');
await DataGridCsvController.download(csvContent);
}
catch (error) {
NotificationComponent.notifyAndThrowError(error.message);
}
finally {
this.generationProgress = undefined;
}
}
}