11cb0ef41Sopenharmony_ciconst { warn, debug } = require('./debug'); 21cb0ef41Sopenharmony_ciconst Cell = require('./cell'); 31cb0ef41Sopenharmony_ciconst { ColSpanCell, RowSpanCell } = Cell; 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci(function () { 61cb0ef41Sopenharmony_ci function next(alloc, col) { 71cb0ef41Sopenharmony_ci if (alloc[col] > 0) { 81cb0ef41Sopenharmony_ci return next(alloc, col + 1); 91cb0ef41Sopenharmony_ci } 101cb0ef41Sopenharmony_ci return col; 111cb0ef41Sopenharmony_ci } 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci function layoutTable(table) { 141cb0ef41Sopenharmony_ci let alloc = {}; 151cb0ef41Sopenharmony_ci table.forEach(function (row, rowIndex) { 161cb0ef41Sopenharmony_ci let col = 0; 171cb0ef41Sopenharmony_ci row.forEach(function (cell) { 181cb0ef41Sopenharmony_ci cell.y = rowIndex; 191cb0ef41Sopenharmony_ci // Avoid erroneous call to next() on first row 201cb0ef41Sopenharmony_ci cell.x = rowIndex ? next(alloc, col) : col; 211cb0ef41Sopenharmony_ci const rowSpan = cell.rowSpan || 1; 221cb0ef41Sopenharmony_ci const colSpan = cell.colSpan || 1; 231cb0ef41Sopenharmony_ci if (rowSpan > 1) { 241cb0ef41Sopenharmony_ci for (let cs = 0; cs < colSpan; cs++) { 251cb0ef41Sopenharmony_ci alloc[cell.x + cs] = rowSpan; 261cb0ef41Sopenharmony_ci } 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci col = cell.x + colSpan; 291cb0ef41Sopenharmony_ci }); 301cb0ef41Sopenharmony_ci Object.keys(alloc).forEach((idx) => { 311cb0ef41Sopenharmony_ci alloc[idx]--; 321cb0ef41Sopenharmony_ci if (alloc[idx] < 1) delete alloc[idx]; 331cb0ef41Sopenharmony_ci }); 341cb0ef41Sopenharmony_ci }); 351cb0ef41Sopenharmony_ci } 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci function maxWidth(table) { 381cb0ef41Sopenharmony_ci let mw = 0; 391cb0ef41Sopenharmony_ci table.forEach(function (row) { 401cb0ef41Sopenharmony_ci row.forEach(function (cell) { 411cb0ef41Sopenharmony_ci mw = Math.max(mw, cell.x + (cell.colSpan || 1)); 421cb0ef41Sopenharmony_ci }); 431cb0ef41Sopenharmony_ci }); 441cb0ef41Sopenharmony_ci return mw; 451cb0ef41Sopenharmony_ci } 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci function maxHeight(table) { 481cb0ef41Sopenharmony_ci return table.length; 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci function cellsConflict(cell1, cell2) { 521cb0ef41Sopenharmony_ci let yMin1 = cell1.y; 531cb0ef41Sopenharmony_ci let yMax1 = cell1.y - 1 + (cell1.rowSpan || 1); 541cb0ef41Sopenharmony_ci let yMin2 = cell2.y; 551cb0ef41Sopenharmony_ci let yMax2 = cell2.y - 1 + (cell2.rowSpan || 1); 561cb0ef41Sopenharmony_ci let yConflict = !(yMin1 > yMax2 || yMin2 > yMax1); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci let xMin1 = cell1.x; 591cb0ef41Sopenharmony_ci let xMax1 = cell1.x - 1 + (cell1.colSpan || 1); 601cb0ef41Sopenharmony_ci let xMin2 = cell2.x; 611cb0ef41Sopenharmony_ci let xMax2 = cell2.x - 1 + (cell2.colSpan || 1); 621cb0ef41Sopenharmony_ci let xConflict = !(xMin1 > xMax2 || xMin2 > xMax1); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci return yConflict && xConflict; 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci function conflictExists(rows, x, y) { 681cb0ef41Sopenharmony_ci let i_max = Math.min(rows.length - 1, y); 691cb0ef41Sopenharmony_ci let cell = { x: x, y: y }; 701cb0ef41Sopenharmony_ci for (let i = 0; i <= i_max; i++) { 711cb0ef41Sopenharmony_ci let row = rows[i]; 721cb0ef41Sopenharmony_ci for (let j = 0; j < row.length; j++) { 731cb0ef41Sopenharmony_ci if (cellsConflict(cell, row[j])) { 741cb0ef41Sopenharmony_ci return true; 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci } 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci return false; 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci function allBlank(rows, y, xMin, xMax) { 821cb0ef41Sopenharmony_ci for (let x = xMin; x < xMax; x++) { 831cb0ef41Sopenharmony_ci if (conflictExists(rows, x, y)) { 841cb0ef41Sopenharmony_ci return false; 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci return true; 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci function addRowSpanCells(table) { 911cb0ef41Sopenharmony_ci table.forEach(function (row, rowIndex) { 921cb0ef41Sopenharmony_ci row.forEach(function (cell) { 931cb0ef41Sopenharmony_ci for (let i = 1; i < cell.rowSpan; i++) { 941cb0ef41Sopenharmony_ci let rowSpanCell = new RowSpanCell(cell); 951cb0ef41Sopenharmony_ci rowSpanCell.x = cell.x; 961cb0ef41Sopenharmony_ci rowSpanCell.y = cell.y + i; 971cb0ef41Sopenharmony_ci rowSpanCell.colSpan = cell.colSpan; 981cb0ef41Sopenharmony_ci insertCell(rowSpanCell, table[rowIndex + i]); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci }); 1011cb0ef41Sopenharmony_ci }); 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci function addColSpanCells(cellRows) { 1051cb0ef41Sopenharmony_ci for (let rowIndex = cellRows.length - 1; rowIndex >= 0; rowIndex--) { 1061cb0ef41Sopenharmony_ci let cellColumns = cellRows[rowIndex]; 1071cb0ef41Sopenharmony_ci for (let columnIndex = 0; columnIndex < cellColumns.length; columnIndex++) { 1081cb0ef41Sopenharmony_ci let cell = cellColumns[columnIndex]; 1091cb0ef41Sopenharmony_ci for (let k = 1; k < cell.colSpan; k++) { 1101cb0ef41Sopenharmony_ci let colSpanCell = new ColSpanCell(); 1111cb0ef41Sopenharmony_ci colSpanCell.x = cell.x + k; 1121cb0ef41Sopenharmony_ci colSpanCell.y = cell.y; 1131cb0ef41Sopenharmony_ci cellColumns.splice(columnIndex + 1, 0, colSpanCell); 1141cb0ef41Sopenharmony_ci } 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci function insertCell(cell, row) { 1201cb0ef41Sopenharmony_ci let x = 0; 1211cb0ef41Sopenharmony_ci while (x < row.length && row[x].x < cell.x) { 1221cb0ef41Sopenharmony_ci x++; 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci row.splice(x, 0, cell); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci function fillInTable(table) { 1281cb0ef41Sopenharmony_ci let h_max = maxHeight(table); 1291cb0ef41Sopenharmony_ci let w_max = maxWidth(table); 1301cb0ef41Sopenharmony_ci debug(`Max rows: ${h_max}; Max cols: ${w_max}`); 1311cb0ef41Sopenharmony_ci for (let y = 0; y < h_max; y++) { 1321cb0ef41Sopenharmony_ci for (let x = 0; x < w_max; x++) { 1331cb0ef41Sopenharmony_ci if (!conflictExists(table, x, y)) { 1341cb0ef41Sopenharmony_ci let opts = { x: x, y: y, colSpan: 1, rowSpan: 1 }; 1351cb0ef41Sopenharmony_ci x++; 1361cb0ef41Sopenharmony_ci while (x < w_max && !conflictExists(table, x, y)) { 1371cb0ef41Sopenharmony_ci opts.colSpan++; 1381cb0ef41Sopenharmony_ci x++; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci let y2 = y + 1; 1411cb0ef41Sopenharmony_ci while (y2 < h_max && allBlank(table, y2, opts.x, opts.x + opts.colSpan)) { 1421cb0ef41Sopenharmony_ci opts.rowSpan++; 1431cb0ef41Sopenharmony_ci y2++; 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci let cell = new Cell(opts); 1461cb0ef41Sopenharmony_ci cell.x = opts.x; 1471cb0ef41Sopenharmony_ci cell.y = opts.y; 1481cb0ef41Sopenharmony_ci warn(`Missing cell at ${cell.y}-${cell.x}.`); 1491cb0ef41Sopenharmony_ci insertCell(cell, table[y]); 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci function generateCells(rows) { 1561cb0ef41Sopenharmony_ci return rows.map(function (row) { 1571cb0ef41Sopenharmony_ci if (!Array.isArray(row)) { 1581cb0ef41Sopenharmony_ci let key = Object.keys(row)[0]; 1591cb0ef41Sopenharmony_ci row = row[key]; 1601cb0ef41Sopenharmony_ci if (Array.isArray(row)) { 1611cb0ef41Sopenharmony_ci row = row.slice(); 1621cb0ef41Sopenharmony_ci row.unshift(key); 1631cb0ef41Sopenharmony_ci } else { 1641cb0ef41Sopenharmony_ci row = [key, row]; 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci return row.map(function (cell) { 1681cb0ef41Sopenharmony_ci return new Cell(cell); 1691cb0ef41Sopenharmony_ci }); 1701cb0ef41Sopenharmony_ci }); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci function makeTableLayout(rows) { 1741cb0ef41Sopenharmony_ci let cellRows = generateCells(rows); 1751cb0ef41Sopenharmony_ci layoutTable(cellRows); 1761cb0ef41Sopenharmony_ci fillInTable(cellRows); 1771cb0ef41Sopenharmony_ci addRowSpanCells(cellRows); 1781cb0ef41Sopenharmony_ci addColSpanCells(cellRows); 1791cb0ef41Sopenharmony_ci return cellRows; 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci module.exports = { 1831cb0ef41Sopenharmony_ci makeTableLayout: makeTableLayout, 1841cb0ef41Sopenharmony_ci layoutTable: layoutTable, 1851cb0ef41Sopenharmony_ci addRowSpanCells: addRowSpanCells, 1861cb0ef41Sopenharmony_ci maxWidth: maxWidth, 1871cb0ef41Sopenharmony_ci fillInTable: fillInTable, 1881cb0ef41Sopenharmony_ci computeWidths: makeComputeWidths('colSpan', 'desiredWidth', 'x', 1), 1891cb0ef41Sopenharmony_ci computeHeights: makeComputeWidths('rowSpan', 'desiredHeight', 'y', 1), 1901cb0ef41Sopenharmony_ci }; 1911cb0ef41Sopenharmony_ci})(); 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_cifunction makeComputeWidths(colSpan, desiredWidth, x, forcedMin) { 1941cb0ef41Sopenharmony_ci return function (vals, table) { 1951cb0ef41Sopenharmony_ci let result = []; 1961cb0ef41Sopenharmony_ci let spanners = []; 1971cb0ef41Sopenharmony_ci let auto = {}; 1981cb0ef41Sopenharmony_ci table.forEach(function (row) { 1991cb0ef41Sopenharmony_ci row.forEach(function (cell) { 2001cb0ef41Sopenharmony_ci if ((cell[colSpan] || 1) > 1) { 2011cb0ef41Sopenharmony_ci spanners.push(cell); 2021cb0ef41Sopenharmony_ci } else { 2031cb0ef41Sopenharmony_ci result[cell[x]] = Math.max(result[cell[x]] || 0, cell[desiredWidth] || 0, forcedMin); 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci }); 2061cb0ef41Sopenharmony_ci }); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci vals.forEach(function (val, index) { 2091cb0ef41Sopenharmony_ci if (typeof val === 'number') { 2101cb0ef41Sopenharmony_ci result[index] = val; 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci }); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci //spanners.forEach(function(cell){ 2151cb0ef41Sopenharmony_ci for (let k = spanners.length - 1; k >= 0; k--) { 2161cb0ef41Sopenharmony_ci let cell = spanners[k]; 2171cb0ef41Sopenharmony_ci let span = cell[colSpan]; 2181cb0ef41Sopenharmony_ci let col = cell[x]; 2191cb0ef41Sopenharmony_ci let existingWidth = result[col]; 2201cb0ef41Sopenharmony_ci let editableCols = typeof vals[col] === 'number' ? 0 : 1; 2211cb0ef41Sopenharmony_ci if (typeof existingWidth === 'number') { 2221cb0ef41Sopenharmony_ci for (let i = 1; i < span; i++) { 2231cb0ef41Sopenharmony_ci existingWidth += 1 + result[col + i]; 2241cb0ef41Sopenharmony_ci if (typeof vals[col + i] !== 'number') { 2251cb0ef41Sopenharmony_ci editableCols++; 2261cb0ef41Sopenharmony_ci } 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci } else { 2291cb0ef41Sopenharmony_ci existingWidth = desiredWidth === 'desiredWidth' ? cell.desiredWidth - 1 : 1; 2301cb0ef41Sopenharmony_ci if (!auto[col] || auto[col] < existingWidth) { 2311cb0ef41Sopenharmony_ci auto[col] = existingWidth; 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci if (cell[desiredWidth] > existingWidth) { 2361cb0ef41Sopenharmony_ci let i = 0; 2371cb0ef41Sopenharmony_ci while (editableCols > 0 && cell[desiredWidth] > existingWidth) { 2381cb0ef41Sopenharmony_ci if (typeof vals[col + i] !== 'number') { 2391cb0ef41Sopenharmony_ci let dif = Math.round((cell[desiredWidth] - existingWidth) / editableCols); 2401cb0ef41Sopenharmony_ci existingWidth += dif; 2411cb0ef41Sopenharmony_ci result[col + i] += dif; 2421cb0ef41Sopenharmony_ci editableCols--; 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci i++; 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci Object.assign(vals, result, auto); 2501cb0ef41Sopenharmony_ci for (let j = 0; j < vals.length; j++) { 2511cb0ef41Sopenharmony_ci vals[j] = Math.max(forcedMin, vals[j] || 0); 2521cb0ef41Sopenharmony_ci } 2531cb0ef41Sopenharmony_ci }; 2541cb0ef41Sopenharmony_ci} 255