diff --git a/package.json b/package.json index c91ee23..3193dc9 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ { "displayName": "test", "testMatch": [ - "/test/*.js" + "/test/**/*.js" ] }, { diff --git a/src/layout-manager.js b/src/layout-manager.js index fe84ef8..cb84d9e 100644 --- a/src/layout-manager.js +++ b/src/layout-manager.js @@ -2,23 +2,33 @@ const Cell = require('./cell'); const { ColSpanCell, RowSpanCell } = Cell; (function () { + function next(alloc, col) { + if (alloc[col] > 0) { + return next(alloc, col + 1); + } + return col; + } + function layoutTable(table) { + let alloc = {}; table.forEach(function (row, rowIndex) { - let prevCell = null; - row.forEach(function (cell, columnIndex) { + let col = 0; + row.forEach(function (cell) { cell.y = rowIndex; - cell.x = prevCell ? prevCell.x + 1 : columnIndex; - for (let y = rowIndex; y >= 0; y--) { - let row2 = table[y]; - let xMax = y === rowIndex ? columnIndex : row2.length; - for (let x = 0; x < xMax; x++) { - let cell2 = row2[x]; - while (cellsConflict(cell, cell2)) { - cell.x++; - } + // Avoid erroneous call to next() on first row + cell.x = rowIndex ? next(alloc, col) : col; + const rowSpan = cell.rowSpan || 1; + const colSpan = cell.colSpan || 1; + if (rowSpan > 1) { + for (let cs = 0; cs < colSpan; cs++) { + alloc[cell.x + cs] = rowSpan; } - prevCell = cell; } + col = cell.x + colSpan; + }); + Object.keys(alloc).forEach((idx) => { + alloc[idx]--; + if (alloc[idx] < 1) delete alloc[idx]; }); }); } diff --git a/test/issues/269-test.js b/test/issues/269-test.js new file mode 100644 index 0000000..9cafd5a --- /dev/null +++ b/test/issues/269-test.js @@ -0,0 +1,16 @@ +const Table = require('../..'); + +test('it renders rowSpan correctly', () => { + let table = new Table({ style: { border: [], head: [] } }); + table.push([{ rowSpan: 3, content: 'A1' }, 'B1', 'C1'], [{ rowSpan: 2, content: 'B2' }, 'C2'], ['C3']); + let expected = [ + '┌────┬────┬────┐', + '│ A1 │ B1 │ C1 │', + '│ ├────┼────┤', + '│ │ B2 │ C2 │', + '│ │ ├────┤', + '│ │ │ C3 │', + '└────┴────┴────┘', + ]; + expect(table.toString()).toEqual(expected.join('\n')); +}); diff --git a/test/table-test.js b/test/table-test.js index b88c177..2cfa0ff 100644 --- a/test/table-test.js +++ b/test/table-test.js @@ -62,6 +62,73 @@ describe('@api Table ', function () { expect(table.toString()).toEqual(expected.join('\n')); }); + + it('supports complex layouts', () => { + let table = new Table({ style: { border: [], head: [] } }); + table.push( + [{ content: 'TOP', colSpan: 9, hAlign: 'center' }], + [ + { content: 'TL', rowSpan: 4, vAlign: 'center' }, + { content: 'A1', rowSpan: 3 }, + 'B1', + 'C1', + { content: 'D1', rowSpan: 3, vAlign: 'center' }, + 'E1', + 'F1', + { content: 'G1', rowSpan: 3 }, + { content: 'TR', rowSpan: 4, vAlign: 'center' }, + ], + [{ rowSpan: 2, content: 'B2' }, 'C2', { rowSpan: 2, colSpan: 2, content: 'E2' }], + ['C3'], + [{ content: 'A2', colSpan: 7, hAlign: 'center' }], + [{ content: 'CLEAR', colSpan: 9, hAlign: 'center' }], + [ + { content: 'BL', rowSpan: 4, vAlign: 'center' }, + { content: 'A3', colSpan: 7, hAlign: 'center' }, + { content: 'BR', rowSpan: 4, vAlign: 'center' }, + ], + [ + { content: 'A4', colSpan: 3, hAlign: 'center' }, + { content: 'D2', rowSpan: 2, vAlign: 'center' }, + { content: 'E3', colSpan: 2, hAlign: 'center' }, + { content: 'G2', rowSpan: 3, vAlign: 'center' }, + ], + [ + { content: 'A5', rowSpan: 2, vAlign: 'center' }, + { content: 'B3', colSpan: 2, hAlign: 'center' }, + { content: 'E4', rowSpan: 2, vAlign: 'center' }, + { content: 'F3', rowSpan: 2, vAlign: 'center' }, + ], + ['B4', { content: 'C4', colSpan: 2, hAlign: 'center' }], + [{ content: 'BOTTOM', colSpan: 9, hAlign: 'center' }] + ); + let expected = [ + '┌────────────────────────────────────────────┐', + '│ TOP │', + '├────┬────┬────┬────┬────┬────┬────┬────┬────┤', + '│ │ A1 │ B1 │ C1 │ │ E1 │ F1 │ G1 │ │', + '│ │ ├────┼────┤ ├────┴────┤ │ │', + '│ │ │ B2 │ C2 │ D1 │ E2 │ │ │', + '│ TL │ │ ├────┤ │ │ │ TR │', + '│ │ │ │ C3 │ │ │ │ │', + '│ ├────┴────┴────┴────┴─────────┴────┤ │', + '│ │ A2 │ │', + '├────┴──────────────────────────────────┴────┤', + '│ CLEAR │', + '├────┬──────────────────────────────────┬────┤', + '│ │ A3 │ │', + '│ ├──────────────┬────┬─────────┬────┤ │', + '│ │ A4 │ │ E3 │ │ │', + '│ BL ├────┬─────────┤ D2 ├────┬────┤ │ BR │', + '│ │ │ B3 │ │ │ │ G2 │ │', + '│ │ A5 ├────┬────┴────┤ E4 │ F3 │ │ │', + '│ │ │ B4 │ C4 │ │ │ │ │', + '├────┴────┴────┴─────────┴────┴────┴────┴────┤', + '│ BOTTOM │', + '└────────────────────────────────────────────┘', + ]; + expect(table.toString()).toEqual(expected.join('\n')); + }); }); /*