class TableWidget extends BaseWidget { $el; #align = ''; #width = ''; #data = ''; #path = ''; constructor(data, renderer) { super(data, renderer); this.makeLayout({ type: 'table', class: 'w_table', name: 'el', }); this.update(data); } update(data) { super.update(data); if ('align' in data) this.#align = data.align; if ('width' in data) this.#width = data.width; if ('value' in data) { let val = data.value; if (!val.includes(';') && val.endsWith(".csv")) { // file this.#path = val; } else { this.#path = ''; this.#data = val; } } if ('action' in data || 'value' in data) this.#reload(); else if ('align' in data || 'width' in data) this.#render(); } #reload() { if (this.#path) { this.$el.innerHTML = waiter(); this.addFile(this.#path, 'text', file => { this.#data = file.replaceAll(/\\n/ig, "\n"); this.#render(); }); } else { this.#render(); } } #render() { const aligns = this.#align.split(/[,;]/); const widths = this.#width.split(/[,;]/); const table = parseCSV(this.#data); const items = []; for (const row of table) { const $row = document.createElement('tr'); for (const col in row) { const $col = document.createElement('td'); if (widths[col]) $col.width = widths[col] + '%'; $col.align = aligns[col] ?? 'center'; $col.textContent = row[col]; $row.append($col); } items.push($row); } this.$el.replaceChildren(...items); } } function parseCSV(str) { // https://stackoverflow.com/a/14991797 const arr = []; let quote = false; for (let row = 0, col = 0, c = 0; c < str.length; c++) { let cc = str[c], nc = str[c + 1]; arr[row] = arr[row] || []; arr[row][col] = arr[row][col] || ''; if (cc == '"' && quote && nc == '"') { arr[row][col] += cc; ++c; continue; } if (cc == '"') { quote = !quote; continue; } if ((cc == ';' || cc == ',' ) && !quote) { ++col; continue; } if (cc == '\r' && nc == '\n' && !quote) { ++row; col = 0; ++c; continue; } if (cc == '\n' && !quote) { ++row; col = 0; continue; } if (cc == '\r' && !quote) { ++row; col = 0; continue; } arr[row][col] += cc; } return arr; } Renderer.register('table', TableWidget);