excel-builder-vanilla
Version:
An easy way of building Excel files with javascript
176 lines (157 loc) • 5.27 kB
text/typescript
import type { ExcelSortState, ExcelTableColumn } from '../interfaces.js';
import { isString } from '../utilities/isTypeOf.js';
import { uniqueId } from '../utilities/uniqueId.js';
import { Util } from './Util.js';
import type { XMLDOM } from './XMLDOM.js';
/**
* @module Excel/Table
*/
export class Table {
name = '';
id = '';
tableId = '';
displayName = '';
dataCellStyle: any = null;
dataDfxId: number | null = null;
headerRowBorderDxfId: number | null = null;
headerRowCellStyle: any = null;
headerRowCount = 1;
headerRowDxfId: number | null = null;
insertRow = false;
insertRowShift = false;
ref: any = null;
tableBorderDxfId: number | null = null;
totalsRowBorderDxfId: number | null = null;
totalsRowCellStyle: any = null;
totalsRowCount = 0;
totalsRowDxfId: number | null = null;
tableColumns: any = [];
autoFilter: any = null;
sortState: any = null;
styleInfo: any = {};
constructor(config?: any) {
this.initialize(config);
}
initialize(config: any) {
this.displayName = uniqueId('Table');
this.name = this.displayName;
this.id = this.name;
this.tableId = this.id.replace('Table', '');
Object.assign(this, config);
}
setReferenceRange(start: number[], end: number[]) {
this.ref = [start, end];
}
setTableColumns(columns: Array<ExcelTableColumn | string>) {
columns.forEach(column => {
this.addTableColumn(column);
});
}
/**
* Expects an object with the following optional properties:
* name (required)
* dataCellStyle
* dataDxfId
* headerRowCellStyle
* headerRowDxfId
* totalsRowCellStyle
* totalsRowDxfId
* totalsRowFunction
* totalsRowLabel
* columnFormula
* columnFormulaIsArrayType (boolean)
* totalFormula
* totalFormulaIsArrayType (boolean)
*/
addTableColumn(column: ExcelTableColumn | string) {
if (isString(column)) {
column = {
name: column,
};
}
if (!column.name) {
throw new Error('Invalid argument for addTableColumn - minimum requirement is a name property');
}
this.tableColumns.push(column);
}
/**
* Expects an object with the following properties:
* caseSensitive (boolean)
* dataRange
* columnSort (assumes true)
* sortDirection
* sortRange (defaults to dataRange)
*/
setSortState(state: ExcelSortState) {
this.sortState = state;
}
toXML() {
const doc = Util.createXmlDoc(Util.schemas.spreadsheetml, 'table');
const table = doc.documentElement;
table.setAttribute('id', this.tableId);
table.setAttribute('name', this.name);
table.setAttribute('displayName', this.displayName);
const s = this.ref[0];
const e = this.ref[1];
table.setAttribute('ref', `${Util.positionToLetterRef(s[0], s[1])}:${Util.positionToLetterRef(e[0], e[1])}`);
/** TOTALS **/
table.setAttribute('totalsRowCount', this.totalsRowCount);
/** HEADER **/
table.setAttribute('headerRowCount', this.headerRowCount);
if (this.headerRowDxfId) {
table.setAttribute('headerRowDxfId', this.headerRowDxfId);
}
if (this.headerRowBorderDxfId) {
table.setAttribute('headerRowBorderDxfId', this.headerRowBorderDxfId);
}
if (!this.ref) {
throw new Error('Needs at least a reference range');
}
if (!this.autoFilter) {
this.addAutoFilter(this.ref[0], this.ref[1]);
}
table.appendChild(this.exportAutoFilter(doc));
table.appendChild(this.exportTableColumns(doc));
table.appendChild(this.exportTableStyleInfo(doc));
return doc;
}
exportTableColumns(doc: XMLDOM) {
const tableColumns = doc.createElement('tableColumns');
tableColumns.setAttribute('count', this.tableColumns.length);
const tcs = this.tableColumns;
for (let i = 0, l = tcs.length; i < l; i++) {
const tc = tcs[i];
const tableColumn = doc.createElement('tableColumn');
tableColumn.setAttribute('id', String(i + 1));
tableColumn.setAttribute('name', tc.name);
tableColumns.appendChild(tableColumn);
if (tc.totalsRowFunction) {
tableColumn.setAttribute('totalsRowFunction', tc.totalsRowFunction);
}
if (tc.totalsRowLabel) {
tableColumn.setAttribute('totalsRowLabel', tc.totalsRowLabel);
}
}
return tableColumns;
}
exportAutoFilter(doc: XMLDOM) {
const autoFilter = doc.createElement('autoFilter');
const s = this.autoFilter[0];
const e = this.autoFilter[1];
autoFilter.setAttribute('ref', `${Util.positionToLetterRef(s[0], s[1])}:${Util.positionToLetterRef(e[0], e[1] - this.totalsRowCount)}`);
return autoFilter;
}
exportTableStyleInfo(doc: XMLDOM) {
const ts = this.styleInfo;
const tableStyle = doc.createElement('tableStyleInfo');
tableStyle.setAttribute('name', ts.themeStyle);
tableStyle.setAttribute('showFirstColumn', ts.showFirstColumn ? '1' : '0');
tableStyle.setAttribute('showLastColumn', ts.showLastColumn ? '1' : '0');
tableStyle.setAttribute('showColumnStripes', ts.showColumnStripes ? '1' : '0');
tableStyle.setAttribute('showRowStripes', ts.showRowStripes ? '1' : '0');
return tableStyle;
}
addAutoFilter(startRef: any, endRef: any) {
this.autoFilter = [startRef, endRef];
}
}