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.
1,514 lines (1,501 loc) • 99.5 kB
text/typescript
import {
type AlignmentOptionKey,
type AsTableOption,
type ConditionalFormatting,
type ExcelTable,
type Formula,
type HeaderFooterOption,
type MergeRowConditionMap,
type ProtectionOptionKey,
type RowMap,
type StyleMapper,
type Buffer,
} from "../data-model/excel-table";
import { generateColumnName } from "../utils/generate-column-name";
import { styleGenerator } from "../utils/content-generator/styles";
import { contentTypeGenerator } from "../utils/content-generator/content-types";
import { appGenerator } from "../utils/content-generator/app";
import { generateCellRowCol } from "../utils/generate-formula-cell";
import { convertToHex } from "../utils/color";
import {
commentConvertor,
defaultCellCommentStyle,
generateCommentTag,
} from "../utils/comment";
import { generateMultiStyleByArray } from "../utils/multi-value";
import {
cols as colsDef,
formatMap as defaultFormatMap,
} from "../data-model/const-data";
import { toDataURL2 } from "../utils/image";
import { getColRowBaseOnRefString } from "../utils/excel-util";
import { specialCharacterConverter } from "../utils/special-character";
import { applyConfig } from "../utils/store";
import type JSZip from "jszip";
import { generateDropDown } from "../utils/drop-down-utils";
export async function generateExcel(
data: ExcelTable,
styleKey: string = ""
): Promise<string | number[] | Blob | Buffer | undefined> {
if (typeof styleKey == "string" && styleKey.length > 0) {
data = applyConfig(styleKey, data);
}
if (typeof data.creator == "string" && data.creator.trim().length <= 0) {
throw 'length of "creator" most be bigger then 0';
}
if (
typeof data.created == "string" &&
new Date(data.created).toString() == "Invalid Date"
) {
throw '"created" is not valid date';
}
if (
typeof data.modified == "string" &&
new Date(data.modified).toString() == "Invalid Date"
) {
throw '"modified" is not valid date';
}
let formatMap = defaultFormatMap;
if (data.formatMap && typeof data.formatMap == "object") {
formatMap = {
...formatMap,
...data.formatMap,
};
}
const isBackend = data.backend;
const operatorMap: Record<string, string> = {
lt: "lessThan",
gt: "greaterThan",
between: "between",
ct: "containsText",
eq: "equal",
};
let cols: string[] = [...colsDef];
if (data.numberOfColumn && data.numberOfColumn > 25) {
cols = generateColumnName(cols, data.numberOfColumn);
}
const module = await import("jszip");
const JSZip1 = module.default;
let zip = new JSZip1();
if (!data.sheet) {
data.sheet = [
{
headers: [],
data: [],
},
];
}
const sheetLength = data.sheet.length;
// xl
let xlFolder = zip.folder("xl");
let xl_media_Folder: JSZip | null | undefined = null;
let xl_drawingsFolder: JSZip | null | undefined = null;
let xl_drawings_relsFolder: JSZip | null | undefined = null;
if (!data.styles) {
data.styles = {};
}
if (data.addDefaultTitleStyle) {
data.styles["titleStyle"] = {
alignment: {
horizontal: "center",
vertical: "center",
},
};
}
const styleKeys = Object.keys(data.styles);
const defaultCommentStyle = defaultCellCommentStyle;
const addCF = data.activateConditionalFormatting
? data.activateConditionalFormatting
: false;
const headerFooterStyle: Record<string, string> = {};
const cFMapIndex: Record<string, number> = {};
let styleMapper: StyleMapper = styleKeys.reduce(
(res: StyleMapper, cur, index) => {
const styleObject = data.styles![cur];
if (
styleObject.type &&
(styleObject.type == "headerFooter" || styleObject.type == "HF")
) {
let result = "";
let fontProcessLeft = "-";
let fontProcessRight = "Regular";
if (styleObject.fontFamily) {
fontProcessLeft = styleObject.fontFamily;
}
if (styleObject.bold) {
fontProcessRight = "Bold";
}
if (styleObject.italic) {
if (fontProcessRight == "Regular") {
fontProcessRight = "";
}
fontProcessRight += "Italic";
}
if (fontProcessLeft != "-" || fontProcessRight != "Regular") {
result =
"&" + '"' + fontProcessLeft + "," + fontProcessRight + '"';
}
if (styleObject.size) {
result += "&" + styleObject.size;
}
if (styleObject.doubleUnderline) {
result += "&E";
} else if (styleObject.underline) {
result += "&U";
}
if (styleObject.color) {
const convertedColor = convertToHex(styleObject.color, isBackend);
if (typeof convertedColor == "string" && convertedColor.length > 0) {
result += "&K" + convertedColor.toUpperCase();
}
}
headerFooterStyle[cur] = result;
return res;
}
if (
addCF &&
typeof styleObject.type == "string" &&
styleObject.type &&
(styleObject.type == "conditionalFormatting" ||
styleObject.type.toUpperCase() == "CF")
) {
cFMapIndex[cur] = res.conditionalFormatting.count;
let color = convertToHex(styleObject.color, isBackend);
let bgColor = convertToHex(styleObject.backgroundColor, isBackend);
res.conditionalFormatting.value +=
'<dxf><font><color rgb="' +
color +
'"/></font><fill> <patternFill> <bgColor rgb="' +
bgColor +
'"/></patternFill></fill></dxf>';
res.conditionalFormatting.count++;
return res;
}
const indexes = {
fillIndex: 0,
fontIndex: 0,
borderIndex: 0,
formatIndex: 0,
};
if (styleObject.backgroundColor) {
let fgConvertor = convertToHex(styleObject.backgroundColor, isBackend);
indexes.fillIndex = res.fill.count;
res.fill.count++;
res.fill.value =
res.fill.value +
"<fill>" +
'<patternFill patternType="solid">' +
(fgConvertor
? '<fgColor rgb="' + fgConvertor.replace("#", "") + '" />'
: "") +
"</patternFill>" +
"</fill>";
}
if (
styleObject.color ||
styleObject.fontFamily ||
styleObject.size ||
styleObject.bold ||
styleObject.italic ||
styleObject.underline ||
styleObject.doubleUnderline
) {
const colors = convertToHex(styleObject.color, isBackend);
indexes.fontIndex = res.font.count;
res.font.count++;
res.font.value =
res.font.value +
"<font>" +
(styleObject.bold ? "<b/>" : "") +
(styleObject.italic ? "<i />" : "") +
(styleObject.underline || styleObject.doubleUnderline
? "<u " +
(styleObject.doubleUnderline ? ' val="double" ' : "") +
"/>"
: "") +
(styleObject.size ? '<sz val="' + styleObject.size + '" />' : "") +
(colors ? '<color rgb="' + colors.replace("#", "") + '" />' : "") +
(styleObject.fontFamily
? '<name val="' + styleObject.fontFamily + '" />'
: "") +
"</font>";
res.commentSyntax.value[cur] =
"<rPr>" +
(styleObject.bold ? "<b/>" : "") +
(styleObject.italic ? "<i/>" : "") +
(styleObject.underline || styleObject.doubleUnderline
? "<u " +
(styleObject.doubleUnderline ? 'val="double" ' : "") +
"/>"
: "") +
'<sz val="' +
(styleObject.size ? styleObject.size : "9") +
'" />' +
(colors ? '<color rgb="' + colors.replace("#", "") + '" />' : "") +
'<rFont val="' +
(styleObject.fontFamily ? styleObject.fontFamily : "Tahoma") +
'" />' +
"</rPr>";
}
let endPart = "/>";
if (styleObject.alignment) {
if (styleObject.alignment.rtl) {
styleObject.alignment["readingOrder"] = 2;
}
delete styleObject.alignment.rtl;
if (styleObject.alignment.ltr) {
styleObject.alignment["readingOrder"] = 1;
}
delete styleObject.alignment.ltr;
endPart =
' applyAlignment="1">' +
"<alignment " +
Object.keys(styleObject.alignment).reduce((al, alignmentOption) => {
return (
al +
" " +
alignmentOption +
'="' +
styleObject.alignment![alignmentOption! as AlignmentOptionKey] +
'" '
);
}, "") +
" />" +
"</xf>";
}
const borderObj = styleObject.border;
let borderStr = "";
if (typeof borderObj == "object") {
if (borderObj.left || borderObj.full) {
borderStr +=
'<left style="' +
(borderObj.left || borderObj.full)!.style +
'">' +
'<color rgb="' +
convertToHex(
(borderObj.left || borderObj.full)!.color,
isBackend
)!.replace("#", "") +
'" />' +
"</left>";
}
if (borderObj.right || borderObj.full) {
borderStr +=
'<right style="' +
(borderObj.right || borderObj.full)!.style +
'">' +
'<color rgb="' +
convertToHex(
(borderObj.right || borderObj.full)!.color,
isBackend
)!.replace("#", "") +
'" />' +
"</right>";
}
if (borderObj.top || borderObj.full) {
borderStr +=
'<top style="' +
(borderObj.top || borderObj.full)!.style +
'">' +
'<color rgb="' +
convertToHex(
(borderObj.top || borderObj.full)!.color,
isBackend
)!.replace("#", "") +
'" />' +
"</top>";
}
if (borderObj.bottom || borderObj.full) {
borderStr +=
'<bottom style="' +
(borderObj.bottom || borderObj.full)!.style +
'">' +
'<color rgb="' +
convertToHex(
(borderObj.bottom || borderObj.full)!.color,
isBackend
)!.replace("#", "") +
'" />' +
"</bottom>";
}
indexes.borderIndex = res.border.count;
res.border.count++;
res.border.value +=
"<border>" + borderStr + "<diagonal />" + "</border>";
}
if (styleObject.format) {
const format = formatMap[styleObject.format];
if (format) {
indexes.formatIndex = format.key;
if ("value" in format) {
res.format.count++;
res.format.value += format.value;
}
}
}
res.cell.value =
res.cell.value +
'<xf numFmtId="' +
indexes.formatIndex +
'"' +
' fontId="' +
indexes.fontIndex +
'" fillId="' +
indexes.fillIndex +
'" borderId="' +
indexes.borderIndex +
'" xfId="0"' +
(indexes.borderIndex > 0 ? ' applyBorder="1" ' : "") +
(indexes.fillIndex > 0 ? ' applyFill="1" ' : "") +
(indexes.fontIndex >= 0 ? ' applyFont="1" ' : "") +
(indexes.formatIndex > 0 ? ' applyNumberFormat="1" ' : "") +
endPart;
data.styles![cur].index = res.cell.count;
res.cell.count++;
return res;
},
{
conditionalFormatting: {
count: addCF ? 1 : 0,
value:
'<dxf><font><color rgb="FF9C0006"/></font><fill> <patternFill> <bgColor rgb="FFFFC7CE"/></patternFill></fill></dxf>',
},
commentSyntax: {
value: {},
},
format: {
count: 0,
value: "",
},
border: {
count: 1,
value: "",
},
fill: {
count: 2,
value: "",
},
font: {
count: 2,
value: "",
},
cell: {
count: 2,
value: "",
},
}
);
xlFolder?.file("styles.xml", styleGenerator(styleMapper, addCF));
let sheetContentType =
'<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet1.xml" />';
let sharedString = "";
let sharedStringIndex = 0;
let workbookString = "";
let workbookRelString = "";
let sharedStringMap: {
[key: string]: string;
} = {};
const mapData: {
[k: string]: {
[k2: string]: string | number | boolean | object;
};
} = {};
let sheetNameApp = "";
let indexId = 4;
let selectedAdded = false;
let activeTabIndex = -1;
let arrTypes: string[] = [];
let imageCounter = 1;
interface ShapeRC {
row: string | number;
col: string | number;
}
const formCtrlMap = {
checkbox:
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' +
'<formControlPr xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" objectType="CheckBox" **value** **fmlaLink** lockText="1" noThreeD="1"/>',
};
let shapeIdCounter = 1024;
const shapeMap = {
checkbox: `<v:shape id="***id***" type="#_x0000_t201" style='position:absolute;
margin-left:1.5pt;margin-top:1.5pt;width:63pt;height:16.5pt;z-index:1;
mso-wrap-style:tight' filled="f" fillcolor="window [65]" stroked="f"
strokecolor="windowText [64]" o:insetmode="auto">
<v:path shadowok="t" strokeok="t" fillok="t"/>
<o:lock v:ext="edit" rotation="t"/>
<v:textbox style='mso-direction-alt:auto' o:singleclick="f">
<div style='text-align:left'><font face="Segoe UI" size="160" color="auto">***text***</font></div>
</v:textbox>
<x:ClientData ObjectType="Checkbox">
<x:SizeWithCells/>
<x:Anchor>
0, 2, 0, 2, 0, 86, 1, 0</x:Anchor>
<x:AutoFill>False</x:AutoFill>
<x:AutoLine>False</x:AutoLine>
<x:TextVAlign>Center</x:TextVAlign>
<x:NoThreeD/>
</x:ClientData>
</v:shape>`,
};
const shapeTypeMap = {
checkbox: `<v:shapetype id="_x0000_t201" coordsize="21600,21600" o:spt="201"
path="m,l,21600r21600,l21600,xe">
<v:stroke joinstyle="miter"/>
<v:path shadowok="f" o:extrusionok="f" strokeok="f" fillok="f" o:connecttype="rect"/>
<o:lock v:ext="edit" shapetype="t"/>
</v:shapetype>`,
};
let checkboxForm: string[] = [];
let calcChainValue = "";
let needCalcChain = false;
let xl_tableFolder: JSZip | null | undefined = null;
for (let index = 0; index < sheetLength; index++) {
const sheetData = data.sheet[index];
const sheetDataId = index + 1;
let rowMap: RowMap = {};
let sheetDimensions = {
start: "",
end: "",
};
const asTable = sheetData.asTable;
let sheetDataTableColumns = "";
let rowCount =
sheetData.shiftTop && sheetData.shiftTop >= 0
? sheetData.shiftTop + 1
: 1;
let sheetDataString = "";
let sheetSizeString = "";
let sheetSortFilter = "";
let splitOption = "";
let sheetViewProperties = "";
let viewType: string = "";
let hasCheckbox = false;
let checkboxDrawingContent = "";
let checkboxShape = "";
let formRel = "";
let checkboxSheetContent = "";
let mergesCellArray: string[] = Object.assign([], sheetData.merges);
let formulaSheetObj: Formula = Object.assign({}, sheetData.formula);
let conditionalFormatting: ConditionalFormatting[] = Object.assign(
[],
sheetData.conditionalFormatting
);
let hasComment = false;
let commentAuthor: string[] = [];
let commentString = "";
let shapeCommentRowCol: ShapeRC[] = [];
let objKey: string[] = [];
let headerFormula: number[] = [];
let headerConditionalFormatting: number[] = [];
let mergeRowConditionMap: MergeRowConditionMap = {};
let sheetHeaderFooter = "";
let isPortrait = false;
let sheetBreakLine = "";
if (sheetData.rtl) {
sheetViewProperties += ' rightToLeft="1" ';
}
if (sheetData.pageBreak) {
const pageBreak = sheetData.pageBreak;
if (pageBreak.row && Array.isArray(pageBreak.row)) {
viewType = "pageBreakPreview";
const rowLength = pageBreak.row.length;
sheetBreakLine +=
'<rowBreaks count="' +
rowLength +
'" manualBreakCount="' +
rowLength +
'">' +
pageBreak.row.reduce(
(result, current) =>
result + '<brk id="' + current + '" max="16383" man="1"/>',
""
) +
"</rowBreaks>";
}
if (pageBreak.column && Array.isArray(pageBreak.column)) {
viewType = "pageBreakPreview";
const columnLength = pageBreak.column.length;
sheetBreakLine +=
'<colBreaks count="' +
columnLength +
'" manualBreakCount="' +
columnLength +
'">' +
pageBreak.column.reduce(
(result, current) =>
result + '<brk id="' + current + '" max="16383" man="1"/>',
""
) +
"</colBreaks>";
}
}
let sheetMargin = "";
if (sheetData.pageOption) {
const pageOption = sheetData.pageOption;
if (pageOption.isPortrait) {
isPortrait = true;
}
if (pageOption.margin) {
const margin = pageOption.margin;
let result = {
left: 0.7,
right: 0.7,
top: 0.75,
bottom: 0.75,
header: 0.3,
footer: 0.3,
};
Object.keys(result).forEach((marginKey) => {
if (typeof margin[marginKey as keyof object] == "number") {
result[marginKey as keyof object] =
margin[marginKey as keyof object];
}
});
sheetMargin =
'<pageMargins left="' +
result["left"] +
'" right="' +
result["right"] +
'" top="' +
result["top"] +
'" bottom="' +
result["bottom"] +
'" header="' +
result["header"] +
'" footer="' +
result["footer"] +
'"/>';
}
let typeKeeper = "";
let odd = "";
let even = "";
let first = "";
const keyKey = ["header", "footer"];
keyKey.forEach((keyObj) => {
const endTag = keyObj.charAt(0).toUpperCase() + keyObj.substring(1);
if (pageOption[keyObj as keyof object]) {
const element = pageOption[keyObj as keyof object];
if (typeof element == "object") {
Object.keys(element).forEach((typeHF) => {
if (typeKeeper.indexOf(typeHF) < 0) {
typeKeeper += typeHF;
}
const typeObj = element[typeHF];
let node = "";
Object.keys(typeObj)
.reduce((resultKey, currentKey) => {
if (currentKey == "l") {
resultKey.splice(0, 0, currentKey);
} else if (currentKey == "c") {
resultKey.splice(1, 0, currentKey);
} else if (currentKey == "r") {
resultKey.splice(2, 0, currentKey);
}
return resultKey;
}, [] as string[])
.forEach((direction) => {
const dirObj = <HeaderFooterOption>typeObj[direction];
node += "&" + direction.toUpperCase();
if (dirObj.styleId && headerFooterStyle[dirObj.styleId]) {
node += headerFooterStyle[dirObj.styleId];
}
if (dirObj.text) {
node += dirObj.text;
}
});
node =
"<" +
typeHF +
endTag +
">" +
node +
"</" +
typeHF +
endTag +
">";
if (typeHF == "odd") {
odd += node;
} else if (typeHF == "even") {
even += node;
} else if (typeHF == "first") {
first += node;
} else {
throw "type error";
}
});
}
}
});
sheetHeaderFooter = odd + even + first;
if (sheetHeaderFooter.length > 0) {
isPortrait = true;
const oddEvenFlag =
typeKeeper.length == "oddeven".length ||
typeKeeper.length == "oddevenfirst".length
? ' differentOddEven="1"'
: "";
const firstFlag =
typeKeeper.indexOf("first") >= 0 ? ' differentFirst="1"' : "";
sheetHeaderFooter =
"<headerFooter" +
oddEvenFlag +
firstFlag +
">" +
sheetHeaderFooter +
"</headerFooter>";
}
}
if (sheetData.viewOption) {
let splitState = "";
const viewOption = sheetData.viewOption;
if (viewOption.type) {
viewType = viewOption.type;
}
if (viewOption.hideRuler) {
sheetViewProperties += ' showRuler="0" ';
}
if (viewOption.hideGrid) {
sheetViewProperties += ' showGridLines="0" ';
}
if (viewOption.hideHeadlines) {
sheetViewProperties += ' showRowColHeaders="0" ';
}
let split = viewOption.splitOption;
if (typeof split == "undefined") {
isPortrait = false;
if (typeof viewOption.frozenOption == "object") {
const frozen = viewOption.frozenOption;
splitState = ' state="frozen" ';
if (frozen.type == "R" || frozen.type == "ROW") {
let fIndex;
if (typeof frozen.index == "object") {
fIndex = frozen.index.r;
} else {
fIndex = frozen.index;
}
split = {
startAt: {
b: "A" + (fIndex + 1),
},
type: "H",
split: fIndex,
};
} else if (frozen.type == "C" || frozen.type == "COLUMN") {
let fIndex;
if (typeof frozen.index == "object") {
fIndex = frozen.index.c;
} else {
fIndex = frozen.index;
}
if (fIndex > cols.length - 1) {
cols = generateColumnName(cols, fIndex);
}
split = {
type: "V",
startAt: {
r: cols[fIndex] + 1,
},
split: fIndex,
};
} else if (frozen.type == "B" || frozen.type == "BOTH") {
let two = "";
let splitO;
if (typeof frozen.index == "number") {
splitO = frozen.index;
two = cols[frozen.index] + (frozen.index + 1);
} else {
splitO = {
y: frozen.index.r,
x: frozen.index.c,
};
two = cols[frozen.index.c] + (frozen.index.r + 1);
}
split = {
startAt: {
two,
},
type: "B",
split: splitO,
};
}
}
}
if (split) {
if (split.type == "H" || split.type == "HORIZONTAL") {
let ref;
if (split.startAt) {
ref = split.startAt.b;
if (split.startAt.t) {
sheetViewProperties += ' topLeftCell="' + split.startAt.t + '"';
}
}
if (!ref) {
ref = "A1";
}
splitOption =
'<pane ySplit="' +
((typeof split.split == "object" && split.split.y) || split.split) +
'" topLeftCell="' +
ref +
'" activePane="bottomLeft"' +
splitState +
"/>";
} else if (split.type == "V" || split.type == "VERTICAL") {
let ref;
if (split.startAt) {
ref = split.startAt.r;
if (split.startAt.l) {
sheetViewProperties += ' topLeftCell="' + split.startAt.l + '"';
}
}
if (!ref) {
ref = "A1";
}
splitOption =
'<pane xSplit="' +
((typeof split.split == "object" && split.split.x) || split.split) +
'" topLeftCell="' +
ref +
'" activePane="topLeft"' +
splitState +
"/>";
} else {
let ref;
if (split.startAt) {
ref = split.startAt.two;
if (split.startAt.one) {
sheetViewProperties += ' topLeftCell="' + split.startAt.one + '"';
}
}
if (!ref) {
ref = "A1";
}
splitOption =
'<pane xSplit="' +
((typeof split.split == "object" && split.split.x) || split.split) +
'" ySplit="' +
((typeof split.split == "object" && split.split.y) || split.split) +
'" topLeftCell="' +
ref +
'" activePane="bottomLeft"' +
splitState +
"/>";
}
}
}
if (isPortrait) {
viewType = "pageLayout";
}
if (sheetData.checkbox) {
hasCheckbox = true;
const strFormDef = formCtrlMap["checkbox"];
sheetData.checkbox.forEach((v, i) => {
let formCtlStr = strFormDef;
if (v.link) {
let linkAddress = getColRowBaseOnRefString(v.link, cols);
formCtlStr = formCtlStr.replace(
"**fmlaLink**",
'fmlaLink="$' +
cols[linkAddress.col] +
"$" +
(linkAddress.row + 1) +
'"'
);
} else {
formCtlStr = formCtlStr.replace("**fmlaLink**", "");
}
if (v.mixed) {
formCtlStr = formCtlStr.replace("**value**", 'checked="Mixed"');
} else {
if (v.checked) {
formCtlStr = formCtlStr.replace("**value**", 'checked="Checked"');
} else {
formCtlStr = formCtlStr.replace("**value**", "");
}
}
if (v.threeD) {
formCtlStr.replace('noThreeD="1"', "");
}
checkboxForm.push(formCtlStr);
shapeIdCounter++;
let shapeId = index + "" + shapeIdCounter++;
const sId = "_x0000_s" + shapeId;
checkboxShape += shapeMap["checkbox"]
.replace("***id***", sId)
.replace("***text***", v.text);
let from = v.startStr;
let to = v.endStr;
let resultVal = {
start: {
col: 0,
row: 0,
},
end: {
col: 1,
row: 1,
},
};
if (v.col && v.row) {
resultVal = {
start: {
col: v.col,
row: v.row - 1,
},
end: {
col: v.col,
row: v.row,
},
};
}
if (typeof from == "string" && from.length >= 2) {
let p = getColRowBaseOnRefString(from, cols);
resultVal.start = {
...p,
};
resultVal.end = {
col: p.col + 1,
row: p.row + 1,
};
}
if (typeof to == "string" && to.length >= 2) {
let p = getColRowBaseOnRefString(to, cols);
p.row += 1;
p.col += 1;
resultVal.end = {
...p,
};
}
checkboxSheetContent +=
'<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice Requires="x14"><control shapeId="' +
shapeId +
'" r:id="rId' +
(7 + i) +
'" name="' +
v.text +
'"><controlPr defaultSize="0" autoFill="0" autoLine="0" autoPict="0"><anchor moveWithCells="1"><from><xdr:col>' +
resultVal.start.col +
"</xdr:col><xdr:colOff>19050</xdr:colOff><xdr:row>" +
resultVal.start.row +
"</xdr:row><xdr:rowOff>19050</xdr:rowOff></from><to><xdr:col>" +
resultVal.end.col +
"</xdr:col><xdr:colOff>819150</xdr:colOff><xdr:row>" +
resultVal.end.row +
"</xdr:row><xdr:rowOff>0</xdr:rowOff></to></anchor></controlPr></control></mc:Choice></mc:AlternateContent>";
formRel +=
'<Relationship Id="rId' +
(7 + i) +
'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp" ' +
'Target="../ctrlProps/ctrlProp' +
checkboxForm.length +
'.xml" />';
checkboxDrawingContent +=
'<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" Requires="a14"><xdr:twoCellAnchor editAs="oneCell"><xdr:from><xdr:col>' +
resultVal.start.col +
"</xdr:col><xdr:colOff>19050</xdr:colOff><xdr:row>" +
resultVal.start.row +
"</xdr:row><xdr:rowOff>19050</xdr:rowOff></xdr:from><xdr:to><xdr:col>" +
resultVal.end.col +
"</xdr:col><xdr:colOff>819150</xdr:colOff><xdr:row>" +
resultVal.end.row +
'</xdr:row><xdr:rowOff>0</xdr:rowOff></xdr:to><xdr:sp macro="" textlink=""><xdr:nvSpPr><xdr:cNvPr id="' +
shapeId +
'" name="' +
v.text +
'" hidden="1"><a:extLst><a:ext uri=""><a14:compatExt spid="' +
sId +
'"/></a:ext><a:ext uri=""><a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id=""/></a:ext>' +
'</a:extLst></xdr:cNvPr><xdr:cNvSpPr/></xdr:nvSpPr><xdr:spPr bwMode="auto"><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></a:xfrm>' +
'<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln></xdr:spPr><xdr:txBody>' +
'<a:bodyPr vertOverflow="clip" wrap="square" lIns="27432" tIns="18288" rIns="0" bIns="18288" anchor="ctr" upright="1"/>' +
'<a:lstStyle/><a:p><a:pPr algn="l" rtl="0"><a:defRPr sz="1000"/></a:pPr><a:r><a:rPr lang="en-US" sz="800" b="0" i="0" u="none" strike="noStrike" baseline="0"><a:solidFill>' +
'<a:srgbClr val="000000"/></a:solidFill><a:latin typeface="Segoe UI"/><a:cs typeface="Segoe UI"/></a:rPr><a:t>' +
v.text +
"</a:t></a:r></a:p></xdr:txBody></xdr:sp><xdr:clientData/></xdr:twoCellAnchor></mc:Choice><mc:Fallback/></mc:AlternateContent>";
});
}
let backgroundImagePromise;
if (sheetData.backgroundImage) {
if (xl_media_Folder == null) {
xl_media_Folder = xlFolder?.folder("media");
}
const urlImg = sheetData.backgroundImage;
backgroundImagePromise = new Promise(async (resolve, reject) => {
let indexImageType = urlImg.lastIndexOf(".");
let type;
if (indexImageType > 0) {
type = urlImg.substring(indexImageType + 1).toLowerCase();
if (type.length > 4) {
if (type.indexOf("gif") >= 0) {
type = "gif";
} else if (type.indexOf("jpg") >= 0) {
type = "jpg";
} else if (type.indexOf("jpeg") >= 0) {
type = "jpeg";
} else {
type = "png";
}
}
} else {
type = "png";
}
const ref = imageCounter++;
const name = "image" + ref + "." + type;
const image = await toDataURL2(urlImg, name, isBackend, data.fetch);
if (!image) {
reject("image not load");
}
arrTypes.push(type);
resolve({
name,
type,
image,
ref,
});
});
}
let imagePromise;
if (sheetData.images) {
if (xl_media_Folder == null) {
xl_media_Folder = xlFolder?.folder("media");
}
imagePromise = Promise.all([
...sheetData.images.map(async (v, i) => {
let indexImageType = v.url.lastIndexOf(".");
let type;
if (indexImageType > 0) {
type = v.url.substring(indexImageType + 1).toLowerCase();
if (type.length > 4) {
if (type.indexOf("gif") >= 0) {
type = "gif";
} else if (type.indexOf("jpg") >= 0) {
type = "jpg";
} else if (type.indexOf("jpeg") >= 0) {
type = "jpeg";
} else {
type = "png";
}
}
} else {
type = "png";
}
arrTypes.push(type);
const name = "image" + imageCounter++ + "." + type;
return {
type,
image: await toDataURL2(v.url, name, isBackend, data.fetch),
obj: v,
i,
name,
};
}),
]);
}
if (Array.isArray(sheetData.headers) && sheetData.headers.length) {
const colsLength = sheetData.headers.length;
let titleRow = "";
if (sheetData.title) {
const title = sheetData.title;
const commentTitle = title.comment;
const top = title.shiftTop && title.shiftTop >= 0 ? title.shiftTop : 0;
const sL =
sheetData.shiftLeft && sheetData.shiftLeft >= 0
? sheetData.shiftLeft
: 0;
const left =
title.shiftLeft && title.shiftLeft + sL >= 0
? title.shiftLeft + sL
: sL;
const consommeRow = title.consommeRow ? title.consommeRow - 1 : 1;
const consommeCol = title.consommeCol ? title.consommeCol : colsLength;
const height =
consommeRow == 0 && typeof title.height == "number"
? ' ht="' + title.height + '" customHeight="1" '
: "";
const tStyle = title.styleId ? title.styleId : "titleStyle";
const refString = cols[left] + "" + (rowCount + top);
mergesCellArray.push(
refString +
":" +
cols[left + consommeCol - 1] +
(rowCount + consommeRow + top)
);
if (typeof commentTitle != "undefined") {
hasComment = true;
const commentObj = commentConvertor(
commentTitle,
styleMapper.commentSyntax.value,
defaultCommentStyle
);
let authorId = commentAuthor.length;
if (commentObj.hasAuthor && typeof commentObj.author != "undefined") {
let auth = commentObj.author.toString();
const index = commentAuthor.indexOf(auth);
if (index < 0) {
commentAuthor.push(auth);
} else {
authorId = index;
}
}
shapeCommentRowCol.push({
row: rowCount + top - 1,
col: left,
});
commentString += generateCommentTag(
refString,
commentObj.commentStr,
commentObj.commentStyle,
authorId
);
}
if (typeof title.text == "string") {
rowMap[rowCount + top] = {
startTag:
'<row r="' +
(rowCount + top) +
'" ' +
height +
' spans="1:' +
Math.max(left + consommeCol - 1, 1) +
'">',
details:
'<c r="' +
refString +
'" ' +
(data.styles[tStyle]
? ' s="' + data.styles[tStyle].index + '" '
: "") +
' t="s"><v>' +
sharedStringIndex +
"</v></c>",
endTag: "</row>",
};
titleRow +=
'<row r="' +
(rowCount + top) +
'" ' +
height +
' spans="1:' +
Math.max(left + consommeCol - 1, 1) +
'">';
titleRow +=
'<c r="' +
refString +
'" ' +
(data.styles[tStyle]
? ' s="' + data.styles[tStyle].index + '" '
: "") +
' t="s"><v>' +
sharedStringIndex +
"</v></c>";
titleRow += "</row>";
sharedStringIndex++;
sharedStringMap[title.text] = title.text;
if (title.multiStyleValue && Array.isArray(title.multiStyleValue)) {
sharedString += generateMultiStyleByArray(
title.multiStyleValue,
styleMapper.commentSyntax.value,
tStyle
);
} else {
sharedString +=
"<si><t>" + specialCharacterConverter(title.text) + "</t></si>";
}
}
rowCount += top + consommeRow + 1;
}
let headerStyleKey = sheetData.headerStyleKey
? sheetData.headerStyleKey
: null;
let shiftCount = 0;
if (typeof sheetData.shiftLeft == "number" && sheetData.shiftLeft >= 0) {
shiftCount = sheetData.shiftLeft;
}
if (asTable) {
sheetDataTableColumns +=
'<tableColumns count="' + sheetData.headers.length + '">';
if (!xl_tableFolder) {
xl_tableFolder = xlFolder?.folder("tables");
}
}
sheetDimensions.start = cols[shiftCount] + "" + rowCount;
sheetDimensions.end =
cols[shiftCount + sheetData.headers.length - 1] +
"" +
(rowCount + sheetData.data.length);
sheetData.headers.forEach((v, innerIndex) => {
if (asTable) {
sheetDataTableColumns +=
'<tableColumn id="' +
(innerIndex + 1) +
'" name="' +
v.text +
'"/>';
}
if (shiftCount) {
innerIndex += shiftCount;
}
if (v.formula) {
headerFormula.push(innerIndex);
}
if (v.conditionalFormatting && addCF) {
headerConditionalFormatting.push(innerIndex);
}
objKey.push(v.label);
if (
sheetData.mergeRowDataCondition &&
typeof sheetData.mergeRowDataCondition == "function"
) {
let result = sheetData.mergeRowDataCondition(
v,
null,
innerIndex,
true
);
if (result === true) {
mergeRowConditionMap[cols[innerIndex]] = {
inProgress: true,
start: rowCount,
};
}
}
if (
sheetData.styleCellCondition &&
typeof sheetData.styleCellCondition == "function"
) {
headerStyleKey =
sheetData.styleCellCondition(
v,
v,
rowCount,
innerIndex,
true,
styleKeys
) || headerStyleKey;
}
if (v.size && v.size > 0) {
sheetSizeString +=
'<col min="' +
(innerIndex + 1) +
'" max="' +
(innerIndex + 1) +
'" width="' +
v.size +
'" customWidth="1" />';
}
if (sheetData.withoutHeader) {
return;
}
const refString = cols[innerIndex] + "" + rowCount;
if (typeof sheetData.commentCondition == "function") {
const checkCommentCondition = sheetData.commentCondition(
v,
null,
v.label,
rowCount,
innerIndex,
true
);
if (
typeof checkCommentCondition == "string" ||
(typeof checkCommentCondition == "object" &&
checkCommentCondition != null)
) {
v.comment = checkCommentCondition;
}
}
if (v.comment) {
hasComment = true;
const commentObj = commentConvertor(
v.comment,
styleMapper.commentSyntax.value,
defaultCommentStyle
);
let authorId = commentAuthor.length;
if (commentObj.hasAuthor && typeof commentObj.author != "undefined") {
let auth = commentObj.author.toString();
const index = commentAuthor.indexOf(auth);
if (index < 0) {
commentAuthor.push(auth);
} else {
authorId = index;
}
}
shapeCommentRowCol.push({
row: rowCount - 1,
col: innerIndex,
});
commentString += generateCommentTag(
refString,
commentObj.commentStr,
commentObj.commentStyle,
authorId
);
}
const formula = formulaSheetObj && formulaSheetObj[refString];
if (formula) {
const f = generateCellRowCol(
refString,
formula,
sheetDataId,
data.styles
);
if (f.needCalcChain) {
needCalcChain = true;
calcChainValue += f.chainCell;
}
sheetDataString += f.cell;
delete formulaSheetObj![refString];
} else {
sheetDataString +=
'<c r="' +
cols[innerIndex] +
rowCount +
'" ' +
(headerStyleKey && data.styles && data.styles[headerStyleKey]
? ' s="' + data.styles[headerStyleKey].index + '" '
: "") +
" " +
't="s"><v>' +
sharedStringIndex +
"</v></c>";
if (typeof sheetData.multiStyleCondition == "function") {
const multi = sheetData.multiStyleCondition(
v,
null,
v.label,
rowCount,
innerIndex,
true
);
if (multi) {
v.multiStyleValue = multi;
}
}
if (v.multiStyleValue && Array.isArray(v.multiStyleValue)) {
sharedString += generateMultiStyleByArray(
v.multiStyleValue,
styleMapper.commentSyntax.value,
headerStyleKey ? headerStyleKey : ""
);
} else {
sharedString +=
"<si><t>" + specialCharacterConverter(v.text) + "</t></si>";
}
sharedStringMap[v.text] = v.text;
sharedStringIndex++;
}
});
if (asTable) {
sheetDataTableColumns += "</tableColumns>";
}
if (!sheetData.withoutHeader) {
const rowTag =
'<row r="' +
rowCount +
'" spans="1:' +
Math.max(colsLength, 1) +
'" ' +
(sheetData.headerHeight
? 'ht="' + sheetData.headerHeight + '" customHeight="1"'
: "") +
(sheetData.headerRowOption
? Object.keys(sheetData.headerRowOption).reduce((res, curr) => {
return (
res +
" " +
curr +
'="' +
sheetData.headerRowOption![curr as keyof object] +
'" '
);
}, " ")
: "") +
">";
rowMap[rowCount] = {
startTag: rowTag,
endTag: "</row>",
details: sheetDataString,
};
sheetDataString = titleRow + rowTag + sheetDataString + "</row>";
rowCount++;
} else {
sheetDataString += titleRow;
}
if (Array.isArray(sheetData.data)) {
const keyOutline =
sheetData.mapSheetDataOption &&
sheetData.mapSheetDataOption.outlineLevel
? sheetData.mapSheetDataOption.outlineLevel
: "outlineLevel";
const keyHidden =
sheetData.mapSheetDataOption && sheetData.mapSheetDataOption.hidden
? sheetData.mapSheetDataOption.hidden
: "hidden";
const keyHeight =
sheetData.mapSheetDataOption && sheetData.mapSheetDataOption.height
? sheetData.mapSheetDataOption.height
: "height";
const rowLength = sheetData.data.length;
sheetData.data.forEach((mData, innerIndex) => {
if (mData.mergeType) {
for (let iIndex = 0; iIndex < mData.mergeType.length; iIndex++) {
const mergeType = mData.mergeType[iIndex];
const mergeStart = mData.mergeStart[iIndex];
const mergeValue = mData.mergeValue[index];
let mergeStr = "";
if (mergeType == "both") {
mergeStr =
cols[mergeStart] +
"" +
rowCount +
":" +
cols[mergeStart + mergeValue[1]] +
"" +
(rowCount + mergeValue[0]);
} else {
if (mergeType == "col") {
mergeStr =
cols[mergeStart] +
"" +
rowCount +
":" +
cols[mergeStart + mergeValue[0]] +
"" +
rowCount;
} else {
mergeStr =
cols[mergeStart] +
"" +
rowCount +
":" +
cols[mergeStart] +
"" +
(rowCount + mergeValue[0]);
}
}
mergesCellArray.push(mergeStr);
}
}
const rowStyle = mData.rowStyle;
const rowTagStart =
'<row r="' +
rowCount +
'" spans="1:' +
Math.max(colsLength, 1) +
'" ' +
(keyHeight in mData
? 'ht="' + mData[keyHeight] + '" customHeight="1"'
: "") +
(keyOutline in mData
? ' outlineLevel="' + mData[keyOutline] + '"'
: "") +
(keyHidden in mData ? ' hidden="' + mData[keyHidden] + '"' : "") +
" >";
sheetDataString += rowTagStart;
let rowDataString = "";
objKey.forEach((key, keyIndex) => {
if (shiftCount) {
keyIndex += shiftCount;
}
const cellValue = mData[key] * 1;
let dataEl =
sheetData.convertStringToNumber && !isNaN(cellValue)
? cellValue
: mData[key];
if (typeof dataEl === "boolean") {
dataEl = dataEl + "";
}
let cellStyle = rowStyle;
if (
sheetData.styleCellCondition &&
typeof sheetData.styleCellCondition == "function"
) {
cellStyle =
sheetData.styleCellCondition(
dataEl,
mData,
rowCount,
keyIndex,
false,
styleKeys
) || rowStyle;
}
if (
sheetData.mergeRowDataCondition &&
typeof sheetData.mergeRowDataCondition == "function"
) {
let result = sheetData.mergeRowDataCondition(
dataEl,
key,
keyIndex,
false
);
const columnKey = cols[keyIndex];
let item = mergeRowConditionMap[columnKey];
if (result === true) {
if (!item || (item && !item.inProgress)) {
mergeRowConditionMap[columnKey] = {
inProgress: true,
start: rowCount,
};
}
} else {
if (item && item.inProgress) {
mergesCellArray.push(
columnKey + item.start + ":" + columnKey + (rowCount - 1)
);
mergeRowConditionMap[columnKey] = {
inProgress: false,
start: -1,
};
}
}
}
if (typeof dataEl == "undefined") {
dataEl = "";
}
const refString = cols[keyIndex] + "" + rowCount;
if (typeof sheetData.commentCondition == "function") {
const checkCommentCondition = sheetData.commentCondition(
dataEl,
mData,
key,
rowCount,
keyIndex,
false
);
if (
typeof checkCommentCondition == "string" ||
(typeof checkCommentCondition == "object" &&
checkCommentCondition != null)
) {
if (typeof mData.comment !== "object") {
mData.comment = {};
}
mData.comment[key] = checkCommentCondition;
}
}
if (typeof mData.comment == "object" && key in mData.comment) {
const cellComment = mData.comment[key];
hasComment = true;
const commentObj = commentConvertor(
cellComment,
styleMapper.commentSyntax.value,
defaultCommentStyle
);
if (
commentObj.hasAuthor &&
typeof commentObj.author != "undefined"
) {
commentAuthor.push(commentObj.author.toString());
}
shapeCommentRowCol.push({
row: rowCount - 1,
col: keyIndex,
});
let authorId = commentAuthor.length;
if (
commentObj.hasAuthor &&
typeof commentObj.author != "undefined"
) {
let auth = commentObj.author.toSt