xlsx-preview
Version:
Preview the .xlsx in the browser, convert to HTML with styles.
128 lines (120 loc) • 3.85 kB
text/typescript
import { Row, Worksheet } from "exceljs";
import {
CELL_HEIGHT,
CELL_WIDTH,
FIRST_ORDER_COL_WIDTH,
FIRST_ORDER_ROW_HEIGHT,
MINIMUM_NUMBER_COLS,
MINIMUM_NUMBER_ROWS,
TABLE_CLS,
TBODY_CLS,
} from "../constants/base";
import { genBaseCSS } from "../CSSStyles/base";
import { genImageHtml } from "../images/genImages";
import { RowsAndColsSpanMap } from "../types/table";
import { genCell } from "./genCell";
import { genEmptyRow, wrapTable } from "./genHtmlStructure";
function genRows(
rows: RowsMap,
maxRow: number,
maxCol: number,
workSheet: Worksheet
) {
let resultRows = "";
const rowsSpan: number[] = [];
for (let index = 1; index <= maxRow; index++) {
let result = "";
const orderCell = `<td class="order order-row">${index}</td>`;
let rowHeight: number;
// add default.
if (!rows[index]) {
rowHeight = CELL_HEIGHT;
result += genEmptyRow(maxCol, orderCell);
} else {
// generate cells.
const { height } = rows[index];
let cellsResult = "";
for (let j = 1; j <= maxCol; j++) {
const curCell = workSheet.findCell(index, j);
if (!curCell) {
cellsResult += "<td></td>";
} else {
cellsResult += genCell(curCell);
}
}
let rowAttrs = "";
if (height) {
rowAttrs += ` style="height:${height}px;"`;
rowHeight = height;
} else {
rowHeight = CELL_HEIGHT;
}
result += `<tr${rowAttrs}>${orderCell}${cellsResult}</tr>`;
}
resultRows += result;
rowsSpan[index] = rowHeight;
}
return { resultRows, rowsSpan };
}
function genOrderCols(maxCol: number, workSheet: Worksheet) {
const curDefaultColWidth = workSheet.properties.defaultColWidth || 9;
let sheetWidth = 0;
let orderCol = '<td class="order order-row"></td>';
let colStyles = "";
const colsSpan: number[] = [];
for (let j = 1; j <= maxCol; j++) {
const column = workSheet.getColumn(j);
orderCol += `<td class="order order-col index-${j}">${column.letter}</td>`;
if (!column.width) {
sheetWidth += CELL_WIDTH;
colsSpan[j] = CELL_WIDTH;
} else {
const curCellWidth = (column.width * CELL_WIDTH) / curDefaultColWidth;
colsSpan[j] = curCellWidth;
sheetWidth += curCellWidth;
colStyles += `.${TBODY_CLS} td.index-${j} { width: ${curCellWidth}px; }`;
}
}
return {
sheetWidth,
orderCol,
colStyles,
colsSpan,
};
}
interface RowsMap {
[key: string]: Row;
}
export default async function genSheet(workSheet: Worksheet) {
const positionMap: RowsAndColsSpanMap = {
rows: [],
cols: [],
};
// generate rows.
const rows: RowsMap = {};
workSheet.eachRow((row, rowNumber) => {
rows[rowNumber] = row;
});
const lastRow = (workSheet.lastRow && workSheet.lastRow.number) || 0;
const maxRow = Math.max(lastRow, MINIMUM_NUMBER_ROWS);
const lastColumn = (workSheet.lastColumn && workSheet.lastColumn.number) || 0;
const maxCol = Math.max(lastColumn, MINIMUM_NUMBER_COLS);
const { resultRows, rowsSpan } = genRows(rows, maxRow, maxCol, workSheet);
positionMap.rows = [FIRST_ORDER_ROW_HEIGHT, ...rowsSpan];
const { sheetWidth, orderCol, colStyles, colsSpan } = genOrderCols(
maxCol,
workSheet
);
positionMap.cols = [FIRST_ORDER_COL_WIDTH, ...colsSpan];
const hideGridLines = workSheet.views.some((view) => !view.showGridLines);
const gridLineStyle = hideGridLines
? `.${TBODY_CLS}.${TBODY_CLS} td:not(.order) { border: none; }`
: "";
let result = wrapTable(orderCol + resultRows);
const tableStyle = `.${TABLE_CLS} { width: ${sheetWidth}px; } ${gridLineStyle}`;
const imgHtml = await genImageHtml(workSheet, positionMap);
result += imgHtml;
result += `<style>${tableStyle}${colStyles}</style>`;
result += genBaseCSS();
return result;
}