Skip to content

Commit 6ea681d

Browse files
committed
chore(slide): select shapes without creationId by name and nameIdx
1 parent 98ee1ca commit 6ea681d

File tree

5 files changed

+100
-45
lines changed

5 files changed

+100
-45
lines changed

src/classes/has-shapes.ts

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { XmlSlideHelper } from '../helper/xml-slide-helper';
3838
import { OLEObject } from '../shapes/ole';
3939
import { Hyperlink } from '../shapes/hyperlink';
4040
import { HyperlinkProcessor } from '../helper/hyperlink-processor';
41-
import { GeneralHelper, vd } from '../helper/general-helper';
41+
import { vd } from '../helper/general-helper';
4242

4343
export default class HasShapes {
4444
/**
@@ -343,14 +343,29 @@ export default class HasShapes {
343343
mode: string,
344344
callback?: ShapeModificationCallback | ShapeModificationCallback[],
345345
): void {
346+
this.importElements.push({
347+
presName,
348+
slideNumber,
349+
selector,
350+
mode,
351+
callback,
352+
});
353+
}
354+
355+
getAlreadyModifiedElement(selector: FindElementSelector) {
346356
// Check if an element with the same selector is already imported in modify mode
347357
const existingElement = this.importElements.find((element) => {
348358
if (
349-
typeof selector === 'object' &&
350-
typeof element.selector === 'object' &&
351-
selector.creationId &&
352-
element.selector?.creationId
359+
typeof selector !== 'object' ||
360+
typeof element.selector !== 'object'
353361
) {
362+
return;
363+
}
364+
365+
if (!selector.creationId) {
366+
// Match by name and nameIdx only if the shape has no creationId
367+
return selector.name === element.selector.name && selector.nameIdx === element.selector.nameIdx;
368+
} else if (selector.creationId && element.selector?.creationId) {
354369
const creaId1 = selector.creationId.replace('{', '').replace('}', '');
355370
const creaId2 = element.selector.creationId
356371
.replace('{', '')
@@ -359,31 +374,7 @@ export default class HasShapes {
359374
return selector.name === element.selector.name && creaId1 === creaId2;
360375
}
361376
});
362-
363-
if (existingElement && mode === 'modify') {
364-
if (callback) {
365-
const addCallback = GeneralHelper.arrayify(callback);
366-
367-
if (existingElement.callback) {
368-
existingElement.callback = GeneralHelper.arrayify(
369-
existingElement.callback,
370-
);
371-
}
372-
373-
if (Array.isArray(existingElement.callback)) {
374-
existingElement.callback.push(...addCallback);
375-
}
376-
}
377-
} else {
378-
// If the element is not already imported or not in modify mode, add it as a new import
379-
this.importElements.push({
380-
presName,
381-
slideNumber,
382-
selector,
383-
mode,
384-
callback,
385-
});
386-
}
377+
return existingElement;
387378
}
388379

389380
/**
@@ -573,14 +564,18 @@ export default class HasShapes {
573564
mode: 'findByElementName',
574565
selector: selector,
575566
});
576-
} else if (selector.name) {
577-
strategies.push({
578-
mode: 'findByElementCreationId',
579-
selector: selector.creationId,
580-
});
567+
} else {
568+
if(selector.creationId) {
569+
strategies.push({
570+
mode: 'findByElementCreationId',
571+
selector: selector.creationId,
572+
});
573+
}
574+
581575
strategies.push({
582576
mode: 'findByElementName',
583577
selector: selector.name,
578+
nameIdx: selector.nameIdx
584579
});
585580
}
586581

@@ -591,6 +586,7 @@ export default class HasShapes {
591586
sourceArchive,
592587
sourcePath,
593588
findElement.selector,
589+
findElement.nameIdx,
594590
);
595591

596592
if (sourceElement) {

src/helper/xml-helper.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ export class XmlHelper {
419419
archive: IArchive,
420420
path: string,
421421
creationId: string,
422+
nameIdx?: number
422423
): Promise<XmlElement> {
423424
const slideXml = await XmlHelper.getXmlFromArchive(archive, path);
424425

@@ -429,18 +430,28 @@ export class XmlHelper {
429430
archive: IArchive,
430431
path: string,
431432
name: string,
433+
nameIdx?: number
432434
): Promise<XmlElement> {
433435
const slideXml = await XmlHelper.getXmlFromArchive(archive, path);
434436

435-
return XmlHelper.findByName(slideXml, name);
437+
return XmlHelper.findByName(slideXml, name, nameIdx);
436438
}
437439

438-
static findByName(doc: Document, name: string): XmlElement {
440+
static findByName(doc: Document, name: string, nameIdx?: number): XmlElement {
439441
const names = doc.getElementsByTagName('p:cNvPr');
442+
let matchCount = 0;
440443

441-
for (const i in names) {
442-
if (names[i].getAttribute && names[i].getAttribute('name') === name) {
443-
return names[i].parentNode.parentNode as XmlElement;
444+
// Default nameIdx to 0 if not provided
445+
const targetIdx = nameIdx !== undefined ? nameIdx : 0;
446+
447+
for (let i = 0; i < names.length; i++) {
448+
const item = names.item(i);
449+
if (item && item.getAttribute && item.getAttribute('name') === name) {
450+
// Check if this is the occurrence we're looking for
451+
if (matchCount === targetIdx) {
452+
return item.parentNode.parentNode as XmlElement;
453+
}
454+
matchCount++;
444455
}
445456
}
446457

src/helper/xml-slide-helper.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ export class XmlSlideHelper {
114114
}
115115

116116
static getElementInfo(slideElement: XmlElement): ElementInfo {
117+
const creationId = XmlSlideHelper.getElementCreationId(slideElement, true);
118+
const nameIdx = (!creationId) ? XmlSlideHelper.getElementNameIdx(slideElement) : 0;
119+
117120
return {
118121
name: XmlSlideHelper.getElementName(slideElement),
119122
id: XmlSlideHelper.getElementCreationId(slideElement),
120-
creationId: XmlSlideHelper.getElementCreationId(slideElement, true),
123+
creationId,
124+
nameIdx,
121125
type: XmlSlideHelper.getElementType(slideElement),
122126
position: XmlSlideHelper.parseShapeCoordinates(slideElement),
123127
placeholder: XmlSlideHelper.parsePlaceholderInfo(slideElement),
@@ -369,6 +373,45 @@ export class XmlSlideHelper {
369373
}
370374
}
371375

376+
static getElementNameIdx(
377+
slideElement: XmlElement,
378+
): number {
379+
const elementName = XmlSlideHelper.getElementName(slideElement);
380+
if (!elementName) {
381+
return 0;
382+
}
383+
384+
// Find the parent slide element (spTree) to search all elements on the slide
385+
const currentNode = XmlHelper.getClosestParent('p:spTree', slideElement)
386+
387+
if (!currentNode) {
388+
return 0; // Unable to find slide parent
389+
}
390+
391+
const spTree = currentNode as XmlElement;
392+
393+
// Get all named elements from the slide
394+
const namedElements: XmlElement[] = [];
395+
const nvPrs = spTree.getElementsByTagNameNS(nsMain, 'cNvPr');
396+
397+
XmlHelper.modifyCollection(nvPrs, (nvPr: any) => {
398+
const parentNode = nvPr.parentNode.parentNode;
399+
const name = nvPr.getAttribute('name');
400+
if (name === elementName) {
401+
namedElements.push(parentNode);
402+
}
403+
});
404+
405+
// Find the index of the current element in the array of elements with the same name
406+
for (let i = 0; i < namedElements.length; i++) {
407+
if (namedElements[i] === slideElement) {
408+
return i;
409+
}
410+
}
411+
412+
return 0;
413+
}
414+
372415
/**
373416
* Parses local tag name to specify element type in case it is a 'graphicFrame'.
374417
* @param slideElementParent

src/types/types.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,18 +251,22 @@ export type GenerateElements = {
251251
addedObjects?: AddedObject[];
252252
};
253253
export type AddedObject = {
254-
objectName: string,
255-
callbacks: ModificationCallback[]
256-
}
254+
objectName: string;
255+
callbacks: ModificationCallback[];
256+
};
257257
export type FindElementSelector =
258258
| string
259259
| {
260-
creationId: string;
260+
creationId?: string;
261261
name: string;
262+
// Specify the nth occurance in case you have more than one
263+
// shape with the same name on your template slide:
264+
nameIdx?: number;
262265
};
263266
export type FindElementStrategy = {
264267
mode: 'findByElementCreationId' | 'findByElementName';
265268
selector: string;
269+
nameIdx?: number;
266270
};
267271
export type ImportedElement = {
268272
mode: string;

src/types/xml-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export type ElementInfo = {
7676
type: ElementType;
7777
id: string;
7878
creationId: string;
79+
nameIdx: number;
7980
position: {
8081
x: number;
8182
y: number;

0 commit comments

Comments
 (0)