node-pptx-templater 1.1.4 → 1.1.6
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/CHANGELOG.md +0 -16
- package/README.md +10 -34
- package/package.json +1 -3
- package/src/core/PPTXTemplater.js +11 -40
- package/src/managers/ShapeManager.js +8 -0
- package/src/managers/TableManager.js +139 -37
package/CHANGELOG.md
CHANGED
|
@@ -5,22 +5,6 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.1.3] - 2026-06-22
|
|
9
|
-
|
|
10
|
-
### Fixed
|
|
11
|
-
|
|
12
|
-
- **Layout Preservation in `addCellShape()`**: Fixed a critical layout bug where querying cell bounds or adding cell shapes dynamically (via `addCellShape()` or `updateCellShape()`) mutated table row heights inside the XML. The sizing/positioning logic now runs in a layout-only mode, keeping the table XML completely untouched and respecting original template custom row heights.
|
|
13
|
-
|
|
14
|
-
## [1.1.2] - 2026-06-22
|
|
15
|
-
|
|
16
|
-
### Fixed
|
|
17
|
-
|
|
18
|
-
- **Slide Link Relationships Target Paths**: Fixed PowerPoint "Repair Mode" errors when adding slide-to-slide hyperlinks (via `addSlideLink` or `addImageLink`). The relative target path resolves correctly to the sibling filename `slideX.xml` instead of using the redundant parent prefix `../slides/slideX.xml` (which exited and re-entered the same directory, violating PowerPoint's relative path resolution rules).
|
|
19
|
-
|
|
20
|
-
### Added
|
|
21
|
-
|
|
22
|
-
- **Redundant Traversal Validation**: Added automated check in `ValidationEngine` to identify and error on redundant relative path traversals inside relationship files (e.g. referencing `../slides/slideX.xml` from a source slide file already located in `ppt/slides/`).
|
|
23
|
-
|
|
24
8
|
## [1.1.0] - 2026-06-12
|
|
25
9
|
|
|
26
10
|
### Added
|
package/README.md
CHANGED
|
@@ -172,51 +172,27 @@ const meta = await ppt.getTableRows('SalesTable', { includeMetadata: true });
|
|
|
172
172
|
```
|
|
173
173
|
|
|
174
174
|
### Table Cell Shapes
|
|
175
|
-
Cell shapes are overlay graphics anchored within table cells. They are positioned absolutely based on cell bounds, and **never** modify row heights, column widths, cell margins, or trigger table reflow.
|
|
176
|
-
|
|
177
|
-
#### Merged Cell Support
|
|
178
|
-
When targeting a merged cell (spanned using `rowSpan` or `colSpan`), `addCellShape()` dynamically resolves the **actual rendered bounds** of the entire merged cell region (summing the width and height of the spanned rows/columns). The shape is positioned and aligned relative to this final merged boundary. Any offset `x` and `y` specified is interpreted relative to the top-left corner of the resolved merged cell region.
|
|
179
|
-
|
|
180
|
-
#### Alignment & Presets
|
|
181
|
-
Shapes can be aligned dynamically within the cell (or merged region) using preset positions or explicit alignments:
|
|
182
|
-
* **Presets**: Use `position` values like `'top-left'`, `'center'`, `'bottom-right'`, etc.
|
|
183
|
-
* **Alignment Options**: Set `alignX: 'left' | 'center' | 'right'` and `alignY: 'top' | 'middle' | 'bottom'`. If no alignments or offsets are provided, shapes default to true centering (`'center'`/`'middle'`).
|
|
184
|
-
* **Offsets & Padding**: Offsets (`x`, `y`) are applied relative to the resolved alignment. For instance, when `alignX: 'right'` is used, the shape is placed at `cellRight - shapeWidth - x` (defaulting to a `5px` padding if `x` is omitted).
|
|
175
|
+
Cell shapes are overlay graphics anchored within table cells. They are positioned absolutely based on cell bounds, and **never** modify row heights, column widths, cell margins, or trigger table reflow. Offsets (`x`, `y`) are relative to the cell's top-left corner. Oversized shapes are scaled down proportionally to fit inside the cell.
|
|
185
176
|
|
|
186
177
|
```javascript
|
|
187
|
-
// Add a
|
|
188
|
-
await ppt.addCellShape('
|
|
178
|
+
// Add a simple indicator
|
|
179
|
+
await ppt.addCellShape('SalesTable', 2, 1, {
|
|
189
180
|
type: 'circle',
|
|
190
181
|
width: 12,
|
|
191
182
|
height: 12,
|
|
192
|
-
fill: '#10B981'
|
|
193
|
-
alignX: 'center',
|
|
194
|
-
alignY: 'middle' // Visually centered in the merged cell
|
|
183
|
+
fill: '#10B981' // Green status dot
|
|
195
184
|
});
|
|
196
185
|
|
|
197
|
-
// Add a badge with text and
|
|
198
|
-
await ppt.addCellShape('
|
|
186
|
+
// Add a badge with text and custom offsets
|
|
187
|
+
await ppt.addCellShape('SalesTable', 1, 2, {
|
|
199
188
|
type: 'badge',
|
|
200
|
-
text: '
|
|
201
|
-
fill: '#
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
x: 5,
|
|
205
|
-
y: 3,
|
|
189
|
+
text: 'Active',
|
|
190
|
+
fill: '#3B82F6',
|
|
191
|
+
x: 4,
|
|
192
|
+
y: 2,
|
|
206
193
|
width: 50,
|
|
207
194
|
height: 16
|
|
208
195
|
});
|
|
209
|
-
|
|
210
|
-
// Add an indicator with bottom-right alignment and custom padding
|
|
211
|
-
await ppt.addCellShape('StatusTable', 1, 1, {
|
|
212
|
-
type: 'icon',
|
|
213
|
-
icon: 'up',
|
|
214
|
-
size: 14,
|
|
215
|
-
alignX: 'right',
|
|
216
|
-
alignY: 'bottom',
|
|
217
|
-
x: 4,
|
|
218
|
-
y: 2
|
|
219
|
-
});
|
|
220
196
|
```
|
|
221
197
|
|
|
222
198
|
### XML Folder Workflow
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pptx-templater",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "High-performance, low-level PowerPoint (PPTX) OpenXML template engine for Node.js. Dynamically replace text, insert images, update charts (with Excel workbook data caching), and merge table cells without PowerPoint corruption or Repair Mode prompts.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -37,8 +37,6 @@
|
|
|
37
37
|
"example:table-extraction": "node examples/table-extraction.js",
|
|
38
38
|
"example:nested-rows": "node examples/nested-table-rows.js",
|
|
39
39
|
"example:xml-folder": "node examples/xml-folder-workflow.js",
|
|
40
|
-
"example:shape-cells": "node examples/shape-cells.js",
|
|
41
|
-
"example:all": "node scripts/run-examples-check.js",
|
|
42
40
|
"prepublishOnly": "npm run lint && npm run test"
|
|
43
41
|
},
|
|
44
42
|
"keywords": [
|
|
@@ -473,10 +473,14 @@ class PPTXTemplater {
|
|
|
473
473
|
throw new PPTXError(`Destination is a file: ${outputPath}`)
|
|
474
474
|
}
|
|
475
475
|
const files = fs.readdirSync(resolvedOut)
|
|
476
|
-
if (files.length > 0
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
476
|
+
if (files.length > 0) {
|
|
477
|
+
if (!options.overwrite) {
|
|
478
|
+
throw new PPTXError(
|
|
479
|
+
`Destination directory "${outputPath}" is not empty. Set overwrite: true to overwrite.`
|
|
480
|
+
)
|
|
481
|
+
} else {
|
|
482
|
+
await fs.emptyDir(resolvedOut)
|
|
483
|
+
}
|
|
480
484
|
}
|
|
481
485
|
} else {
|
|
482
486
|
await fs.ensureDir(resolvedOut)
|
|
@@ -1569,30 +1573,11 @@ class PPTXTemplater {
|
|
|
1569
1573
|
}
|
|
1570
1574
|
|
|
1571
1575
|
/**
|
|
1572
|
-
* Appends one or more rows to a table. Supports flat arrays
|
|
1573
|
-
* for rowspan-merged cells
|
|
1574
|
-
* a graphic indicator directly inside a cell.
|
|
1575
|
-
*
|
|
1576
|
-
* ### Shape Cell Object
|
|
1577
|
-
* Instead of a string value you may pass an object with the following keys:
|
|
1578
|
-
*
|
|
1579
|
-
* | Key | Type | Default | Description |
|
|
1580
|
-
* |-----|------|---------|-------------|
|
|
1581
|
-
* | `type` | `string` | **required** | Shape preset: `'circle'`, `'square'`, `'rectangle'`, `'triangle'`, `'diamond'`, `'hexagon'`, `'line'`. |
|
|
1582
|
-
* | `text` | `string` | `''` | Optional label rendered next to the shape. |
|
|
1583
|
-
* | `color` | `string` | `'#4CAF50'` | Fill colour of the shape (hex). |
|
|
1584
|
-
* | `width` | `number` | `14` | Shape width in points. |
|
|
1585
|
-
* | `height` | `number` | `14` | Shape height in points. |
|
|
1586
|
-
* | `position` | `string` | `'center'` | Alignment inside the cell: `'center'`, `'left'`, `'right'`, `'top'`, `'bottom'`, `'top-left'`, `'top-right'`, `'bottom-left'`, `'bottom-right'`. |
|
|
1587
|
-
* | `offsetX` | `number` | `0` | Additional horizontal offset from the resolved anchor (pt). |
|
|
1588
|
-
* | `offsetY` | `number` | `0` | Additional vertical offset from the resolved anchor (pt). |
|
|
1589
|
-
*
|
|
1590
|
-
* The shape is added as a floating overlay anchored to the cell; the table
|
|
1591
|
-
* dimensions (row heights, column widths) are **never mutated**.
|
|
1576
|
+
* Appends one or more rows to a table. Supports flat arrays and nested arrays
|
|
1577
|
+
* for rowspan-merged cells.
|
|
1592
1578
|
*
|
|
1593
1579
|
* @param {string} tableId - Table name or shape ID.
|
|
1594
|
-
* @param {Array<string|Array<string
|
|
1595
|
-
* a plain string, a nested array (rowspan), or a Shape Cell configuration object.
|
|
1580
|
+
* @param {Array<string|Array<string>>} rowData - Row data. Nested arrays create rowspan cells.
|
|
1596
1581
|
* @param {Object} [options] - Row insertion options.
|
|
1597
1582
|
* @param {'rowspan'|'auto'|'none'} [options.mergeStrategy='rowspan'] - How to handle nested arrays.
|
|
1598
1583
|
* `'rowspan'` creates OpenXML vertical spans, `'auto'` merges identical adjacent values,
|
|
@@ -1605,20 +1590,6 @@ class PPTXTemplater {
|
|
|
1605
1590
|
*
|
|
1606
1591
|
* // Nested row with rowspan
|
|
1607
1592
|
* ppt.addTableRow('SalesTable', ['Region', ['Q1', 'Q2'], '$5K'], { mergeStrategy: 'rowspan' });
|
|
1608
|
-
*
|
|
1609
|
-
* // KPI indicator – green circle placed in the cell centre, no label
|
|
1610
|
-
* await ppt.addTableRow('StatusTable', [
|
|
1611
|
-
* 'Alice',
|
|
1612
|
-
* 'Engineering',
|
|
1613
|
-
* { type: 'circle', color: '#4CAF50', width: 12, height: 12, position: 'center' },
|
|
1614
|
-
* ]);
|
|
1615
|
-
*
|
|
1616
|
-
* // Status badge – shape with accompanying text label, aligned to the left
|
|
1617
|
-
* await ppt.addTableRow('StatusTable', [
|
|
1618
|
-
* 'Bob',
|
|
1619
|
-
* 'Design',
|
|
1620
|
-
* { type: 'circle', color: '#F44336', text: 'Blocked', position: 'left' },
|
|
1621
|
-
* ]);
|
|
1622
1593
|
*/
|
|
1623
1594
|
addTableRow(tableId, rowData, options = {}) {
|
|
1624
1595
|
this.#assertLoaded()
|
|
@@ -433,6 +433,14 @@ class ShapeManager {
|
|
|
433
433
|
if (!options) return options
|
|
434
434
|
const normalized = { ...options }
|
|
435
435
|
|
|
436
|
+
// Fallback mapping between id and name for compatibility
|
|
437
|
+
if (normalized.id === undefined && normalized.name !== undefined) {
|
|
438
|
+
normalized.id = normalized.name
|
|
439
|
+
}
|
|
440
|
+
if (normalized.name === undefined && normalized.id !== undefined) {
|
|
441
|
+
normalized.name = normalized.id
|
|
442
|
+
}
|
|
443
|
+
|
|
436
444
|
// 1. Map color alias to fill
|
|
437
445
|
const fillVal = options.fill !== undefined ? options.fill : options.color
|
|
438
446
|
if (fillVal !== undefined) {
|
|
@@ -1719,40 +1719,52 @@ class TableManager {
|
|
|
1719
1719
|
}
|
|
1720
1720
|
|
|
1721
1721
|
// 2. Determine alignment settings
|
|
1722
|
-
let alignX =
|
|
1723
|
-
let alignY =
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
.
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1722
|
+
let alignX = config.alignX
|
|
1723
|
+
let alignY = config.alignY
|
|
1724
|
+
|
|
1725
|
+
if (config.position) {
|
|
1726
|
+
switch (config.position) {
|
|
1727
|
+
case 'top-left':
|
|
1728
|
+
if (!alignX) alignX = 'left'
|
|
1729
|
+
if (!alignY) alignY = 'top'
|
|
1730
|
+
break
|
|
1731
|
+
case 'top-center':
|
|
1732
|
+
case 'top':
|
|
1733
|
+
if (!alignX) alignX = 'center'
|
|
1734
|
+
if (!alignY) alignY = 'top'
|
|
1735
|
+
break
|
|
1736
|
+
case 'top-right':
|
|
1737
|
+
if (!alignX) alignX = 'right'
|
|
1738
|
+
if (!alignY) alignY = 'top'
|
|
1739
|
+
break
|
|
1740
|
+
case 'middle-left':
|
|
1741
|
+
case 'left':
|
|
1742
|
+
if (!alignX) alignX = 'left'
|
|
1743
|
+
if (!alignY) alignY = 'middle'
|
|
1744
|
+
break
|
|
1745
|
+
case 'center':
|
|
1746
|
+
case 'middle-center':
|
|
1747
|
+
if (!alignX) alignX = 'center'
|
|
1748
|
+
if (!alignY) alignY = 'middle'
|
|
1749
|
+
break
|
|
1750
|
+
case 'middle-right':
|
|
1751
|
+
case 'right':
|
|
1752
|
+
if (!alignX) alignX = 'right'
|
|
1753
|
+
if (!alignY) alignY = 'middle'
|
|
1754
|
+
break
|
|
1755
|
+
case 'bottom-left':
|
|
1756
|
+
if (!alignX) alignX = 'left'
|
|
1757
|
+
if (!alignY) alignY = 'bottom'
|
|
1758
|
+
break
|
|
1759
|
+
case 'bottom-center':
|
|
1760
|
+
case 'bottom':
|
|
1761
|
+
if (!alignX) alignX = 'center'
|
|
1762
|
+
if (!alignY) alignY = 'bottom'
|
|
1763
|
+
break
|
|
1764
|
+
case 'bottom-right':
|
|
1765
|
+
if (!alignX) alignX = 'right'
|
|
1766
|
+
if (!alignY) alignY = 'bottom'
|
|
1767
|
+
break
|
|
1756
1768
|
}
|
|
1757
1769
|
}
|
|
1758
1770
|
|
|
@@ -2057,7 +2069,7 @@ class TableManager {
|
|
|
2057
2069
|
slideManager,
|
|
2058
2070
|
shapeManager,
|
|
2059
2071
|
tblObj,
|
|
2060
|
-
|
|
2072
|
+
frameObj
|
|
2061
2073
|
) {
|
|
2062
2074
|
if (!cellShapes || !shapeManager) return
|
|
2063
2075
|
|
|
@@ -2075,6 +2087,54 @@ class TableManager {
|
|
|
2075
2087
|
}
|
|
2076
2088
|
}
|
|
2077
2089
|
|
|
2090
|
+
const xfrm = frameObj['p:xfrm']
|
|
2091
|
+
const tableX = xfrm?.['a:off']?.['@_x'] ? parseInt(xfrm['a:off']['@_x'], 10) : 0
|
|
2092
|
+
const tableY = xfrm?.['a:off']?.['@_y'] ? parseInt(xfrm['a:off']['@_y'], 10) : 0
|
|
2093
|
+
|
|
2094
|
+
const gridCols = tblObj['a:tblGrid']?.['a:gridCol'] || []
|
|
2095
|
+
const gridColsArr = Array.isArray(gridCols) ? gridCols : [gridCols]
|
|
2096
|
+
const colWidths = gridColsArr.map(col => parseInt(col['@_w'] || 0, 10))
|
|
2097
|
+
|
|
2098
|
+
const trsArr = tblObj['a:tr'] || []
|
|
2099
|
+
const rowHeights = trsArr.map(row => parseInt(row['@_h'] || 0, 10))
|
|
2100
|
+
|
|
2101
|
+
const getCellBounds = (r, c) => {
|
|
2102
|
+
const parent = this.getMergeParent(slideIndex, tableId, r, c, slideManager)
|
|
2103
|
+
const pr = parent.row
|
|
2104
|
+
const pc = parent.col
|
|
2105
|
+
|
|
2106
|
+
let cellLeft = tableX
|
|
2107
|
+
for (let idx = 0; idx < pc; idx++) {
|
|
2108
|
+
cellLeft += colWidths[idx] || 0
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
let cellTop = tableY
|
|
2112
|
+
for (let idx = 0; idx < pr; idx++) {
|
|
2113
|
+
cellTop += rowHeights[idx] || 0
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
const parentCell = trsArr[pr]?.['a:tc']?.[pc]
|
|
2117
|
+
const gridSpan = parentCell?.['@_gridSpan'] ? parseInt(parentCell['@_gridSpan'], 10) : 1
|
|
2118
|
+
const rowSpan = parentCell?.['@_rowSpan'] ? parseInt(parentCell['@_rowSpan'], 10) : 1
|
|
2119
|
+
|
|
2120
|
+
let cellWidth = 0
|
|
2121
|
+
for (let idx = 0; idx < gridSpan; idx++) {
|
|
2122
|
+
cellWidth += colWidths[pc + idx] || 0
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
let cellHeight = 0
|
|
2126
|
+
for (let idx = 0; idx < rowSpan; idx++) {
|
|
2127
|
+
cellHeight += rowHeights[pr + idx] || 0
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
return {
|
|
2131
|
+
left: cellLeft,
|
|
2132
|
+
top: cellTop,
|
|
2133
|
+
width: cellWidth,
|
|
2134
|
+
height: cellHeight,
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2078
2138
|
const shapesToCreate = []
|
|
2079
2139
|
const headerNames = (tblObj['a:tr']?.[0]?.['a:tc'] || []).map(cell =>
|
|
2080
2140
|
this.#getCellText(cell).trim()
|
|
@@ -2204,7 +2264,45 @@ class TableManager {
|
|
|
2204
2264
|
}
|
|
2205
2265
|
|
|
2206
2266
|
addCellShape(slideIndex, tableId, rowIndex, colIndex, options, slideManager, shapeManager) {
|
|
2207
|
-
const { resolvedTableId } = this.#getTableContext(
|
|
2267
|
+
const { tblObj, frameObj, resolvedTableId } = this.#getTableContext(
|
|
2268
|
+
slideIndex,
|
|
2269
|
+
tableId,
|
|
2270
|
+
slideManager
|
|
2271
|
+
)
|
|
2272
|
+
|
|
2273
|
+
const xfrm = frameObj['p:xfrm']
|
|
2274
|
+
const tableX = xfrm?.['a:off']?.['@_x'] ? parseInt(xfrm['a:off']['@_x'], 10) : 0
|
|
2275
|
+
const tableY = xfrm?.['a:off']?.['@_y'] ? parseInt(xfrm['a:off']['@_y'], 10) : 0
|
|
2276
|
+
|
|
2277
|
+
const gridCols = tblObj['a:tblGrid']?.['a:gridCol'] || []
|
|
2278
|
+
const gridColsArr = Array.isArray(gridCols) ? gridCols : [gridCols]
|
|
2279
|
+
const colWidths = gridColsArr.map(col => parseInt(col['@_w'] || 0, 10))
|
|
2280
|
+
|
|
2281
|
+
const trsArr = tblObj['a:tr'] || []
|
|
2282
|
+
const rowHeights = trsArr.map(row => parseInt(row['@_h'] || 0, 10))
|
|
2283
|
+
|
|
2284
|
+
const parent = this.getMergeParent(slideIndex, tableId, rowIndex, colIndex, slideManager)
|
|
2285
|
+
const pr = parent.row
|
|
2286
|
+
const pc = parent.col
|
|
2287
|
+
|
|
2288
|
+
let cellLeft = tableX
|
|
2289
|
+
for (let idx = 0; idx < pc; idx++) {
|
|
2290
|
+
cellLeft += colWidths[idx] || 0
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
let cellTop = tableY
|
|
2294
|
+
for (let idx = 0; idx < pr; idx++) {
|
|
2295
|
+
cellTop += rowHeights[idx] || 0
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
const parentCell = trsArr[pr]?.['a:tc']?.[pc]
|
|
2299
|
+
const gridSpan = parentCell?.['@_gridSpan'] ? parseInt(parentCell['@_gridSpan'], 10) : 1
|
|
2300
|
+
const rowSpan = parentCell?.['@_rowSpan'] ? parseInt(parentCell['@_rowSpan'], 10) : 1
|
|
2301
|
+
|
|
2302
|
+
let cellWidth = 0
|
|
2303
|
+
for (let idx = 0; idx < gridSpan; idx++) {
|
|
2304
|
+
cellWidth += colWidths[pc + idx] || 0
|
|
2305
|
+
}
|
|
2208
2306
|
|
|
2209
2307
|
const bounds = this.getCellBounds(slideIndex, tableId, rowIndex, colIndex, slideManager)
|
|
2210
2308
|
if (!bounds) {
|
|
@@ -2259,7 +2357,11 @@ class TableManager {
|
|
|
2259
2357
|
slideManager,
|
|
2260
2358
|
shapeManager
|
|
2261
2359
|
) {
|
|
2262
|
-
const { resolvedTableId } = this.#getTableContext(
|
|
2360
|
+
const { tblObj, frameObj, resolvedTableId } = this.#getTableContext(
|
|
2361
|
+
slideIndex,
|
|
2362
|
+
tableId,
|
|
2363
|
+
slideManager
|
|
2364
|
+
)
|
|
2263
2365
|
|
|
2264
2366
|
const shapes = shapeManager.getShapes(slideIndex, slideManager)
|
|
2265
2367
|
const prefix = `cellshape_${resolvedTableId}_${rowIndex}_${colIndex}_${shapeIndex}`
|