@cj-tech-master/excelts 5.1.9 → 5.1.10-canary.20260306122956.f4bcbe6
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/cell.js +15 -5
- package/dist/browser/modules/excel/row.js +3 -2
- package/dist/browser/modules/excel/table.js +1 -1
- package/dist/browser/modules/excel/types.d.ts +5 -0
- package/dist/browser/modules/excel/worksheet.js +6 -6
- package/dist/browser/modules/excel/xlsx/xform/table/table-column-xform.d.ts +7 -2
- package/dist/browser/modules/excel/xlsx/xform/table/table-column-xform.js +40 -7
- package/dist/cjs/modules/excel/cell.js +15 -5
- package/dist/cjs/modules/excel/row.js +3 -2
- package/dist/cjs/modules/excel/table.js +1 -1
- package/dist/cjs/modules/excel/worksheet.js +6 -6
- package/dist/cjs/modules/excel/xlsx/xform/table/table-column-xform.js +40 -7
- package/dist/esm/modules/excel/cell.js +15 -5
- package/dist/esm/modules/excel/row.js +3 -2
- package/dist/esm/modules/excel/table.js +1 -1
- package/dist/esm/modules/excel/worksheet.js +6 -6
- package/dist/esm/modules/excel/xlsx/xform/table/table-column-xform.js +40 -7
- package/dist/iife/excelts.iife.js +82 -61
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +24 -24
- package/dist/types/modules/excel/types.d.ts +5 -0
- package/dist/types/modules/excel/xlsx/xform/table/table-column-xform.d.ts +7 -2
- package/package.json +1 -1
|
@@ -3,6 +3,11 @@ import { Enums } from "./enums.js";
|
|
|
3
3
|
import { Note } from "./note.js";
|
|
4
4
|
import { escapeHtml } from "./utils/under-dash.js";
|
|
5
5
|
import { slideFormula } from "./utils/shared-formula.js";
|
|
6
|
+
// Returns true if the value is a non-empty object (has at least one own key),
|
|
7
|
+
// or any truthy non-object value. Returns false for undefined, null, false, 0,
|
|
8
|
+
// empty string, and empty objects `{}`. This is used to prevent an empty `{}`
|
|
9
|
+
// style property on a row from shadowing a real style property on a column.
|
|
10
|
+
const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
|
|
6
11
|
// Cell requirements
|
|
7
12
|
// Operate inside a worksheet
|
|
8
13
|
// Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
|
|
@@ -78,23 +83,28 @@ class Cell {
|
|
|
78
83
|
if (numFmt) {
|
|
79
84
|
style.numFmt = numFmt;
|
|
80
85
|
}
|
|
81
|
-
const font = (rowStyle && rowStyle.font)
|
|
86
|
+
const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
|
|
87
|
+
(colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
|
|
82
88
|
if (font) {
|
|
83
89
|
style.font = font;
|
|
84
90
|
}
|
|
85
|
-
const alignment = (rowStyle && rowStyle.alignment)
|
|
91
|
+
const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
|
|
92
|
+
(colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
|
|
86
93
|
if (alignment) {
|
|
87
94
|
style.alignment = alignment;
|
|
88
95
|
}
|
|
89
|
-
const border = (rowStyle && rowStyle.border)
|
|
96
|
+
const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
|
|
97
|
+
(colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
|
|
90
98
|
if (border) {
|
|
91
99
|
style.border = border;
|
|
92
100
|
}
|
|
93
|
-
const fill = (rowStyle && rowStyle.fill)
|
|
101
|
+
const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
|
|
102
|
+
(colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
|
|
94
103
|
if (fill) {
|
|
95
104
|
style.fill = fill;
|
|
96
105
|
}
|
|
97
|
-
const protection = (rowStyle && rowStyle.protection)
|
|
106
|
+
const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
|
|
107
|
+
(colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
|
|
98
108
|
if (protection) {
|
|
99
109
|
style.protection = protection;
|
|
100
110
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Enums } from "./enums.js";
|
|
2
2
|
import { colCache } from "./utils/col-cache.js";
|
|
3
3
|
import { Cell } from "./cell.js";
|
|
4
|
+
import { copyStyle } from "./utils/copy-style.js";
|
|
4
5
|
class Row {
|
|
5
6
|
constructor(worksheet, number) {
|
|
6
7
|
this._worksheet = worksheet;
|
|
@@ -95,7 +96,7 @@ class Row {
|
|
|
95
96
|
if (cSrc) {
|
|
96
97
|
cDst = this.getCell(i);
|
|
97
98
|
cDst.value = cSrc.value;
|
|
98
|
-
cDst.style = cSrc.style;
|
|
99
|
+
cDst.style = copyStyle(cSrc.style) ?? {};
|
|
99
100
|
cDst.comment = cSrc.comment;
|
|
100
101
|
}
|
|
101
102
|
else if (cDst) {
|
|
@@ -112,7 +113,7 @@ class Row {
|
|
|
112
113
|
if (cSrc) {
|
|
113
114
|
cDst = this.getCell(i + nExpand);
|
|
114
115
|
cDst.value = cSrc.value;
|
|
115
|
-
cDst.style = cSrc.style;
|
|
116
|
+
cDst.style = copyStyle(cSrc.style) ?? {};
|
|
116
117
|
cDst.comment = cSrc.comment;
|
|
117
118
|
}
|
|
118
119
|
else {
|
|
@@ -468,6 +468,11 @@ export interface TableColumnProperties {
|
|
|
468
468
|
totalsRowFunction?: "none" | "average" | "countNums" | "count" | "max" | "min" | "stdDev" | "var" | "sum" | "custom";
|
|
469
469
|
totalsRowFormula?: string;
|
|
470
470
|
totalsRowResult?: CellFormulaValue["result"];
|
|
471
|
+
/**
|
|
472
|
+
* Formula applied to every data row in this column.
|
|
473
|
+
* Corresponds to the OOXML `<calculatedColumnFormula>` element.
|
|
474
|
+
*/
|
|
475
|
+
calculatedColumnFormula?: string;
|
|
471
476
|
style?: Partial<Style>;
|
|
472
477
|
}
|
|
473
478
|
export interface TableProperties {
|
|
@@ -508,10 +508,10 @@ class Worksheet {
|
|
|
508
508
|
// now copy styles...
|
|
509
509
|
for (let i = 0; i < count; i++) {
|
|
510
510
|
const rDst = this._rows[rowNum + i];
|
|
511
|
-
rDst.style = rSrc.style;
|
|
511
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
512
512
|
rDst.height = rSrc.height;
|
|
513
513
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
514
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
514
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
515
515
|
});
|
|
516
516
|
}
|
|
517
517
|
// Duplicate single-row merges from source row into each new row
|
|
@@ -599,10 +599,10 @@ class Worksheet {
|
|
|
599
599
|
if (rSrc) {
|
|
600
600
|
const rDst = this.getRow(i + nExpand);
|
|
601
601
|
rDst.values = rSrc.values;
|
|
602
|
-
rDst.style = rSrc.style;
|
|
602
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
603
603
|
rDst.height = rSrc.height;
|
|
604
604
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
605
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
605
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
606
606
|
});
|
|
607
607
|
this._rows[i - 1] = undefined;
|
|
608
608
|
}
|
|
@@ -618,10 +618,10 @@ class Worksheet {
|
|
|
618
618
|
if (rSrc) {
|
|
619
619
|
const rDst = this.getRow(i + nExpand);
|
|
620
620
|
rDst.values = rSrc.values;
|
|
621
|
-
rDst.style = rSrc.style;
|
|
621
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
622
622
|
rDst.height = rSrc.height;
|
|
623
623
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
624
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
624
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
625
625
|
});
|
|
626
626
|
}
|
|
627
627
|
else {
|
|
@@ -4,17 +4,22 @@ interface TableColumnModel {
|
|
|
4
4
|
name: string;
|
|
5
5
|
totalsRowLabel?: string;
|
|
6
6
|
totalsRowFunction?: string;
|
|
7
|
+
totalsRowFormula?: string;
|
|
8
|
+
calculatedColumnFormula?: string;
|
|
7
9
|
dxfId?: string;
|
|
8
10
|
}
|
|
9
11
|
declare class TableColumnXform extends BaseXform<TableColumnModel> {
|
|
12
|
+
private _childTag;
|
|
13
|
+
private _childText;
|
|
10
14
|
constructor();
|
|
11
15
|
get tag(): string;
|
|
12
16
|
prepare(model: TableColumnModel, options: {
|
|
13
17
|
index: number;
|
|
14
18
|
}): void;
|
|
19
|
+
private _renderAttributes;
|
|
15
20
|
render(xmlStream: any, model: TableColumnModel): void;
|
|
16
21
|
parseOpen(node: any): boolean;
|
|
17
|
-
parseText(): void;
|
|
18
|
-
parseClose(): boolean;
|
|
22
|
+
parseText(text: string): void;
|
|
23
|
+
parseClose(name: string): boolean;
|
|
19
24
|
}
|
|
20
25
|
export { TableColumnXform };
|
|
@@ -2,6 +2,7 @@ import { BaseXform } from "../base-xform.js";
|
|
|
2
2
|
class TableColumnXform extends BaseXform {
|
|
3
3
|
constructor() {
|
|
4
4
|
super();
|
|
5
|
+
this._childText = "";
|
|
5
6
|
this.model = { name: "" };
|
|
6
7
|
}
|
|
7
8
|
get tag() {
|
|
@@ -10,15 +11,30 @@ class TableColumnXform extends BaseXform {
|
|
|
10
11
|
prepare(model, options) {
|
|
11
12
|
model.id = options.index + 1;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
_renderAttributes(model) {
|
|
15
|
+
return {
|
|
15
16
|
id: model.id.toString(),
|
|
16
17
|
name: model.name,
|
|
17
18
|
totalsRowLabel: model.totalsRowLabel,
|
|
18
19
|
// Excel doesn't output totalsRowFunction when value is 'none'
|
|
19
20
|
totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
|
|
20
21
|
dxfId: model.dxfId
|
|
21
|
-
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
render(xmlStream, model) {
|
|
25
|
+
if (model.calculatedColumnFormula || model.totalsRowFormula) {
|
|
26
|
+
xmlStream.openNode(this.tag, this._renderAttributes(model));
|
|
27
|
+
if (model.calculatedColumnFormula) {
|
|
28
|
+
xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
|
|
29
|
+
}
|
|
30
|
+
if (model.totalsRowFormula) {
|
|
31
|
+
xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
|
|
32
|
+
}
|
|
33
|
+
xmlStream.closeNode();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
xmlStream.leafNode(this.tag, this._renderAttributes(model));
|
|
37
|
+
}
|
|
22
38
|
}
|
|
23
39
|
parseOpen(node) {
|
|
24
40
|
if (node.name === this.tag) {
|
|
@@ -31,11 +47,28 @@ class TableColumnXform extends BaseXform {
|
|
|
31
47
|
};
|
|
32
48
|
return true;
|
|
33
49
|
}
|
|
34
|
-
|
|
50
|
+
// Recognise child elements whose text content we want to capture
|
|
51
|
+
if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
|
|
52
|
+
this._childTag = node.name;
|
|
53
|
+
this._childText = "";
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
parseText(text) {
|
|
58
|
+
if (this._childTag) {
|
|
59
|
+
this._childText += text;
|
|
60
|
+
}
|
|
35
61
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
parseClose(name) {
|
|
63
|
+
if (name === this.tag) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// Closing a recognised child element — store captured text
|
|
67
|
+
if (this._childTag && name === this._childTag) {
|
|
68
|
+
this.model[this._childTag] = this._childText;
|
|
69
|
+
this._childTag = undefined;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
39
72
|
}
|
|
40
73
|
}
|
|
41
74
|
export { TableColumnXform };
|
|
@@ -6,6 +6,11 @@ const enums_1 = require("./enums.js");
|
|
|
6
6
|
const note_1 = require("./note.js");
|
|
7
7
|
const under_dash_1 = require("./utils/under-dash.js");
|
|
8
8
|
const shared_formula_1 = require("./utils/shared-formula.js");
|
|
9
|
+
// Returns true if the value is a non-empty object (has at least one own key),
|
|
10
|
+
// or any truthy non-object value. Returns false for undefined, null, false, 0,
|
|
11
|
+
// empty string, and empty objects `{}`. This is used to prevent an empty `{}`
|
|
12
|
+
// style property on a row from shadowing a real style property on a column.
|
|
13
|
+
const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
|
|
9
14
|
// Cell requirements
|
|
10
15
|
// Operate inside a worksheet
|
|
11
16
|
// Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
|
|
@@ -81,23 +86,28 @@ class Cell {
|
|
|
81
86
|
if (numFmt) {
|
|
82
87
|
style.numFmt = numFmt;
|
|
83
88
|
}
|
|
84
|
-
const font = (rowStyle && rowStyle.font)
|
|
89
|
+
const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
|
|
90
|
+
(colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
|
|
85
91
|
if (font) {
|
|
86
92
|
style.font = font;
|
|
87
93
|
}
|
|
88
|
-
const alignment = (rowStyle && rowStyle.alignment)
|
|
94
|
+
const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
|
|
95
|
+
(colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
|
|
89
96
|
if (alignment) {
|
|
90
97
|
style.alignment = alignment;
|
|
91
98
|
}
|
|
92
|
-
const border = (rowStyle && rowStyle.border)
|
|
99
|
+
const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
|
|
100
|
+
(colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
|
|
93
101
|
if (border) {
|
|
94
102
|
style.border = border;
|
|
95
103
|
}
|
|
96
|
-
const fill = (rowStyle && rowStyle.fill)
|
|
104
|
+
const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
|
|
105
|
+
(colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
|
|
97
106
|
if (fill) {
|
|
98
107
|
style.fill = fill;
|
|
99
108
|
}
|
|
100
|
-
const protection = (rowStyle && rowStyle.protection)
|
|
109
|
+
const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
|
|
110
|
+
(colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
|
|
101
111
|
if (protection) {
|
|
102
112
|
style.protection = protection;
|
|
103
113
|
}
|
|
@@ -4,6 +4,7 @@ exports.Row = void 0;
|
|
|
4
4
|
const enums_1 = require("./enums.js");
|
|
5
5
|
const col_cache_1 = require("./utils/col-cache.js");
|
|
6
6
|
const cell_1 = require("./cell.js");
|
|
7
|
+
const copy_style_1 = require("./utils/copy-style.js");
|
|
7
8
|
class Row {
|
|
8
9
|
constructor(worksheet, number) {
|
|
9
10
|
this._worksheet = worksheet;
|
|
@@ -98,7 +99,7 @@ class Row {
|
|
|
98
99
|
if (cSrc) {
|
|
99
100
|
cDst = this.getCell(i);
|
|
100
101
|
cDst.value = cSrc.value;
|
|
101
|
-
cDst.style = cSrc.style;
|
|
102
|
+
cDst.style = (0, copy_style_1.copyStyle)(cSrc.style) ?? {};
|
|
102
103
|
cDst.comment = cSrc.comment;
|
|
103
104
|
}
|
|
104
105
|
else if (cDst) {
|
|
@@ -115,7 +116,7 @@ class Row {
|
|
|
115
116
|
if (cSrc) {
|
|
116
117
|
cDst = this.getCell(i + nExpand);
|
|
117
118
|
cDst.value = cSrc.value;
|
|
118
|
-
cDst.style = cSrc.style;
|
|
119
|
+
cDst.style = (0, copy_style_1.copyStyle)(cSrc.style) ?? {};
|
|
119
120
|
cDst.comment = cSrc.comment;
|
|
120
121
|
}
|
|
121
122
|
else {
|
|
@@ -511,10 +511,10 @@ class Worksheet {
|
|
|
511
511
|
// now copy styles...
|
|
512
512
|
for (let i = 0; i < count; i++) {
|
|
513
513
|
const rDst = this._rows[rowNum + i];
|
|
514
|
-
rDst.style = rSrc.style;
|
|
514
|
+
rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
|
|
515
515
|
rDst.height = rSrc.height;
|
|
516
516
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
517
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
517
|
+
rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
|
|
518
518
|
});
|
|
519
519
|
}
|
|
520
520
|
// Duplicate single-row merges from source row into each new row
|
|
@@ -602,10 +602,10 @@ class Worksheet {
|
|
|
602
602
|
if (rSrc) {
|
|
603
603
|
const rDst = this.getRow(i + nExpand);
|
|
604
604
|
rDst.values = rSrc.values;
|
|
605
|
-
rDst.style = rSrc.style;
|
|
605
|
+
rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
|
|
606
606
|
rDst.height = rSrc.height;
|
|
607
607
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
608
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
608
|
+
rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
|
|
609
609
|
});
|
|
610
610
|
this._rows[i - 1] = undefined;
|
|
611
611
|
}
|
|
@@ -621,10 +621,10 @@ class Worksheet {
|
|
|
621
621
|
if (rSrc) {
|
|
622
622
|
const rDst = this.getRow(i + nExpand);
|
|
623
623
|
rDst.values = rSrc.values;
|
|
624
|
-
rDst.style = rSrc.style;
|
|
624
|
+
rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
|
|
625
625
|
rDst.height = rSrc.height;
|
|
626
626
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
627
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
627
|
+
rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
|
|
628
628
|
});
|
|
629
629
|
}
|
|
630
630
|
else {
|
|
@@ -5,6 +5,7 @@ const base_xform_1 = require("../base-xform.js");
|
|
|
5
5
|
class TableColumnXform extends base_xform_1.BaseXform {
|
|
6
6
|
constructor() {
|
|
7
7
|
super();
|
|
8
|
+
this._childText = "";
|
|
8
9
|
this.model = { name: "" };
|
|
9
10
|
}
|
|
10
11
|
get tag() {
|
|
@@ -13,15 +14,30 @@ class TableColumnXform extends base_xform_1.BaseXform {
|
|
|
13
14
|
prepare(model, options) {
|
|
14
15
|
model.id = options.index + 1;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
_renderAttributes(model) {
|
|
18
|
+
return {
|
|
18
19
|
id: model.id.toString(),
|
|
19
20
|
name: model.name,
|
|
20
21
|
totalsRowLabel: model.totalsRowLabel,
|
|
21
22
|
// Excel doesn't output totalsRowFunction when value is 'none'
|
|
22
23
|
totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
|
|
23
24
|
dxfId: model.dxfId
|
|
24
|
-
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
render(xmlStream, model) {
|
|
28
|
+
if (model.calculatedColumnFormula || model.totalsRowFormula) {
|
|
29
|
+
xmlStream.openNode(this.tag, this._renderAttributes(model));
|
|
30
|
+
if (model.calculatedColumnFormula) {
|
|
31
|
+
xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
|
|
32
|
+
}
|
|
33
|
+
if (model.totalsRowFormula) {
|
|
34
|
+
xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
|
|
35
|
+
}
|
|
36
|
+
xmlStream.closeNode();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
xmlStream.leafNode(this.tag, this._renderAttributes(model));
|
|
40
|
+
}
|
|
25
41
|
}
|
|
26
42
|
parseOpen(node) {
|
|
27
43
|
if (node.name === this.tag) {
|
|
@@ -34,11 +50,28 @@ class TableColumnXform extends base_xform_1.BaseXform {
|
|
|
34
50
|
};
|
|
35
51
|
return true;
|
|
36
52
|
}
|
|
37
|
-
|
|
53
|
+
// Recognise child elements whose text content we want to capture
|
|
54
|
+
if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
|
|
55
|
+
this._childTag = node.name;
|
|
56
|
+
this._childText = "";
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
parseText(text) {
|
|
61
|
+
if (this._childTag) {
|
|
62
|
+
this._childText += text;
|
|
63
|
+
}
|
|
38
64
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
parseClose(name) {
|
|
66
|
+
if (name === this.tag) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
// Closing a recognised child element — store captured text
|
|
70
|
+
if (this._childTag && name === this._childTag) {
|
|
71
|
+
this.model[this._childTag] = this._childText;
|
|
72
|
+
this._childTag = undefined;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
42
75
|
}
|
|
43
76
|
}
|
|
44
77
|
exports.TableColumnXform = TableColumnXform;
|
|
@@ -3,6 +3,11 @@ import { Enums } from "./enums.js";
|
|
|
3
3
|
import { Note } from "./note.js";
|
|
4
4
|
import { escapeHtml } from "./utils/under-dash.js";
|
|
5
5
|
import { slideFormula } from "./utils/shared-formula.js";
|
|
6
|
+
// Returns true if the value is a non-empty object (has at least one own key),
|
|
7
|
+
// or any truthy non-object value. Returns false for undefined, null, false, 0,
|
|
8
|
+
// empty string, and empty objects `{}`. This is used to prevent an empty `{}`
|
|
9
|
+
// style property on a row from shadowing a real style property on a column.
|
|
10
|
+
const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
|
|
6
11
|
// Cell requirements
|
|
7
12
|
// Operate inside a worksheet
|
|
8
13
|
// Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
|
|
@@ -78,23 +83,28 @@ class Cell {
|
|
|
78
83
|
if (numFmt) {
|
|
79
84
|
style.numFmt = numFmt;
|
|
80
85
|
}
|
|
81
|
-
const font = (rowStyle && rowStyle.font)
|
|
86
|
+
const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
|
|
87
|
+
(colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
|
|
82
88
|
if (font) {
|
|
83
89
|
style.font = font;
|
|
84
90
|
}
|
|
85
|
-
const alignment = (rowStyle && rowStyle.alignment)
|
|
91
|
+
const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
|
|
92
|
+
(colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
|
|
86
93
|
if (alignment) {
|
|
87
94
|
style.alignment = alignment;
|
|
88
95
|
}
|
|
89
|
-
const border = (rowStyle && rowStyle.border)
|
|
96
|
+
const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
|
|
97
|
+
(colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
|
|
90
98
|
if (border) {
|
|
91
99
|
style.border = border;
|
|
92
100
|
}
|
|
93
|
-
const fill = (rowStyle && rowStyle.fill)
|
|
101
|
+
const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
|
|
102
|
+
(colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
|
|
94
103
|
if (fill) {
|
|
95
104
|
style.fill = fill;
|
|
96
105
|
}
|
|
97
|
-
const protection = (rowStyle && rowStyle.protection)
|
|
106
|
+
const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
|
|
107
|
+
(colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
|
|
98
108
|
if (protection) {
|
|
99
109
|
style.protection = protection;
|
|
100
110
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Enums } from "./enums.js";
|
|
2
2
|
import { colCache } from "./utils/col-cache.js";
|
|
3
3
|
import { Cell } from "./cell.js";
|
|
4
|
+
import { copyStyle } from "./utils/copy-style.js";
|
|
4
5
|
class Row {
|
|
5
6
|
constructor(worksheet, number) {
|
|
6
7
|
this._worksheet = worksheet;
|
|
@@ -95,7 +96,7 @@ class Row {
|
|
|
95
96
|
if (cSrc) {
|
|
96
97
|
cDst = this.getCell(i);
|
|
97
98
|
cDst.value = cSrc.value;
|
|
98
|
-
cDst.style = cSrc.style;
|
|
99
|
+
cDst.style = copyStyle(cSrc.style) ?? {};
|
|
99
100
|
cDst.comment = cSrc.comment;
|
|
100
101
|
}
|
|
101
102
|
else if (cDst) {
|
|
@@ -112,7 +113,7 @@ class Row {
|
|
|
112
113
|
if (cSrc) {
|
|
113
114
|
cDst = this.getCell(i + nExpand);
|
|
114
115
|
cDst.value = cSrc.value;
|
|
115
|
-
cDst.style = cSrc.style;
|
|
116
|
+
cDst.style = copyStyle(cSrc.style) ?? {};
|
|
116
117
|
cDst.comment = cSrc.comment;
|
|
117
118
|
}
|
|
118
119
|
else {
|
|
@@ -508,10 +508,10 @@ class Worksheet {
|
|
|
508
508
|
// now copy styles...
|
|
509
509
|
for (let i = 0; i < count; i++) {
|
|
510
510
|
const rDst = this._rows[rowNum + i];
|
|
511
|
-
rDst.style = rSrc.style;
|
|
511
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
512
512
|
rDst.height = rSrc.height;
|
|
513
513
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
514
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
514
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
515
515
|
});
|
|
516
516
|
}
|
|
517
517
|
// Duplicate single-row merges from source row into each new row
|
|
@@ -599,10 +599,10 @@ class Worksheet {
|
|
|
599
599
|
if (rSrc) {
|
|
600
600
|
const rDst = this.getRow(i + nExpand);
|
|
601
601
|
rDst.values = rSrc.values;
|
|
602
|
-
rDst.style = rSrc.style;
|
|
602
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
603
603
|
rDst.height = rSrc.height;
|
|
604
604
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
605
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
605
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
606
606
|
});
|
|
607
607
|
this._rows[i - 1] = undefined;
|
|
608
608
|
}
|
|
@@ -618,10 +618,10 @@ class Worksheet {
|
|
|
618
618
|
if (rSrc) {
|
|
619
619
|
const rDst = this.getRow(i + nExpand);
|
|
620
620
|
rDst.values = rSrc.values;
|
|
621
|
-
rDst.style = rSrc.style;
|
|
621
|
+
rDst.style = copyStyle(rSrc.style) ?? {};
|
|
622
622
|
rDst.height = rSrc.height;
|
|
623
623
|
rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
|
624
|
-
rDst.getCell(colNumber).style = cell.style;
|
|
624
|
+
rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
|
|
625
625
|
});
|
|
626
626
|
}
|
|
627
627
|
else {
|
|
@@ -2,6 +2,7 @@ import { BaseXform } from "../base-xform.js";
|
|
|
2
2
|
class TableColumnXform extends BaseXform {
|
|
3
3
|
constructor() {
|
|
4
4
|
super();
|
|
5
|
+
this._childText = "";
|
|
5
6
|
this.model = { name: "" };
|
|
6
7
|
}
|
|
7
8
|
get tag() {
|
|
@@ -10,15 +11,30 @@ class TableColumnXform extends BaseXform {
|
|
|
10
11
|
prepare(model, options) {
|
|
11
12
|
model.id = options.index + 1;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
_renderAttributes(model) {
|
|
15
|
+
return {
|
|
15
16
|
id: model.id.toString(),
|
|
16
17
|
name: model.name,
|
|
17
18
|
totalsRowLabel: model.totalsRowLabel,
|
|
18
19
|
// Excel doesn't output totalsRowFunction when value is 'none'
|
|
19
20
|
totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
|
|
20
21
|
dxfId: model.dxfId
|
|
21
|
-
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
render(xmlStream, model) {
|
|
25
|
+
if (model.calculatedColumnFormula || model.totalsRowFormula) {
|
|
26
|
+
xmlStream.openNode(this.tag, this._renderAttributes(model));
|
|
27
|
+
if (model.calculatedColumnFormula) {
|
|
28
|
+
xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
|
|
29
|
+
}
|
|
30
|
+
if (model.totalsRowFormula) {
|
|
31
|
+
xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
|
|
32
|
+
}
|
|
33
|
+
xmlStream.closeNode();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
xmlStream.leafNode(this.tag, this._renderAttributes(model));
|
|
37
|
+
}
|
|
22
38
|
}
|
|
23
39
|
parseOpen(node) {
|
|
24
40
|
if (node.name === this.tag) {
|
|
@@ -31,11 +47,28 @@ class TableColumnXform extends BaseXform {
|
|
|
31
47
|
};
|
|
32
48
|
return true;
|
|
33
49
|
}
|
|
34
|
-
|
|
50
|
+
// Recognise child elements whose text content we want to capture
|
|
51
|
+
if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
|
|
52
|
+
this._childTag = node.name;
|
|
53
|
+
this._childText = "";
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
parseText(text) {
|
|
58
|
+
if (this._childTag) {
|
|
59
|
+
this._childText += text;
|
|
60
|
+
}
|
|
35
61
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
parseClose(name) {
|
|
63
|
+
if (name === this.tag) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// Closing a recognised child element — store captured text
|
|
67
|
+
if (this._childTag && name === this._childTag) {
|
|
68
|
+
this.model[this._childTag] = this._childText;
|
|
69
|
+
this._childTag = undefined;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
39
72
|
}
|
|
40
73
|
}
|
|
41
74
|
export { TableColumnXform };
|