UNPKG

mr-excel

Version:

A versatile JavaScript library for effortlessly generating .xlsx files from input objects. Seamlessly create Excel spreadsheets with data, formatting, formulas, and more.

409 lines (406 loc) 12.9 kB
import { type BorderOption, type Data, type ExcelTable, type Header, } from "../data-model/excel-table"; import { rgbToHex } from "../utils/color"; function generateRowsBaseOnColAndRowSpan( col: number, row: number, start: number, length: number, rowV: any, text: string | number, mergeString: string, data: any ) { let rows = []; let type = "both"; let mergeValue = []; if (!row || row === 0) { row = 1; type = "col"; } else { mergeValue.push(row - 1); } if (!col || col === 0) { col = 0; type = "row"; } else { mergeValue.push(col - 1); } let rowEl = rowV ? rowV : {}; rowEl.mergeType = data && data.mergeType ? [...data.mergeType, type] : [type]; rowEl.mergeValue = data && data.mergeValue ? [...data.mergeValue, mergeValue] : [mergeValue]; rowEl.mergeStart = data && data.mergeStart ? [...data.mergeStart, start] : [start]; for (let index = 0; index < row; index++) { let countCol = col; for (let colI = 0; colI < length; colI++) { if (start <= colI) { if (countCol >= 1) { rowEl["c" + colI] = text; text = ""; mergeString += "*"; countCol--; } else { if (row >= 2 && start == colI) { rowEl["c" + colI] = text; text = ""; mergeString += "+"; } else { mergeString += "-"; } } } else { if (index > 0) { mergeString += "-"; } } } rows.push({ ...rowEl, mergeString, }); rowEl = {}; mergeString = ""; } return rows; } export type RowHeightScaleFunction = ( data: number, rowIndex: number, fromHeader: boolean ) => number; export type ColWidthScaleFunction = (data: number, colIndex: number) => number; export function createExcelTableBaseOnDomElement( queryForTable?: string | null, table?: HTMLTableElement | null, keepStyle?: boolean, rowHeightScaleFunction?: RowHeightScaleFunction, colWidthScaleFunction?: ColWidthScaleFunction ): ExcelTable { if (!queryForTable && !table) { throw "Error: One of the function inputs is required."; } let nodes; if (queryForTable) { nodes = document.querySelector(queryForTable)?.querySelectorAll("tr"); } else { nodes = table?.querySelectorAll("tr"); } let head: any = []; let dataObjs: any = []; let styleMap: any = { header: {}, rows: [], }; let headerHeight = 40; if (nodes) { let headerSet = false; let cellStyleMap: any = {}; let headerLength = 0; nodes.forEach((tr, rowIndex) => { var a = [].slice.call(tr.children); const trEl = window.getComputedStyle(tr, null); let bgTr = rgbToHex(trEl.backgroundColor); if (!headerSet) { headerLength = a.length; headerSet = true; if (typeof rowHeightScaleFunction == "function") { headerHeight = rowHeightScaleFunction( Number(trEl.height.substring(0, trEl.height.length - 2)), rowIndex, true ); } else { headerHeight = Number( trEl.height.substring(0, trEl.height.length - 2) ); } a.forEach((n, index) => { let styles = window.getComputedStyle(n, null); let border: BorderOption | null = null; if (styles.borderBottomWidth !== "0px") { const borderBottomColor = rgbToHex(styles.borderBottomColor); if (borderBottomColor) { if (!border) { border = {}; } border["bottom"] = { style: "thin", color: borderBottomColor, }; } } if (styles.borderTopWidth !== "0px") { const borderTopColor = rgbToHex(styles.borderTopColor); if (borderTopColor) { if (!border) { border = {}; } border["top"] = { style: "thin", color: borderTopColor, }; } } if (styles.borderLeftWidth !== "0px") { const borderLeftColor = rgbToHex(styles.borderLeftColor); if (borderLeftColor) { if (!border) { border = {}; } border["left"] = { style: "thin", color: borderLeftColor, }; } } if (styles.borderRightWidth !== "0px") { const borderRightColor = rgbToHex(styles.borderRightColor); if (borderRightColor) { if (!border) { border = {}; } border["right"] = { style: "thin", color: borderRightColor, }; } } let backgroundColor = rgbToHex(styles.backgroundColor); if (!backgroundColor && bgTr) { backgroundColor = bgTr; } const fontSizeStyle = parseInt( styles.fontSize.substring(0, styles.fontSize.indexOf("p")) ); let style = { ...(backgroundColor ? { backgroundColor } : {}), bold: parseInt(styles.fontWeight) > 500, ...(isNaN(fontSizeStyle) ? {} : { size: fontSizeStyle }), ...(border ? { border } : {}), alignment: { ...(typeof styles.textAlign == "string" && styles.textAlign.length > 0 ? { horizontal: styles.textAlign } : {}), vertical: "center", ...(styles.direction == "rtl" ? { rtl: true } : { ltr: true }), }, }; styleMap.header[rowIndex + "-" + index] = style; cellStyleMap[rowIndex + "-" + index] = rowIndex + "-" + index; let headWidth; if (typeof colWidthScaleFunction == "function") { headWidth = colWidthScaleFunction( Number(styles.width.substring(0, styles.width.length - 2)), index ); } else { headWidth = Number(styles.width.substring(0, styles.width.length - 2)) * 0.15; } const colSpanValue = (n as any).getAttribute("colspan"); const rowSpanValue = (n as any).getAttribute("rowspan"); head.push({ label: "c" + index, ...(colSpanValue ? { colspan: colSpanValue } : {}), ...(rowSpanValue ? { rowspan: rowSpanValue } : {}), text: (n as any).textContent, ...(isNaN(headWidth) || headWidth <= 0 ? {} : { size: headWidth }), }); }); } else { let data: any = {}; let mergeString = ""; let inMergeMode = false; if (dataObjs.length >= rowIndex) { data = dataObjs[rowIndex - 1]; mergeString = "mergeString" in data ? (data.mergeString as string) : ""; inMergeMode = true; } let counter = 0; a.forEach((n, index) => { if ("c" + (index + counter) in data) { for (let gh = 0; gh <= headerLength + 1; gh++) { let key = "c" + (index + gh); if (!(key in data)) { break; } else { counter++; } } } index += counter; let styles = window.getComputedStyle(n, null); if ( (n as any).getAttribute("colspan") || (n as any).getAttribute("rowspan") ) { let mergeData = generateRowsBaseOnColAndRowSpan( (n as any).getAttribute("colspan") * 1, (n as any).getAttribute("rowspan") * 1, index, headerLength, data, (n as any).textContent, mergeString, data ); if (dataObjs.length < rowIndex) { dataObjs.push(...mergeData); } else { mergeData.forEach((v, index) => { if (dataObjs.length < rowIndex + index) { dataObjs.push(...mergeData); } else { dataObjs[rowIndex + index] = { ...dataObjs[rowIndex + index], ...v, }; } }); } data = mergeData[0]; mergeString = mergeData[0].mergeString; inMergeMode = true; } else { if (!inMergeMode) { mergeString += "-"; } } let border: BorderOption | null = null; if (styles.borderBottomWidth !== "0px") { const borderBottomColor = rgbToHex(styles.borderBottomColor); if (borderBottomColor) { if (!border) { border = {}; } border["bottom"] = { style: "thin", color: borderBottomColor, }; } } if (styles.borderTopWidth !== "0px") { const borderTopColor = rgbToHex(styles.borderTopColor); if (borderTopColor) { if (!border) { border = {}; } border["top"] = { style: "thin", color: borderTopColor, }; } } if (styles.borderLeftWidth !== "0px") { const borderLeftColor = rgbToHex(styles.borderLeftColor); if (borderLeftColor) { if (!border) { border = {}; } border["left"] = { style: "thin", color: borderLeftColor, }; } } if (styles.borderRightWidth !== "0px") { const borderRightColor = rgbToHex(styles.borderRightColor); if (borderRightColor) { if (!border) { border = {}; } border["right"] = { style: "thin", color: borderRightColor, }; } } let backgroundColor = rgbToHex(styles.backgroundColor); if (!backgroundColor && bgTr) { backgroundColor = bgTr; } const fontSizeStyle = parseInt( styles.fontSize.substring(0, styles.fontSize.indexOf("p")) ); let style = { ...(backgroundColor ? { backgroundColor } : {}), bold: parseInt(styles.fontWeight) > 500, ...(isNaN(fontSizeStyle) ? {} : { size: fontSizeStyle }), ...(border ? { border } : {}), alignment: { ...(typeof styles.textAlign == "string" && styles.textAlign.length > 0 ? { horizontal: styles.textAlign } : {}), vertical: "center", ...(styles.direction == "rtl" ? { rtl: true } : { ltr: true }), }, }; styleMap.header[rowIndex + "-" + index] = style; data["c" + index] = (n as any).textContent; cellStyleMap[rowIndex + "-" + index] = rowIndex + "-" + index; }); if (typeof rowHeightScaleFunction == "function") { data.height = rowHeightScaleFunction( Number(trEl.height.substring(0, trEl.height.length - 2)), rowIndex, false ); } else { data.height = trEl.height.substring(0, trEl.height.length - 2); } if (typeof data.height == "string" && data.height.length == 0) { delete data.height; } if (dataObjs.length < rowIndex) { dataObjs.push(data); } else { dataObjs[rowIndex - 1] = data; } } }); } else { throw "Error: DOM Element Not Found"; } let data: ExcelTable = { styles: styleMap.header, sheet: [ { ...(headerHeight ? { headerHeight } : {}), styleCellCondition: function ( data: Header | string | number | undefined, object: Header | Data, rowIndex: number, colIndex: number, fromHeader: boolean, styleKeys: string[] ) { if (keepStyle) { if (fromHeader) { return styleKeys.includes(rowIndex - 1 + "-" + colIndex) ? rowIndex - 1 + "-" + colIndex : ""; } else { return styleKeys.includes(rowIndex - 1 + "-" + colIndex) ? rowIndex - 1 + "-" + colIndex : ""; } } else { return null; } }, data: dataObjs, headers: head, }, ], }; return data; }