UNPKG

pptx-automizer

Version:

A template based pptx generator

315 lines 17.1 kB
"use strict"; 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.Hyperlink = void 0; const xml_helper_1 = require("../helper/xml-helper"); const shape_1 = require("../classes/shape"); const content_tracker_1 = require("../helper/content-tracker"); class Hyperlink extends shape_1.Shape { constructor(shape, targetType, sourceArchive, hyperlinkType = 'external', hyperlinkTarget) { super(shape, targetType); this.sourceArchive = sourceArchive; this.hyperlinkType = hyperlinkType; this.hyperlinkTarget = hyperlinkTarget || ''; this.relRootTag = 'a:hlinkClick'; this.relAttribute = 'r:id'; } modify(targetTemplate, targetSlideNumber) { return __awaiter(this, void 0, void 0, function* () { yield this.prepare(targetTemplate, targetSlideNumber); yield this.editTargetHyperlinkRel(); yield this.replaceIntoSlideTree(); return this; }); } append(targetTemplate, targetSlideNumber) { return __awaiter(this, void 0, void 0, function* () { yield this.prepare(targetTemplate, targetSlideNumber); yield this.setTargetElement(); yield this.appendToSlideTree(); yield this.editTargetHyperlinkRel(); yield this.updateHyperlinkInSlide(); return this; }); } remove(targetTemplate, targetSlideNumber) { return __awaiter(this, void 0, void 0, function* () { yield this.prepare(targetTemplate, targetSlideNumber); if (this.target && this.target.rId) { this.sourceRid = this.target.rId; } yield this.removeFromSlideTree(); yield this.removeFromSlideRels(); return this; }); } prepare(targetTemplate, targetSlideNumber) { return __awaiter(this, void 0, void 0, function* () { yield this.setTarget(targetTemplate, targetSlideNumber); if (!this.createdRid) { const baseId = yield xml_helper_1.XmlHelper.getNextRelId(this.targetArchive, this.targetSlideRelFile); // Strip '-created' suffix more robustly this.createdRid = baseId.endsWith('-created') ? baseId.slice(0, -8) : baseId; } if (this.shape && this.shape.target && this.shape.target.rId) { this.sourceRid = this.shape.target.rId; } // If hyperlinkTarget is not set, try to get it from the original rel target if (!this.hyperlinkTarget && this.shape && this.shape.target && this.shape.target.file) { this.hyperlinkTarget = this.shape.target.file; this.hyperlinkType = (this.shape.target.isExternal || this.shape.target.type === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') ? 'external' : 'internal'; } }); } editTargetHyperlinkRel() { return __awaiter(this, void 0, void 0, function* () { const targetRelFile = this.targetSlideRelFile; const relXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(this.targetArchive, targetRelFile); const relationships = relXml.getElementsByTagName('Relationship'); // Check if the relationship already exists let relationshipExists = false; for (let i = 0; i < relationships.length; i++) { if (relationships[i].getAttribute('Id') === this.createdRid) { this.updateHyperlinkRelation(relationships[i]); relationshipExists = true; break; } } // If the relationship doesn't exist, create it if (!relationshipExists) { const newRel = relXml.createElement('Relationship'); newRel.setAttribute('Id', this.createdRid); newRel.setAttribute('Type', this.getRelationshipType()); newRel.setAttribute('Target', this.getRelationshipTarget()); if (this.hyperlinkType === 'external') { newRel.setAttribute('TargetMode', 'External'); } relXml.documentElement.appendChild(newRel); // Track the relationship for content integrity content_tracker_1.contentTracker.trackRelation(targetRelFile, { Id: this.createdRid, Target: this.getRelationshipTarget(), Type: this.getRelationshipType(), }); } xml_helper_1.XmlHelper.writeXmlToArchive(this.targetArchive, targetRelFile, relXml); }); } // Add a method to update the hyperlink in the slide XML updateHyperlinkInSlide() { return __awaiter(this, void 0, void 0, function* () { if (!this.targetElement && this.sourceRid && this.createdRid) { const slideXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(this.targetArchive, this.targetSlideFile); const allHyperlinkElements = slideXml.getElementsByTagName('a:hlinkClick'); let foundAndUpdatedInSlide = false; for (let i = 0; i < allHyperlinkElements.length; i++) { const hlinkClick = allHyperlinkElements[i]; if (hlinkClick.getAttribute('r:id') === this.sourceRid) { hlinkClick.setAttribute('r:id', this.createdRid); hlinkClick.setAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); foundAndUpdatedInSlide = true; break; } } if (foundAndUpdatedInSlide) { xml_helper_1.XmlHelper.writeXmlToArchive(this.targetArchive, this.targetSlideFile, slideXml); } } }); } updateHyperlinkRelation(element) { element.setAttribute('Type', this.getRelationshipType()); element.setAttribute('Target', this.getRelationshipTarget()); if (this.hyperlinkType === 'external') { element.setAttribute('TargetMode', 'External'); } else if (element.hasAttribute('TargetMode')) { element.removeAttribute('TargetMode'); } content_tracker_1.contentTracker.trackRelation(this.targetSlideRelFile, { Id: element.getAttribute('Id') || '', Target: this.getRelationshipTarget(), Type: this.getRelationshipType(), }); } getRelationshipType() { if (this.hyperlinkType === 'internal') { return 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide'; } return 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink'; } getRelationshipTarget() { var _a, _b; if (this.hyperlinkType === 'internal') { // Enhanced internal slide link handling const slideNumber = ((_b = (_a = this.hyperlinkTarget) === null || _a === void 0 ? void 0 : _a.match(/\d+/)) === null || _b === void 0 ? void 0 : _b[0]) || this.targetSlideNumber.toString(); // Ensure proper slide path format return `../slides/slide${slideNumber}.xml`; } return this.hyperlinkTarget || 'https://example.com'; } removeFromSlideRels() { return __awaiter(this, void 0, void 0, function* () { const targetRelFile = this.targetSlideRelFile; const relXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(this.targetArchive, targetRelFile); const relationships = relXml.getElementsByTagName('Relationship'); const ridToRemove = this.sourceRid || this.createdRid; if (ridToRemove) { for (let i = relationships.length - 1; i >= 0; i--) { if (relationships[i].getAttribute('Id') === ridToRemove) { relationships[i].parentNode.removeChild(relationships[i]); break; } } xml_helper_1.XmlHelper.writeXmlToArchive(this.targetArchive, targetRelFile, relXml); } }); } static getAllOnSlide(archive, relsPath) { return __awaiter(this, void 0, void 0, function* () { const hyperlinkRelType = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink'; const slideRelType = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide'; return xml_helper_1.XmlHelper.getRelationshipItems(archive, relsPath, (element, rels) => { const type = element.getAttribute('Type'); if (type === hyperlinkRelType || type === slideRelType) { rels.push({ rId: element.getAttribute('Id'), type: element.getAttribute('Type'), file: element.getAttribute('Target'), filename: element.getAttribute('Target'), element: element, isExternal: element.getAttribute('TargetMode') === 'External' || type === hyperlinkRelType, }); } }); }); } modifyOnAddedSlide(targetTemplate, targetSlideNumber) { return __awaiter(this, void 0, void 0, function* () { if (!this.target || !this.target.rId) { console.warn('modifyOnAddedSlide called on Hyperlink without a valid source target/rId.'); return; } this.sourceRid = this.target.rId; this.hyperlinkTarget = this.target.file; this.hyperlinkType = (this.target.isExternal || this.target.type === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') ? 'external' : 'internal'; yield this.prepare(targetTemplate, targetSlideNumber); // 1. Modify the copied _rels file: const targetRelFile = this.targetSlideRelFile; const relXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(this.targetArchive, targetRelFile); const relationships = relXml.getElementsByTagName('Relationship'); let relFoundAndUpdated = false; for (let i = 0; i < relationships.length; i++) { const relElement = relationships[i]; if (relElement.getAttribute('Id') === this.sourceRid) { // Find by original rId relElement.setAttribute('Id', this.createdRid); // Update Id to new unique rId relElement.setAttribute('Target', this.getRelationshipTarget()); if (this.hyperlinkType === 'external') { relElement.setAttribute('TargetMode', 'External'); } else { if (relElement.hasAttribute('TargetMode')) relElement.removeAttribute('TargetMode'); } relFoundAndUpdated = true; content_tracker_1.contentTracker.trackRelation(targetRelFile, { Id: this.createdRid, Target: relElement.getAttribute('Target') || '', Type: relElement.getAttribute('Type') || '', }); break; } } if (!relFoundAndUpdated) { console.warn(`modifyOnAddedSlide: Relationship with sourceRId ${this.sourceRid} not found in target rels ${targetRelFile}. It might have been processed by another instance or was missing in the copied rels.`); const newRel = relXml.createElement('Relationship'); newRel.setAttribute('Id', this.createdRid); newRel.setAttribute('Type', this.getRelationshipType()); newRel.setAttribute('Target', this.getRelationshipTarget()); if (this.hyperlinkType === 'external') { newRel.setAttribute('TargetMode', 'External'); } relXml.documentElement.appendChild(newRel); content_tracker_1.contentTracker.trackRelation(targetRelFile, { Id: this.createdRid, Target: this.getRelationshipTarget(), Type: this.getRelationshipType() }); } yield xml_helper_1.XmlHelper.writeXmlToArchive(this.targetArchive, targetRelFile, relXml); // 2. Modify the copied slide content XML yield this.updateHyperlinkInSlide(); }); } // Helper method to create a hyperlink in a shape static addHyperlinkToShape(archive, slidePath, slideRelsPath, shapeId, hyperlinkTarget) { return __awaiter(this, void 0, void 0, function* () { const slideXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(archive, slidePath); // Find the shape by ID or name const shape = xml_helper_1.XmlHelper.isElementCreationId(shapeId) ? xml_helper_1.XmlHelper.findByCreationId(slideXml, shapeId) : xml_helper_1.XmlHelper.findByName(slideXml, shapeId); if (!shape) { throw new Error(`Shape with ID/name "${shapeId}" not found`); } // Create a new relationship ID const relId = yield xml_helper_1.XmlHelper.getNextRelId(archive, slideRelsPath); // Add the hyperlink relationship to the slide relationships const relXml = yield xml_helper_1.XmlHelper.getXmlFromArchive(archive, slideRelsPath); const newRel = relXml.createElement('Relationship'); newRel.setAttribute('Id', relId); // Improved internal link detection const isInternalLink = typeof hyperlinkTarget === 'number' || (typeof hyperlinkTarget === 'string' && /^\d+$/.test(hyperlinkTarget)); if (isInternalLink) { // Enhanced internal slide link handling const slideNumber = typeof hyperlinkTarget === 'number' ? hyperlinkTarget : parseInt(hyperlinkTarget, 10); newRel.setAttribute('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide'); newRel.setAttribute('Target', `../slides/slide${slideNumber}.xml`); } else { newRel.setAttribute('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink'); newRel.setAttribute('Target', hyperlinkTarget.toString()); newRel.setAttribute('TargetMode', 'External'); } relXml.documentElement.appendChild(newRel); yield xml_helper_1.XmlHelper.writeXmlToArchive(archive, slideRelsPath, relXml); // Add the hyperlink to the shape const txBody = shape.getElementsByTagName('p:txBody')[0]; if (txBody) { const paragraphs = txBody.getElementsByTagName('a:p'); if (paragraphs.length > 0) { const paragraph = paragraphs[0]; const runs = paragraph.getElementsByTagName('a:r'); if (runs.length > 0) { const run = runs[0]; const rPr = run.getElementsByTagName('a:rPr')[0]; if (rPr) { const hlinkClick = slideXml.createElement('a:hlinkClick'); hlinkClick.setAttribute('r:id', relId); if (isInternalLink) { hlinkClick.setAttribute('action', 'ppaction://hlinksldjump'); } hlinkClick.setAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); rPr.appendChild(hlinkClick); } } } } yield xml_helper_1.XmlHelper.writeXmlToArchive(archive, slidePath, slideXml); return relId; }); } } exports.Hyperlink = Hyperlink; //# sourceMappingURL=hyperlink.js.map