From 9e14963bad67ab2c640e98bb2148635b551727ae Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Wed, 16 Jul 2025 19:18:50 -0400 Subject: add csv download --- csv-dump.mjs | 22 +++++++++++++++++ csv-parse.mjs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ csv.mjs | 79 ----------------------------------------------------------- index.html | 2 +- pnit-form.mjs | 13 ++++++++++ worker.js | 2 +- 6 files changed, 116 insertions(+), 81 deletions(-) create mode 100644 csv-dump.mjs create mode 100644 csv-parse.mjs delete mode 100644 csv.mjs diff --git a/csv-dump.mjs b/csv-dump.mjs new file mode 100644 index 0000000..76e1e08 --- /dev/null +++ b/csv-dump.mjs @@ -0,0 +1,22 @@ +export default class { + constructor(rows) { + this.rows = rows; + } + + download() { + // XXX: should escape various things, but the quick-n-dirty + // calls. + const data = this.rows.map(row => row.join(',')).join('\r\n'); + const file = new Blob([data], { type: 'text/csv' }) + let a = document.createElement('a'); + const url = URL.createObjectURL(file); + a.href = url; + a.download = 'filename.csv'; + document.body.appendChild(a); + a.click(); + setTimeout(_ => { + document.body.removeChild(a); + URL.revokeObjectURL(url); + }, 0); + } +} diff --git a/csv-parse.mjs b/csv-parse.mjs new file mode 100644 index 0000000..b096ab4 --- /dev/null +++ b/csv-parse.mjs @@ -0,0 +1,79 @@ +export default class { + constructor() { + this.state = this.awaitingTokenOrComma; + this.inProgress = ''; + this._rowResults = []; + this._results = []; + } + + push(c) { + this.state(c); + } + + get results() { + return this._results.concat([this._rowResults.concat([this.inProgress])]); + } + + awaitingTokenOrComma(c) { + switch (c) { + case ',': + // empty column + this._rowResults.push(''); + break; + case '\n': + this._results.push(this._rowResults); + this._rowResults = []; + break; + default: + if (/\s/.test(c)) { + return; + } + this.inProgress += c; + this.state = this.awaitingComma; + } + } + + awaitingComma(c) { + switch (c) { + case ',': + this._rowResults.push(this.inProgress); + this.inProgress = ''; + this.state = this.awaitingTokenOrComma; + break; + case '\r': + break; + case '\n': + this._results.push(this._rowResults.concat(this.inProgress)); + this._rowResults = []; + this.inProgress = ''; + this.state = this.awaitingTokenOrComma; + break; + case '"': + this.state = this.checkForDoubleQuote; + break; + default: + this.inProgress += c; + } + } + + checkForDoubleQuote(c) { + this.inProgress += c + switch (c) { + case '"': + this.state = this.awaitingComma; + break; + default: + this.state = this.awaitingQuote; + } + } + + awaitingQuote(c) { + switch (c) { + case '"': + this.state = this.awaitingComma; + break; + default: + this.inProgress += c; + } + } +} diff --git a/csv.mjs b/csv.mjs deleted file mode 100644 index b096ab4..0000000 --- a/csv.mjs +++ /dev/null @@ -1,79 +0,0 @@ -export default class { - constructor() { - this.state = this.awaitingTokenOrComma; - this.inProgress = ''; - this._rowResults = []; - this._results = []; - } - - push(c) { - this.state(c); - } - - get results() { - return this._results.concat([this._rowResults.concat([this.inProgress])]); - } - - awaitingTokenOrComma(c) { - switch (c) { - case ',': - // empty column - this._rowResults.push(''); - break; - case '\n': - this._results.push(this._rowResults); - this._rowResults = []; - break; - default: - if (/\s/.test(c)) { - return; - } - this.inProgress += c; - this.state = this.awaitingComma; - } - } - - awaitingComma(c) { - switch (c) { - case ',': - this._rowResults.push(this.inProgress); - this.inProgress = ''; - this.state = this.awaitingTokenOrComma; - break; - case '\r': - break; - case '\n': - this._results.push(this._rowResults.concat(this.inProgress)); - this._rowResults = []; - this.inProgress = ''; - this.state = this.awaitingTokenOrComma; - break; - case '"': - this.state = this.checkForDoubleQuote; - break; - default: - this.inProgress += c; - } - } - - checkForDoubleQuote(c) { - this.inProgress += c - switch (c) { - case '"': - this.state = this.awaitingComma; - break; - default: - this.state = this.awaitingQuote; - } - } - - awaitingQuote(c) { - switch (c) { - case '"': - this.state = this.awaitingComma; - break; - default: - this.inProgress += c; - } - } -} diff --git a/index.html b/index.html index 8ae4fa2..2dfb927 100644 --- a/index.html +++ b/index.html @@ -21,7 +21,7 @@ - + diff --git a/pnit-form.mjs b/pnit-form.mjs index c1fa16c..f85457b 100644 --- a/pnit-form.mjs +++ b/pnit-form.mjs @@ -1,3 +1,5 @@ +import CSVDump from './csv-dump.mjs'; + const worker = new Worker('worker.js', { type: 'module' }); export default class extends HTMLElement { @@ -24,6 +26,10 @@ export default class extends HTMLElement { return inputs.flatMap(inp => Array.from(inp.files)); } + get downloadButton() { + return this.querySelector('#csv-download'); + } + get resultTable() { return document.getElementById('pnit-results'); } @@ -37,6 +43,11 @@ export default class extends HTMLElement { this.form.onchange = this.process.bind(this); this.form.onchange(); + + this.downloadButton.onclick = _ => { + const dumper = new CSVDump(this.results); + dumper.download(); + } } handleWorkerMessage(e) { @@ -46,6 +57,7 @@ export default class extends HTMLElement { col.innerText = v; row.appendChild(col); }); + this.results.push(e.data); this.resultTable.appendChild(row); } @@ -60,6 +72,7 @@ export default class extends HTMLElement { process() { console.debug('PNITForm#process', this); + this.results = []; this.resultTable.innerHTML = ''; if (isNaN(this.threshold)) { diff --git a/worker.js b/worker.js index 77a861b..4812203 100644 --- a/worker.js +++ b/worker.js @@ -1,4 +1,4 @@ -import CSVParse from './csv.mjs'; +import CSVParse from './csv-parse.mjs'; let ignoreLines = 0; let sequenceNames = []; -- cgit v1.3
foo