odf.js 1.13.2 → 2.1.0
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/README.md +19 -4
- package/dist/index.cjs +10 -0
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +7 -3
- package/dist/ns.cjs +2 -1
- package/dist/ns.d.cts +1 -0
- package/dist/ns.d.ts +1 -0
- package/dist/ns.js +2 -1
- package/dist/typed/draw/embedded.cjs +42 -0
- package/dist/typed/draw/embedded.d.cts +13 -0
- package/dist/typed/draw/embedded.d.ts +13 -0
- package/dist/typed/draw/embedded.js +41 -0
- package/dist/typed/draw/shapes.cjs +86 -30
- package/dist/typed/draw/shapes.d.cts +4 -1
- package/dist/typed/draw/shapes.d.ts +4 -1
- package/dist/typed/draw/shapes.js +86 -30
- package/dist/typed/formula/read.cjs +14 -0
- package/dist/typed/formula/read.d.cts +3 -2
- package/dist/typed/formula/read.d.ts +3 -2
- package/dist/typed/formula/read.js +14 -1
- package/dist/typed/odb/form.cjs +85 -0
- package/dist/typed/odb/form.d.cts +31 -0
- package/dist/typed/odb/form.d.ts +31 -0
- package/dist/typed/odb/form.js +84 -0
- package/dist/typed/odb/read.cjs +60 -23
- package/dist/typed/odb/read.d.cts +15 -4
- package/dist/typed/odb/read.d.ts +15 -4
- package/dist/typed/odb/read.js +60 -24
- package/dist/typed/odb/report.cjs +161 -0
- package/dist/typed/odb/report.d.cts +48 -0
- package/dist/typed/odb/report.d.ts +48 -0
- package/dist/typed/odb/report.js +160 -0
- package/dist/typed/odb/subdocument.cjs +16 -0
- package/dist/typed/odb/subdocument.d.cts +8 -0
- package/dist/typed/odb/subdocument.d.ts +8 -0
- package/dist/typed/odb/subdocument.js +15 -0
- package/dist/typed/ods/read.cjs +98 -4
- package/dist/typed/ods/read.js +100 -6
- package/dist/typed/shared/table.cjs +94 -7
- package/dist/typed/shared/table.d.cts +9 -2
- package/dist/typed/shared/table.d.ts +9 -2
- package/dist/typed/shared/table.js +94 -8
- package/package.json +1 -1
package/dist/typed/ods/read.js
CHANGED
|
@@ -2,11 +2,18 @@ import { parseOdfLength } from "../shared/units.js";
|
|
|
2
2
|
import { attrValue, childrenWithTag, findChildElement, rootElement } from "../../xml/query.js";
|
|
3
3
|
import { TableCursor, parseCellReference } from "../shared/a1.js";
|
|
4
4
|
import { parseMargins, parsePageSize } from "../shared/geometry.js";
|
|
5
|
-
import { findStyleElement } from "../shared/cascade.js";
|
|
5
|
+
import { findStyleElement, resolveStyleElementChain } from "../shared/cascade.js";
|
|
6
6
|
import { readOdfMetadata } from "../shared/metadata.js";
|
|
7
7
|
import { readOdfParagraph } from "../shared/paragraph.js";
|
|
8
|
+
import { readCellStyleDecoration } from "../shared/table.js";
|
|
9
|
+
import { parseOdfTransform } from "../shared/transform.js";
|
|
8
10
|
import { resolvePageLayoutProperties } from "../shared/masterpage.js";
|
|
9
|
-
import {
|
|
11
|
+
import { readDrawFrame } from "../draw/shapes.js";
|
|
12
|
+
import { readDrawObjectReference } from "../draw/embedded.js";
|
|
13
|
+
import { readOdp } from "../odp/read.js";
|
|
14
|
+
import { readOdt } from "../odt/read.js";
|
|
15
|
+
import { readOdg } from "../odg/read.js";
|
|
16
|
+
import { CONTENT_FORMAT_VERSION, PAGE_SIZE_A4 } from "document-schema.js";
|
|
10
17
|
//#region src/typed/ods/read.ts
|
|
11
18
|
const CONTENT_PART = "content.xml";
|
|
12
19
|
function parseKnownOdfLength(value) {
|
|
@@ -154,10 +161,84 @@ function parseNonNegativeInteger(value) {
|
|
|
154
161
|
const parsed = Number.parseInt(value, 10);
|
|
155
162
|
return Number.isInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
156
163
|
}
|
|
164
|
+
function readEmbeddedObjectDocument(reference) {
|
|
165
|
+
switch (reference.objectKind) {
|
|
166
|
+
case "wordprocessing": {
|
|
167
|
+
const { metadata, sections } = readOdt(reference.package);
|
|
168
|
+
return {
|
|
169
|
+
kind: "wordprocessing",
|
|
170
|
+
formatVersion: CONTENT_FORMAT_VERSION,
|
|
171
|
+
metadata,
|
|
172
|
+
sections
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
case "presentation": {
|
|
176
|
+
const { metadata, slides } = readOdp(reference.package);
|
|
177
|
+
return {
|
|
178
|
+
kind: "presentation",
|
|
179
|
+
formatVersion: CONTENT_FORMAT_VERSION,
|
|
180
|
+
metadata,
|
|
181
|
+
slides
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
case "drawing": {
|
|
185
|
+
const { metadata, pages } = readOdg(reference.package);
|
|
186
|
+
return {
|
|
187
|
+
kind: "drawing",
|
|
188
|
+
formatVersion: CONTENT_FORMAT_VERSION,
|
|
189
|
+
metadata,
|
|
190
|
+
pages
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
case "spreadsheet": {
|
|
194
|
+
const { metadata, sheets } = readOds(reference.package);
|
|
195
|
+
return {
|
|
196
|
+
kind: "spreadsheet",
|
|
197
|
+
formatVersion: CONTENT_FORMAT_VERSION,
|
|
198
|
+
metadata,
|
|
199
|
+
sheets
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function collectAnchoredFrame(frameElement, groupFunctions, pkg, anchorRow, anchorColumn, images, embeddedObjects) {
|
|
205
|
+
const shape = readDrawFrame(frameElement, groupFunctions, pkg);
|
|
206
|
+
if (shape === void 0) return;
|
|
207
|
+
const reference = readDrawObjectReference(frameElement, pkg);
|
|
208
|
+
if (reference !== void 0) {
|
|
209
|
+
embeddedObjects.push({
|
|
210
|
+
objectKind: reference.objectKind,
|
|
211
|
+
document: readEmbeddedObjectDocument(reference),
|
|
212
|
+
frame: shape.frame
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
for (const block of shape.blocks) if (block.kind === "image") images.push({
|
|
217
|
+
...block,
|
|
218
|
+
anchorRow,
|
|
219
|
+
anchorColumn,
|
|
220
|
+
offsetXPt: shape.frame.xPt,
|
|
221
|
+
offsetYPt: shape.frame.yPt
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function collectAnchoredFrames(children, groupFunctions, pkg, anchorRow, anchorColumn, images, embeddedObjects) {
|
|
225
|
+
for (const child of children) {
|
|
226
|
+
if (child.type !== "element") continue;
|
|
227
|
+
if (child.tag === "draw:frame") collectAnchoredFrame(child, groupFunctions, pkg, anchorRow, anchorColumn, images, embeddedObjects);
|
|
228
|
+
else if (child.tag === "draw:g") {
|
|
229
|
+
const ownValue = attrValue(child, "draw:transform");
|
|
230
|
+
const ownFunctions = ownValue === void 0 ? [] : parseOdfTransform(ownValue);
|
|
231
|
+
const nested = ownFunctions.length === 0 ? groupFunctions : [...ownFunctions, ...groupFunctions];
|
|
232
|
+
collectAnchoredFrames(child.children, nested, pkg, anchorRow, anchorColumn, images, embeddedObjects);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
157
236
|
function readTable(tableElement, pkg) {
|
|
158
237
|
const columns = [];
|
|
159
238
|
const rows = [];
|
|
160
239
|
const cells = [];
|
|
240
|
+
const images = [];
|
|
241
|
+
const embeddedObjects = [];
|
|
161
242
|
const manualBreakRows = [];
|
|
162
243
|
const manualBreakColumns = [];
|
|
163
244
|
let repeatColumns;
|
|
@@ -182,6 +263,7 @@ function readTable(tableElement, pkg) {
|
|
|
182
263
|
const columnIndex = cursor.columnIndex;
|
|
183
264
|
const rowIndex = cursor.rowIndex;
|
|
184
265
|
cursor.nextCell(readRepeatCount(child, "table:number-columns-repeated"));
|
|
266
|
+
collectAnchoredFrames(child.children, [], pkg, rowIndex, columnIndex, images, embeddedObjects);
|
|
185
267
|
const formula = attrValue(child, "table:formula");
|
|
186
268
|
const { runs, displayText } = readCellText(child, pkg);
|
|
187
269
|
if (!(attrValue(child, "office:value-type") !== void 0) && formula === void 0 && displayText.length === 0) continue;
|
|
@@ -198,6 +280,13 @@ function readTable(tableElement, pkg) {
|
|
|
198
280
|
if (runs.length > 0) cell.runs = runs;
|
|
199
281
|
if (colSpan !== void 0) cell.colSpan = colSpan;
|
|
200
282
|
if (rowSpan !== void 0) cell.rowSpan = rowSpan;
|
|
283
|
+
const cellStyleName = attrValue(child, "table:style-name");
|
|
284
|
+
const { elements: cellStyleChain } = resolveStyleElementChain(cellStyleName, "table-cell", pkg);
|
|
285
|
+
const decoration = readCellStyleDecoration(cellStyleChain);
|
|
286
|
+
if (decoration.background !== void 0) cell.background = decoration.background;
|
|
287
|
+
if (decoration.borders !== void 0) cell.borders = decoration.borders;
|
|
288
|
+
if (decoration.alignment !== void 0) cell.alignment = decoration.alignment;
|
|
289
|
+
if (decoration.verticalAlignment !== void 0) cell.verticalAlignment = decoration.verticalAlignment;
|
|
201
290
|
cells.push(cell);
|
|
202
291
|
}
|
|
203
292
|
}
|
|
@@ -216,7 +305,8 @@ function readTable(tableElement, pkg) {
|
|
|
216
305
|
}
|
|
217
306
|
for (const child of tableElement.children) {
|
|
218
307
|
if (child.type !== "element") continue;
|
|
219
|
-
if (child.tag === "table:
|
|
308
|
+
if (child.tag === "table:shapes") collectAnchoredFrames(child.children, [], pkg, 0, 0, images, embeddedObjects);
|
|
309
|
+
else if (child.tag === "table:table-column") processColumn(child);
|
|
220
310
|
else if (child.tag === "table:table-header-columns") {
|
|
221
311
|
const startIndex = columnCursor;
|
|
222
312
|
for (const headerChild of child.children) if (headerChild.type === "element" && headerChild.tag === "table:table-column") processColumn(headerChild);
|
|
@@ -238,6 +328,8 @@ function readTable(tableElement, pkg) {
|
|
|
238
328
|
columns,
|
|
239
329
|
rows,
|
|
240
330
|
cells,
|
|
331
|
+
images,
|
|
332
|
+
embeddedObjects,
|
|
241
333
|
repeatColumns,
|
|
242
334
|
repeatRows,
|
|
243
335
|
manualBreakRows,
|
|
@@ -287,15 +379,17 @@ function readPrintSettings(tableElement, pkg, repeatColumns, repeatRows, manualB
|
|
|
287
379
|
function readSheet(tableElement, pkg) {
|
|
288
380
|
const name = attrValue(tableElement, "table:name");
|
|
289
381
|
if (name === void 0) return;
|
|
290
|
-
const { columns, rows, cells, repeatColumns, repeatRows, manualBreakRows, manualBreakColumns } = readTable(tableElement, pkg);
|
|
291
|
-
|
|
382
|
+
const { columns, rows, cells, images, embeddedObjects, repeatColumns, repeatRows, manualBreakRows, manualBreakColumns } = readTable(tableElement, pkg);
|
|
383
|
+
const sheet = {
|
|
292
384
|
name,
|
|
293
385
|
cells,
|
|
294
386
|
columns,
|
|
295
387
|
rows,
|
|
296
|
-
images
|
|
388
|
+
images,
|
|
297
389
|
printSettings: readPrintSettings(tableElement, pkg, repeatColumns, repeatRows, manualBreakRows, manualBreakColumns)
|
|
298
390
|
};
|
|
391
|
+
if (embeddedObjects.length > 0) sheet.embeddedObjects = embeddedObjects;
|
|
392
|
+
return sheet;
|
|
299
393
|
}
|
|
300
394
|
function readOds(pkg) {
|
|
301
395
|
const contentPart = pkg.parts[CONTENT_PART];
|
|
@@ -25,22 +25,108 @@ function resolveRowHeightPt(rowElement, pkg) {
|
|
|
25
25
|
const heightValue = props === void 0 ? void 0 : require_xml_query.attrValue(props, "style:row-height");
|
|
26
26
|
return heightValue === void 0 ? void 0 : require_typed_shared_units.parseOdfLength(heightValue);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const BORDER_STYLE_MAP = {
|
|
29
|
+
solid: "solid",
|
|
30
|
+
dashed: "dashed",
|
|
31
|
+
dotted: "dotted",
|
|
32
|
+
double: "double"
|
|
33
|
+
};
|
|
34
|
+
const BORDER_EDGE_KEYS = [
|
|
35
|
+
"left",
|
|
36
|
+
"right",
|
|
37
|
+
"top",
|
|
38
|
+
"bottom"
|
|
39
|
+
];
|
|
40
|
+
const BORDER_EDGE_ATTRS = {
|
|
41
|
+
left: "fo:border-left",
|
|
42
|
+
right: "fo:border-right",
|
|
43
|
+
top: "fo:border-top",
|
|
44
|
+
bottom: "fo:border-bottom"
|
|
45
|
+
};
|
|
46
|
+
function isVerticalAlign(value) {
|
|
47
|
+
return value === "top" || value === "middle" || value === "bottom";
|
|
48
|
+
}
|
|
49
|
+
function parseBorderEdge(value) {
|
|
50
|
+
const tokens = value.trim().split(/\s+/);
|
|
51
|
+
if (tokens.length !== 3) return;
|
|
52
|
+
const [widthToken, styleToken, colorToken] = tokens;
|
|
53
|
+
if (widthToken === void 0 || styleToken === void 0 || colorToken === void 0) return;
|
|
54
|
+
if (styleToken === "none" || styleToken === "hidden") return { none: true };
|
|
55
|
+
const widthPt = require_typed_shared_units.parseOdfLength(widthToken);
|
|
56
|
+
const color = require_typed_shared_color.parseOdfColor(colorToken);
|
|
57
|
+
if (widthPt === void 0 || widthPt <= 0 || color === void 0) return;
|
|
58
|
+
const style = BORDER_STYLE_MAP[styleToken];
|
|
59
|
+
return { border: style === void 0 ? {
|
|
60
|
+
color,
|
|
61
|
+
widthPt
|
|
62
|
+
} : {
|
|
63
|
+
color,
|
|
64
|
+
widthPt,
|
|
65
|
+
style
|
|
66
|
+
} };
|
|
67
|
+
}
|
|
68
|
+
function applyBorderEdgeUpdates(accumulated, cellProperties) {
|
|
69
|
+
const shorthandValue = require_xml_query.attrValue(cellProperties, "fo:border");
|
|
70
|
+
const shorthandUpdate = shorthandValue === void 0 ? void 0 : parseBorderEdge(shorthandValue);
|
|
71
|
+
if (shorthandUpdate !== void 0) for (const edge of BORDER_EDGE_KEYS) applyBorderEdgeUpdate(accumulated, edge, shorthandUpdate);
|
|
72
|
+
for (const edge of BORDER_EDGE_KEYS) {
|
|
73
|
+
const rawValue = require_xml_query.attrValue(cellProperties, BORDER_EDGE_ATTRS[edge]);
|
|
74
|
+
const update = rawValue === void 0 ? void 0 : parseBorderEdge(rawValue);
|
|
75
|
+
if (update !== void 0) applyBorderEdgeUpdate(accumulated, edge, update);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function applyBorderEdgeUpdate(accumulated, edge, update) {
|
|
79
|
+
if ("none" in update) delete accumulated[edge];
|
|
80
|
+
else accumulated[edge] = update.border;
|
|
81
|
+
}
|
|
82
|
+
function bordersFromAccumulated(accumulated) {
|
|
83
|
+
if (accumulated.left === void 0 && accumulated.right === void 0 && accumulated.top === void 0 && accumulated.bottom === void 0) return;
|
|
84
|
+
const borders = {};
|
|
85
|
+
if (accumulated.left !== void 0) borders.left = accumulated.left;
|
|
86
|
+
if (accumulated.right !== void 0) borders.right = accumulated.right;
|
|
87
|
+
if (accumulated.top !== void 0) borders.top = accumulated.top;
|
|
88
|
+
if (accumulated.bottom !== void 0) borders.bottom = accumulated.bottom;
|
|
89
|
+
return borders;
|
|
90
|
+
}
|
|
91
|
+
function readCellStyleDecoration(elements) {
|
|
92
|
+
let background;
|
|
93
|
+
let alignment;
|
|
94
|
+
let verticalAlignment;
|
|
95
|
+
const borderAccumulator = {};
|
|
96
|
+
for (const styleElement of elements) {
|
|
97
|
+
const cellProperties = require_xml_query.childrenWithTag(styleElement, "style:table-cell-properties")[0];
|
|
98
|
+
if (cellProperties !== void 0) {
|
|
99
|
+
const backgroundValue = require_xml_query.attrValue(cellProperties, "fo:background-color");
|
|
100
|
+
const parsedBackground = backgroundValue === void 0 ? void 0 : require_typed_shared_color.parseOdfColor(backgroundValue);
|
|
101
|
+
if (parsedBackground !== void 0) background = parsedBackground;
|
|
102
|
+
applyBorderEdgeUpdates(borderAccumulator, cellProperties);
|
|
103
|
+
const verticalAlignValue = require_xml_query.attrValue(cellProperties, "style:vertical-align");
|
|
104
|
+
if (verticalAlignValue !== void 0 && isVerticalAlign(verticalAlignValue)) verticalAlignment = verticalAlignValue;
|
|
105
|
+
}
|
|
106
|
+
const paragraphProperties = require_xml_query.childrenWithTag(styleElement, "style:paragraph-properties")[0];
|
|
107
|
+
const textAlignValue = paragraphProperties === void 0 ? void 0 : require_xml_query.attrValue(paragraphProperties, "fo:text-align");
|
|
108
|
+
if (textAlignValue === "left" || textAlignValue === "center" || textAlignValue === "right" || textAlignValue === "justify") alignment = textAlignValue;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
background,
|
|
112
|
+
borders: bordersFromAccumulated(borderAccumulator),
|
|
113
|
+
alignment,
|
|
114
|
+
verticalAlignment
|
|
115
|
+
};
|
|
34
116
|
}
|
|
35
117
|
function readTableCell(cellElement, pkg) {
|
|
36
118
|
const blocks = require_xml_query.childrenWithTag(cellElement, "text:p").map((p) => require_typed_shared_paragraph.readOdfParagraph(p, pkg));
|
|
37
119
|
const colSpanRaw = require_xml_query.attrValue(cellElement, "table:number-columns-spanned");
|
|
38
120
|
const rowSpanRaw = require_xml_query.attrValue(cellElement, "table:number-rows-spanned");
|
|
121
|
+
const styleName = require_xml_query.attrValue(cellElement, "table:style-name");
|
|
122
|
+
const styleElement = styleName === void 0 ? void 0 : require_typed_shared_cascade.findStyleElement(styleName, "table-cell", pkg);
|
|
123
|
+
const { background, borders } = readCellStyleDecoration(styleElement === void 0 ? [] : [styleElement]);
|
|
39
124
|
return {
|
|
40
125
|
blocks,
|
|
41
126
|
colSpan: colSpanRaw === void 0 ? void 0 : Number.parseInt(colSpanRaw, 10),
|
|
42
127
|
rowSpan: rowSpanRaw === void 0 ? void 0 : Number.parseInt(rowSpanRaw, 10),
|
|
43
|
-
background
|
|
128
|
+
background,
|
|
129
|
+
borders
|
|
44
130
|
};
|
|
45
131
|
}
|
|
46
132
|
function readTableRow(rowElement, pkg) {
|
|
@@ -81,4 +167,5 @@ function readOdfTable(tableElement, pkg) {
|
|
|
81
167
|
};
|
|
82
168
|
}
|
|
83
169
|
//#endregion
|
|
170
|
+
exports.readCellStyleDecoration = readCellStyleDecoration;
|
|
84
171
|
exports.readOdfTable = readOdfTable;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { l as XmlElement } from "../../node-CkBWRjNR.cjs";
|
|
2
2
|
import { Package } from "../../model/package.cjs";
|
|
3
|
-
import { ContentTable } from "document-schema.js";
|
|
3
|
+
import { Alignment, Color, ContentCellBorders, ContentTable } from "document-schema.js";
|
|
4
4
|
//#region src/typed/shared/table.d.ts
|
|
5
|
+
interface CellStyleDecoration {
|
|
6
|
+
background?: Color;
|
|
7
|
+
borders?: ContentCellBorders;
|
|
8
|
+
alignment?: Alignment;
|
|
9
|
+
verticalAlignment?: 'top' | 'middle' | 'bottom';
|
|
10
|
+
}
|
|
11
|
+
declare function readCellStyleDecoration(elements: readonly XmlElement[]): CellStyleDecoration;
|
|
5
12
|
declare function readOdfTable(tableElement: XmlElement, pkg: Package): ContentTable;
|
|
6
13
|
//#endregion
|
|
7
|
-
export { readOdfTable };
|
|
14
|
+
export { CellStyleDecoration, readCellStyleDecoration, readOdfTable };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { l as XmlElement } from "../../node-CkBWRjNR.js";
|
|
2
2
|
import { Package } from "../../model/package.js";
|
|
3
|
-
import { ContentTable } from "document-schema.js";
|
|
3
|
+
import { Alignment, Color, ContentCellBorders, ContentTable } from "document-schema.js";
|
|
4
4
|
//#region src/typed/shared/table.d.ts
|
|
5
|
+
interface CellStyleDecoration {
|
|
6
|
+
background?: Color;
|
|
7
|
+
borders?: ContentCellBorders;
|
|
8
|
+
alignment?: Alignment;
|
|
9
|
+
verticalAlignment?: 'top' | 'middle' | 'bottom';
|
|
10
|
+
}
|
|
11
|
+
declare function readCellStyleDecoration(elements: readonly XmlElement[]): CellStyleDecoration;
|
|
5
12
|
declare function readOdfTable(tableElement: XmlElement, pkg: Package): ContentTable;
|
|
6
13
|
//#endregion
|
|
7
|
-
export { readOdfTable };
|
|
14
|
+
export { CellStyleDecoration, readCellStyleDecoration, readOdfTable };
|
|
@@ -24,22 +24,108 @@ function resolveRowHeightPt(rowElement, pkg) {
|
|
|
24
24
|
const heightValue = props === void 0 ? void 0 : attrValue(props, "style:row-height");
|
|
25
25
|
return heightValue === void 0 ? void 0 : parseOdfLength(heightValue);
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const BORDER_STYLE_MAP = {
|
|
28
|
+
solid: "solid",
|
|
29
|
+
dashed: "dashed",
|
|
30
|
+
dotted: "dotted",
|
|
31
|
+
double: "double"
|
|
32
|
+
};
|
|
33
|
+
const BORDER_EDGE_KEYS = [
|
|
34
|
+
"left",
|
|
35
|
+
"right",
|
|
36
|
+
"top",
|
|
37
|
+
"bottom"
|
|
38
|
+
];
|
|
39
|
+
const BORDER_EDGE_ATTRS = {
|
|
40
|
+
left: "fo:border-left",
|
|
41
|
+
right: "fo:border-right",
|
|
42
|
+
top: "fo:border-top",
|
|
43
|
+
bottom: "fo:border-bottom"
|
|
44
|
+
};
|
|
45
|
+
function isVerticalAlign(value) {
|
|
46
|
+
return value === "top" || value === "middle" || value === "bottom";
|
|
47
|
+
}
|
|
48
|
+
function parseBorderEdge(value) {
|
|
49
|
+
const tokens = value.trim().split(/\s+/);
|
|
50
|
+
if (tokens.length !== 3) return;
|
|
51
|
+
const [widthToken, styleToken, colorToken] = tokens;
|
|
52
|
+
if (widthToken === void 0 || styleToken === void 0 || colorToken === void 0) return;
|
|
53
|
+
if (styleToken === "none" || styleToken === "hidden") return { none: true };
|
|
54
|
+
const widthPt = parseOdfLength(widthToken);
|
|
55
|
+
const color = parseOdfColor(colorToken);
|
|
56
|
+
if (widthPt === void 0 || widthPt <= 0 || color === void 0) return;
|
|
57
|
+
const style = BORDER_STYLE_MAP[styleToken];
|
|
58
|
+
return { border: style === void 0 ? {
|
|
59
|
+
color,
|
|
60
|
+
widthPt
|
|
61
|
+
} : {
|
|
62
|
+
color,
|
|
63
|
+
widthPt,
|
|
64
|
+
style
|
|
65
|
+
} };
|
|
66
|
+
}
|
|
67
|
+
function applyBorderEdgeUpdates(accumulated, cellProperties) {
|
|
68
|
+
const shorthandValue = attrValue(cellProperties, "fo:border");
|
|
69
|
+
const shorthandUpdate = shorthandValue === void 0 ? void 0 : parseBorderEdge(shorthandValue);
|
|
70
|
+
if (shorthandUpdate !== void 0) for (const edge of BORDER_EDGE_KEYS) applyBorderEdgeUpdate(accumulated, edge, shorthandUpdate);
|
|
71
|
+
for (const edge of BORDER_EDGE_KEYS) {
|
|
72
|
+
const rawValue = attrValue(cellProperties, BORDER_EDGE_ATTRS[edge]);
|
|
73
|
+
const update = rawValue === void 0 ? void 0 : parseBorderEdge(rawValue);
|
|
74
|
+
if (update !== void 0) applyBorderEdgeUpdate(accumulated, edge, update);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function applyBorderEdgeUpdate(accumulated, edge, update) {
|
|
78
|
+
if ("none" in update) delete accumulated[edge];
|
|
79
|
+
else accumulated[edge] = update.border;
|
|
80
|
+
}
|
|
81
|
+
function bordersFromAccumulated(accumulated) {
|
|
82
|
+
if (accumulated.left === void 0 && accumulated.right === void 0 && accumulated.top === void 0 && accumulated.bottom === void 0) return;
|
|
83
|
+
const borders = {};
|
|
84
|
+
if (accumulated.left !== void 0) borders.left = accumulated.left;
|
|
85
|
+
if (accumulated.right !== void 0) borders.right = accumulated.right;
|
|
86
|
+
if (accumulated.top !== void 0) borders.top = accumulated.top;
|
|
87
|
+
if (accumulated.bottom !== void 0) borders.bottom = accumulated.bottom;
|
|
88
|
+
return borders;
|
|
89
|
+
}
|
|
90
|
+
function readCellStyleDecoration(elements) {
|
|
91
|
+
let background;
|
|
92
|
+
let alignment;
|
|
93
|
+
let verticalAlignment;
|
|
94
|
+
const borderAccumulator = {};
|
|
95
|
+
for (const styleElement of elements) {
|
|
96
|
+
const cellProperties = childrenWithTag(styleElement, "style:table-cell-properties")[0];
|
|
97
|
+
if (cellProperties !== void 0) {
|
|
98
|
+
const backgroundValue = attrValue(cellProperties, "fo:background-color");
|
|
99
|
+
const parsedBackground = backgroundValue === void 0 ? void 0 : parseOdfColor(backgroundValue);
|
|
100
|
+
if (parsedBackground !== void 0) background = parsedBackground;
|
|
101
|
+
applyBorderEdgeUpdates(borderAccumulator, cellProperties);
|
|
102
|
+
const verticalAlignValue = attrValue(cellProperties, "style:vertical-align");
|
|
103
|
+
if (verticalAlignValue !== void 0 && isVerticalAlign(verticalAlignValue)) verticalAlignment = verticalAlignValue;
|
|
104
|
+
}
|
|
105
|
+
const paragraphProperties = childrenWithTag(styleElement, "style:paragraph-properties")[0];
|
|
106
|
+
const textAlignValue = paragraphProperties === void 0 ? void 0 : attrValue(paragraphProperties, "fo:text-align");
|
|
107
|
+
if (textAlignValue === "left" || textAlignValue === "center" || textAlignValue === "right" || textAlignValue === "justify") alignment = textAlignValue;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
background,
|
|
111
|
+
borders: bordersFromAccumulated(borderAccumulator),
|
|
112
|
+
alignment,
|
|
113
|
+
verticalAlignment
|
|
114
|
+
};
|
|
33
115
|
}
|
|
34
116
|
function readTableCell(cellElement, pkg) {
|
|
35
117
|
const blocks = childrenWithTag(cellElement, "text:p").map((p) => readOdfParagraph(p, pkg));
|
|
36
118
|
const colSpanRaw = attrValue(cellElement, "table:number-columns-spanned");
|
|
37
119
|
const rowSpanRaw = attrValue(cellElement, "table:number-rows-spanned");
|
|
120
|
+
const styleName = attrValue(cellElement, "table:style-name");
|
|
121
|
+
const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-cell", pkg);
|
|
122
|
+
const { background, borders } = readCellStyleDecoration(styleElement === void 0 ? [] : [styleElement]);
|
|
38
123
|
return {
|
|
39
124
|
blocks,
|
|
40
125
|
colSpan: colSpanRaw === void 0 ? void 0 : Number.parseInt(colSpanRaw, 10),
|
|
41
126
|
rowSpan: rowSpanRaw === void 0 ? void 0 : Number.parseInt(rowSpanRaw, 10),
|
|
42
|
-
background
|
|
127
|
+
background,
|
|
128
|
+
borders
|
|
43
129
|
};
|
|
44
130
|
}
|
|
45
131
|
function readTableRow(rowElement, pkg) {
|
|
@@ -80,4 +166,4 @@ function readOdfTable(tableElement, pkg) {
|
|
|
80
166
|
};
|
|
81
167
|
}
|
|
82
168
|
//#endregion
|
|
83
|
-
export { readOdfTable };
|
|
169
|
+
export { readCellStyleDecoration, readOdfTable };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odf.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Type-safe, lossless round-trip conversion between OpenDocument Format packages (odt, ods, odp) and JSON, hand-written and dependency-minimal, built on Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|