node-pptx-templater 1.1.2 → 1.1.4
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/package.json +3 -1
- package/src/core/OutputWriter.js +5 -5
- package/src/core/PPTXTemplater.js +218 -34
- package/src/managers/ShapeManager.js +288 -85
- package/src/managers/TableManager.js +676 -284
- package/src/managers/ZipManager.js +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pptx-templater",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
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,6 +37,8 @@
|
|
|
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",
|
|
40
42
|
"prepublishOnly": "npm run lint && npm run test"
|
|
41
43
|
},
|
|
42
44
|
"keywords": [
|
package/src/core/OutputWriter.js
CHANGED
|
@@ -161,11 +161,11 @@ class OutputWriter {
|
|
|
161
161
|
: e.compressionMethod === 0
|
|
162
162
|
? 'STORE'
|
|
163
163
|
: `UNKNOWN(${e.compressionMethod})`
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
logger.info(e.name)
|
|
165
|
+
logger.info(`compressed: ${e.compressedSize}`)
|
|
166
|
+
logger.info(`uncompressed: ${e.uncompressedSize}`)
|
|
167
|
+
logger.info(`crc: ${e.crc32}`)
|
|
168
|
+
logger.info(`method: ${methodStr}`)
|
|
169
169
|
})
|
|
170
170
|
logger.info('--- End of ZIP debug output ---')
|
|
171
171
|
}
|
|
@@ -1569,11 +1569,30 @@ class PPTXTemplater {
|
|
|
1569
1569
|
}
|
|
1570
1570
|
|
|
1571
1571
|
/**
|
|
1572
|
-
* Appends one or more rows to a table. Supports flat arrays
|
|
1573
|
-
* for rowspan-merged cells
|
|
1572
|
+
* Appends one or more rows to a table. Supports flat arrays, nested arrays
|
|
1573
|
+
* for rowspan-merged cells, and **Shape Cell** configuration objects that insert
|
|
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**.
|
|
1574
1592
|
*
|
|
1575
1593
|
* @param {string} tableId - Table name or shape ID.
|
|
1576
|
-
* @param {Array<string|Array<string
|
|
1594
|
+
* @param {Array<string|Array<string>|Object>} rowData - Row data. Each element may be
|
|
1595
|
+
* a plain string, a nested array (rowspan), or a Shape Cell configuration object.
|
|
1577
1596
|
* @param {Object} [options] - Row insertion options.
|
|
1578
1597
|
* @param {'rowspan'|'auto'|'none'} [options.mergeStrategy='rowspan'] - How to handle nested arrays.
|
|
1579
1598
|
* `'rowspan'` creates OpenXML vertical spans, `'auto'` merges identical adjacent values,
|
|
@@ -1586,12 +1605,33 @@ class PPTXTemplater {
|
|
|
1586
1605
|
*
|
|
1587
1606
|
* // Nested row with rowspan
|
|
1588
1607
|
* 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
|
+
* ]);
|
|
1589
1622
|
*/
|
|
1590
1623
|
addTableRow(tableId, rowData, options = {}) {
|
|
1591
1624
|
this.#assertLoaded()
|
|
1592
1625
|
const targetIndices = this.#getTargetSlideIndices()
|
|
1593
1626
|
for (const idx of targetIndices) {
|
|
1594
|
-
this.#tableManager.addTableRow(
|
|
1627
|
+
this.#tableManager.addTableRow(
|
|
1628
|
+
idx,
|
|
1629
|
+
tableId,
|
|
1630
|
+
rowData,
|
|
1631
|
+
this.#slideManager,
|
|
1632
|
+
this.#shapeManager,
|
|
1633
|
+
options
|
|
1634
|
+
)
|
|
1595
1635
|
}
|
|
1596
1636
|
return this
|
|
1597
1637
|
}
|
|
@@ -1610,7 +1650,13 @@ class PPTXTemplater {
|
|
|
1610
1650
|
this.#assertLoaded()
|
|
1611
1651
|
const targetIndices = this.#getTargetSlideIndices()
|
|
1612
1652
|
for (const idx of targetIndices) {
|
|
1613
|
-
this.#tableManager.removeTableRow(
|
|
1653
|
+
this.#tableManager.removeTableRow(
|
|
1654
|
+
idx,
|
|
1655
|
+
tableId,
|
|
1656
|
+
rowIndex,
|
|
1657
|
+
this.#slideManager,
|
|
1658
|
+
this.#shapeManager
|
|
1659
|
+
)
|
|
1614
1660
|
}
|
|
1615
1661
|
return this
|
|
1616
1662
|
}
|
|
@@ -1630,7 +1676,14 @@ class PPTXTemplater {
|
|
|
1630
1676
|
this.#assertLoaded()
|
|
1631
1677
|
const targetIndices = this.#getTargetSlideIndices()
|
|
1632
1678
|
for (const idx of targetIndices) {
|
|
1633
|
-
this.#tableManager.insertTableRow(
|
|
1679
|
+
this.#tableManager.insertTableRow(
|
|
1680
|
+
idx,
|
|
1681
|
+
tableId,
|
|
1682
|
+
rowIndex,
|
|
1683
|
+
rowData,
|
|
1684
|
+
this.#slideManager,
|
|
1685
|
+
this.#shapeManager
|
|
1686
|
+
)
|
|
1634
1687
|
}
|
|
1635
1688
|
return this
|
|
1636
1689
|
}
|
|
@@ -1655,7 +1708,8 @@ class PPTXTemplater {
|
|
|
1655
1708
|
tableId,
|
|
1656
1709
|
sourceRowIndex,
|
|
1657
1710
|
targetRowIndex,
|
|
1658
|
-
this.#slideManager
|
|
1711
|
+
this.#slideManager,
|
|
1712
|
+
this.#shapeManager
|
|
1659
1713
|
)
|
|
1660
1714
|
}
|
|
1661
1715
|
return this
|
|
@@ -1735,7 +1789,16 @@ class PPTXTemplater {
|
|
|
1735
1789
|
}
|
|
1736
1790
|
|
|
1737
1791
|
for (const idx of targetIndices) {
|
|
1738
|
-
this.#tableManager.mergeCells(
|
|
1792
|
+
this.#tableManager.mergeCells(
|
|
1793
|
+
idx,
|
|
1794
|
+
tableId,
|
|
1795
|
+
sRow,
|
|
1796
|
+
sCol,
|
|
1797
|
+
eRow,
|
|
1798
|
+
eCol,
|
|
1799
|
+
this.#slideManager,
|
|
1800
|
+
this.#shapeManager
|
|
1801
|
+
)
|
|
1739
1802
|
}
|
|
1740
1803
|
return this
|
|
1741
1804
|
}
|
|
@@ -1786,9 +1849,25 @@ class PPTXTemplater {
|
|
|
1786
1849
|
|
|
1787
1850
|
for (const idx of targetIndices) {
|
|
1788
1851
|
if (isCellCoord) {
|
|
1789
|
-
this.#tableManager.unmergeCells(
|
|
1852
|
+
this.#tableManager.unmergeCells(
|
|
1853
|
+
idx,
|
|
1854
|
+
tableId,
|
|
1855
|
+
cellRow,
|
|
1856
|
+
cellCol,
|
|
1857
|
+
this.#slideManager,
|
|
1858
|
+
this.#shapeManager
|
|
1859
|
+
)
|
|
1790
1860
|
} else {
|
|
1791
|
-
this.#tableManager.unmergeCells(
|
|
1861
|
+
this.#tableManager.unmergeCells(
|
|
1862
|
+
idx,
|
|
1863
|
+
tableId,
|
|
1864
|
+
sRow,
|
|
1865
|
+
sCol,
|
|
1866
|
+
eRow,
|
|
1867
|
+
eCol,
|
|
1868
|
+
this.#slideManager,
|
|
1869
|
+
this.#shapeManager
|
|
1870
|
+
)
|
|
1792
1871
|
}
|
|
1793
1872
|
}
|
|
1794
1873
|
return this
|
|
@@ -2654,6 +2733,16 @@ class PPTXTemplater {
|
|
|
2654
2733
|
return this.#shapeManager.validateShape(options)
|
|
2655
2734
|
}
|
|
2656
2735
|
|
|
2736
|
+
/**
|
|
2737
|
+
* Adds a new shape to the targeted slide(s).
|
|
2738
|
+
*
|
|
2739
|
+
* @param {string|Object} typeOrOptions Either the shape type string (e.g., 'rect', 'ellipse') or a full options object.
|
|
2740
|
+
* @param {Object} [options={}] Additional configuration options if type was specified as a string.
|
|
2741
|
+
* @returns {Promise<PPTXTemplater>} The templater instance for chaining.
|
|
2742
|
+
*
|
|
2743
|
+
* @example
|
|
2744
|
+
* await ppt.addShape('rect', { id: 'MyShape', x: 100, y: 100, width: 200, height: 100 });
|
|
2745
|
+
*/
|
|
2657
2746
|
async addShape(typeOrOptions, options = {}) {
|
|
2658
2747
|
this.#assertLoaded()
|
|
2659
2748
|
let resolvedOptions = {}
|
|
@@ -2738,14 +2827,28 @@ class PPTXTemplater {
|
|
|
2738
2827
|
*/
|
|
2739
2828
|
async addCellShape(tableId, rowIndex, colIndex, options) {
|
|
2740
2829
|
this.#assertLoaded()
|
|
2830
|
+
let row = rowIndex
|
|
2831
|
+
let col = colIndex
|
|
2832
|
+
let opts = options
|
|
2833
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
2834
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
2835
|
+
col =
|
|
2836
|
+
rowIndex.column !== undefined
|
|
2837
|
+
? rowIndex.column
|
|
2838
|
+
: rowIndex.col !== undefined
|
|
2839
|
+
? rowIndex.col
|
|
2840
|
+
: rowIndex.colIndex
|
|
2841
|
+
opts = rowIndex
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2741
2844
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2742
2845
|
for (const idx of targetIndices) {
|
|
2743
2846
|
this.#tableManager.addCellShape(
|
|
2744
2847
|
idx,
|
|
2745
2848
|
tableId,
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2849
|
+
row,
|
|
2850
|
+
col,
|
|
2851
|
+
opts,
|
|
2749
2852
|
this.#slideManager,
|
|
2750
2853
|
this.#shapeManager
|
|
2751
2854
|
)
|
|
@@ -2765,15 +2868,36 @@ class PPTXTemplater {
|
|
|
2765
2868
|
*/
|
|
2766
2869
|
async updateCellShape(tableId, rowIndex, colIndex, shapeIndex, options) {
|
|
2767
2870
|
this.#assertLoaded()
|
|
2871
|
+
let row = rowIndex
|
|
2872
|
+
let col = colIndex
|
|
2873
|
+
let shpIdx = shapeIndex
|
|
2874
|
+
let opts = options
|
|
2875
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
2876
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
2877
|
+
col =
|
|
2878
|
+
rowIndex.column !== undefined
|
|
2879
|
+
? rowIndex.column
|
|
2880
|
+
: rowIndex.col !== undefined
|
|
2881
|
+
? rowIndex.col
|
|
2882
|
+
: rowIndex.colIndex
|
|
2883
|
+
shpIdx =
|
|
2884
|
+
rowIndex.shapeIndex !== undefined
|
|
2885
|
+
? rowIndex.shapeIndex
|
|
2886
|
+
: rowIndex.shape !== undefined
|
|
2887
|
+
? rowIndex.shape
|
|
2888
|
+
: colIndex
|
|
2889
|
+
opts = options !== undefined ? options : rowIndex
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2768
2892
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2769
2893
|
for (const idx of targetIndices) {
|
|
2770
2894
|
this.#tableManager.updateCellShape(
|
|
2771
2895
|
idx,
|
|
2772
2896
|
tableId,
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2897
|
+
row,
|
|
2898
|
+
col,
|
|
2899
|
+
shpIdx,
|
|
2900
|
+
opts,
|
|
2777
2901
|
this.#slideManager,
|
|
2778
2902
|
this.#shapeManager
|
|
2779
2903
|
)
|
|
@@ -2792,14 +2916,33 @@ class PPTXTemplater {
|
|
|
2792
2916
|
*/
|
|
2793
2917
|
async removeCellShape(tableId, rowIndex, colIndex, shapeIndex) {
|
|
2794
2918
|
this.#assertLoaded()
|
|
2919
|
+
let row = rowIndex
|
|
2920
|
+
let col = colIndex
|
|
2921
|
+
let shpIdx = shapeIndex
|
|
2922
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
2923
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
2924
|
+
col =
|
|
2925
|
+
rowIndex.column !== undefined
|
|
2926
|
+
? rowIndex.column
|
|
2927
|
+
: rowIndex.col !== undefined
|
|
2928
|
+
? rowIndex.col
|
|
2929
|
+
: rowIndex.colIndex
|
|
2930
|
+
shpIdx =
|
|
2931
|
+
rowIndex.shapeIndex !== undefined
|
|
2932
|
+
? rowIndex.shapeIndex
|
|
2933
|
+
: rowIndex.shape !== undefined
|
|
2934
|
+
? rowIndex.shape
|
|
2935
|
+
: colIndex
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2795
2938
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2796
2939
|
for (const idx of targetIndices) {
|
|
2797
2940
|
this.#tableManager.removeCellShape(
|
|
2798
2941
|
idx,
|
|
2799
2942
|
tableId,
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2943
|
+
row,
|
|
2944
|
+
col,
|
|
2945
|
+
shpIdx,
|
|
2803
2946
|
this.#slideManager,
|
|
2804
2947
|
this.#shapeManager
|
|
2805
2948
|
)
|
|
@@ -2818,14 +2961,33 @@ class PPTXTemplater {
|
|
|
2818
2961
|
*/
|
|
2819
2962
|
getCellShape(tableId, rowIndex, colIndex, shapeIndex) {
|
|
2820
2963
|
this.#assertLoaded()
|
|
2964
|
+
let row = rowIndex
|
|
2965
|
+
let col = colIndex
|
|
2966
|
+
let shpIdx = shapeIndex
|
|
2967
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
2968
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
2969
|
+
col =
|
|
2970
|
+
rowIndex.column !== undefined
|
|
2971
|
+
? rowIndex.column
|
|
2972
|
+
: rowIndex.col !== undefined
|
|
2973
|
+
? rowIndex.col
|
|
2974
|
+
: rowIndex.colIndex
|
|
2975
|
+
shpIdx =
|
|
2976
|
+
rowIndex.shapeIndex !== undefined
|
|
2977
|
+
? rowIndex.shapeIndex
|
|
2978
|
+
: rowIndex.shape !== undefined
|
|
2979
|
+
? rowIndex.shape
|
|
2980
|
+
: colIndex
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2821
2983
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2822
2984
|
for (const idx of targetIndices) {
|
|
2823
2985
|
const shape = this.#tableManager.getCellShape(
|
|
2824
2986
|
idx,
|
|
2825
2987
|
tableId,
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2988
|
+
row,
|
|
2989
|
+
col,
|
|
2990
|
+
shpIdx,
|
|
2829
2991
|
this.#slideManager,
|
|
2830
2992
|
this.#shapeManager
|
|
2831
2993
|
)
|
|
@@ -2848,16 +3010,22 @@ class PPTXTemplater {
|
|
|
2848
3010
|
typeof tableIdOrObj === 'object'
|
|
2849
3011
|
? tableIdOrObj.id || tableIdOrObj.name || tableIdOrObj.tableId
|
|
2850
3012
|
: tableIdOrObj
|
|
3013
|
+
let row = rowIndex
|
|
3014
|
+
let col = colIndex
|
|
3015
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
3016
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
3017
|
+
col =
|
|
3018
|
+
rowIndex.column !== undefined
|
|
3019
|
+
? rowIndex.column
|
|
3020
|
+
: rowIndex.col !== undefined
|
|
3021
|
+
? rowIndex.col
|
|
3022
|
+
: rowIndex.colIndex
|
|
3023
|
+
}
|
|
3024
|
+
|
|
2851
3025
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2852
3026
|
for (const idx of targetIndices) {
|
|
2853
3027
|
try {
|
|
2854
|
-
const bounds = this.#tableManager.getCellBounds(
|
|
2855
|
-
idx,
|
|
2856
|
-
tableId,
|
|
2857
|
-
rowIndex,
|
|
2858
|
-
colIndex,
|
|
2859
|
-
this.#slideManager
|
|
2860
|
-
)
|
|
3028
|
+
const bounds = this.#tableManager.getCellBounds(idx, tableId, row, col, this.#slideManager)
|
|
2861
3029
|
if (bounds) return bounds
|
|
2862
3030
|
} catch (err) {
|
|
2863
3031
|
logger.debug(
|
|
@@ -2885,17 +3053,33 @@ class PPTXTemplater {
|
|
|
2885
3053
|
typeof tableIdOrObj === 'object'
|
|
2886
3054
|
? tableIdOrObj.id || tableIdOrObj.name || tableIdOrObj.tableId
|
|
2887
3055
|
: tableIdOrObj
|
|
3056
|
+
let row = rowIndex
|
|
3057
|
+
let col = colIndex
|
|
3058
|
+
let widthOrOpts = shapeWidthOrOptions
|
|
3059
|
+
let height = shapeHeight
|
|
3060
|
+
if (rowIndex && typeof rowIndex === 'object') {
|
|
3061
|
+
row = rowIndex.row !== undefined ? rowIndex.row : rowIndex.rowIndex
|
|
3062
|
+
col =
|
|
3063
|
+
rowIndex.column !== undefined
|
|
3064
|
+
? rowIndex.column
|
|
3065
|
+
: rowIndex.col !== undefined
|
|
3066
|
+
? rowIndex.col
|
|
3067
|
+
: rowIndex.colIndex
|
|
3068
|
+
widthOrOpts = colIndex
|
|
3069
|
+
height = shapeWidthOrOptions
|
|
3070
|
+
}
|
|
3071
|
+
|
|
2888
3072
|
const targetIndices = this.#getTargetSlideIndices()
|
|
2889
3073
|
for (const idx of targetIndices) {
|
|
2890
3074
|
try {
|
|
2891
3075
|
const pos = this.#tableManager.getCellPosition(
|
|
2892
3076
|
idx,
|
|
2893
3077
|
tableId,
|
|
2894
|
-
|
|
2895
|
-
|
|
3078
|
+
row,
|
|
3079
|
+
col,
|
|
2896
3080
|
this.#slideManager,
|
|
2897
|
-
|
|
2898
|
-
|
|
3081
|
+
widthOrOpts,
|
|
3082
|
+
height
|
|
2899
3083
|
)
|
|
2900
3084
|
if (pos) return pos
|
|
2901
3085
|
} catch (err) {
|