Skip to content

Commit f97b116

Browse files
committed
feature(slide): add elements to slide by creationId OR by name fallback
1 parent 0b3f616 commit f97b116

File tree

4 files changed

+130
-19
lines changed

4 files changed

+130
-19
lines changed

__tests__/modify-by-creation-id.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,16 @@ test('create presentation, add and modify an existing table by creation id.', as
2828
slide.modifyElement('{EFC74B4C-D832-409B-9CF4-73C1EFF132D8}', [
2929
modify.setTableData(data1),
3030
]);
31-
31+
})
32+
.addSlide('tables', 1950777067, (slide) => {
3233
slide.addElement(
3334
'tables',
3435
1950777067,
3536
'{EFC74B4C-D832-409B-9CF4-73C1EFF132D8}',
3637
[modify.setTableData(data1)],
3738
);
3839
})
39-
.write(`modify-existing-table.test.pptx`);
40+
.write(`modify-by-creation-id.test.pptx`);
4041

4142
// expect(result.tables).toBe(2); // tbd
4243
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Automizer, { modify } from '../src/index';
2+
import { vd } from '../src/helper/general-helper';
3+
4+
test('create presentation, add and modify an existing table by FindElementSelector', async () => {
5+
const automizer = new Automizer({
6+
templateDir: `${__dirname}/pptx-templates`,
7+
outputDir: `${__dirname}/pptx-output`,
8+
useCreationIds: true,
9+
});
10+
11+
const data1 = {
12+
body: [
13+
{ label: 'item test r1', values: ['test1', 10, 16, 12, 11] },
14+
{ label: 'item test r2', values: ['test2', 12, 18, 15, 12] },
15+
{ label: 'item test r3', values: ['test3', 14, 12, 11, 14] },
16+
],
17+
};
18+
19+
const pres = automizer
20+
.loadRoot(`RootTemplate.pptx`)
21+
.load(`SlideWithTables.pptx`, 'tables');
22+
23+
const creationIds = await pres.setCreationIds();
24+
// vd(creationIds);
25+
26+
const result = await pres
27+
.addSlide('tables', 1950777067, (slide) => {
28+
// This will try to match the given creationId first, and, if failed,
29+
// match by element name.
30+
slide.modifyElement(
31+
{
32+
creationId: '{EFC74B4C-D832-409B-9CF4-73C1EFF132D8}',
33+
name: 'TableDefault',
34+
},
35+
[modify.setTableData(data1)],
36+
);
37+
38+
// CreationID is not valid/has changed, but we can use a fallback element name:
39+
slide.addElement(
40+
'tables',
41+
1950777067,
42+
{
43+
creationId: '{XXXXX-XXXXX-XXXXX-XX-XXX}',
44+
name: 'TableWithLabels',
45+
},
46+
[modify.setTableData(data1)],
47+
);
48+
})
49+
.write(`modify-by-element-selector.test.pptx`);
50+
51+
// expect(result.tables).toBe(2); // tbd
52+
});

src/classes/slide.ts

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { FileHelper } from '../helper/file-helper';
22
import { XmlHelper } from '../helper/xml-helper';
33
import {
44
AnalyzedElementType,
5+
FindElementSelector,
6+
FindElementStrategy,
57
ImportedElement,
68
ImportElement,
79
ShapeModificationCallback,
@@ -239,7 +241,7 @@ export class Slide implements ISlide {
239241
* Depending on the shape type (e.g. chart or table), different arguments will be passed to the callback.
240242
*/
241243
modifyElement(
242-
selector: string,
244+
selector: FindElementSelector,
243245
callback: ShapeModificationCallback | ShapeModificationCallback[],
244246
): this {
245247
const presName = this.sourceTemplate.name;
@@ -265,7 +267,7 @@ export class Slide implements ISlide {
265267
addElement(
266268
presName: string,
267269
slideNumber: number,
268-
selector: string,
270+
selector: FindElementSelector,
269271
callback?: ShapeModificationCallback | ShapeModificationCallback[],
270272
): this {
271273
return this.addElementToModificationsList(
@@ -281,7 +283,7 @@ export class Slide implements ISlide {
281283
* Remove a single element from slide.
282284
* @param {string} selector - Element's name on the slide.
283285
*/
284-
removeElement(selector: string): this {
286+
removeElement(selector: FindElementSelector): this {
285287
const presName = this.sourceTemplate.name;
286288
const slideNumber = this.sourceNumber;
287289

@@ -290,6 +292,7 @@ export class Slide implements ISlide {
290292
slideNumber,
291293
selector,
292294
'remove',
295+
undefined,
293296
);
294297
}
295298

@@ -306,7 +309,7 @@ export class Slide implements ISlide {
306309
private addElementToModificationsList(
307310
presName: string,
308311
slideNumber: number,
309-
selector: string,
312+
selector: FindElementSelector,
310313
mode: string,
311314
callback?: ShapeModificationCallback | ShapeModificationCallback[],
312315
): this {
@@ -374,24 +377,19 @@ export class Slide implements ISlide {
374377
const sourceArchive = await template.archive;
375378
const useCreationIds =
376379
template.useCreationIds === true && template.creationIds !== undefined;
377-
const method = useCreationIds
378-
? 'findByElementCreationId'
379-
: 'findByElementName';
380380

381-
const sourceElement = await XmlHelper[method](
381+
const { sourceElement, selector } = await this.findElementOnSlide(
382+
importElement.selector,
382383
sourceArchive,
383384
sourcePath,
384-
importElement.selector,
385+
useCreationIds,
385386
);
386387

387388
if (!sourceElement) {
388-
vd(importElement);
389-
vd(
390-
`Can't find ${importElement.selector} on slide ${slideNumber} in ${importElement.presName}`,
389+
console.error(
390+
`Can't find element on slide ${slideNumber} in ${importElement.presName}: `,
391391
);
392-
// throw new Error(
393-
// `Can't find ${importElement.selector} on slide ${slideNumber} in ${importElement.presName}`,
394-
// );
392+
console.log(importElement);
395393
return;
396394
}
397395

@@ -403,7 +401,7 @@ export class Slide implements ISlide {
403401

404402
return {
405403
mode: importElement.mode,
406-
name: importElement.selector,
404+
name: selector,
407405
hasCreationId: useCreationIds,
408406
sourceArchive,
409407
sourceSlideNumber: slideNumber,
@@ -414,6 +412,55 @@ export class Slide implements ISlide {
414412
};
415413
}
416414

415+
async findElementOnSlide(
416+
selector: FindElementSelector,
417+
sourceArchive: IArchive,
418+
sourcePath: string,
419+
useCreationIds: boolean,
420+
): Promise<{
421+
sourceElement: XmlDocument;
422+
selector: string;
423+
}> {
424+
const strategies: FindElementStrategy[] = [];
425+
if (typeof selector === 'string') {
426+
if (useCreationIds) {
427+
strategies.push({
428+
mode: 'findByElementCreationId',
429+
selector: selector,
430+
});
431+
}
432+
strategies.push({
433+
mode: 'findByElementName',
434+
selector: selector,
435+
});
436+
} else if (selector.name) {
437+
strategies.push({
438+
mode: 'findByElementCreationId',
439+
selector: selector.creationId,
440+
});
441+
strategies.push({
442+
mode: 'findByElementName',
443+
selector: selector.name,
444+
});
445+
}
446+
447+
for (const findElement of strategies) {
448+
const mode = findElement.mode;
449+
450+
const sourceElement = await XmlHelper[mode](
451+
sourceArchive,
452+
sourcePath,
453+
findElement.selector,
454+
);
455+
456+
if (sourceElement) {
457+
return { sourceElement, selector: findElement.selector };
458+
}
459+
}
460+
461+
return { sourceElement: undefined, selector: JSON.stringify(selector) };
462+
}
463+
417464
/**
418465
* Analyzes element
419466
* @internal

src/types/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,20 @@ export type ArchiveParams = {
130130
export type ImportElement = {
131131
presName: string;
132132
slideNumber: number;
133-
selector: string;
133+
selector: FindElementSelector;
134134
mode: string;
135135
callback?: ShapeModificationCallback | ShapeModificationCallback[];
136+
info?: any;
137+
};
138+
export type FindElementSelector =
139+
| string
140+
| {
141+
creationId: string;
142+
name: string;
143+
};
144+
export type FindElementStrategy = {
145+
mode: 'findByElementCreationId' | 'findByElementName';
146+
selector: string;
136147
};
137148
export type ImportedElement = {
138149
mode: string;

0 commit comments

Comments
 (0)