Skip to content

Commit 25643df

Browse files
authored
Merge pull request #156 from singerla/main
Sync with main
2 parents 02d3d03 + e59b2fa commit 25643df

File tree

91 files changed

+5421
-966
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+5421
-966
lines changed

README.md

Lines changed: 49 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# pptx-automizer: A Powerful .pptx Modifier for Node.js
22

3-
`pptx-automizer` is a Node.js-based PowerPoint (.pptx) generator that automates the manipulation of existing .pptx files. With `pptx-automizer`, you can import your library of .pptx templates, merge templates, and customize slide content. `pptx-automizer` will not write files from scratch, but edit and merge existing pptx files. You can style template slides within PowerPoint, and these templates will be seamlessly integrated into the output presentation. Most of the content can be modified by using callbacks with [xmldom](https://github.com/xmldom/xmldom).
3+
`pptx-automizer` is a Node.js-based PowerPoint (.pptx) generator that automates the manipulation of existing .pptx files. With `pptx-automizer`, you can import your library of .pptx templates, merge templates, and customize slide content. `pptx-automizer` will edit and merge existing pptx files. You can style template slides within PowerPoint, and these templates will be seamlessly integrated into the output presentation. Most of the content can be modified by using callbacks with [xmldom](https://github.com/xmldom/xmldom).
4+
5+
If you require to create elements from scratch, `pptx-automizer` wraps around [PptxGenJS](https://github.com/gitbrent/PptxGenJS). Use the powerful syntax of `PptxGenJS` to add dynamic content to your existing .pptx template files. See an example on [how to add a chart from scratch](https://github.com/singerla/pptx-automizer/blob/main/__tests__/generate-pptxgenjs-charts.test.ts).
46

57
`pptx-automizer` is particularly well-suited for users who aim to manage their own library of .pptx template files, making it an ideal choice for those who work with intricate, well-designed customized layouts. With this tool, any existing slide or even a single element can serve as a data-driven template for generating output .pptx files.
68

@@ -36,6 +38,11 @@ If you require commercial support for complex .pptx automation, you can explore
3638
- [Modify Charts](#modify-charts)
3739
- [Modify Extended Charts](#modify-extended-charts)
3840
- [Remove elements from a slide](#remove-elements-from-a-slide)
41+
- [🔗 Hyperlink Management](#🔗-hyperlink-management)
42+
- [Hyperlink Helper Functions](#hyperlink-helper-functions)
43+
- [Adding Hyperlinks](#adding-hyperlinks)
44+
45+
3946
- [Tipps and Tricks](#tipps-and-tricks)
4047
- [Loop through the slides of a presentation](#loop-through-the-slides-of-a-presentation)
4148
- [Quickly get all slide numbers of a template](#quickly-get-all-slide-numbers-of-a-template)
@@ -44,10 +51,10 @@ If you require commercial support for complex .pptx automation, you can explore
4451
- [Import and modify slide Masters](#import-and-modify-slide-masters)
4552
- [Track status of automation process](#track-status-of-automation-process)
4653
- [More examples](#more-examples)
47-
- [Create a new modifier](#create-a-new-modifier)
4854
- [Troubleshooting](#troubleshooting)
4955
- [Testing](#testing)
5056
- [Special Thanks](#special-thanks)
57+
5158
<!-- TOC -->
5259

5360
# Requirements and Limitations
@@ -174,6 +181,13 @@ const automizer = new Automizer({
174181

175182
// use a callback function to track pptx generation process.
176183
// statusTracker: myStatusTracker,
184+
185+
// Use 1 to show warnings or 2 for detailed information
186+
// 0 disables logging
187+
verbosity: 1,
188+
189+
// Remove all unused placeholders to prevent unwanted overlays:
190+
cleanupPlaceholders: false
177191
});
178192

179193
// Now we can start and load a pptx template.
@@ -582,6 +596,36 @@ pres
582596
});
583597
```
584598

599+
## 🔗 Hyperlink Management
600+
601+
PowerPoint presentations often use hyperlinks to connect to external websites or internal slides. The PPTX Automizer provides simple and powerful functions to manage hyperlinks in your presentations.
602+
603+
### Hyperlink Helper Functions
604+
605+
Three core functions are available for all your hyperlink needs:
606+
607+
| Function | Description |
608+
|----------|-------------|
609+
| `addHyperlink` | Add a new hyperlink to an element |
610+
611+
612+
### Adding Hyperlinks
613+
614+
You can add hyperlinks to text elements using the `addHyperlink` helper function. The function accepts either a URL string for external links or a slide number for internal slide links:
615+
616+
```ts
617+
// Add an external hyperlink
618+
slide.modifyElement('TextShape', modify.addHyperlink('https://example.com'));
619+
620+
621+
// Add an internal slide link (to slide 3)
622+
slide.modifyElement('TextShape', (element, relation) => {
623+
modify.addHyperlink(3)(element, relation);
624+
});
625+
```
626+
627+
The `addHyperlink` function will automatically detect whether the target is an external URL or an internal slide number and set up the appropriate relationship type and attributes.
628+
585629
# Tipps and Tricks
586630

587631
## Loop through the slides of a presentation
@@ -590,7 +634,7 @@ If you would like to modify elements in a single .pptx file, it is important to
590634

591635
This is how it works internally:
592636

593-
- Load a root template to append slides to it
637+
- Load a root template to append slides to
594638
- (Probably) load root template again to modify slides
595639
- Load other templates
596640
- Append a loaded slide to (probably truncated) root template
@@ -622,7 +666,7 @@ const run = async () => {
622666
// Defining a "name" as second params makes it a little easier
623667
.load(`SlideWithShapes.pptx`, 'myTemplate');
624668

625-
// Get useful information about loaded templates:
669+
// This is brandnew: get useful information about loaded templates:
626670
const myTemplates = await pres.getInfo();
627671
const mySlides = myTemplates.slidesByTemplate(`myTemplate`);
628672

@@ -783,10 +827,6 @@ To specify another slideLayout for an added output slide, you need to count slid
783827

784828
To add and modify shapes on a slide master, please take a look at [Add and modify shapes](https://github.com/singerla/pptx-automizer#add-and-modify-shapes).
785829

786-
If you require to modify slide master backgrounds, please refer to
787-
- [Modify master background color](https://github.com/singerla/pptx-automizer/blob/main/__tests__/modify-master-background-color.test.ts).
788-
- [Modify master background image](https://github.com/singerla/pptx-automizer/blob/main/__tests__/modify-master-background-image.test.ts).
789-
790830
```ts
791831
// Import another slide master and all its slide layouts.
792832
// Index 1 means, you want to import the first of all masters:
@@ -861,55 +901,6 @@ const automizer = new Automizer({
861901
});
862902
```
863903

864-
## Create a new modifier
865-
866-
If the built-in modifiers of `pptx-automizer` are not sufficient to your task, you can access the target xml elements with [xmldom](https://github.com/xmldom/xmldom). A modifier is a wrapper for such an operation.
867-
868-
Let's first take a look at a (simplified) existing modifier: `ModifyTextHelper.content('This is my text')`.
869-
870-
```ts
871-
// "setTextContent" is a function that returns a function.
872-
// A "label" argument needs to be passed to "setTextContent".
873-
const setTextContent = function (label: number | string) {
874-
// On setup, we can handle the argument.
875-
const newTextContent = String(label);
876-
877-
// A new function is returned to apply the label at runtime.
878-
return function (shape: XmlElement) {
879-
// "shape" contains a modifiable xmldom object.
880-
// You can use a selector to find the required 'a:t' element:
881-
const textElement = shape.getElementsByTagName('a:t').item(0);
882-
883-
// You can now apply the "newTextContent".
884-
if (textElement?.firstChild) {
885-
// Refer to xmldom for available functions.
886-
textElement.firstChild.textContent = newTextContent;
887-
}
888-
// It is possible to output the xml to console at any time.
889-
// XmlHelper.dump(element);
890-
};
891-
};
892-
```
893-
This function will construct an anonymous callback function on setup, while the callback function itself will be executed on runtime, when it's up to the target element on a slide.
894-
895-
You can use the modifier e.g. on adding an element:
896-
897-
```ts
898-
pres.addSlide('SlideWithShapes.pptx', 2, (slide) => {
899-
// This will import the 'Drum' shape
900-
slide.modifyElement('Cloud', [
901-
// 1. Dump the original xml:
902-
// Notice: don't call XmlHelper.dump, just pass it
903-
XmlHelper.dump,
904-
// 2. Apply modifier from the example above:
905-
setTextContent('New text'),
906-
XmlHelper.dump,
907-
]);
908-
});
909-
```
910-
911-
We can wrap any xml modification by such a modifier. If you have a working example and you think it will be useful to others, you are very welcome to fork this repo and send a pull request or simply [post it](https://github.com/singerla/pptx-automizer/issues/new).
912-
913904
## More examples
914905

915906
Take a look into [**tests**-directory](https://github.com/singerla/pptx-automizer/blob/main/__tests__) to see a lot of examples for several use cases, e.g.:
@@ -922,17 +913,13 @@ Take a look into [**tests**-directory](https://github.com/singerla/pptx-automize
922913
- [Update chart legend](https://github.com/singerla/pptx-automizer/blob/main/__tests__/modify-chart-legend.test.ts)
923914

924915
## Troubleshooting
925-
926916
If you encounter problems when opening a `.pptx`-file modified by this library, you might worry about PowerPoint not giving any details about the error. It can be hard to find the cause, but there are some things you can check:
927917

928918
- **Broken relation**: There are still unsupported shape types and `pptx-automizer` wil not copy required relations of those. You can inflate `.pptx`-output and check `ppt/slides/_rels/slide[#].xml.rels`-files to find possible missing files.
929919
- **Unsupported media**: You can also take a look at the `ppt/media`-directory of an inflated `.pptx`-file. If you discover any unusual file formats, remove or replace the files by one of the [known types](https://github.com/singerla/pptx-automizer/blob/main/src/enums/content-type-map.ts).
930920
- **Broken animation**: Pay attention to modified/removed shapes which are part of an animation. In case of doubt, (temporarily) remove all animations from your template. (see [#78](https://github.com/singerla/pptx-automizer/issues/78))
931921
- **Proprietary/Binary contents** (e.g. ThinkCell): Walk through all slides, slideMasters and slideLayouts and seek for hidden Objects. Hit `ALT+F10` to toggle the sidebar.
932-
- **Chart styles not working**: If you try to change e.g. color or size of a chart data label, and it doesn't work as expected, try to remove all data labels and activate them again. If this does not help, try to give the first data label of a series a slightly different style (this creates a single data point).
933-
- **Replace Text not working**: Cut out your e.g. {CustomerName} tag from textbox to clipboard, paste it into a plaintext editor to remove all (visible and invisible) formatting. Copy & paste {CustomerName} back to the textbox. (see [#82](https://github.com/singerla/pptx-automizer/issues/82) and [#73](https://github.com/singerla/pptx-automizer/issues/73))
934-
- **No related chart worksheet**: It might happen to PowerPoint to lose the worksheet relation for a chart. If a chart gets corrupted by this, you will see a normal chart on your slide, but get an error message if you try to open the datasheet. Please replace the corrupted chart by a working one. (see [#104](https://github.com/singerla/pptx-automizer/issues/104))
935-
922+
- **Chart datasheet won't open** If you encounter an error message on opening a chart's datasheet, please make sure that the data table (blue bordered rectangle in worksheet view) of your template starts at cell A:1. If not, open worksheet in Excel mode and edit the table size in the table draft tab.
936923

937924
If none of these could help, please don't hesitate to [talk about it](https://github.com/singerla/pptx-automizer/issues/new).
938925

__tests__/add-external-image.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test('Load external media, add/modify image and set image target', async () => {
1313

1414
const pres = automizer
1515
.loadRoot(`RootTemplate.pptx`)
16-
.loadMedia([`feather.png`, `test.png`])
16+
.loadMedia([`feather.png`, `test.png`, `Dàngerous Dinösaur.png`])
1717
.loadMedia(`test.png`, `${__dirname}/../__tests__/media`, 'pre_')
1818
.load(`SlideWithShapes.pptx`, 'shapes')
1919
.load(`SlideWithImages.pptx`, 'images');
@@ -34,10 +34,16 @@ test('Load external media, add/modify image and set image target', async () => {
3434
]);
3535
});
3636

37+
pres.addSlide('images', 1, (slide) => {
38+
slide.modifyElement('Grafik 5', [
39+
ModifyImageHelper.setRelationTarget('Dàngerous Dinösaur.png'),
40+
]);
41+
});
42+
3743
const result = await pres.write(`add-external-image.test.pptx`);
3844

3945
// expect a 5x3cm light-blue duotone feather instead of imagePNG cord loop on page 1
4046
// expect imagePNG cord loop on page 2 instead of cut tree jpg
4147

42-
expect(result.images).toBe(3);
48+
expect(result.images).toBe(5);
4349
});

__tests__/add-slide-master.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ test('Append and modify slideMastes and use slideLayouts', async () => {
55
const automizer = new Automizer({
66
templateDir: `${__dirname}/pptx-templates`,
77
outputDir: `${__dirname}/pptx-output`,
8+
verbosity: 2,
89
});
910

1011
const pres = await automizer

__tests__/add-slide-notes.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import Automizer from '../src/automizer';
2+
import { vd } from '../src/helper/general-helper';
23

34
test('create presentation and append slides with notes', async () => {
45
const automizer = new Automizer({
56
templateDir: `${__dirname}/pptx-templates`,
6-
outputDir: `${__dirname}/pptx-output`
7+
outputDir: `${__dirname}/pptx-output`,
78
});
89

9-
const pres = automizer.loadRoot(`RootTemplate.pptx`)
10+
const pres = automizer
11+
.loadRoot(`RootTemplate.pptx`)
1012
.load(`SlideWithNotes.pptx`, 'notes');
1113

1214
pres.addSlide('notes', 1);
1315

16+
const creationIds = await pres.setCreationIds();
17+
// This will print out the first line of a slide note field
18+
// OR the slide title, if there is no slide note present:
19+
console.log(creationIds[0].slides[0].info);
20+
1421
const result = await pres.write(`add-slide-notes.test.pptx`);
1522

1623
expect(result.slides).toBe(2);

__tests__/add-svg-images.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Automizer from '../src/automizer';
2+
3+
test('create presentation and append slides with images', async () => {
4+
const automizer = new Automizer({
5+
templateDir: `${__dirname}/pptx-templates`,
6+
outputDir: `${__dirname}/pptx-output`,
7+
});
8+
9+
const pres = automizer
10+
.loadRoot(`RootTemplate.pptx`)
11+
.load(`EmptySlide.pptx`, 'empty')
12+
.load(`SVGImages.pptx`, 'images');
13+
14+
pres.addSlide('empty', 1, (slide) => {
15+
slide.addElement('images', 1, 'Heart');
16+
slide.addElement('images', 1, 'Leaf');
17+
});
18+
19+
const result = await pres.write(`add-svg-images.test.pptx`);
20+
21+
expect(result.images).toBe(4);
22+
});

0 commit comments

Comments
 (0)