@cj-tech-master/excelts 4.2.3-canary.20260122080306.cc11b20 → 5.0.0-canary.20260123012457.1fdf506
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/modules/excel/column.d.ts +5 -0
- package/dist/browser/modules/excel/column.js +10 -2
- package/dist/browser/modules/excel/row.d.ts +2 -0
- package/dist/browser/modules/excel/row.js +3 -1
- package/dist/browser/modules/excel/workbook.d.ts +4 -0
- package/dist/browser/modules/excel/workbook.js +4 -1
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +17 -10
- package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +2 -1
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
- package/dist/browser/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +7 -0
- package/dist/cjs/modules/excel/column.js +10 -2
- package/dist/cjs/modules/excel/row.js +3 -1
- package/dist/cjs/modules/excel/workbook.js +4 -1
- package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +17 -10
- package/dist/cjs/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +2 -1
- package/dist/cjs/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/cjs/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +7 -0
- package/dist/esm/modules/excel/column.js +10 -2
- package/dist/esm/modules/excel/row.js +3 -1
- package/dist/esm/modules/excel/workbook.js +4 -1
- package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +17 -10
- package/dist/esm/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
- package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +2 -1
- package/dist/esm/modules/excel/xlsx/xform/style/style-xform.js +26 -6
- package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +7 -0
- package/dist/iife/excelts.iife.js +450 -394
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +7 -7
- package/dist/types/modules/excel/column.d.ts +5 -0
- package/dist/types/modules/excel/row.d.ts +2 -0
- package/dist/types/modules/excel/workbook.d.ts +4 -0
- package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
- package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
- package/package.json +14 -14
|
@@ -11,6 +11,8 @@ export interface ColumnDefn {
|
|
|
11
11
|
outlineLevel?: number;
|
|
12
12
|
hidden?: boolean;
|
|
13
13
|
style?: Partial<Style>;
|
|
14
|
+
/** Whether the column width is auto-fitted to content */
|
|
15
|
+
bestFit?: boolean;
|
|
14
16
|
}
|
|
15
17
|
export interface ColumnModel {
|
|
16
18
|
min: number;
|
|
@@ -21,6 +23,7 @@ export interface ColumnModel {
|
|
|
21
23
|
hidden?: boolean;
|
|
22
24
|
outlineLevel?: number;
|
|
23
25
|
collapsed?: boolean;
|
|
26
|
+
bestFit?: boolean;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
29
|
* Column defines the column properties for 1 column.
|
|
@@ -36,6 +39,8 @@ declare class Column {
|
|
|
36
39
|
width?: number;
|
|
37
40
|
private _hidden;
|
|
38
41
|
private _outlineLevel;
|
|
42
|
+
/** Whether the column width is auto-fitted to content */
|
|
43
|
+
bestFit?: boolean;
|
|
39
44
|
/** Styles applied to the column */
|
|
40
45
|
style: Partial<Style>;
|
|
41
46
|
constructor(worksheet: Worksheet, number: number, defn?: ColumnDefn | false);
|
|
@@ -38,7 +38,8 @@ class Column {
|
|
|
38
38
|
width: this.width,
|
|
39
39
|
style: this.style,
|
|
40
40
|
hidden: this.hidden,
|
|
41
|
-
outlineLevel: this.outlineLevel
|
|
41
|
+
outlineLevel: this.outlineLevel,
|
|
42
|
+
bestFit: this.bestFit
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
set defn(value) {
|
|
@@ -55,6 +56,7 @@ class Column {
|
|
|
55
56
|
// headers must be set after style
|
|
56
57
|
this.header = value.header;
|
|
57
58
|
this._hidden = !!value.hidden;
|
|
59
|
+
this.bestFit = value.bestFit;
|
|
58
60
|
}
|
|
59
61
|
else {
|
|
60
62
|
delete this._header;
|
|
@@ -62,6 +64,7 @@ class Column {
|
|
|
62
64
|
delete this.width;
|
|
63
65
|
this.style = {};
|
|
64
66
|
this.outlineLevel = 0;
|
|
67
|
+
delete this.bestFit;
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
/**
|
|
@@ -151,6 +154,7 @@ class Column {
|
|
|
151
154
|
return (this.width === model.width &&
|
|
152
155
|
this.hidden === model.hidden &&
|
|
153
156
|
this.outlineLevel === model.outlineLevel &&
|
|
157
|
+
this.bestFit === model.bestFit &&
|
|
154
158
|
isEqual(this.style, model.style));
|
|
155
159
|
}
|
|
156
160
|
get isDefault() {
|
|
@@ -163,6 +167,9 @@ class Column {
|
|
|
163
167
|
if (this.outlineLevel) {
|
|
164
168
|
return false;
|
|
165
169
|
}
|
|
170
|
+
if (this.bestFit) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
166
173
|
const s = this.style;
|
|
167
174
|
if (s && (s.font || s.numFmt || s.alignment || s.border || s.fill || s.protection)) {
|
|
168
175
|
return false;
|
|
@@ -313,7 +320,8 @@ class Column {
|
|
|
313
320
|
isCustomWidth: column.isCustomWidth,
|
|
314
321
|
hidden: column.hidden,
|
|
315
322
|
outlineLevel: column.outlineLevel,
|
|
316
|
-
collapsed: column.collapsed
|
|
323
|
+
collapsed: column.collapsed,
|
|
324
|
+
bestFit: column.bestFit
|
|
317
325
|
};
|
|
318
326
|
cols.push(col);
|
|
319
327
|
}
|
|
@@ -15,6 +15,7 @@ export interface RowModel {
|
|
|
15
15
|
hidden: boolean;
|
|
16
16
|
outlineLevel: number;
|
|
17
17
|
collapsed: boolean;
|
|
18
|
+
dyDescent?: number;
|
|
18
19
|
}
|
|
19
20
|
declare class Row {
|
|
20
21
|
private _worksheet;
|
|
@@ -24,6 +25,7 @@ declare class Row {
|
|
|
24
25
|
private _hidden?;
|
|
25
26
|
private _outlineLevel?;
|
|
26
27
|
height?: number;
|
|
28
|
+
dyDescent?: number;
|
|
27
29
|
constructor(worksheet: Worksheet, number: number);
|
|
28
30
|
/**
|
|
29
31
|
* The row number
|
|
@@ -388,7 +388,8 @@ class Row {
|
|
|
388
388
|
style: this.style,
|
|
389
389
|
hidden: this.hidden,
|
|
390
390
|
outlineLevel: this.outlineLevel,
|
|
391
|
-
collapsed: this.collapsed
|
|
391
|
+
collapsed: this.collapsed,
|
|
392
|
+
dyDescent: this.dyDescent
|
|
392
393
|
}
|
|
393
394
|
: null;
|
|
394
395
|
}
|
|
@@ -435,6 +436,7 @@ class Row {
|
|
|
435
436
|
}
|
|
436
437
|
this.hidden = value.hidden;
|
|
437
438
|
this.outlineLevel = value.outlineLevel || 0;
|
|
439
|
+
this.dyDescent = value.dyDescent;
|
|
438
440
|
this.style = (value.style && JSON.parse(JSON.stringify(value.style))) || {};
|
|
439
441
|
}
|
|
440
442
|
}
|
|
@@ -59,6 +59,8 @@ export interface WorkbookModel {
|
|
|
59
59
|
passthrough?: Record<string, Uint8Array>;
|
|
60
60
|
/** Raw drawing XML data for passthrough (when drawing contains chart references) */
|
|
61
61
|
rawDrawings?: Record<string, Uint8Array>;
|
|
62
|
+
/** Default font preserved from the original file for round-trip fidelity */
|
|
63
|
+
defaultFont?: any;
|
|
62
64
|
}
|
|
63
65
|
declare class Workbook {
|
|
64
66
|
/**
|
|
@@ -102,6 +104,8 @@ declare class Workbook {
|
|
|
102
104
|
private _passthrough;
|
|
103
105
|
/** Raw drawing XML data for passthrough (when drawing contains chart references) */
|
|
104
106
|
private _rawDrawings;
|
|
107
|
+
/** Default font preserved from original file for round-trip fidelity */
|
|
108
|
+
private _defaultFont?;
|
|
105
109
|
private _xlsx?;
|
|
106
110
|
private _csv?;
|
|
107
111
|
constructor();
|
|
@@ -255,7 +255,8 @@ class Workbook {
|
|
|
255
255
|
pivotTables: this.pivotTables,
|
|
256
256
|
calcProperties: this.calcProperties,
|
|
257
257
|
passthrough: this._passthrough,
|
|
258
|
-
rawDrawings: this._rawDrawings
|
|
258
|
+
rawDrawings: this._rawDrawings,
|
|
259
|
+
defaultFont: this._defaultFont
|
|
259
260
|
};
|
|
260
261
|
}
|
|
261
262
|
set model(value) {
|
|
@@ -300,6 +301,8 @@ class Workbook {
|
|
|
300
301
|
this._passthrough = value.passthrough || {};
|
|
301
302
|
// Preserve raw drawing data for drawings with chart references
|
|
302
303
|
this._rawDrawings = value.rawDrawings || {};
|
|
304
|
+
// Preserve default font for round-trip fidelity
|
|
305
|
+
this._defaultFont = value.defaultFont;
|
|
303
306
|
}
|
|
304
307
|
}
|
|
305
308
|
// ===========================================================================
|
|
@@ -245,18 +245,21 @@ class PivotTableXform extends BaseXform {
|
|
|
245
245
|
xmlStream.writeXml('<rowItems count="1"><i t="grand"><x/></i></rowItems>');
|
|
246
246
|
}
|
|
247
247
|
// Col fields
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
xmlStream.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
248
|
+
// Only render colFields if it was present in the original file or if there are actual column fields
|
|
249
|
+
// Some pivot tables don't have colFields element at all
|
|
250
|
+
if (model.hasColFields || model.colFields.length > 0) {
|
|
251
|
+
const colFieldCount = model.colFields.length === 0 ? 1 : model.colFields.length;
|
|
252
|
+
xmlStream.openNode("colFields", { count: colFieldCount });
|
|
253
|
+
if (model.colFields.length === 0) {
|
|
254
|
+
xmlStream.leafNode("field", { x: -2 });
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
for (const fieldIndex of model.colFields) {
|
|
258
|
+
xmlStream.leafNode("field", { x: fieldIndex });
|
|
259
|
+
}
|
|
257
260
|
}
|
|
261
|
+
xmlStream.closeNode();
|
|
258
262
|
}
|
|
259
|
-
xmlStream.closeNode();
|
|
260
263
|
// Col items - use parsed items if available
|
|
261
264
|
if (model.colItems && model.colItems.length > 0) {
|
|
262
265
|
xmlStream.openNode("colItems", { count: model.colItems.length });
|
|
@@ -459,6 +462,10 @@ class PivotTableXform extends BaseXform {
|
|
|
459
462
|
break;
|
|
460
463
|
case "colFields":
|
|
461
464
|
this.state.inColFields = true;
|
|
465
|
+
// Track that colFields element was present in original file
|
|
466
|
+
if (this.model) {
|
|
467
|
+
this.model.hasColFields = true;
|
|
468
|
+
}
|
|
462
469
|
break;
|
|
463
470
|
case "dataFields":
|
|
464
471
|
this.state.inDataFields = true;
|
|
@@ -48,7 +48,10 @@ class RowXform extends BaseXform {
|
|
|
48
48
|
xmlStream.addAttribute("s", model.styleId);
|
|
49
49
|
xmlStream.addAttribute("customFormat", "1");
|
|
50
50
|
}
|
|
51
|
-
//
|
|
51
|
+
// Output dyDescent if present (MS extension for font descent)
|
|
52
|
+
if (model.dyDescent !== undefined) {
|
|
53
|
+
xmlStream.addAttribute("x14ac:dyDescent", model.dyDescent);
|
|
54
|
+
}
|
|
52
55
|
if (model.outlineLevel) {
|
|
53
56
|
xmlStream.addAttribute("outlineLevel", model.outlineLevel);
|
|
54
57
|
}
|
|
@@ -99,6 +102,9 @@ class RowXform extends BaseXform {
|
|
|
99
102
|
if (parseBoolean(node.attributes.collapsed)) {
|
|
100
103
|
model.collapsed = true;
|
|
101
104
|
}
|
|
105
|
+
if (node.attributes["x14ac:dyDescent"] !== undefined) {
|
|
106
|
+
model.dyDescent = parseFloat(node.attributes["x14ac:dyDescent"]);
|
|
107
|
+
}
|
|
102
108
|
return true;
|
|
103
109
|
}
|
|
104
110
|
this.parser = this.map[node.name];
|
|
@@ -11,14 +11,14 @@ class SheetFormatPropertiesXform extends BaseXform {
|
|
|
11
11
|
outlineLevelRow: model.outlineLevelRow || undefined,
|
|
12
12
|
outlineLevelCol: model.outlineLevelCol || undefined,
|
|
13
13
|
// Only output dyDescent if explicitly set (MS extension, not ECMA-376 standard)
|
|
14
|
-
"x14ac:dyDescent": model.dyDescent
|
|
14
|
+
"x14ac:dyDescent": model.dyDescent !== undefined && model.dyDescent !== 0 ? model.dyDescent : undefined
|
|
15
15
|
};
|
|
16
16
|
// Only output defaultColWidth if explicitly set
|
|
17
17
|
if (model.defaultColWidth) {
|
|
18
18
|
attributes.defaultColWidth = model.defaultColWidth;
|
|
19
19
|
}
|
|
20
|
-
//
|
|
21
|
-
if (
|
|
20
|
+
// Only output customHeight if it was present in the original file
|
|
21
|
+
if (model.customHeight) {
|
|
22
22
|
attributes.customHeight = "1";
|
|
23
23
|
}
|
|
24
24
|
if (Object.values(attributes).some((value) => value !== undefined)) {
|
|
@@ -30,13 +30,18 @@ class SheetFormatPropertiesXform extends BaseXform {
|
|
|
30
30
|
if (node.name === "sheetFormatPr") {
|
|
31
31
|
this.model = {
|
|
32
32
|
defaultRowHeight: parseFloat(node.attributes.defaultRowHeight || "0"),
|
|
33
|
-
dyDescent:
|
|
33
|
+
dyDescent: node.attributes["x14ac:dyDescent"] !== undefined
|
|
34
|
+
? parseFloat(node.attributes["x14ac:dyDescent"])
|
|
35
|
+
: undefined,
|
|
34
36
|
outlineLevelRow: parseInt(node.attributes.outlineLevelRow || "0", 10),
|
|
35
37
|
outlineLevelCol: parseInt(node.attributes.outlineLevelCol || "0", 10)
|
|
36
38
|
};
|
|
37
39
|
if (node.attributes.defaultColWidth) {
|
|
38
40
|
this.model.defaultColWidth = parseFloat(node.attributes.defaultColWidth);
|
|
39
41
|
}
|
|
42
|
+
if (node.attributes.customHeight === "1") {
|
|
43
|
+
this.model.customHeight = true;
|
|
44
|
+
}
|
|
40
45
|
return true;
|
|
41
46
|
}
|
|
42
47
|
return false;
|
|
@@ -37,8 +37,8 @@ class SheetViewXform extends BaseXform {
|
|
|
37
37
|
add("showRuler", "0", model.showRuler === false);
|
|
38
38
|
add("showRowColHeaders", "0", model.showRowColHeaders === false);
|
|
39
39
|
add("showGridLines", "0", model.showGridLines === false);
|
|
40
|
-
add("zoomScale", model.zoomScale, model.zoomScale);
|
|
41
|
-
add("zoomScaleNormal", model.zoomScaleNormal, model.zoomScaleNormal);
|
|
40
|
+
add("zoomScale", model.zoomScale, model.zoomScale !== undefined && model.zoomScale !== 100);
|
|
41
|
+
add("zoomScaleNormal", model.zoomScaleNormal, model.zoomScaleNormal !== undefined && model.zoomScaleNormal !== 100);
|
|
42
42
|
add("view", model.style, model.style);
|
|
43
43
|
let topLeftCell;
|
|
44
44
|
let xSplit;
|
|
@@ -143,6 +143,7 @@ class SheetViewXform extends BaseXform {
|
|
|
143
143
|
model = this.model = {
|
|
144
144
|
workbookViewId: this.sheetView.workbookViewId,
|
|
145
145
|
rightToLeft: this.sheetView.rightToLeft,
|
|
146
|
+
tabSelected: this.sheetView.tabSelected,
|
|
146
147
|
state: VIEW_STATES[this.pane.state] || "split", // split is default
|
|
147
148
|
xSplit: this.pane.xSplit,
|
|
148
149
|
ySplit: this.pane.ySplit,
|
|
@@ -168,6 +169,7 @@ class SheetViewXform extends BaseXform {
|
|
|
168
169
|
model = this.model = {
|
|
169
170
|
workbookViewId: this.sheetView.workbookViewId,
|
|
170
171
|
rightToLeft: this.sheetView.rightToLeft,
|
|
172
|
+
tabSelected: this.sheetView.tabSelected,
|
|
171
173
|
state: "normal",
|
|
172
174
|
showRuler: this.sheetView.showRuler,
|
|
173
175
|
showRowColHeaders: this.sheetView.showRowColHeaders,
|
|
@@ -384,7 +384,8 @@ class WorkSheetXform extends BaseXform {
|
|
|
384
384
|
defaultRowHeight: model.properties.defaultRowHeight,
|
|
385
385
|
dyDescent: model.properties.dyDescent,
|
|
386
386
|
outlineLevelCol: model.properties.outlineLevelCol,
|
|
387
|
-
outlineLevelRow: model.properties.outlineLevelRow
|
|
387
|
+
outlineLevelRow: model.properties.outlineLevelRow,
|
|
388
|
+
customHeight: model.properties.customHeight
|
|
388
389
|
}
|
|
389
390
|
: undefined;
|
|
390
391
|
if (model.properties && model.properties.defaultColWidth) {
|
|
@@ -11,6 +11,13 @@ interface StyleModel {
|
|
|
11
11
|
protection?: any;
|
|
12
12
|
checkbox?: boolean;
|
|
13
13
|
xfComplementIndex?: number;
|
|
14
|
+
pivotButton?: boolean;
|
|
15
|
+
applyNumberFormat?: boolean;
|
|
16
|
+
applyFont?: boolean;
|
|
17
|
+
applyFill?: boolean;
|
|
18
|
+
applyBorder?: boolean;
|
|
19
|
+
applyAlignment?: boolean;
|
|
20
|
+
applyProtection?: boolean;
|
|
14
21
|
}
|
|
15
22
|
interface StyleOptions {
|
|
16
23
|
xfId?: boolean;
|
|
@@ -24,24 +24,27 @@ class StyleXform extends BaseXform {
|
|
|
24
24
|
if (this.xfId) {
|
|
25
25
|
xmlStream.addAttribute("xfId", model.xfId || 0);
|
|
26
26
|
}
|
|
27
|
-
if (model.numFmtId) {
|
|
27
|
+
if (model.applyNumberFormat || model.numFmtId) {
|
|
28
28
|
xmlStream.addAttribute("applyNumberFormat", "1");
|
|
29
29
|
}
|
|
30
|
-
if (model.fontId) {
|
|
30
|
+
if (model.applyFont || model.fontId) {
|
|
31
31
|
xmlStream.addAttribute("applyFont", "1");
|
|
32
32
|
}
|
|
33
|
-
if (model.fillId) {
|
|
33
|
+
if (model.applyFill || model.fillId) {
|
|
34
34
|
xmlStream.addAttribute("applyFill", "1");
|
|
35
35
|
}
|
|
36
|
-
if (model.borderId) {
|
|
36
|
+
if (model.applyBorder || model.borderId) {
|
|
37
37
|
xmlStream.addAttribute("applyBorder", "1");
|
|
38
38
|
}
|
|
39
|
-
if (model.alignment) {
|
|
39
|
+
if (model.applyAlignment || model.alignment) {
|
|
40
40
|
xmlStream.addAttribute("applyAlignment", "1");
|
|
41
41
|
}
|
|
42
|
-
if (model.protection) {
|
|
42
|
+
if (model.applyProtection || model.protection) {
|
|
43
43
|
xmlStream.addAttribute("applyProtection", "1");
|
|
44
44
|
}
|
|
45
|
+
if (model.pivotButton) {
|
|
46
|
+
xmlStream.addAttribute("pivotButton", "1");
|
|
47
|
+
}
|
|
45
48
|
/**
|
|
46
49
|
* Rendering tags causes close of XML stream.
|
|
47
50
|
* Therefore adding attributes must be done before rendering tags.
|
|
@@ -82,6 +85,23 @@ class StyleXform extends BaseXform {
|
|
|
82
85
|
if (this.xfId) {
|
|
83
86
|
this.model.xfId = parseInt(node.attributes.xfId, 10);
|
|
84
87
|
}
|
|
88
|
+
if (node.attributes.pivotButton === "1") {
|
|
89
|
+
this.model.pivotButton = true;
|
|
90
|
+
}
|
|
91
|
+
// Preserve apply* flags from original file
|
|
92
|
+
const applyFlags = [
|
|
93
|
+
"applyNumberFormat",
|
|
94
|
+
"applyFont",
|
|
95
|
+
"applyFill",
|
|
96
|
+
"applyBorder",
|
|
97
|
+
"applyAlignment",
|
|
98
|
+
"applyProtection"
|
|
99
|
+
];
|
|
100
|
+
for (const flag of applyFlags) {
|
|
101
|
+
if (node.attributes[flag] === "1") {
|
|
102
|
+
this.model[flag] = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
85
105
|
return true;
|
|
86
106
|
case "alignment":
|
|
87
107
|
this.parser = this.map.alignment;
|
|
@@ -12,11 +12,17 @@ declare class StylesXform extends BaseXform {
|
|
|
12
12
|
private index?;
|
|
13
13
|
private weakMap?;
|
|
14
14
|
private _hasCheckboxes?;
|
|
15
|
+
defaultFont?: any;
|
|
15
16
|
parser: any;
|
|
16
17
|
static Mock: typeof StylesXform;
|
|
17
18
|
constructor(initialise?: boolean);
|
|
18
19
|
initIndex(): void;
|
|
19
20
|
init(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Set the default font to use when no font is explicitly specified.
|
|
23
|
+
* This preserves the original file's default font during round-trip.
|
|
24
|
+
*/
|
|
25
|
+
setDefaultFont(font: any): void;
|
|
20
26
|
render(xmlStream: any, model?: StylesModel): void;
|
|
21
27
|
parseOpen(node: any): boolean;
|
|
22
28
|
parseText(text: string): void;
|
|
@@ -84,6 +84,13 @@ class StylesXform extends BaseXform {
|
|
|
84
84
|
this.weakMap = new WeakMap();
|
|
85
85
|
this._hasCheckboxes = false;
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Set the default font to use when no font is explicitly specified.
|
|
89
|
+
* This preserves the original file's default font during round-trip.
|
|
90
|
+
*/
|
|
91
|
+
setDefaultFont(font) {
|
|
92
|
+
this.defaultFont = font;
|
|
93
|
+
}
|
|
87
94
|
render(xmlStream, model) {
|
|
88
95
|
const renderModel = model || this.model;
|
|
89
96
|
//
|
|
@@ -100,8 +107,8 @@ class StylesXform extends BaseXform {
|
|
|
100
107
|
xmlStream.closeNode();
|
|
101
108
|
}
|
|
102
109
|
if (!renderModel.fonts.length) {
|
|
103
|
-
// default (zero) font
|
|
104
|
-
this._addFont({
|
|
110
|
+
// default (zero) font - use preserved font or fallback to Calibri
|
|
111
|
+
this._addFont(this.defaultFont || {
|
|
105
112
|
size: 11,
|
|
106
113
|
color: { theme: 1 },
|
|
107
114
|
name: "Calibri",
|
|
@@ -193,6 +200,10 @@ class StylesXform extends BaseXform {
|
|
|
193
200
|
add("borders", this.map.borders);
|
|
194
201
|
add("styles", this.map.cellXfs);
|
|
195
202
|
add("dxfs", this.map.dxfs);
|
|
203
|
+
// preserve the default (first) font from the original file
|
|
204
|
+
if (this.map.fonts.model && this.map.fonts.model.length > 0) {
|
|
205
|
+
this.defaultFont = this.map.fonts.model[0];
|
|
206
|
+
}
|
|
196
207
|
// index numFmts
|
|
197
208
|
this.index = {
|
|
198
209
|
model: [],
|
|
@@ -220,8 +231,14 @@ class StylesXform extends BaseXform {
|
|
|
220
231
|
}
|
|
221
232
|
// if we have no default font, add it here now
|
|
222
233
|
if (!this.model.fonts.length) {
|
|
223
|
-
// default (zero) font
|
|
224
|
-
this._addFont(
|
|
234
|
+
// default (zero) font - use preserved font or fallback to Calibri
|
|
235
|
+
this._addFont(this.defaultFont || {
|
|
236
|
+
size: 11,
|
|
237
|
+
color: { theme: 1 },
|
|
238
|
+
name: "Calibri",
|
|
239
|
+
family: 2,
|
|
240
|
+
scheme: "minor"
|
|
241
|
+
});
|
|
225
242
|
}
|
|
226
243
|
const type = cellType || Enums.ValueType.Number;
|
|
227
244
|
// If we have seen this style object before, assume it has the same styleId.
|
|
@@ -262,6 +279,21 @@ class StylesXform extends BaseXform {
|
|
|
262
279
|
if (model.protection) {
|
|
263
280
|
style.protection = model.protection;
|
|
264
281
|
}
|
|
282
|
+
// Preserve xf-level attributes (pivotButton, apply* flags)
|
|
283
|
+
const xfFlags = [
|
|
284
|
+
"pivotButton",
|
|
285
|
+
"applyNumberFormat",
|
|
286
|
+
"applyFont",
|
|
287
|
+
"applyFill",
|
|
288
|
+
"applyBorder",
|
|
289
|
+
"applyAlignment",
|
|
290
|
+
"applyProtection"
|
|
291
|
+
];
|
|
292
|
+
for (const flag of xfFlags) {
|
|
293
|
+
if (model[flag]) {
|
|
294
|
+
style[flag] = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
265
297
|
if (type === Enums.ValueType.Checkbox) {
|
|
266
298
|
// Checkbox rendering relies on style extensions (extLst) and workbook-level parts.
|
|
267
299
|
// Force applyAlignment="1" (without emitting an <alignment/> node) by providing
|
|
@@ -322,6 +354,22 @@ class StylesXform extends BaseXform {
|
|
|
322
354
|
if (style.protection) {
|
|
323
355
|
model.protection = style.protection;
|
|
324
356
|
}
|
|
357
|
+
// -------------------------------------------------------
|
|
358
|
+
// xf-level attributes (pivotButton, apply* flags)
|
|
359
|
+
const xfFlags = [
|
|
360
|
+
"pivotButton",
|
|
361
|
+
"applyNumberFormat",
|
|
362
|
+
"applyFont",
|
|
363
|
+
"applyFill",
|
|
364
|
+
"applyBorder",
|
|
365
|
+
"applyAlignment",
|
|
366
|
+
"applyProtection"
|
|
367
|
+
];
|
|
368
|
+
for (const flag of xfFlags) {
|
|
369
|
+
if (style[flag]) {
|
|
370
|
+
model[flag] = true;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
325
373
|
return model;
|
|
326
374
|
}
|
|
327
375
|
addDxfStyle(style) {
|
|
@@ -600,6 +600,8 @@ class XLSX {
|
|
|
600
600
|
delete model.sharedStrings;
|
|
601
601
|
delete model.workbookRels;
|
|
602
602
|
delete model.sheetDefs;
|
|
603
|
+
// Preserve default font before deleting styles
|
|
604
|
+
model.defaultFont = model.styles?.defaultFont;
|
|
603
605
|
delete model.styles;
|
|
604
606
|
delete model.mediaIndex;
|
|
605
607
|
delete model.drawings;
|
|
@@ -1235,7 +1237,12 @@ class XLSX {
|
|
|
1235
1237
|
options.useSharedStrings !== undefined ? options.useSharedStrings : true;
|
|
1236
1238
|
model.useStyles = options.useStyles !== undefined ? options.useStyles : true;
|
|
1237
1239
|
model.sharedStrings = new SharedStringsXform();
|
|
1240
|
+
// Preserve default font from parsed styles if available
|
|
1241
|
+
const oldDefaultFont = model.defaultFont;
|
|
1238
1242
|
model.styles = model.useStyles ? new StylesXform(true) : new StylesXform.Mock();
|
|
1243
|
+
if (oldDefaultFont && model.styles.setDefaultFont) {
|
|
1244
|
+
model.styles.setDefaultFont(oldDefaultFont);
|
|
1245
|
+
}
|
|
1239
1246
|
const workbookXform = new WorkbookXform();
|
|
1240
1247
|
const worksheetXform = new WorkSheetXform();
|
|
1241
1248
|
workbookXform.prepare(model);
|
|
@@ -41,7 +41,8 @@ class Column {
|
|
|
41
41
|
width: this.width,
|
|
42
42
|
style: this.style,
|
|
43
43
|
hidden: this.hidden,
|
|
44
|
-
outlineLevel: this.outlineLevel
|
|
44
|
+
outlineLevel: this.outlineLevel,
|
|
45
|
+
bestFit: this.bestFit
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
set defn(value) {
|
|
@@ -58,6 +59,7 @@ class Column {
|
|
|
58
59
|
// headers must be set after style
|
|
59
60
|
this.header = value.header;
|
|
60
61
|
this._hidden = !!value.hidden;
|
|
62
|
+
this.bestFit = value.bestFit;
|
|
61
63
|
}
|
|
62
64
|
else {
|
|
63
65
|
delete this._header;
|
|
@@ -65,6 +67,7 @@ class Column {
|
|
|
65
67
|
delete this.width;
|
|
66
68
|
this.style = {};
|
|
67
69
|
this.outlineLevel = 0;
|
|
70
|
+
delete this.bestFit;
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
@@ -154,6 +157,7 @@ class Column {
|
|
|
154
157
|
return (this.width === model.width &&
|
|
155
158
|
this.hidden === model.hidden &&
|
|
156
159
|
this.outlineLevel === model.outlineLevel &&
|
|
160
|
+
this.bestFit === model.bestFit &&
|
|
157
161
|
(0, under_dash_1.isEqual)(this.style, model.style));
|
|
158
162
|
}
|
|
159
163
|
get isDefault() {
|
|
@@ -166,6 +170,9 @@ class Column {
|
|
|
166
170
|
if (this.outlineLevel) {
|
|
167
171
|
return false;
|
|
168
172
|
}
|
|
173
|
+
if (this.bestFit) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
169
176
|
const s = this.style;
|
|
170
177
|
if (s && (s.font || s.numFmt || s.alignment || s.border || s.fill || s.protection)) {
|
|
171
178
|
return false;
|
|
@@ -316,7 +323,8 @@ class Column {
|
|
|
316
323
|
isCustomWidth: column.isCustomWidth,
|
|
317
324
|
hidden: column.hidden,
|
|
318
325
|
outlineLevel: column.outlineLevel,
|
|
319
|
-
collapsed: column.collapsed
|
|
326
|
+
collapsed: column.collapsed,
|
|
327
|
+
bestFit: column.bestFit
|
|
320
328
|
};
|
|
321
329
|
cols.push(col);
|
|
322
330
|
}
|
|
@@ -391,7 +391,8 @@ class Row {
|
|
|
391
391
|
style: this.style,
|
|
392
392
|
hidden: this.hidden,
|
|
393
393
|
outlineLevel: this.outlineLevel,
|
|
394
|
-
collapsed: this.collapsed
|
|
394
|
+
collapsed: this.collapsed,
|
|
395
|
+
dyDescent: this.dyDescent
|
|
395
396
|
}
|
|
396
397
|
: null;
|
|
397
398
|
}
|
|
@@ -438,6 +439,7 @@ class Row {
|
|
|
438
439
|
}
|
|
439
440
|
this.hidden = value.hidden;
|
|
440
441
|
this.outlineLevel = value.outlineLevel || 0;
|
|
442
|
+
this.dyDescent = value.dyDescent;
|
|
441
443
|
this.style = (value.style && JSON.parse(JSON.stringify(value.style))) || {};
|
|
442
444
|
}
|
|
443
445
|
}
|
|
@@ -258,7 +258,8 @@ class Workbook {
|
|
|
258
258
|
pivotTables: this.pivotTables,
|
|
259
259
|
calcProperties: this.calcProperties,
|
|
260
260
|
passthrough: this._passthrough,
|
|
261
|
-
rawDrawings: this._rawDrawings
|
|
261
|
+
rawDrawings: this._rawDrawings,
|
|
262
|
+
defaultFont: this._defaultFont
|
|
262
263
|
};
|
|
263
264
|
}
|
|
264
265
|
set model(value) {
|
|
@@ -303,6 +304,8 @@ class Workbook {
|
|
|
303
304
|
this._passthrough = value.passthrough || {};
|
|
304
305
|
// Preserve raw drawing data for drawings with chart references
|
|
305
306
|
this._rawDrawings = value.rawDrawings || {};
|
|
307
|
+
// Preserve default font for round-trip fidelity
|
|
308
|
+
this._defaultFont = value.defaultFont;
|
|
306
309
|
}
|
|
307
310
|
}
|
|
308
311
|
exports.Workbook = Workbook;
|