node-pptx-templater 1.0.19 → 1.0.21
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 +279 -0
- package/package.json +1 -1
- package/src/core/PPTXTemplater.js +341 -3
- package/src/managers/ShapeManager.js +700 -0
- package/src/managers/TableManager.js +1366 -79
package/README.md
CHANGED
|
@@ -173,6 +173,22 @@ if (!report.valid) {
|
|
|
173
173
|
}
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
+
### 5. PPTX Extraction & Rebuilding Utilities
|
|
177
|
+
|
|
178
|
+
You can programmatically extract standard zipped `.pptx` archives into OpenXML folder templates or compile them back. Target directories are created automatically:
|
|
179
|
+
|
|
180
|
+
#### Extract PPTX to Folder Template
|
|
181
|
+
```javascript
|
|
182
|
+
const { PPTXTemplate } = require('node-pptx-templater');
|
|
183
|
+
|
|
184
|
+
await PPTXTemplate.extractPptx('./sample.pptx', './output/template', { overwrite: true });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### Rebuild PPTX from Folder Template
|
|
188
|
+
```javascript
|
|
189
|
+
await PPTXTemplate.buildPptx('./templates/sample', './output.pptx');
|
|
190
|
+
```
|
|
191
|
+
|
|
176
192
|
---
|
|
177
193
|
|
|
178
194
|
## 📋 OpenXML Presentation Architecture
|
|
@@ -208,6 +224,95 @@ Naively duplicating rows in slide tables can leave duplicate `rowId` values or b
|
|
|
208
224
|
|
|
209
225
|
---
|
|
210
226
|
|
|
227
|
+
## 📊 Reading Table Data & JSON Extraction
|
|
228
|
+
|
|
229
|
+
PPTXForge allows you to read table data from your template and return it as structured JSON objects or raw arrays. This is extremely useful for reverse-engineering data or verifying layouts.
|
|
230
|
+
|
|
231
|
+
### 1. Object-Based Extraction (Default)
|
|
232
|
+
By default, the first row is treated as headers, and subsequent rows are returned as objects keyed by header names. Merged cells automatically resolve to their parent cell's value:
|
|
233
|
+
```javascript
|
|
234
|
+
const rows = await ppt.getTableRows('SalesTable');
|
|
235
|
+
// Returns:
|
|
236
|
+
// [
|
|
237
|
+
// { region: 'North', sales: '1200', growth: '15%' },
|
|
238
|
+
// { region: 'South', sales: '1800', growth: '22%' }
|
|
239
|
+
// ]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### 2. Raw Extraction
|
|
243
|
+
Return a raw 2D array of string values (excluding the header row) by passing `{ raw: true }`:
|
|
244
|
+
```javascript
|
|
245
|
+
const rows = await ppt.getTableRows('SalesTable', { raw: true });
|
|
246
|
+
// Returns:
|
|
247
|
+
// [
|
|
248
|
+
// ['North', '1200', '15%'],
|
|
249
|
+
// ['South', '1800', '22%']
|
|
250
|
+
// ]
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 3. Including Table Metadata
|
|
254
|
+
Pass `{ includeMetadata: true }` to retrieve row counts, column counts, and the list of merged cell ranges alongside the rows:
|
|
255
|
+
```javascript
|
|
256
|
+
const result = await ppt.getTableRows('SalesTable', { includeMetadata: true });
|
|
257
|
+
// Returns:
|
|
258
|
+
// {
|
|
259
|
+
// rows: [...],
|
|
260
|
+
// rowCount: 10,
|
|
261
|
+
// columnCount: 5,
|
|
262
|
+
// mergedCells: [ { startRow: 1, startCol: 0, endRow: 2, endCol: 0 }, ... ]
|
|
263
|
+
// }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 📈 Nested Table Rows & Rowspan Support
|
|
269
|
+
|
|
270
|
+
When building financial sheets, invoices, or hierarchical dashboards, you often need to stack multiple rows vertically inside a single column while spanning cells in other columns. PPTXForge supports nested arrays in `addTableRow()` to automatically handle:
|
|
271
|
+
- Proportional height scaling.
|
|
272
|
+
- Vertical merge (`vMerge`) and row span (`rowSpan`) generation.
|
|
273
|
+
- Dynamic layout adjustments.
|
|
274
|
+
|
|
275
|
+
### 1. Vertical Row Nesting Example
|
|
276
|
+
```javascript
|
|
277
|
+
await ppt.addTableRow('Table1', [
|
|
278
|
+
'Region',
|
|
279
|
+
['Sales', '1200'],
|
|
280
|
+
['Growth', '15%']
|
|
281
|
+
]);
|
|
282
|
+
```
|
|
283
|
+
Generates:
|
|
284
|
+
```text
|
|
285
|
+
+---------+---------+---------+
|
|
286
|
+
| Region | Sales | Growth |
|
|
287
|
+
| | 1200 | 15% |
|
|
288
|
+
+---------+---------+---------+
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 2. Deep Nesting Example
|
|
292
|
+
```javascript
|
|
293
|
+
await ppt.addTableRow('Table1', [
|
|
294
|
+
'Parent',
|
|
295
|
+
[
|
|
296
|
+
'Child 1',
|
|
297
|
+
'Child 2',
|
|
298
|
+
'Child 3'
|
|
299
|
+
]
|
|
300
|
+
]);
|
|
301
|
+
```
|
|
302
|
+
Generates 3 sub-rows where column 0 automatically spans all 3 rows.
|
|
303
|
+
|
|
304
|
+
### 3. Merge Strategies
|
|
305
|
+
Configure merge behavior via `options.mergeStrategy`:
|
|
306
|
+
- `'auto'` (default): Creates structural merges from nested arrays, and additionally merges consecutive duplicate values in the same column.
|
|
307
|
+
- `'rowspan'`: Creates structural rowspan/merges strictly from the nested array structure.
|
|
308
|
+
- `'none'`: Pads columns to match the target generated height but does not merge cells (leaving them as individual cells).
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
await ppt.addTableRow('Table1', data, { mergeStrategy: 'rowspan' });
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
211
316
|
## 📊 Feature Comparison Matrix
|
|
212
317
|
|
|
213
318
|
Compare PPTXForge with other popular PowerPoint automation libraries:
|
|
@@ -243,6 +348,98 @@ ppt.useSlide(1).updateTable('summary-table', [
|
|
|
243
348
|
]);
|
|
244
349
|
```
|
|
245
350
|
|
|
351
|
+
#### `addCellShape(tableId, rowIndex, colIndex, options)`
|
|
352
|
+
Dynamically adds a shape inside a table cell based on cell coordinates.
|
|
353
|
+
|
|
354
|
+
* **Arguments**:
|
|
355
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
356
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
357
|
+
* `colIndex` (`number`): 0-based column index.
|
|
358
|
+
* `options` (`Object`): Shape configuration options.
|
|
359
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
await ppt.addCellShape('Table', 1, 2, { type: 'circle', fill: '#10B981' });
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
#### `updateCellShape(tableId, rowIndex, colIndex, shapeIndex, options)`
|
|
366
|
+
Updates an existing shape inside a table cell.
|
|
367
|
+
|
|
368
|
+
* **Arguments**:
|
|
369
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
370
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
371
|
+
* `colIndex` (`number`): 0-based column index.
|
|
372
|
+
* `shapeIndex` (`number`): 0-based shape index in the cell.
|
|
373
|
+
* `options` (`Object`): Shape configuration properties to update.
|
|
374
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
await ppt.updateCellShape('Table', 1, 2, 0, { fill: '#EF4444' });
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### `removeCellShape(tableId, rowIndex, colIndex, shapeIndex)`
|
|
381
|
+
Removes a shape from a table cell.
|
|
382
|
+
|
|
383
|
+
* **Arguments**:
|
|
384
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
385
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
386
|
+
* `colIndex` (`number`): 0-based column index.
|
|
387
|
+
* `shapeIndex` (`number`): 0-based shape index in the cell.
|
|
388
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
await ppt.removeCellShape('Table', 1, 2, 0);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
#### `getCellShape(tableId, rowIndex, colIndex, shapeIndex)`
|
|
395
|
+
Discovers and retrieves details of an existing cell shape on the targeted slide.
|
|
396
|
+
|
|
397
|
+
* **Arguments**:
|
|
398
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
399
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
400
|
+
* `colIndex` (`number`): 0-based column index.
|
|
401
|
+
* `shapeIndex` (`number`): 0-based shape index in the cell.
|
|
402
|
+
* **Returns**: `Object|null` - Shape details object, or null if not found.
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
const shape = ppt.getCellShape('Table', 1, 2, 0);
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
#### `getCellBounds(tableId, rowIndex, colIndex)`
|
|
409
|
+
Retrieves final rendered bounds of a table cell in pixels.
|
|
410
|
+
|
|
411
|
+
* **Arguments**:
|
|
412
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
413
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
414
|
+
* `colIndex` (`number`): 0-based column index.
|
|
415
|
+
* **Returns**: `Object|null` - Cell bounds { x, y, width, height } in pixels, or null.
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
const bounds = ppt.getCellBounds('summary-table', 1, 1);
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### `getCellPosition(tableId, rowIndex, colIndex)`
|
|
422
|
+
Retrieves final rendered position of a table cell in pixels.
|
|
423
|
+
|
|
424
|
+
* **Arguments**:
|
|
425
|
+
* `tableId` (`string`): Table name or shape ID.
|
|
426
|
+
* `rowIndex` (`number`): 0-based row index.
|
|
427
|
+
* `colIndex` (`number`): 0-based column index.
|
|
428
|
+
* **Returns**: `Object|null` - Cell position { row, column, x, y } in pixels, or null.
|
|
429
|
+
|
|
430
|
+
```javascript
|
|
431
|
+
const pos = ppt.getCellPosition('summary-table', 1, 1);
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### `getTableRows(())`
|
|
435
|
+
Delegates core actions to slide element sub-managers.
|
|
436
|
+
|
|
437
|
+
* **Returns**: `PPTXTemplater` - The fluent engine instance.
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
const rows = await ppt.getTableRows('SalesTable');
|
|
441
|
+
```
|
|
442
|
+
|
|
246
443
|
#### `addTableRow(())`
|
|
247
444
|
Delegates core actions to slide element sub-managers.
|
|
248
445
|
|
|
@@ -1016,6 +1213,70 @@ Updates the position and/or dimensions of an existing textbox on targeted slides
|
|
|
1016
1213
|
ppt.useSlide(1).updateTextBoxPosition('TextBox 2', { x: 1000000, y: 1500000 });
|
|
1017
1214
|
```
|
|
1018
1215
|
|
|
1216
|
+
#### `validateShape(options)`
|
|
1217
|
+
Validates shape options configuration.
|
|
1218
|
+
|
|
1219
|
+
* **Arguments**:
|
|
1220
|
+
* `options` (`Object`):
|
|
1221
|
+
* **Returns**: `string[]` - List of validation error messages.
|
|
1222
|
+
|
|
1223
|
+
```javascript
|
|
1224
|
+
const errors = ppt.validateShape(shapeOptions);
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
#### `addShape(options)`
|
|
1228
|
+
Adds a new shape dynamically to the targeted slide(s).
|
|
1229
|
+
|
|
1230
|
+
* **Arguments**:
|
|
1231
|
+
* `options` (`Object`):
|
|
1232
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
1233
|
+
|
|
1234
|
+
```javascript
|
|
1235
|
+
await ppt.useSlide(1).addShape({
|
|
1236
|
+
type: 'rectangle',
|
|
1237
|
+
id: 'sales-box',
|
|
1238
|
+
x: 100,
|
|
1239
|
+
y: 100,
|
|
1240
|
+
width: 200,
|
|
1241
|
+
height: 100,
|
|
1242
|
+
fill: '#2563EB'
|
|
1243
|
+
});
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
#### `updateShape(shapeId, options)`
|
|
1247
|
+
Updates an existing shape in-place.
|
|
1248
|
+
|
|
1249
|
+
* **Arguments**:
|
|
1250
|
+
* `shapeId` (`string`):
|
|
1251
|
+
* `options` (`Object`):
|
|
1252
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
1253
|
+
|
|
1254
|
+
```javascript
|
|
1255
|
+
await ppt.useSlide(1).updateShape('sales-box', { fill: '#10B981' });
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
#### `removeShape(shapeId)`
|
|
1259
|
+
Removes a shape from the targeted slide(s).
|
|
1260
|
+
|
|
1261
|
+
* **Arguments**:
|
|
1262
|
+
* `shapeId` (`string`):
|
|
1263
|
+
* **Returns**: `this` - The chainable presentation templater instance.
|
|
1264
|
+
|
|
1265
|
+
```javascript
|
|
1266
|
+
await ppt.useSlide(1).removeShape('sales-box');
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
#### `getShape(shapeId)`
|
|
1270
|
+
Discovers and retrieves details of an existing shape on the targeted slides.
|
|
1271
|
+
|
|
1272
|
+
* **Arguments**:
|
|
1273
|
+
* `shapeId` (`string`):
|
|
1274
|
+
* **Returns**: `Object|null` - Shape details object, or null if not found.
|
|
1275
|
+
|
|
1276
|
+
```javascript
|
|
1277
|
+
const shape = ppt.getShape('sales-box');
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1019
1280
|
#### `updateShapeText(())`
|
|
1020
1281
|
Delegates core actions to slide element sub-managers.
|
|
1021
1282
|
|
|
@@ -1466,6 +1727,24 @@ Delegates core actions to slide element sub-managers.
|
|
|
1466
1727
|
const ppt = await PPTXTemplate.fromPresentationXml('./template-folder');
|
|
1467
1728
|
```
|
|
1468
1729
|
|
|
1730
|
+
#### `extractPptx(())`
|
|
1731
|
+
Delegates core actions to slide element sub-managers.
|
|
1732
|
+
|
|
1733
|
+
* **Returns**: `PPTXTemplater` - The fluent engine instance.
|
|
1734
|
+
|
|
1735
|
+
```javascript
|
|
1736
|
+
await PPTXTemplater.extractPptx('sample.pptx', './extracted');
|
|
1737
|
+
```
|
|
1738
|
+
|
|
1739
|
+
#### `buildPptx(())`
|
|
1740
|
+
Delegates core actions to slide element sub-managers.
|
|
1741
|
+
|
|
1742
|
+
* **Returns**: `PPTXTemplater` - The fluent engine instance.
|
|
1743
|
+
|
|
1744
|
+
```javascript
|
|
1745
|
+
await PPTXTemplater.buildPptx('./extracted', 'output.pptx');
|
|
1746
|
+
```
|
|
1747
|
+
|
|
1469
1748
|
#### `validatePresentation(())`
|
|
1470
1749
|
Delegates core actions to slide element sub-managers.
|
|
1471
1750
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pptx-templater",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
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",
|
|
@@ -340,6 +340,89 @@ class PPTXTemplater {
|
|
|
340
340
|
return engine
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Extracts a PPTX file into an unzipped OpenXML folder structure.
|
|
345
|
+
*
|
|
346
|
+
* @static
|
|
347
|
+
* @param {string} pptxPath - Path to the source PPTX file.
|
|
348
|
+
* @param {string} outputPath - Path to the destination folder.
|
|
349
|
+
* @param {Object} [options] - Options (e.g. { overwrite: true }).
|
|
350
|
+
* @returns {Promise<void>}
|
|
351
|
+
*/
|
|
352
|
+
static async extractPptx(pptxPath, outputPath, options = {}) {
|
|
353
|
+
const fs = require('fs-extra')
|
|
354
|
+
const path = require('path')
|
|
355
|
+
|
|
356
|
+
const resolvedPptx = path.resolve(pptxPath)
|
|
357
|
+
const resolvedOut = path.resolve(outputPath)
|
|
358
|
+
|
|
359
|
+
if (!fs.existsSync(resolvedPptx)) {
|
|
360
|
+
throw new PPTXError(`Source PPTX file not found: ${pptxPath}`)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (fs.existsSync(resolvedOut)) {
|
|
364
|
+
const stats = fs.statSync(resolvedOut)
|
|
365
|
+
if (stats.isFile()) {
|
|
366
|
+
throw new PPTXError(`Destination is a file: ${outputPath}`)
|
|
367
|
+
}
|
|
368
|
+
const files = fs.readdirSync(resolvedOut)
|
|
369
|
+
if (files.length > 0 && !options.overwrite) {
|
|
370
|
+
throw new PPTXError(
|
|
371
|
+
`Destination directory "${outputPath}" is not empty. Set overwrite: true to overwrite.`
|
|
372
|
+
)
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
await fs.ensureDir(resolvedOut)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const engine = await PPTXTemplater.load(resolvedPptx)
|
|
379
|
+
await engine.#zipManager.toFolder(resolvedOut)
|
|
380
|
+
|
|
381
|
+
// Validation
|
|
382
|
+
const criticalParts = ['ppt/presentation.xml', 'ppt/slides', 'ppt/_rels', '[Content_Types].xml']
|
|
383
|
+
|
|
384
|
+
for (const part of criticalParts) {
|
|
385
|
+
const p = path.join(resolvedOut, part)
|
|
386
|
+
if (!fs.existsSync(p)) {
|
|
387
|
+
throw new PPTXError(`Extracted structure is missing critical part: ${part}`)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Rebuilds a PPTX file from an unzipped OpenXML folder structure.
|
|
394
|
+
*
|
|
395
|
+
* @static
|
|
396
|
+
* @param {string} folderPath - Path to the source folder structure.
|
|
397
|
+
* @param {string} pptxPath - Path to the destination PPTX file.
|
|
398
|
+
* @returns {Promise<void>}
|
|
399
|
+
*/
|
|
400
|
+
static async buildPptx(folderPath, pptxPath) {
|
|
401
|
+
const fs = require('fs-extra')
|
|
402
|
+
const path = require('path')
|
|
403
|
+
|
|
404
|
+
const resolvedFolder = path.resolve(folderPath)
|
|
405
|
+
const resolvedPptx = path.resolve(pptxPath)
|
|
406
|
+
|
|
407
|
+
if (!fs.existsSync(resolvedFolder)) {
|
|
408
|
+
throw new PPTXError(`Source folder not found: ${folderPath}`)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Validation of the source folder
|
|
412
|
+
const criticalParts = ['ppt/presentation.xml', 'ppt/slides', 'ppt/_rels', '[Content_Types].xml']
|
|
413
|
+
|
|
414
|
+
for (const part of criticalParts) {
|
|
415
|
+
const p = path.join(resolvedFolder, part)
|
|
416
|
+
if (!fs.existsSync(p)) {
|
|
417
|
+
throw new PPTXError(`Source folder is missing critical OpenXML part: ${part}`)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const engine = await PPTXTemplater.load(resolvedFolder)
|
|
422
|
+
await fs.ensureDir(path.dirname(resolvedPptx))
|
|
423
|
+
await engine.saveToFile(resolvedPptx)
|
|
424
|
+
}
|
|
425
|
+
|
|
343
426
|
/**
|
|
344
427
|
* Initializes the engine by loading a PPTX file/buffer.
|
|
345
428
|
* @private
|
|
@@ -588,7 +671,13 @@ class PPTXTemplater {
|
|
|
588
671
|
const targetIndices = this.#getTargetSlideIndices()
|
|
589
672
|
|
|
590
673
|
for (const slideIndex of targetIndices) {
|
|
591
|
-
this.#tableManager.updateTable(
|
|
674
|
+
this.#tableManager.updateTable(
|
|
675
|
+
slideIndex,
|
|
676
|
+
tableId,
|
|
677
|
+
rows,
|
|
678
|
+
this.#slideManager,
|
|
679
|
+
this.#shapeManager
|
|
680
|
+
)
|
|
592
681
|
}
|
|
593
682
|
|
|
594
683
|
logger.debug(`Updated table "${tableId}" in ${targetIndices.length} slide(s)`)
|
|
@@ -1291,11 +1380,21 @@ class PPTXTemplater {
|
|
|
1291
1380
|
}
|
|
1292
1381
|
|
|
1293
1382
|
// === Table Features ===
|
|
1294
|
-
|
|
1383
|
+
getTableRows(tableId, options = {}) {
|
|
1384
|
+
this.#assertLoaded()
|
|
1385
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
1386
|
+
if (targetIndices.length === 0) {
|
|
1387
|
+
throw new PPTXError('No slides active/loaded')
|
|
1388
|
+
}
|
|
1389
|
+
const idx = targetIndices[0]
|
|
1390
|
+
return this.#tableManager.getTableRows(idx, tableId, options, this.#slideManager)
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
addTableRow(tableId, rowData, options = {}) {
|
|
1295
1394
|
this.#assertLoaded()
|
|
1296
1395
|
const targetIndices = this.#getTargetSlideIndices()
|
|
1297
1396
|
for (const idx of targetIndices) {
|
|
1298
|
-
this.#tableManager.addTableRow(idx, tableId, rowData, this.#slideManager)
|
|
1397
|
+
this.#tableManager.addTableRow(idx, tableId, rowData, this.#slideManager, options)
|
|
1299
1398
|
}
|
|
1300
1399
|
return this
|
|
1301
1400
|
}
|
|
@@ -1914,6 +2013,245 @@ class PPTXTemplater {
|
|
|
1914
2013
|
return shapes
|
|
1915
2014
|
}
|
|
1916
2015
|
|
|
2016
|
+
/**
|
|
2017
|
+
* Validates shape options configuration.
|
|
2018
|
+
*
|
|
2019
|
+
* @param {Object} options Shape creation/update options.
|
|
2020
|
+
* @returns {string[]} List of validation error messages.
|
|
2021
|
+
*/
|
|
2022
|
+
validateShape(options) {
|
|
2023
|
+
return this.#shapeManager.validateShape(options)
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* Adds a new shape dynamically to the targeted slide(s).
|
|
2028
|
+
*
|
|
2029
|
+
* @param {Object} options Shape configuration options.
|
|
2030
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2031
|
+
*/
|
|
2032
|
+
async addShape(options) {
|
|
2033
|
+
this.#assertLoaded()
|
|
2034
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2035
|
+
for (const idx of targetIndices) {
|
|
2036
|
+
this.#shapeManager.addShape(idx, options, this.#slideManager)
|
|
2037
|
+
}
|
|
2038
|
+
return this
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
/**
|
|
2042
|
+
* Updates an existing shape in-place.
|
|
2043
|
+
*
|
|
2044
|
+
* @param {string} shapeId Shape ID or template name to update.
|
|
2045
|
+
* @param {Object} options Configuration properties to update.
|
|
2046
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2047
|
+
*/
|
|
2048
|
+
async updateShape(shapeId, options) {
|
|
2049
|
+
this.#assertLoaded()
|
|
2050
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2051
|
+
for (const idx of targetIndices) {
|
|
2052
|
+
this.#shapeManager.updateShape(idx, shapeId, options, this.#slideManager)
|
|
2053
|
+
}
|
|
2054
|
+
return this
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
/**
|
|
2058
|
+
* Removes a shape from the targeted slide(s).
|
|
2059
|
+
*
|
|
2060
|
+
* @param {string} shapeId Shape ID or template name to remove.
|
|
2061
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2062
|
+
*/
|
|
2063
|
+
async removeShape(shapeId) {
|
|
2064
|
+
this.#assertLoaded()
|
|
2065
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2066
|
+
for (const idx of targetIndices) {
|
|
2067
|
+
this.#shapeManager.removeShape(idx, shapeId, this.#slideManager)
|
|
2068
|
+
}
|
|
2069
|
+
return this
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Discovers and retrieves details of an existing shape on the targeted slides.
|
|
2074
|
+
*
|
|
2075
|
+
* @param {string} shapeId Shape ID or template name to locate.
|
|
2076
|
+
* @returns {Object|null} Shape details object, or null if not found.
|
|
2077
|
+
*/
|
|
2078
|
+
getShape(shapeId) {
|
|
2079
|
+
this.#assertLoaded()
|
|
2080
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2081
|
+
for (const idx of targetIndices) {
|
|
2082
|
+
const shape = this.#shapeManager.getShape(idx, shapeId, this.#slideManager)
|
|
2083
|
+
if (shape) return shape
|
|
2084
|
+
}
|
|
2085
|
+
return null
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Dynamically adds a shape inside a table cell based on cell coordinates.
|
|
2090
|
+
*
|
|
2091
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2092
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2093
|
+
* @param {number} colIndex - 0-based column index.
|
|
2094
|
+
* @param {Object} options - Shape configuration options.
|
|
2095
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2096
|
+
*/
|
|
2097
|
+
async addCellShape(tableId, rowIndex, colIndex, options) {
|
|
2098
|
+
this.#assertLoaded()
|
|
2099
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2100
|
+
for (const idx of targetIndices) {
|
|
2101
|
+
this.#tableManager.addCellShape(
|
|
2102
|
+
idx,
|
|
2103
|
+
tableId,
|
|
2104
|
+
rowIndex,
|
|
2105
|
+
colIndex,
|
|
2106
|
+
options,
|
|
2107
|
+
this.#slideManager,
|
|
2108
|
+
this.#shapeManager
|
|
2109
|
+
)
|
|
2110
|
+
}
|
|
2111
|
+
return this
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Updates an existing shape inside a table cell.
|
|
2116
|
+
*
|
|
2117
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2118
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2119
|
+
* @param {number} colIndex - 0-based column index.
|
|
2120
|
+
* @param {number} shapeIndex - 0-based shape index in the cell.
|
|
2121
|
+
* @param {Object} options - Shape configuration properties to update.
|
|
2122
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2123
|
+
*/
|
|
2124
|
+
async updateCellShape(tableId, rowIndex, colIndex, shapeIndex, options) {
|
|
2125
|
+
this.#assertLoaded()
|
|
2126
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2127
|
+
for (const idx of targetIndices) {
|
|
2128
|
+
this.#tableManager.updateCellShape(
|
|
2129
|
+
idx,
|
|
2130
|
+
tableId,
|
|
2131
|
+
rowIndex,
|
|
2132
|
+
colIndex,
|
|
2133
|
+
shapeIndex,
|
|
2134
|
+
options,
|
|
2135
|
+
this.#slideManager,
|
|
2136
|
+
this.#shapeManager
|
|
2137
|
+
)
|
|
2138
|
+
}
|
|
2139
|
+
return this
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
/**
|
|
2143
|
+
* Removes a shape from a table cell.
|
|
2144
|
+
*
|
|
2145
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2146
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2147
|
+
* @param {number} colIndex - 0-based column index.
|
|
2148
|
+
* @param {number} shapeIndex - 0-based shape index in the cell.
|
|
2149
|
+
* @returns {this} The chainable presentation templater instance.
|
|
2150
|
+
*/
|
|
2151
|
+
async removeCellShape(tableId, rowIndex, colIndex, shapeIndex) {
|
|
2152
|
+
this.#assertLoaded()
|
|
2153
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2154
|
+
for (const idx of targetIndices) {
|
|
2155
|
+
this.#tableManager.removeCellShape(
|
|
2156
|
+
idx,
|
|
2157
|
+
tableId,
|
|
2158
|
+
rowIndex,
|
|
2159
|
+
colIndex,
|
|
2160
|
+
shapeIndex,
|
|
2161
|
+
this.#slideManager,
|
|
2162
|
+
this.#shapeManager
|
|
2163
|
+
)
|
|
2164
|
+
}
|
|
2165
|
+
return this
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* Discovers and retrieves details of an existing cell shape on the targeted slide.
|
|
2170
|
+
*
|
|
2171
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2172
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2173
|
+
* @param {number} colIndex - 0-based column index.
|
|
2174
|
+
* @param {number} shapeIndex - 0-based shape index in the cell.
|
|
2175
|
+
* @returns {Object|null} Shape details object, or null if not found.
|
|
2176
|
+
*/
|
|
2177
|
+
getCellShape(tableId, rowIndex, colIndex, shapeIndex) {
|
|
2178
|
+
this.#assertLoaded()
|
|
2179
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2180
|
+
for (const idx of targetIndices) {
|
|
2181
|
+
const shape = this.#tableManager.getCellShape(
|
|
2182
|
+
idx,
|
|
2183
|
+
tableId,
|
|
2184
|
+
rowIndex,
|
|
2185
|
+
colIndex,
|
|
2186
|
+
shapeIndex,
|
|
2187
|
+
this.#slideManager,
|
|
2188
|
+
this.#shapeManager
|
|
2189
|
+
)
|
|
2190
|
+
if (shape) return shape
|
|
2191
|
+
}
|
|
2192
|
+
return null
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
/**
|
|
2196
|
+
* Retrieves final rendered bounds of a table cell in pixels.
|
|
2197
|
+
*
|
|
2198
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2199
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2200
|
+
* @param {number} colIndex - 0-based column index.
|
|
2201
|
+
* @returns {Object|null} Cell bounds { x, y, width, height } in pixels, or null.
|
|
2202
|
+
*/
|
|
2203
|
+
getCellBounds(tableId, rowIndex, colIndex) {
|
|
2204
|
+
this.#assertLoaded()
|
|
2205
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2206
|
+
for (const idx of targetIndices) {
|
|
2207
|
+
try {
|
|
2208
|
+
const bounds = this.#tableManager.getCellBounds(
|
|
2209
|
+
idx,
|
|
2210
|
+
tableId,
|
|
2211
|
+
rowIndex,
|
|
2212
|
+
colIndex,
|
|
2213
|
+
this.#slideManager
|
|
2214
|
+
)
|
|
2215
|
+
if (bounds) return bounds
|
|
2216
|
+
} catch (err) {
|
|
2217
|
+
logger.debug(
|
|
2218
|
+
`Could not get cell bounds for table ${tableId} on slide ${idx}: ${err.message}`
|
|
2219
|
+
)
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
return null
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
/**
|
|
2226
|
+
* Retrieves final rendered position of a table cell in pixels.
|
|
2227
|
+
*
|
|
2228
|
+
* @param {string} tableId - Table name or shape ID.
|
|
2229
|
+
* @param {number} rowIndex - 0-based row index.
|
|
2230
|
+
* @param {number} colIndex - 0-based column index.
|
|
2231
|
+
* @returns {Object|null} Cell position { row, column, x, y } in pixels, or null.
|
|
2232
|
+
*/
|
|
2233
|
+
getCellPosition(tableId, rowIndex, colIndex) {
|
|
2234
|
+
this.#assertLoaded()
|
|
2235
|
+
const targetIndices = this.#getTargetSlideIndices()
|
|
2236
|
+
for (const idx of targetIndices) {
|
|
2237
|
+
try {
|
|
2238
|
+
const pos = this.#tableManager.getCellPosition(
|
|
2239
|
+
idx,
|
|
2240
|
+
tableId,
|
|
2241
|
+
rowIndex,
|
|
2242
|
+
colIndex,
|
|
2243
|
+
this.#slideManager
|
|
2244
|
+
)
|
|
2245
|
+
if (pos) return pos
|
|
2246
|
+
} catch (err) {
|
|
2247
|
+
logger.debug(
|
|
2248
|
+
`Could not get cell position for table ${tableId} on slide ${idx}: ${err.message}`
|
|
2249
|
+
)
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
return null
|
|
2253
|
+
}
|
|
2254
|
+
|
|
1917
2255
|
// === Image Features ===
|
|
1918
2256
|
async replaceImage(imageIdOrName, sourcePathOrBuffer) {
|
|
1919
2257
|
this.#assertLoaded()
|