xml-slide-helper.jsā¢9.05 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.XmlSlideHelper = exports.mapUriType = exports.nsMain = void 0;
const xml_helper_1 = require("./xml-helper");
exports.nsMain = 'http://schemas.openxmlformats.org/presentationml/2006/main';
exports.mapUriType = {
'http://schemas.openxmlformats.org/drawingml/2006/table': 'table',
'http://schemas.openxmlformats.org/drawingml/2006/chart': 'chart',
};
/**
* Class that represents an XML slide helper
*/
class XmlSlideHelper {
/**
* Constructor for the XmlSlideHelper class.
* @param {XmlDocument} slideXml - The slide XML document to be used by the helper.
* @param hasShapes
*/
constructor(slideXml, hasShapes) {
/**
* Fetches an XML file from the given path and extracts the dimensions.
*
* @param {string} path - The path of the XML file.
* @returns {Promise<{ width: number; height: number } | null>} - A promise that resolves with an object containing the width and height, or `null` if there was an error.
*/
this.getAndExtractDimensions = (path) => __awaiter(this, void 0, void 0, function* () {
try {
const xml = yield xml_helper_1.XmlHelper.getXmlFromArchive(this.hasShapes.sourceTemplate.archive, path);
if (!xml)
return null;
const sldSz = xml.getElementsByTagName('p:sldSz')[0];
if (sldSz) {
const width = XmlSlideHelper.parseCoordinate(sldSz, 'cx');
const height = XmlSlideHelper.parseCoordinate(sldSz, 'cy');
return { width, height };
}
return null;
}
catch (error) {
console.warn(`Error while fetching XML from path ${path}: ${error}`);
return null;
}
});
if (!slideXml) {
throw Error('Slide XML is not defined');
}
this.slideXml = slideXml;
this.hasShapes = hasShapes;
}
getSlideCreationId() {
const creationIdItem = this.slideXml
.getElementsByTagName('p14:creationId')
.item(0);
if (!creationIdItem) {
return;
}
const creationIdSlide = creationIdItem.getAttribute('val');
if (!creationIdSlide) {
return;
}
return Number(creationIdSlide);
}
/**
* Get an array of ElementInfo objects for all named elements on a slide.
* @param filterTags Use an array of strings to filter the output array
*/
getAllElements(filterTags) {
const elementInfo = [];
try {
const shapeNodes = this.getNamedElements(filterTags);
shapeNodes.forEach((shapeNode) => {
elementInfo.push(XmlSlideHelper.getElementInfo(shapeNode));
});
}
catch (error) {
console.error(error);
throw new Error(`Failed to retrieve elements: ${error.message}`);
}
return elementInfo;
}
/**
* Get all text element IDs from the slide.
* @return {string[]} An array of text element IDs.
*/
getAllTextElementIds(useCreationIds) {
const elementIds = [];
try {
elementIds.push(...this.getAllElements(['sp'])
.filter((element) => element.hasTextBody)
.map((element) => (useCreationIds ? element.id : element.name)));
}
catch (error) {
console.error(error);
throw new Error(`Failed to retrieve text element IDs: ${error.message}`);
}
return elementIds;
}
static getElementInfo(slideElement) {
return {
name: XmlSlideHelper.getElementName(slideElement),
id: XmlSlideHelper.getElementCreationId(slideElement),
type: XmlSlideHelper.getElementType(slideElement),
position: XmlSlideHelper.parseShapeCoordinates(slideElement),
hasTextBody: !!XmlSlideHelper.getTextBody(slideElement),
getXmlElement: () => slideElement,
};
}
/**
* Retreives a list of all named elements on a slide. Automation requires at least a name.
* @param filterTags Use an array of strings to filter the output array
*/
getNamedElements(filterTags) {
const skipTags = ['spTree'];
const nvPrs = this.slideXml.getElementsByTagNameNS(exports.nsMain, 'cNvPr');
const namedElements = [];
xml_helper_1.XmlHelper.modifyCollection(nvPrs, (nvPr) => {
const parentNode = nvPr.parentNode.parentNode;
const parentTag = parentNode.localName;
if (!skipTags.includes(parentTag) &&
(!(filterTags === null || filterTags === void 0 ? void 0 : filterTags.length) || filterTags.includes(parentTag))) {
namedElements.push(parentNode);
}
});
return namedElements;
}
static getTextBody(shapeNode) {
return shapeNode.getElementsByTagNameNS(exports.nsMain, 'txBody').item(0);
}
static getNonVisibleProperties(shapeNode) {
return shapeNode.getElementsByTagNameNS(exports.nsMain, 'cNvPr').item(0);
}
static getElementName(slideElement) {
const cNvPr = XmlSlideHelper.getNonVisibleProperties(slideElement);
if (cNvPr) {
return cNvPr.getAttribute('name');
}
}
static getElementCreationId(slideElement) {
const cNvPr = XmlSlideHelper.getNonVisibleProperties(slideElement);
if (cNvPr) {
const creationIdElement = cNvPr
.getElementsByTagName('a16:creationId')
.item(0);
if (creationIdElement) {
return creationIdElement.getAttribute('id');
}
}
}
/**
* Parses local tag name to specify element type in case it is a 'graphicFrame'.
* @param slideElementParent
*/
static getElementType(slideElementParent) {
let type = slideElementParent.localName;
switch (type) {
case 'graphicFrame':
const graphicData = slideElementParent.getElementsByTagName('a:graphicData')[0];
const uri = graphicData.getAttribute('uri');
type = exports.mapUriType[uri] ? exports.mapUriType[uri] : type;
break;
}
return type;
}
static parseShapeCoordinates(slideElementParent) {
const xFrmsA = slideElementParent.getElementsByTagName('a:xfrm');
const xFrmsP = slideElementParent.getElementsByTagName('p:xfrm');
const xFrms = xFrmsP.item(0) ? xFrmsP : xFrmsA;
const position = {
x: 0,
y: 0,
cx: 0,
cy: 0,
};
if (!xFrms.item(0)) {
return position;
}
const xFrm = xFrms.item(0);
const Off = xFrm.getElementsByTagName('a:off').item(0);
const Ext = xFrm.getElementsByTagName('a:ext').item(0);
position.x = XmlSlideHelper.parseCoordinate(Off, 'x');
position.y = XmlSlideHelper.parseCoordinate(Off, 'y');
position.cx = XmlSlideHelper.parseCoordinate(Ext, 'cx');
position.cy = XmlSlideHelper.parseCoordinate(Ext, 'cy');
return position;
}
/**
* Asynchronously retrieves the dimensions of a slide.
* Tries to find the dimensions from the slide XML, then from the layout, master, and presentation XMLs in order.
*
* @returns {Promise<{ width: number, height: number }>} The dimensions of the slide.
* @throws Error if unable to determine dimensions.
*/
getDimensions() {
return __awaiter(this, void 0, void 0, function* () {
try {
const dimensions = yield this.getAndExtractDimensions('ppt/presentation.xml');
if (dimensions)
return dimensions;
}
catch (error) {
console.error(`Error while fetching slide dimensions: ${error}`);
throw error;
}
});
}
}
exports.XmlSlideHelper = XmlSlideHelper;
XmlSlideHelper.parseCoordinate = (element, attributeName) => {
return parseInt(element.getAttribute(attributeName), 10);
};
//# sourceMappingURL=xml-slide-helper.js.map