pptx-ts 3.7.0 → 4.0.1
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 +116 -269
- package/dist/autopage-odPz7zZO.js +536 -0
- package/dist/autopage-odPz7zZO.js.map +1 -0
- package/dist/binary-string-CKVAYI3M.js +24 -0
- package/dist/binary-string-CKVAYI3M.js.map +1 -0
- package/dist/body-insets-Dw_BeWD_.js +54 -0
- package/dist/body-insets-Dw_BeWD_.js.map +1 -0
- package/dist/browser.d.ts +29 -9
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +41 -14
- package/dist/browser.js.map +1 -1
- package/dist/clip-Bl01BPcN.d.ts +67 -0
- package/dist/clip-Bl01BPcN.d.ts.map +1 -0
- package/dist/diagnostics-D8ot4Ei7.d.ts +244 -0
- package/dist/diagnostics-D8ot4Ei7.d.ts.map +1 -0
- package/dist/embedded-fonts-DarT9aoa.d.ts +20 -0
- package/dist/embedded-fonts-DarT9aoa.d.ts.map +1 -0
- package/dist/entry-compose-DCnvBZz2.d.ts +1046 -0
- package/dist/entry-compose-DCnvBZz2.d.ts.map +1 -0
- package/dist/{enums-CvRYniUA.d.ts → enums-BUKTUB6V.d.ts} +21 -13
- package/dist/{enums-CvRYniUA.d.ts.map → enums-BUKTUB6V.d.ts.map} +1 -1
- package/dist/{errors-Bvln0H-7.js → errors-C4oENPcu.js} +92 -2
- package/dist/errors-C4oENPcu.js.map +1 -0
- package/dist/families.d.ts +260 -0
- package/dist/families.d.ts.map +1 -0
- package/dist/families.js +57 -0
- package/dist/families.js.map +1 -0
- package/dist/{fit-BKs0zxMI.js → fit-Cb7naFj6.js} +249 -167
- package/dist/fit-Cb7naFj6.js.map +1 -0
- package/dist/font-metrics-v5fn7s7e.d.ts +613 -0
- package/dist/font-metrics-v5fn7s7e.d.ts.map +1 -0
- package/dist/grid-DikTjFey.js +187 -0
- package/dist/grid-DikTjFey.js.map +1 -0
- package/dist/{html-dom-B0I0QSbU.js → html-dom-Iuog2wdK.js} +121 -91
- package/dist/html-dom-Iuog2wdK.js.map +1 -0
- package/dist/html.d.ts +6 -6
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +7 -6
- package/dist/html.js.map +1 -1
- package/dist/image-size-CvN2iCA4.js +1611 -0
- package/dist/image-size-CvN2iCA4.js.map +1 -0
- package/dist/index.d.ts +24 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -11
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +40 -31
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +40 -48
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +7 -5
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +16 -7
- package/dist/math.js.map +1 -1
- package/dist/measure.d.ts +12 -225
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +3 -3
- package/dist/node.d.ts +22 -8
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +27 -7
- package/dist/node.js.map +1 -1
- package/dist/notes-Dh12JAbn.js +3264 -0
- package/dist/notes-Dh12JAbn.js.map +1 -0
- package/dist/options-internal-WqgMf720.js +43 -0
- package/dist/options-internal-WqgMf720.js.map +1 -0
- package/dist/{package-CaOLXSNi.d.ts → package-J49Ck6S2.d.ts} +27 -12
- package/dist/package-J49Ck6S2.d.ts.map +1 -0
- package/dist/playbtn-CUqQdoDf.js +22 -0
- package/dist/playbtn-CUqQdoDf.js.map +1 -0
- package/dist/{slide-ZqAdVvHV.d.ts → pres-C6qgOFAa.d.ts} +1021 -1423
- package/dist/pres-C6qgOFAa.d.ts.map +1 -0
- package/dist/{presentation-DrJtj3-C.js → presentation-DGYlAWhl.js} +3208 -2727
- package/dist/presentation-DGYlAWhl.js.map +1 -0
- package/dist/{presentation-types-CDjScsev.d.ts → presentation-types-8jLQHI4M.d.ts} +1070 -683
- package/dist/presentation-types-8jLQHI4M.d.ts.map +1 -0
- package/dist/read.d.ts +9 -9
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +4 -4
- package/dist/script.d.ts +80 -66
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +2399 -1139
- package/dist/script.js.map +1 -1
- package/dist/{shapes-BemroU-z.js → shapes-re0KyQk_.js} +2807 -1609
- package/dist/shapes-re0KyQk_.js.map +1 -0
- package/dist/slide-Dx2ZeVZ6.d.ts +1256 -0
- package/dist/slide-Dx2ZeVZ6.d.ts.map +1 -0
- package/dist/slide-size-BalTjFuv.js +88 -0
- package/dist/slide-size-BalTjFuv.js.map +1 -0
- package/dist/{units-internal-Dg95w_YD.js → table-cell-margins-EVg0EwxT.js} +235 -273
- package/dist/table-cell-margins-EVg0EwxT.js.map +1 -0
- package/dist/table-dom-BTDP3lEP.js +21 -0
- package/dist/table-dom-BTDP3lEP.js.map +1 -0
- package/dist/text-anchor-CrYXAfUu.js +176 -0
- package/dist/text-anchor-CrYXAfUu.js.map +1 -0
- package/dist/text-sN64Otf_.js +3980 -0
- package/dist/text-sN64Otf_.js.map +1 -0
- package/dist/transition-speed-kUEWDWTx.js +14 -0
- package/dist/transition-speed-kUEWDWTx.js.map +1 -0
- package/dist/units-internal-XJlf-hOl.js +649 -0
- package/dist/units-internal-XJlf-hOl.js.map +1 -0
- package/dist/zip-C0leZZMj.d.ts +67 -0
- package/dist/zip-C0leZZMj.d.ts.map +1 -0
- package/dist/zip-CKd8ihcf.js +177 -0
- package/dist/zip-CKd8ihcf.js.map +1 -0
- package/dist/zip.d.ts +3 -68
- package/dist/zip.js +3 -163
- package/dist/zoom-DPUHh85d.js +8865 -0
- package/dist/zoom-DPUHh85d.js.map +1 -0
- package/package.json +106 -19
- package/skills/ts-pptx-upstream/SKILL.md +58 -57
- package/dist/autopage-DkjYZUFD.js +0 -423
- package/dist/autopage-DkjYZUFD.js.map +0 -1
- package/dist/diagnostics-DfBdDHre.d.ts +0 -829
- package/dist/diagnostics-DfBdDHre.d.ts.map +0 -1
- package/dist/errors-Bvln0H-7.js.map +0 -1
- package/dist/errors-PflMPWBn.d.ts +0 -182
- package/dist/errors-PflMPWBn.d.ts.map +0 -1
- package/dist/fit-BKs0zxMI.js.map +0 -1
- package/dist/html-dom-B0I0QSbU.js.map +0 -1
- package/dist/namespaces-BVnNu7sg.js +0 -666
- package/dist/namespaces-BVnNu7sg.js.map +0 -1
- package/dist/notes-CJFJaG6M.js +0 -1724
- package/dist/notes-CJFJaG6M.js.map +0 -1
- package/dist/package-CaOLXSNi.d.ts.map +0 -1
- package/dist/pres-BcBR3CSM.d.ts +0 -202
- package/dist/pres-BcBR3CSM.d.ts.map +0 -1
- package/dist/presentation-DrJtj3-C.js.map +0 -1
- package/dist/presentation-types-CDjScsev.d.ts.map +0 -1
- package/dist/shapes-BemroU-z.js.map +0 -1
- package/dist/slide-ZqAdVvHV.d.ts.map +0 -1
- package/dist/text-B8SLEaZx.js +0 -11327
- package/dist/text-B8SLEaZx.js.map +0 -1
- package/dist/units-1kRzYShk.js +0 -231
- package/dist/units-1kRzYShk.js.map +0 -1
- package/dist/units-internal-Dg95w_YD.js.map +0 -1
- package/dist/zip.d.ts.map +0 -1
- package/dist/zip.js.map +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { l as warn } from "./errors-C4oENPcu.js";
|
|
2
|
+
//#region src/gen/table/spans.ts
|
|
3
|
+
/**
|
|
4
|
+
* The largest `colspan`/`rowspan` this library will honour.
|
|
5
|
+
*
|
|
6
|
+
* Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`
|
|
7
|
+
* is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order
|
|
8
|
+
* of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns
|
|
9
|
+
* and 75 rows), which is what makes it something no authored table can reach. What it stops is
|
|
10
|
+
* the other end, where the allocation takes the host process with it.
|
|
11
|
+
*/
|
|
12
|
+
const MAX_TABLE_SPAN = 1e3;
|
|
13
|
+
/**
|
|
14
|
+
* Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole
|
|
15
|
+
* number in `1..MAX_TABLE_SPAN`.
|
|
16
|
+
*
|
|
17
|
+
* `undefined` is the common case and means "no span" — it warns about nothing and returns `1`.
|
|
18
|
+
* Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all
|
|
19
|
+
* describe a table that cannot be built (a fractional span silently truncates, a negative one
|
|
20
|
+
* shifts every column after it, an enormous one is the allocation above).
|
|
21
|
+
*
|
|
22
|
+
* The parameter is typed `unknown` because this is also **the** reading of a span for the six
|
|
23
|
+
* sites that consume one after {@link withCheckedSpans} has run. Those had six different
|
|
24
|
+
* coercions — `Number(x) ? … : 1`, `Math.max(1, Number(x) || 1)`, `x ?? 1` — which agreed only
|
|
25
|
+
* on the values that were already valid, and one of them let a non-numeric span reach a grid
|
|
26
|
+
* column count as `NaN`. Reading a span through one function is what stops them drifting apart
|
|
27
|
+
* again if the up-front check is ever moved.
|
|
28
|
+
* @param value - the raw option value, as the caller wrote it
|
|
29
|
+
* @param kind - `'colspan'` or `'rowspan'`, for the diagnostic
|
|
30
|
+
* @returns the span to use, at least 1
|
|
31
|
+
*/
|
|
32
|
+
function resolveSpan(value, kind) {
|
|
33
|
+
if (value === void 0 || value === null || value === "") return 1;
|
|
34
|
+
if (typeof value !== "number") {
|
|
35
|
+
warn("table/span-out-of-range", `table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`);
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
if (!Number.isInteger(value) || value < 1 || value > 1e3) {
|
|
39
|
+
warn("table/span-out-of-range", `table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.
|
|
46
|
+
*
|
|
47
|
+
* Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's
|
|
48
|
+
* grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at
|
|
49
|
+
* each of those sites instead would warn several times per bad cell and could still disagree.
|
|
50
|
+
*
|
|
51
|
+
* A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the
|
|
52
|
+
* merge dummies back to the origin *object*, and the all-valid path is every real table, which
|
|
53
|
+
* must stay allocation-free and byte-identical.
|
|
54
|
+
* @param rows - the rows to check; row arrays are never mutated
|
|
55
|
+
* @returns the same rows with only the offending cells replaced
|
|
56
|
+
*/
|
|
57
|
+
function withCheckedSpans(rows) {
|
|
58
|
+
return rows.map((cells) => cells.map((cell) => {
|
|
59
|
+
const opts = cell?.options;
|
|
60
|
+
if (!opts) return cell;
|
|
61
|
+
const colspan = resolveSpan(opts.colspan, "colspan");
|
|
62
|
+
const rowspan = resolveSpan(opts.rowspan, "rowspan");
|
|
63
|
+
const colspanOk = opts.colspan === void 0 || opts.colspan === colspan;
|
|
64
|
+
const rowspanOk = opts.rowspan === void 0 || opts.rowspan === rowspan;
|
|
65
|
+
if (colspanOk && rowspanOk) return cell;
|
|
66
|
+
return {
|
|
67
|
+
...cell,
|
|
68
|
+
options: {
|
|
69
|
+
...opts,
|
|
70
|
+
...opts.colspan === void 0 ? {} : { colspan },
|
|
71
|
+
...opts.rowspan === void 0 ? {} : { rowspan }
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Whether any cell in the grid carries a hyperlink — on the cell itself, or on any run of a
|
|
78
|
+
* cell whose `text` is a run array.
|
|
79
|
+
*
|
|
80
|
+
* `addTable` uses this to decide whether to stand its black text default down: the default is
|
|
81
|
+
* direct formatting on the table, so it would paint the words *after* a link black rather than
|
|
82
|
+
* letting them follow the link colour. The test used to be
|
|
83
|
+
* `JSON.stringify({ arrRows }).includes('hyperlink')`, which matched the literal word anywhere
|
|
84
|
+
* in the grid's *content* — a cell reading "see the hyperlink docs" suppressed the default for
|
|
85
|
+
* the whole table — and serialized every cell on every `addTable` to ask.
|
|
86
|
+
* @param rows - the table's rows
|
|
87
|
+
*/
|
|
88
|
+
function tableHasHyperlink(rows) {
|
|
89
|
+
return rows.some((cells) => cells.some((cell) => {
|
|
90
|
+
if (!cell) return false;
|
|
91
|
+
if (cell.options?.hyperlink) return true;
|
|
92
|
+
if (!Array.isArray(cell.text)) return false;
|
|
93
|
+
return cell.text.some((run) => !!run?.options?.hyperlink);
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/gen/table/grid.ts
|
|
98
|
+
/**
|
|
99
|
+
* How many grid columns a table has: the sum of the first row's colspans.
|
|
100
|
+
*
|
|
101
|
+
* The count cannot come from `rows[0].length` -- a colspan makes one cell occupy several
|
|
102
|
+
* columns -- and it is read off the first row alone, which is the writer's standing rule: a
|
|
103
|
+
* later row wider than the first is ragged input, and the grid it is measured, paged and
|
|
104
|
+
* emitted against is the one `a:tblGrid` declares.
|
|
105
|
+
*/
|
|
106
|
+
function tableColCount(rows) {
|
|
107
|
+
const first = rows[0];
|
|
108
|
+
return first ? first.reduce((n, c) => n + resolveSpan(c?.options?.colspan, "colspan"), 0) : 0;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The rowspan-occupancy rule, stated once.
|
|
112
|
+
*
|
|
113
|
+
* A row states only the cells it *starts*: a column held by a `rowspan` from above is filled
|
|
114
|
+
* without the row mentioning it, so a cell's position in its row array is not its column. Tracking
|
|
115
|
+
* that is three operations -- skip what is held, mark what this cell holds, age the holds by a row
|
|
116
|
+
* -- and getting the ageing off by one silently shifts every column below.
|
|
117
|
+
*
|
|
118
|
+
* It has two callers asking different questions on different input. {@link walkTableGrid} places
|
|
119
|
+
* authored `TableCell`s into a grid whose width `a:tblGrid` already declares; `measureGridColumns`
|
|
120
|
+
* (`gen/table/html-dom.ts`) measures how wide an imported HTML table's grid *is*, reading spans off
|
|
121
|
+
* HTML attributes, with no width known up front. Neither can be expressed as the other without
|
|
122
|
+
* giving one of them a mode it does not want -- but the rule underneath is the same rule, and it is
|
|
123
|
+
* here rather than in both.
|
|
124
|
+
*
|
|
125
|
+
* The array is sparse and unbounded on purpose: a caller that knows its width clamps what it
|
|
126
|
+
* `hold`s, and then nothing past that width is ever held, so an unbounded `nextFree` returns the
|
|
127
|
+
* same answer a bounded one would.
|
|
128
|
+
*/
|
|
129
|
+
function createRowSpanOccupancy() {
|
|
130
|
+
const held = [];
|
|
131
|
+
return {
|
|
132
|
+
nextFree(col) {
|
|
133
|
+
let free = col;
|
|
134
|
+
while ((held[free] ?? 0) > 0) free++;
|
|
135
|
+
return free;
|
|
136
|
+
},
|
|
137
|
+
hold(col, colSpan, rowSpan) {
|
|
138
|
+
for (let idx = 0; idx < colSpan; idx++) held[col + idx] = rowSpan;
|
|
139
|
+
},
|
|
140
|
+
endRow() {
|
|
141
|
+
for (let idx = 0; idx < held.length; idx++) {
|
|
142
|
+
const rows = held[idx] ?? 0;
|
|
143
|
+
if (rows > 0) held[idx] = rows - 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Walk a table's cell grid in row-major order, resolving each authored cell to its
|
|
150
|
+
* grid origin (`row`/`col`) and clamped colspan/rowspan. Tracks rowspan occupancy so
|
|
151
|
+
* a cell never lands beneath one spanned from above. This is the single traversal the
|
|
152
|
+
* auto-pager, the measured-fit shrink pass, {@link computeTableLayout} and the table emitter's
|
|
153
|
+
* merge grid all read, so the table that is paged and measured is the table that is written.
|
|
154
|
+
*
|
|
155
|
+
* A cell that starts past the last grid column is not yielded: a row longer than the first is
|
|
156
|
+
* ragged input, and the grid is the one `a:tblGrid` declares.
|
|
157
|
+
*/
|
|
158
|
+
function* walkTableGrid(rows, numCols) {
|
|
159
|
+
const occupancy = createRowSpanOccupancy();
|
|
160
|
+
for (let r = 0; r < rows.length; r++) {
|
|
161
|
+
const row = rows[r];
|
|
162
|
+
if (!row) continue;
|
|
163
|
+
let col = 0;
|
|
164
|
+
for (const cell of row) {
|
|
165
|
+
col = occupancy.nextFree(col);
|
|
166
|
+
if (col >= numCols) break;
|
|
167
|
+
const colspan = resolveSpan(cell?.options?.colspan, "colspan");
|
|
168
|
+
const rowspan = Math.min(resolveSpan(cell?.options?.rowspan, "rowspan"), rows.length - r);
|
|
169
|
+
const colStart = col;
|
|
170
|
+
const colEnd = Math.min(colStart + colspan, numCols);
|
|
171
|
+
occupancy.hold(colStart, colEnd - colStart, rowspan);
|
|
172
|
+
col = colEnd;
|
|
173
|
+
yield {
|
|
174
|
+
cell,
|
|
175
|
+
row: r,
|
|
176
|
+
col: colStart,
|
|
177
|
+
rowSpan: rowspan,
|
|
178
|
+
colSpan: colEnd - colStart
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
occupancy.endRow();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
export { resolveSpan as a, MAX_TABLE_SPAN as i, tableColCount as n, tableHasHyperlink as o, walkTableGrid as r, withCheckedSpans as s, createRowSpanOccupancy as t };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=grid-DikTjFey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid-DikTjFey.js","names":[],"sources":["../src/gen/table/spans.ts","../src/gen/table/grid.ts"],"sourcesContent":["/**\n * ts-pptx: table `colspan`/`rowspan` range checking.\n *\n * The spans decide two allocations, on two different paths, and both used to trust the caller:\n * the merge grid's `new Array(colspan - 1)` in `gen/slide/objects/table.ts`, and the auto-pager's\n * per-column depth array, sized from a column count that is a sum of colspans\n * (`gen/table/autopage.ts`). `new Array(4294967294).fill(undefined)` is not a slow path — V8\n * aborts on the allocation and there is no exception to catch — so a table built with\n * `autoPage: true` and one without needed the same guard, which is why it lives here rather than\n * in either of them.\n *\n * This is the write side, so the bad number comes from the calling program rather than from a\n * hostile file, which makes it far less serious than the read-side twin in the chart point caches\n * (`read/oxml/point-cache.ts`, the model this copies). It is still the project's stated line: warn\n * on out-of-range input rather than emit a degenerate result.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { warn } from '../../diagnostics.js'\n\n/**\n * The largest `colspan`/`rowspan` this library will honour.\n *\n * Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`\n * is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order\n * of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns\n * and 75 rows), which is what makes it something no authored table can reach. What it stops is\n * the other end, where the allocation takes the host process with it.\n */\nexport const MAX_TABLE_SPAN = 1000\n\n/**\n * Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole\n * number in `1..MAX_TABLE_SPAN`.\n *\n * `undefined` is the common case and means \"no span\" — it warns about nothing and returns `1`.\n * Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all\n * describe a table that cannot be built (a fractional span silently truncates, a negative one\n * shifts every column after it, an enormous one is the allocation above).\n *\n * The parameter is typed `unknown` because this is also **the** reading of a span for the six\n * sites that consume one after {@link withCheckedSpans} has run. Those had six different\n * coercions — `Number(x) ? … : 1`, `Math.max(1, Number(x) || 1)`, `x ?? 1` — which agreed only\n * on the values that were already valid, and one of them let a non-numeric span reach a grid\n * column count as `NaN`. Reading a span through one function is what stops them drifting apart\n * again if the up-front check is ever moved.\n * @param value - the raw option value, as the caller wrote it\n * @param kind - `'colspan'` or `'rowspan'`, for the diagnostic\n * @returns the span to use, at least 1\n */\nexport function resolveSpan(value: unknown, kind: 'colspan' | 'rowspan'): number {\n\tif (value === undefined || value === null || value === '') return 1\n\tif (typeof value !== 'number') {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\tif (!Number.isInteger(value) || value < 1 || value > MAX_TABLE_SPAN) {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\treturn value\n}\n\n/**\n * Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.\n *\n * Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's\n * grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at\n * each of those sites instead would warn several times per bad cell and could still disagree.\n *\n * A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the\n * merge dummies back to the origin *object*, and the all-valid path is every real table, which\n * must stay allocation-free and byte-identical.\n * @param rows - the rows to check; row arrays are never mutated\n * @returns the same rows with only the offending cells replaced\n */\nexport function withCheckedSpans(rows: TableCellInternal[][]): TableCellInternal[][] {\n\treturn rows.map((cells) =>\n\t\tcells.map((cell) => {\n\t\t\tconst opts = cell?.options\n\t\t\tif (!opts) return cell\n\t\t\tconst colspan = resolveSpan(opts.colspan, 'colspan')\n\t\t\tconst rowspan = resolveSpan(opts.rowspan, 'rowspan')\n\t\t\tconst colspanOk = opts.colspan === undefined || opts.colspan === colspan\n\t\t\tconst rowspanOk = opts.rowspan === undefined || opts.rowspan === rowspan\n\t\t\tif (colspanOk && rowspanOk) return cell\n\t\t\treturn {\n\t\t\t\t...cell,\n\t\t\t\toptions: {\n\t\t\t\t\t...opts,\n\t\t\t\t\t...(opts.colspan === undefined ? {} : { colspan }),\n\t\t\t\t\t...(opts.rowspan === undefined ? {} : { rowspan }),\n\t\t\t\t},\n\t\t\t}\n\t\t})\n\t)\n}\n\n/**\n * Whether any cell in the grid carries a hyperlink — on the cell itself, or on any run of a\n * cell whose `text` is a run array.\n *\n * `addTable` uses this to decide whether to stand its black text default down: the default is\n * direct formatting on the table, so it would paint the words *after* a link black rather than\n * letting them follow the link colour. The test used to be\n * `JSON.stringify({ arrRows }).includes('hyperlink')`, which matched the literal word anywhere\n * in the grid's *content* — a cell reading \"see the hyperlink docs\" suppressed the default for\n * the whole table — and serialized every cell on every `addTable` to ask.\n * @param rows - the table's rows\n */\nexport function tableHasHyperlink(rows: TableCellInternal[][]): boolean {\n\treturn rows.some((cells) =>\n\t\tcells.some((cell) => {\n\t\t\tif (!cell) return false\n\t\t\tif (cell.options?.hyperlink) return true\n\t\t\tif (!Array.isArray(cell.text)) return false\n\t\t\treturn cell.text.some((run) => !!run?.options?.hyperlink)\n\t\t})\n\t)\n}\n","/**\n * ts-pptx: a table's cell grid.\n *\n * Rows arrive lopsided -- `row1: [A, B, C]`, `row2: [D]` when the first two columns are held by\n * a rowspan from above -- so a cell's position in its row array is not its column. Four places\n * needed to know where a cell actually lands (the auto-pager, twice, in one function; the\n * measured-fit pass; the table emitter) and each walked the grid itself, tracking rowspan\n * occupancy in its own array with its own off-by-one convention.\n *\n * This is that traversal, once. It lives beside {@link resolveSpan} rather than in `measure/`\n * because the grid is a fact about the authored table, not a measurement of it -- the pager and\n * the emitter want it as much as the fitter does, and `measure/table-fit.ts` was already\n * reaching into `gen/table/` for the span reader it is built on.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { resolveSpan } from './spans.js'\n\n/**\n * How many grid columns a table has: the sum of the first row's colspans.\n *\n * The count cannot come from `rows[0].length` -- a colspan makes one cell occupy several\n * columns -- and it is read off the first row alone, which is the writer's standing rule: a\n * later row wider than the first is ragged input, and the grid it is measured, paged and\n * emitted against is the one `a:tblGrid` declares.\n */\nexport function tableColCount(rows: TableCellInternal[][]): number {\n\tconst first = rows[0]\n\treturn first ? first.reduce((n, c) => n + resolveSpan(c?.options?.colspan, 'colspan'), 0) : 0\n}\n\n/** The bookkeeping a row-major grid walk needs to route around rowspans; see {@link createRowSpanOccupancy}. */\ninterface RowSpanOccupancy {\n\t/** The first column at or after `col` that no rowspan from above is holding. */\n\tnextFree: (col: number) => number\n\t/** Record that `colSpan` columns from `col` are held for `rowSpan` rows, this one included. */\n\thold: (col: number, colSpan: number, rowSpan: number) => void\n\t/** Close the current row: every held column has one fewer row left to hold. */\n\tendRow: () => void\n}\n\n/**\n * The rowspan-occupancy rule, stated once.\n *\n * A row states only the cells it *starts*: a column held by a `rowspan` from above is filled\n * without the row mentioning it, so a cell's position in its row array is not its column. Tracking\n * that is three operations -- skip what is held, mark what this cell holds, age the holds by a row\n * -- and getting the ageing off by one silently shifts every column below.\n *\n * It has two callers asking different questions on different input. {@link walkTableGrid} places\n * authored `TableCell`s into a grid whose width `a:tblGrid` already declares; `measureGridColumns`\n * (`gen/table/html-dom.ts`) measures how wide an imported HTML table's grid *is*, reading spans off\n * HTML attributes, with no width known up front. Neither can be expressed as the other without\n * giving one of them a mode it does not want -- but the rule underneath is the same rule, and it is\n * here rather than in both.\n *\n * The array is sparse and unbounded on purpose: a caller that knows its width clamps what it\n * `hold`s, and then nothing past that width is ever held, so an unbounded `nextFree` returns the\n * same answer a bounded one would.\n */\nexport function createRowSpanOccupancy(): RowSpanOccupancy {\n\t// held[c] = rows still covered by a rowspan started at or above the current row.\n\tconst held: number[] = []\n\treturn {\n\t\tnextFree(col) {\n\t\t\tlet free = col\n\t\t\twhile ((held[free] ?? 0) > 0) free++\n\t\t\treturn free\n\t\t},\n\t\thold(col, colSpan, rowSpan) {\n\t\t\tfor (let idx = 0; idx < colSpan; idx++) held[col + idx] = rowSpan\n\t\t},\n\t\tendRow() {\n\t\t\tfor (let idx = 0; idx < held.length; idx++) {\n\t\t\t\tconst rows = held[idx] ?? 0\n\t\t\t\tif (rows > 0) held[idx] = rows - 1\n\t\t\t}\n\t\t},\n\t}\n}\n\n/** A placed (non-merged origin) cell yielded by {@link walkTableGrid}. */\nexport interface GridPlacement {\n\tcell: TableCellInternal\n\t/** Zero-based grid row of the cell's top-left origin. */\n\trow: number\n\t/** Zero-based grid column of the cell's top-left origin. */\n\tcol: number\n\t/** Rows spanned, clamped to the available rows. */\n\trowSpan: number\n\t/** Columns spanned, clamped to the grid width. */\n\tcolSpan: number\n}\n\n/**\n * Walk a table's cell grid in row-major order, resolving each authored cell to its\n * grid origin (`row`/`col`) and clamped colspan/rowspan. Tracks rowspan occupancy so\n * a cell never lands beneath one spanned from above. This is the single traversal the\n * auto-pager, the measured-fit shrink pass, {@link computeTableLayout} and the table emitter's\n * merge grid all read, so the table that is paged and measured is the table that is written.\n *\n * A cell that starts past the last grid column is not yielded: a row longer than the first is\n * ragged input, and the grid is the one `a:tblGrid` declares.\n */\nexport function* walkTableGrid(rows: TableCellInternal[][], numCols: number): Generator<GridPlacement> {\n\tconst occupancy = createRowSpanOccupancy()\n\tfor (let r = 0; r < rows.length; r++) {\n\t\tconst row = rows[r]\n\t\tif (!row) continue\n\t\tlet col = 0\n\t\tfor (const cell of row) {\n\t\t\tcol = occupancy.nextFree(col)\n\t\t\tif (col >= numCols) break\n\t\t\tconst colspan = resolveSpan(cell?.options?.colspan, 'colspan')\n\t\t\tconst rowspan = Math.min(resolveSpan(cell?.options?.rowspan, 'rowspan'), rows.length - r)\n\t\t\tconst colStart = col\n\t\t\t// Clamped to the declared width, which is also what keeps `nextFree` unbounded and still\n\t\t\t// correct: nothing past `numCols` is ever held, so it never has a reason to walk past it.\n\t\t\tconst colEnd = Math.min(colStart + colspan, numCols)\n\t\t\toccupancy.hold(colStart, colEnd - colStart, rowspan)\n\t\t\tcol = colEnd\n\t\t\tyield { cell, row: r, col: colStart, rowSpan: rowspan, colSpan: colEnd - colStart }\n\t\t}\n\t\toccupancy.endRow()\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
1
|
+
import { l as warn, n as InvalidOptionError } from "./errors-C4oENPcu.js";
|
|
2
|
+
import { C as usableTableWidthEmu, c as inch2Emu, s as getSmartParseNumber, y as resolveSlideMarginsInches } from "./units-internal-XJlf-hOl.js";
|
|
3
|
+
import { F as EMU_PER_INCH } from "./table-cell-margins-EVg0EwxT.js";
|
|
4
|
+
import { a as resolveSpan, t as createRowSpanOccupancy } from "./grid-DikTjFey.js";
|
|
5
|
+
import { t as getSlidesForTableRows } from "./autopage-odPz7zZO.js";
|
|
5
6
|
//#region src/gen/table/html-dom.ts
|
|
6
7
|
/**
|
|
8
|
+
* CSS `text-align` / `vertical-align` values this converter can express as a table cell's own
|
|
9
|
+
* alignment. The two logical values map onto the physical pair; everything else — `justify`,
|
|
10
|
+
* `initial`, a value the browser did not resolve — is absent here and so leaves the cell's
|
|
11
|
+
* alignment alone.
|
|
12
|
+
*/
|
|
13
|
+
const CSS_TEXT_ALIGN = {
|
|
14
|
+
left: "left",
|
|
15
|
+
center: "center",
|
|
16
|
+
right: "right",
|
|
17
|
+
start: "left",
|
|
18
|
+
end: "right"
|
|
19
|
+
};
|
|
20
|
+
const CSS_VERTICAL_ALIGN = {
|
|
21
|
+
top: "top",
|
|
22
|
+
middle: "middle",
|
|
23
|
+
bottom: "bottom"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
7
26
|
* Stand-in for `getComputedStyle` on a document that has no view — a document produced by
|
|
8
27
|
* parsing rather than by a browsing context has a `null` `defaultView` and therefore no
|
|
9
28
|
* cascade to compute against. Every property reads as `''`, which every consumer below
|
|
@@ -82,18 +101,25 @@ function rgbToHex(r, g, b) {
|
|
|
82
101
|
* Convert a computed CSS border (width string + color string) from `getComputedStyle` into a
|
|
83
102
|
* pptx `BorderProps`.
|
|
84
103
|
*
|
|
104
|
+
* `StrokeProps.width` is in **points**, so the px magnitude is converted through
|
|
105
|
+
* {@link htmlCssPxToPoints} rather than copied across: a `1px` CSS border is 0.75pt, not 1pt.
|
|
106
|
+
* This was the third read in this file to make that mistake and the last one left — the font
|
|
107
|
+
* size and the cell padding were each corrected against `DEFAULT_PX_PER_INCH` on their own, and
|
|
108
|
+
* routing this one through the same converter is what stops a fourth from drifting apart again.
|
|
109
|
+
*
|
|
85
110
|
* Preserves *fractional* widths: a hairline CSS border such as `0.5px` must not be rounded to
|
|
86
111
|
* `0pt` and silently vanish — the table serializer (`ptsToEmuLenient`) emits fractional points just
|
|
87
112
|
* fine, so there is no reason to integer-round here. A
|
|
88
113
|
* computed width of `0` (or a non-finite value) yields `{ type: 'none' }` so we never emit a
|
|
89
|
-
* zero-width line.
|
|
114
|
+
* zero-width line. `''`, `auto` and `3em` are non-finite for the same reason
|
|
115
|
+
* {@link parseCssPx} says they are, and take the same exit.
|
|
90
116
|
* @param {string} widthStr - computed `border-<side>-width`, e.g. `"0.5px"`
|
|
91
117
|
* @param {string} colorStr - computed `border-<side>-color`, e.g. `"rgb(102, 102, 102)"`
|
|
92
118
|
* @returns {BorderProps} border props for the cell side
|
|
93
119
|
*/
|
|
94
120
|
function htmlBorderToProps(widthStr, colorStr) {
|
|
95
|
-
const pt =
|
|
96
|
-
if (!isFinite(pt) || pt <= 0) return { type: "none" };
|
|
121
|
+
const pt = htmlCssPxToPoints(widthStr);
|
|
122
|
+
if (!Number.isFinite(pt) || pt <= 0) return { type: "none" };
|
|
97
123
|
return {
|
|
98
124
|
width: pt,
|
|
99
125
|
color: cssColorToHex(colorStr) ?? "000000"
|
|
@@ -124,7 +150,7 @@ function cssColorToHex(value) {
|
|
|
124
150
|
const parts = (rgbMatch[1] ?? "").split(/[,/\s]+/).filter((part) => part.length > 0);
|
|
125
151
|
if (parts.length < 3) return void 0;
|
|
126
152
|
const channels = parts.slice(0, 3).map((part) => Number(part.replace("%", "")));
|
|
127
|
-
if (channels.some((channel) => !isFinite(channel))) return void 0;
|
|
153
|
+
if (channels.some((channel) => !Number.isFinite(channel))) return void 0;
|
|
128
154
|
if (parts.length > 3 && Number(parts[3]) === 0) return void 0;
|
|
129
155
|
const [r = 0, g = 0, b = 0] = channels.map((channel) => Math.max(0, Math.min(255, Math.round(channel))));
|
|
130
156
|
return rgbToHex(r, g, b);
|
|
@@ -150,9 +176,9 @@ function cssColorToHex(value) {
|
|
|
150
176
|
* @returns {number} resolved column width
|
|
151
177
|
*/
|
|
152
178
|
function resolveHtmlColWidth(calcWidth, setWidth, minWidth) {
|
|
153
|
-
const safeCalc = isFinite(calcWidth) ? calcWidth : 0;
|
|
154
|
-
if (isFinite(setWidth) && setWidth > 0) return setWidth;
|
|
155
|
-
return isFinite(minWidth) && minWidth > safeCalc ? minWidth : safeCalc;
|
|
179
|
+
const safeCalc = Number.isFinite(calcWidth) ? calcWidth : 0;
|
|
180
|
+
if (Number.isFinite(setWidth) && setWidth > 0) return setWidth;
|
|
181
|
+
return Number.isFinite(minWidth) && minWidth > safeCalc ? minWidth : safeCalc;
|
|
156
182
|
}
|
|
157
183
|
/** A CSS value that is a bare number, or a number with a `px`/`%` unit. Nothing else parses. */
|
|
158
184
|
const CSS_LENGTH = /^\s*(-?(?:\d+\.?\d*|\.\d+))\s*(px|%)?\s*$/i;
|
|
@@ -174,6 +200,30 @@ function parseCssPx(value) {
|
|
|
174
200
|
return Number(match[1]);
|
|
175
201
|
}
|
|
176
202
|
/**
|
|
203
|
+
* A computed CSS px length as the points every `pt`-measured table property is in, or `NaN` when
|
|
204
|
+
* the value is not an absolute px length.
|
|
205
|
+
*
|
|
206
|
+
* This is the file's **one** px→pt conversion, and it is one because the same mistake was made
|
|
207
|
+
* three separate times under the same stale "px to pt 1:1" note. A default `16px` cell emitted
|
|
208
|
+
* `sz="1600"` — 16pt, a third larger than the 12pt the browser rendered; the cell padding read
|
|
209
|
+
* a px magnitude as the inches `TableCellProps.margin` wants, until 2026-07-31; and a `1px`
|
|
210
|
+
* border was emitted as 1pt, a third too thick. Each was found and corrected on its own, and
|
|
211
|
+
* the next went on being wrong, because there was no shared converter for a sweep to land on.
|
|
212
|
+
* Now there is, for the two properties measured in points. The padding is not one of them --
|
|
213
|
+
* it resolves to inches -- so it divides by `DEFAULT_PX_PER_INCH` at its own site and this
|
|
214
|
+
* comment is the link between them.
|
|
215
|
+
*
|
|
216
|
+
* CSS defines the reference pixel as 1/96in, so the conversion is the same density the `"<n>px"`
|
|
217
|
+
* coordinate unit uses. An `em`, a `%` or a keyword has no absolute size here and comes back
|
|
218
|
+
* `NaN`, which each caller reads as its own kind of absence — the font size is left off the
|
|
219
|
+
* cell, and a border becomes `{ type: 'none' }`.
|
|
220
|
+
* @param value - computed CSS value, e.g. `"16px"`
|
|
221
|
+
* @returns the length in points, or `NaN` when the value is not an absolute px length
|
|
222
|
+
*/
|
|
223
|
+
function htmlCssPxToPoints(value) {
|
|
224
|
+
return parseCssPx(value) * 72 / 96;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
177
227
|
* Parse a whole row of computed CSS widths into a column basis, or reject the set.
|
|
178
228
|
*
|
|
179
229
|
* The result is only ever used *proportionally* (each column's share of the total), so the
|
|
@@ -197,7 +247,7 @@ function parseCssWidthBasis(values) {
|
|
|
197
247
|
const match = CSS_LENGTH.exec(String(value ?? ""));
|
|
198
248
|
if (!match) return [];
|
|
199
249
|
const magnitude = Number(match[1]);
|
|
200
|
-
if (!isFinite(magnitude) || magnitude < 0) return [];
|
|
250
|
+
if (!Number.isFinite(magnitude) || magnitude < 0) return [];
|
|
201
251
|
const valueUnit = (match[2] ?? "px").toLowerCase();
|
|
202
252
|
if (!unit) unit = valueUnit;
|
|
203
253
|
else if (unit !== valueUnit) return [];
|
|
@@ -238,7 +288,7 @@ function parseCssWidthBasis(values) {
|
|
|
238
288
|
* @returns {number[]} the basis vector to run the proportional calc on
|
|
239
289
|
*/
|
|
240
290
|
function pickColWidthBasis(measured, cssWidths) {
|
|
241
|
-
const sum = (arr) => arr.reduce((acc, n) => acc + (isFinite(n) ? n : 0), 0);
|
|
291
|
+
const sum = (arr) => arr.reduce((acc, n) => acc + (Number.isFinite(n) ? n : 0), 0);
|
|
242
292
|
if (sum(measured) > 0) return [...measured];
|
|
243
293
|
if (cssWidths.length === measured.length && sum(cssWidths) > 0) return [...cssWidths];
|
|
244
294
|
return measured.map(() => 1);
|
|
@@ -253,9 +303,10 @@ function pickColWidthBasis(measured, cssWidths) {
|
|
|
253
303
|
* @param {unknown} value - the raw attribute value
|
|
254
304
|
* @returns {number} tracks covered, at least 1
|
|
255
305
|
*/
|
|
256
|
-
function gridSpan(value) {
|
|
306
|
+
function gridSpan(value, kind) {
|
|
257
307
|
const num = Math.floor(Number(value));
|
|
258
|
-
|
|
308
|
+
if (!Number.isFinite(num) || num <= 1) return 1;
|
|
309
|
+
return num > 1e3 ? resolveSpan(num, kind) : num;
|
|
259
310
|
}
|
|
260
311
|
/**
|
|
261
312
|
* Measure the column grid a set of table rows actually occupies.
|
|
@@ -271,27 +322,26 @@ function gridSpan(value) {
|
|
|
271
322
|
* the two is exactly the padding a ragged row needs; the merge cells for `colspan`/`rowspan` are
|
|
272
323
|
* *not* padding — the table emitter synthesizes those itself, so they are counted as filled here.
|
|
273
324
|
*
|
|
274
|
-
* Spans are read through {@link gridSpan}, so a bad attribute cannot shift the whole grid.
|
|
325
|
+
* Spans are read through {@link gridSpan}, so a bad attribute cannot shift the whole grid. The
|
|
326
|
+
* occupancy bookkeeping underneath is {@link createRowSpanOccupancy}, shared with
|
|
327
|
+
* `walkTableGrid` -- the same rowspan rule, asked a different question: that one places authored
|
|
328
|
+
* cells into a grid whose width is already declared, this one measures how wide the grid *is*.
|
|
275
329
|
* @param {readonly (readonly GridCellSpans[])[]} rows - per-row cell spans, in emission order
|
|
276
330
|
* @returns {{ columns: number, filled: number[] }} grid width, and columns reached per row
|
|
277
331
|
*/
|
|
278
332
|
function measureGridColumns(rows) {
|
|
279
|
-
const
|
|
333
|
+
const occupancy = createRowSpanOccupancy();
|
|
280
334
|
const filled = [];
|
|
281
335
|
for (const row of rows) {
|
|
282
336
|
let col = 0;
|
|
283
337
|
for (const cell of row) {
|
|
284
|
-
|
|
285
|
-
const colspan = gridSpan(cell?.colspan);
|
|
286
|
-
|
|
338
|
+
col = occupancy.nextFree(col);
|
|
339
|
+
const colspan = gridSpan(cell?.colspan, "colspan");
|
|
340
|
+
occupancy.hold(col, colspan, gridSpan(cell?.rowspan, "rowspan"));
|
|
287
341
|
col += colspan;
|
|
288
342
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
for (let idx = 0; idx < carry.length; idx++) {
|
|
292
|
-
const held = carry[idx] ?? 0;
|
|
293
|
-
if (held > 0) carry[idx] = held - 1;
|
|
294
|
-
}
|
|
343
|
+
filled.push(occupancy.nextFree(col));
|
|
344
|
+
occupancy.endRow();
|
|
295
345
|
}
|
|
296
346
|
return {
|
|
297
347
|
columns: filled.reduce((max, reached) => reached > max ? reached : max, 0),
|
|
@@ -312,7 +362,7 @@ function measureGridColumns(rows) {
|
|
|
312
362
|
*/
|
|
313
363
|
function extendColBasis(basis, columns) {
|
|
314
364
|
const extended = [...basis];
|
|
315
|
-
const total = extended.reduce((acc, width) => acc + (isFinite(width) ? width : 0), 0);
|
|
365
|
+
const total = extended.reduce((acc, width) => acc + (Number.isFinite(width) ? width : 0), 0);
|
|
316
366
|
const share = extended.length > 0 && total > 0 ? total / extended.length : 1;
|
|
317
367
|
while (extended.length < columns) extended.push(share);
|
|
318
368
|
return extended;
|
|
@@ -463,10 +513,8 @@ function collectTableRows(table) {
|
|
|
463
513
|
* @param {TableToSlidesProps} options - array of options (e.g.: tabsize)
|
|
464
514
|
*/
|
|
465
515
|
function genTableToSlides(pptx, target, options = {}) {
|
|
466
|
-
const opts = options
|
|
516
|
+
const opts = { ...options };
|
|
467
517
|
const masterSlide = resolveMasterSlide(pptx, opts.masterTitle);
|
|
468
|
-
opts.slideMargin = opts.slideMargin || opts.slideMargin === 0 ? opts.slideMargin : .5;
|
|
469
|
-
let emuSlideTabW = opts.w || pptx.presLayout.width;
|
|
470
518
|
const arrObjTabHeadRows = [];
|
|
471
519
|
const arrObjTabBodyRows = [];
|
|
472
520
|
const arrObjTabFootRows = [];
|
|
@@ -481,25 +529,9 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
481
529
|
];
|
|
482
530
|
let intTabW = 0;
|
|
483
531
|
const ctx = resolveDomContext(target, opts);
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
masterSlide._margin,
|
|
488
|
-
masterSlide._margin,
|
|
489
|
-
masterSlide._margin,
|
|
490
|
-
masterSlide._margin
|
|
491
|
-
];
|
|
492
|
-
opts.slideMargin = arrInchMargins;
|
|
493
|
-
} else if (opts?.slideMargin) {
|
|
494
|
-
if (Array.isArray(opts.slideMargin)) arrInchMargins = opts.slideMargin;
|
|
495
|
-
else if (!isNaN(opts.slideMargin)) arrInchMargins = [
|
|
496
|
-
opts.slideMargin,
|
|
497
|
-
opts.slideMargin,
|
|
498
|
-
opts.slideMargin,
|
|
499
|
-
opts.slideMargin
|
|
500
|
-
];
|
|
501
|
-
}
|
|
502
|
-
emuSlideTabW = (opts.w ? inch2Emu(opts.w) : pptx.presLayout.width) - inch2Emu(arrInchMargins[1] + arrInchMargins[3]);
|
|
532
|
+
arrInchMargins = resolveSlideMarginsInches(masterSlide?._margin, opts.slideMargin);
|
|
533
|
+
const tableXEmu = opts.x === void 0 || opts.x === null ? inch2Emu(arrInchMargins[3]) : getSmartParseNumber(opts.x, "X", pptx.presLayout);
|
|
534
|
+
const emuSlideTabW = opts.w === void 0 || opts.w === null ? usableTableWidthEmu(pptx.presLayout, tableXEmu, arrInchMargins) : getSmartParseNumber(opts.w, "X", pptx.presLayout);
|
|
503
535
|
if (opts.verbose) {
|
|
504
536
|
console.log("[[VERBOSE MODE]]");
|
|
505
537
|
console.log("|-- `tableToSlides` ----------------------------------------------------|");
|
|
@@ -510,19 +542,28 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
510
542
|
console.log(`| emuSlideTabW .................................... = ${(emuSlideTabW / EMU_PER_INCH).toFixed(1)}`);
|
|
511
543
|
}
|
|
512
544
|
const domRows = collectTableRows(ctx.table);
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
545
|
+
const spansByCell = /* @__PURE__ */ new Map();
|
|
546
|
+
const spansOf = (cell) => {
|
|
547
|
+
let spans = spansByCell.get(cell);
|
|
548
|
+
if (!spans) {
|
|
549
|
+
spans = {
|
|
550
|
+
colspan: gridSpan(cell.getAttribute("colspan"), "colspan"),
|
|
551
|
+
rowspan: gridSpan(cell.getAttribute("rowspan"), "rowspan")
|
|
552
|
+
};
|
|
553
|
+
spansByCell.set(cell, spans);
|
|
554
|
+
}
|
|
555
|
+
return spans;
|
|
556
|
+
};
|
|
557
|
+
const { columns: intColCnt, filled: arrRowFilled } = measureGridColumns(domRows.map(({ row }) => rowCells(row).map(spansOf)));
|
|
517
558
|
const srcRow = domRows.find(({ row }) => rowCells(row).length > 0);
|
|
518
559
|
if (!srcRow) throw new InvalidOptionError("html/table-has-no-cells", "tableToSlides: the table has no cells to convert - expected at least one <tr> with a <td>/<th>.");
|
|
519
560
|
const arrColSrc = [];
|
|
520
561
|
const arrCellSpans = [];
|
|
521
562
|
rowCells(srcRow.row).forEach((cell) => {
|
|
522
563
|
const offsetW = Number(cell.offsetWidth);
|
|
523
|
-
const measured = isFinite(offsetW) ? offsetW : 0;
|
|
564
|
+
const measured = Number.isFinite(offsetW) ? offsetW : 0;
|
|
524
565
|
arrTabColCssW.push(ctx.getComputedStyle(cell).getPropertyValue("width"));
|
|
525
|
-
const span =
|
|
566
|
+
const span = spansOf(cell).colspan;
|
|
526
567
|
arrCellSpans.push(span);
|
|
527
568
|
for (let idxc = 0; idxc < span; idxc++) {
|
|
528
569
|
arrTabColW.push(Math.round(measured / span));
|
|
@@ -559,33 +600,19 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
559
600
|
const cellOpts = {
|
|
560
601
|
bold: !!(style.getPropertyValue("font-weight") === "bold" || Number(style.getPropertyValue("font-weight")) >= 500),
|
|
561
602
|
color: textColor,
|
|
562
|
-
fill: { color: fillColor }
|
|
563
|
-
fontSize: Number(style.getPropertyValue("font-size").replace(/[a-z]/gi, ""))
|
|
603
|
+
fill: { color: fillColor }
|
|
564
604
|
};
|
|
605
|
+
const fontSizePt = htmlCssPxToPoints(style.getPropertyValue("font-size"));
|
|
606
|
+
if (Number.isFinite(fontSizePt)) cellOpts.fontSize = fontSizePt;
|
|
565
607
|
const fontFace = ((style.getPropertyValue("font-family") || "").split(",")[0] ?? "").replace(/"/g, "").replace("inherit", "").replace("initial", "");
|
|
566
|
-
const colspan =
|
|
567
|
-
const rowspan = gridSpan(cell.getAttribute("rowspan"));
|
|
608
|
+
const { colspan, rowspan } = spansOf(cell);
|
|
568
609
|
if (fontFace) cellOpts.fontFace = fontFace;
|
|
569
610
|
if (colspan > 1) cellOpts.colspan = colspan;
|
|
570
611
|
if (rowspan > 1) cellOpts.rowspan = rowspan;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
"start",
|
|
576
|
-
"end"
|
|
577
|
-
].includes(style.getPropertyValue("text-align"))) {
|
|
578
|
-
const align = style.getPropertyValue("text-align").replace("start", "left").replace("end", "right");
|
|
579
|
-
cellOpts.align = align === "center" ? "center" : align === "left" ? "left" : align === "right" ? "right" : void 0;
|
|
580
|
-
}
|
|
581
|
-
if ([
|
|
582
|
-
"top",
|
|
583
|
-
"middle",
|
|
584
|
-
"bottom"
|
|
585
|
-
].includes(style.getPropertyValue("vertical-align"))) {
|
|
586
|
-
const valign = style.getPropertyValue("vertical-align");
|
|
587
|
-
cellOpts.valign = valign === "top" ? "top" : valign === "middle" ? "middle" : valign === "bottom" ? "bottom" : void 0;
|
|
588
|
-
}
|
|
612
|
+
const align = CSS_TEXT_ALIGN[style.getPropertyValue("text-align")];
|
|
613
|
+
if (align) cellOpts.align = align;
|
|
614
|
+
const valign = CSS_VERTICAL_ALIGN[style.getPropertyValue("vertical-align")];
|
|
615
|
+
if (valign) cellOpts.valign = valign;
|
|
589
616
|
if (style.getPropertyValue("padding-left")) {
|
|
590
617
|
const cellMargin = [
|
|
591
618
|
0,
|
|
@@ -600,7 +627,7 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
600
627
|
"padding-left"
|
|
601
628
|
].forEach((val, idxs) => {
|
|
602
629
|
const pad = parseCssPx(style.getPropertyValue(val));
|
|
603
|
-
cellMargin[idxs] = isFinite(pad) ? pad / 96 : 0;
|
|
630
|
+
cellMargin[idxs] = Number.isFinite(pad) ? pad / 96 : 0;
|
|
604
631
|
});
|
|
605
632
|
cellOpts.margin = cellMargin;
|
|
606
633
|
}
|
|
@@ -642,29 +669,32 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
642
669
|
...arrObjTabHeadRows,
|
|
643
670
|
...arrObjTabBodyRows,
|
|
644
671
|
...arrObjTabFootRows
|
|
645
|
-
], opts, pptx.presLayout, masterSlide).forEach((slide
|
|
646
|
-
const newSlide = pptx.addSlide({ masterTitle: opts.masterTitle
|
|
647
|
-
if (
|
|
648
|
-
if (idxTr > 0) opts.y = opts.autoPageSlideStartY || arrInchMargins[0];
|
|
672
|
+
], opts, pptx.presLayout, masterSlide).forEach((slide) => {
|
|
673
|
+
const newSlide = pptx.addSlide(opts.masterTitle ? { masterTitle: opts.masterTitle } : {});
|
|
674
|
+
if (slide.y !== void 0) opts.y = slide.y;
|
|
649
675
|
if (opts.verbose) console.log(`| opts.autoPageSlideStartY: ${opts.autoPageSlideStartY} / arrInchMargins[0]: ${arrInchMargins[0]} => opts.y = ${opts.y}`);
|
|
650
|
-
|
|
651
|
-
x: opts.x
|
|
652
|
-
y: opts.y,
|
|
676
|
+
const slideTableProps = {
|
|
677
|
+
x: opts.x ?? arrInchMargins[3],
|
|
653
678
|
w: Number(emuSlideTabW) / EMU_PER_INCH,
|
|
654
679
|
colW: arrColW,
|
|
655
680
|
autoPage: false
|
|
656
|
-
}
|
|
681
|
+
};
|
|
682
|
+
if (opts.y !== void 0) slideTableProps.y = opts.y;
|
|
683
|
+
newSlide.addTable(slide.rows, slideTableProps);
|
|
657
684
|
if (opts.addImage) {
|
|
658
685
|
opts.addImage.options = opts.addImage.options || {};
|
|
659
686
|
if (!opts.addImage.image || !opts.addImage.image.path && !opts.addImage.image.data) warn("html/image-missing-source", "tableToSlides.addImage requires either `path` or `data`");
|
|
660
687
|
else {
|
|
661
688
|
const imageProps = opts.addImage.image.path ? { path: opts.addImage.image.path } : { data: opts.addImage.image.data };
|
|
689
|
+
const imageOptions = opts.addImage.options;
|
|
690
|
+
const geometry = {};
|
|
691
|
+
if (imageOptions.x !== void 0) geometry.x = imageOptions.x;
|
|
692
|
+
if (imageOptions.y !== void 0) geometry.y = imageOptions.y;
|
|
693
|
+
if (imageOptions.w !== void 0) geometry.w = imageOptions.w;
|
|
694
|
+
if (imageOptions.h !== void 0) geometry.h = imageOptions.h;
|
|
662
695
|
newSlide.addImage({
|
|
663
696
|
...imageProps,
|
|
664
|
-
|
|
665
|
-
y: opts.addImage.options.y,
|
|
666
|
-
w: opts.addImage.options.w,
|
|
667
|
-
h: opts.addImage.options.h
|
|
697
|
+
...geometry
|
|
668
698
|
});
|
|
669
699
|
}
|
|
670
700
|
}
|
|
@@ -676,4 +706,4 @@ function genTableToSlides(pptx, target, options = {}) {
|
|
|
676
706
|
//#endregion
|
|
677
707
|
export { genTableToSlides as t };
|
|
678
708
|
|
|
679
|
-
//# sourceMappingURL=html-dom-
|
|
709
|
+
//# sourceMappingURL=html-dom-Iuog2wdK.js.map
|