From b5ebb0a09c93a34431d330dc1dc68865f6a6895e Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:11:03 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/term/widgets/listtable.js | 277 +++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 js/term/widgets/listtable.js diff --git a/js/term/widgets/listtable.js b/js/term/widgets/listtable.js new file mode 100644 index 0000000..ed8c94b --- /dev/null +++ b/js/term/widgets/listtable.js @@ -0,0 +1,277 @@ +/** + ** ============================== + ** O O O OOOO + ** O O O O O O + ** O O O O O O + ** OOOO OOOO O OOO OOOO + ** O O O O O O O + ** O O O O O O O + ** OOOO OOOO O O OOOO + ** ============================== + ** Dr. Stefan Bosse http://www.bsslab.de + ** + ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED + ** BY THE AUTHOR(S). + ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, + ** MODIFIED, OR OTHERWISE USED IN A CONTEXT + ** OUTSIDE OF THE SOFTWARE SYSTEM. + ** + ** $AUTHORS: Christopher Jeffrey and contributors, Stefan Bosse + ** $INITIAL: (C) 2013-2015, Christopher Jeffrey and contributors + ** $CREATED: sbosse on 28-3-15. + ** $VERSION: 1.2.1 + ** + ** $INFO: + * + * listtable.js - list table element for blessed + * + ** $ENDOFINFO + */ +/** + * Modules + */ +var Comp = Require('com/compat'); + +var Node = Require('term/widgets/node'); +var Box = Require('term/widgets/box'); +var List = Require('term/widgets/list'); +var Table = Require('term/widgets/table'); + +/** + * ListTable + */ + +function ListTable(options) { + var self = this; + + if (!instanceOf(this,Node)) { + return new ListTable(options); + } + + options = options || {}; + options.shrink = true; + options.normalShrink = true; + options.style = options.style || {}; + options.style.border = options.style.border || {}; + options.style.header = options.style.header || {}; + options.style.cell = options.style.cell || {}; + this.__align = options.align || 'center'; + delete options.align; + + options.style.selected = options.style.cell.selected; + options.style.item = options.style.cell; + + List.call(this, options); + + this._header = new Box({ + parent: this, + left: this.screen.autoPadding ? 0 : this.ileft, + top: 0, + width: 'shrink', + height: 1, + style: options.style.header, + tags: options.parseTags || options.tags + }); + + this.on('scroll', function() { + self._header.setFront(); + self._header.rtop = self.childBase; + if (!self.screen.autoPadding) { + self._header.rtop = self.childBase + (self.border ? 1 : 0); + } + }); + + this.pad = options.pad != null + ? options.pad + : 2; + + this.setData(options.rows || options.data); + + this.on('attach', function() { + self.setData(self.rows); + }); + + this.on('resize', function() { + var selected = self.selected; + self.setData(self.rows); + self.select(selected); + self.screen.render(); + }); +} + +//ListTable.prototype.__proto__ = List.prototype; +inheritPrototype(ListTable,List); + +ListTable.prototype.type = 'list-table'; + +ListTable.prototype._calculateMaxes = Table.prototype._calculateMaxes; + +ListTable.prototype.setRows = +ListTable.prototype.setData = function(rows) { + var self = this + , align = this.__align; + + if (this.visible && this.lpos) { + this.clearPos(); + } + + this.clearItems(); + + this.rows = rows || []; + + this._calculateMaxes(); + + if (!this._maxes) return; + + this.addItem(''); + + this.rows.forEach(function(row, i) { + var isHeader = i === 0; + var text = ''; + row.forEach(function(cell, i) { + var width = self._maxes[i]; + var clen = self.strWidth(cell); + + if (i !== 0) { + text += ' '; + } + + while (clen < width) { + if (align === 'center') { + cell = ' ' + cell + ' '; + clen += 2; + } else if (align === 'left') { + cell = cell + ' '; + clen += 1; + } else if (align === 'right') { + cell = ' ' + cell; + clen += 1; + } + } + + if (clen > width) { + if (align === 'center') { + cell = cell.substring(1); + clen--; + } else if (align === 'left') { + cell = cell.slice(0, -1); + clen--; + } else if (align === 'right') { + cell = cell.substring(1); + clen--; + } + } + + text += cell; + }); + if (isHeader) { + self._header.setContent(text); + } else { + self.addItem(text); + } + }); + + this._header.setFront(); + + this.select(0); +}; + +ListTable.prototype._select = ListTable.prototype.select; +ListTable.prototype.select = function(i) { + if (i === 0) { + i = 1; + } + if (i <= this.childBase) { + this.setScroll(this.childBase - 1); + } + return this._select(i); +}; + +ListTable.prototype.render = function() { + var self = this; + + var coords = this._render(); + if (!coords) return; + + this._calculateMaxes(); + + if (!this._maxes) return coords; + + var lines = this.screen.lines + , xi = coords.xi + , yi = coords.yi + , rx + , ry + , i; + + var battr = this.sattr(this.style.border); + + var height = coords.yl - coords.yi - this.ibottom; + + if (!this.border || this.options.noCellBorders) return coords; + + // Draw border with correct angles. + ry = 0; + for (i = 0; i < height + 1; i++) { + if (!lines[yi + ry]) break; + rx = 0; + self._maxes.slice(0, -1).forEach(function(max) { + rx += max; + if (!lines[yi + ry][xi + rx + 1]) return; + // center + if (ry === 0) { + // top + rx++; + lines[yi + ry][xi + rx][0] = battr; + lines[yi + ry][xi + rx][1] = '\u252c'; // '┬' + // XXX If we alter iheight and itop for no borders - nothing should be written here + if (!self.border.top) { + lines[yi + ry][xi + rx][1] = '\u2502'; // '│' + } + lines[yi + ry].dirty = true; + } else if (ry === height) { + // bottom + rx++; + lines[yi + ry][xi + rx][0] = battr; + lines[yi + ry][xi + rx][1] = '\u2534'; // '┴' + // XXX If we alter iheight and ibottom for no borders - nothing should be written here + if (!self.border.bottom) { + lines[yi + ry][xi + rx][1] = '\u2502'; // '│' + } + lines[yi + ry].dirty = true; + } else { + // middle + rx++; + } + }); + ry += 1; + } + + // Draw internal borders. + for (ry = 1; ry < height; ry++) { + if (!lines[yi + ry]) break; + rx = 0; + self._maxes.slice(0, -1).forEach(function(max) { + rx += max; + if (!lines[yi + ry][xi + rx + 1]) return; + if (self.options.fillCellBorders !== false) { + var lbg = lines[yi + ry][xi + rx][0] & 0x1ff; + rx++; + lines[yi + ry][xi + rx][0] = (battr & ~0x1ff) | lbg; + } else { + rx++; + lines[yi + ry][xi + rx][0] = battr; + } + lines[yi + ry][xi + rx][1] = '\u2502'; // '│' + lines[yi + ry].dirty = true; + }); + } + + return coords; +}; + +/** + * Expose + */ + +module.exports = ListTable;