pptx-automizer
Version:
A template based pptx generator
229 lines • 10.6 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HyperlinkProcessor = void 0;
const xml_helper_1 = require("./xml-helper");
const general_helper_1 = require("./general-helper");
/**
* Hyperlink processing utilities
*/
class HyperlinkProcessor {
/**
* Finds all hyperlink elements within a given element
*/
static findHyperlinks(element) {
const hyperlinks = [];
try {
// Find hyperlinks in shape properties (shape-level hyperlinks)
const shapeProps = element.getElementsByTagName('p:cNvPr');
for (let i = 0; i < shapeProps.length; i++) {
const prop = shapeProps[i];
const shapeHyperlinks = prop.getElementsByTagName(this.HYPERLINK_TAG);
for (let j = 0; j < shapeHyperlinks.length; j++) {
hyperlinks.push(shapeHyperlinks[j]);
}
}
// Find hyperlinks in text runs (text-level hyperlinks)
// Only look for hyperlinks that actually exist, don't process all text runs
const allHyperlinks = element.getElementsByTagName(this.HYPERLINK_TAG);
for (let i = 0; i < allHyperlinks.length; i++) {
const hlink = allHyperlinks[i];
// Check if this hyperlink is in a text run (has a:rPr as parent)
const parent = hlink.parentNode;
if (parent && parent.nodeName === 'a:rPr') {
// Only add if not already added (avoid duplicates from shape properties)
if (!hyperlinks.includes(hlink)) {
hyperlinks.push(hlink);
}
}
}
}
catch (error) {
general_helper_1.Logger.log(`Error finding hyperlinks: ${error}`, 1);
}
return hyperlinks;
}
/**
* Checks if an element contains hyperlinks
*/
static hasHyperlinks(element) {
return this.findHyperlinks(element).length > 0;
}
/**
* Checks if an element contains multiple hyperlinks
*/
static hasMultipleHyperlinks(element) {
return this.findHyperlinks(element).length > 1;
}
/**
* Determines if an element should be processed as a hyperlink element
* @param element - Element to analyze
* @returns True if element should be processed as hyperlink
*/
static shouldProcessAsHyperlink(element) {
const hyperlinks = this.findHyperlinks(element);
// Single hyperlink elements can be processed as hyperlink shapes
// Multiple hyperlinks (like tables) should be processed as generic shapes
return hyperlinks.length === 1;
}
/**
* Gets the primary hyperlink target from an element
* @param element - Element to analyze
* @returns Target information or null if no hyperlink found
*/
static getPrimaryHyperlinkTarget(element) {
try {
const hyperlinks = this.findHyperlinks(element);
if (hyperlinks.length === 0) {
return null;
}
// Return the first hyperlink's target
const firstHyperlink = hyperlinks[0];
const rId = firstHyperlink.getAttribute(this.RELATIONSHIP_ATTRIBUTE);
if (!rId) {
return null;
}
return {
rId,
type: 'hyperlink'
};
}
catch (error) {
general_helper_1.Logger.log(`Error getting primary hyperlink target: ${error}`, 1);
return null;
}
}
/**
* Extracts hyperlink relationship IDs from an element
* @param element - The XML element to extract from
* @returns Array of relationship IDs
*/
static extractHyperlinkRelationshipIds(element) {
const hyperlinks = this.findHyperlinks(element);
return hyperlinks
.map(hlink => hlink.getAttribute(this.RELATIONSHIP_ATTRIBUTE))
.filter((rId) => rId !== null);
}
/**
* Updates hyperlink relationship IDs in an element
*/
static updateHyperlinkRelationshipIds(element, relationshipMap) {
try {
const hyperlinks = this.findHyperlinks(element);
hyperlinks.forEach(hlink => {
const currentRId = hlink.getAttribute(this.RELATIONSHIP_ATTRIBUTE);
if (currentRId && relationshipMap.has(currentRId)) {
const newRId = relationshipMap.get(currentRId);
if (newRId) {
hlink.setAttribute(this.RELATIONSHIP_ATTRIBUTE, newRId);
}
}
});
}
catch (error) {
general_helper_1.Logger.log(`Error updating hyperlink relationship IDs: ${error}`, 1);
}
}
/**
* Processes hyperlinks for single-hyperlink elements
*/
static processSingleHyperlink(element, newRid) {
return __awaiter(this, void 0, void 0, function* () {
const hyperlinks = this.findHyperlinks(element);
// Only process if there's exactly one hyperlink
if (hyperlinks.length !== 1) {
general_helper_1.Logger.log(`Expected single hyperlink, found ${hyperlinks.length}`, 1);
return;
}
// Update the single hyperlink with the new relationship ID
const hyperlink = hyperlinks[0];
hyperlink.setAttribute(this.RELATIONSHIP_ATTRIBUTE, newRid);
});
}
/**
* Copies multiple hyperlinks from source to target slide
*/
static copyMultipleHyperlinks(element, sourceArchive, sourceSlideNumber, targetArchive, targetSlideRelFile) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.hasHyperlinks(element)) {
return;
}
const hyperlinkRIds = this.extractHyperlinkRelationshipIds(element);
if (hyperlinkRIds.length === 0) {
return;
}
const sourceRelPath = `ppt/slides/_rels/slide${sourceSlideNumber}.xml.rels`;
const sourceRelDoc = yield xml_helper_1.XmlHelper.getXmlFromArchive(sourceArchive, sourceRelPath);
if (!sourceRelDoc) {
general_helper_1.Logger.log(`Source relationships not found: ${sourceRelPath}`, 1);
return;
}
const sourceRelationships = sourceRelDoc.getElementsByTagName('Relationship');
const targetRelXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(targetArchive, targetSlideRelFile);
if (!targetRelXml) {
general_helper_1.Logger.log(`Target relationships not found: ${targetSlideRelFile}`, 1);
return;
}
const relationshipMap = new Map();
const processedTargets = new Set();
for (let i = 0; i < hyperlinkRIds.length; i++) {
const rId = hyperlinkRIds[i];
let sourceRel = null;
for (let j = 0; j < sourceRelationships.length; j++) {
if (sourceRelationships[j].getAttribute('Id') === rId) {
sourceRel = sourceRelationships[j];
break;
}
}
if (sourceRel) {
const relType = sourceRel.getAttribute('Type');
const target = sourceRel.getAttribute('Target');
const targetMode = sourceRel.getAttribute('TargetMode');
if (relType && target) {
const relationshipKey = `${relType}:${target}:${targetMode || ''}`;
let newRId;
if (processedTargets.has(relationshipKey)) {
const existingRels = targetRelXml.getElementsByTagName('Relationship');
for (let k = 0; k < existingRels.length; k++) {
const existingRel = existingRels[k];
if (existingRel.getAttribute('Type') === relType &&
existingRel.getAttribute('Target') === target &&
existingRel.getAttribute('TargetMode') === targetMode) {
newRId = existingRel.getAttribute('Id') || '';
break;
}
}
}
else {
newRId = yield xml_helper_1.XmlHelper.getNextRelId(targetArchive, targetSlideRelFile);
const newRelationship = targetRelXml.createElement('Relationship');
newRelationship.setAttribute('Id', newRId);
newRelationship.setAttribute('Type', relType);
newRelationship.setAttribute('Target', target);
if (targetMode) {
newRelationship.setAttribute('TargetMode', targetMode);
}
targetRelXml.documentElement.appendChild(newRelationship);
processedTargets.add(relationshipKey);
}
relationshipMap.set(rId, newRId);
}
}
}
this.updateHyperlinkRelationshipIds(element, relationshipMap);
yield xml_helper_1.XmlHelper.writeXmlToArchive(targetArchive, targetSlideRelFile, targetRelXml);
});
}
}
exports.HyperlinkProcessor = HyperlinkProcessor;
HyperlinkProcessor.HYPERLINK_TAG = 'a:hlinkClick';
HyperlinkProcessor.RELATIONSHIP_ATTRIBUTE = 'r:id';
//# sourceMappingURL=hyperlink-processor.js.map