UNPKG

pptx-automizer

Version:

A template based pptx generator

335 lines 13.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiTextHelper = void 0; const modify_text_helper_1 = __importDefault(require("./modify-text-helper")); const xml_helper_1 = require("./xml-helper"); const modify_hyperlink_element_1 = __importDefault(require("./modify-hyperlink-element")); class MultiTextHelper { constructor(element, relationElement) { this.element = element; this.document = element.ownerDocument; this.relationElement = relationElement; } /** * Apply multi-text paragraphs to the element */ run(paragraphs) { const txBody = this.getOrCreateTxBody(); const defaultStyle = this.extractDefaultStyle(txBody); this.clearExistingParagraphs(txBody); this.createParagraphs(txBody, paragraphs, defaultStyle); } /** * Extract default style from existing paragraphs */ extractDefaultStyle(txBody) { const defaultStyle = {}; const existingParagraphs = txBody.getElementsByTagName('a:p'); if (existingParagraphs.length === 0) { return defaultStyle; } // Try to get font size from the first text run const firstPara = existingParagraphs[0]; const firstRun = firstPara.getElementsByTagName('a:r')[0]; if (firstRun) { const rPr = firstRun.getElementsByTagName('a:rPr')[0]; if (rPr) { // Extract font size if it exists const fontSize = rPr.getAttribute('sz'); if (fontSize) { defaultStyle.size = parseInt(fontSize); } // Extract color if it exists const solidFill = rPr.getElementsByTagName('a:solidFill')[0]; if (solidFill) { const srgbClr = solidFill.getElementsByTagName('a:srgbClr')[0]; if (srgbClr) { const colorValue = srgbClr.getAttribute('val'); if (colorValue) { defaultStyle.color = { type: 'srgbClr', value: colorValue, }; } } } // Extract bold and italic if they exist const bold = rPr.getAttribute('b'); if (bold === '1') { defaultStyle.isBold = true; } const italic = rPr.getAttribute('i'); if (italic === '1') { defaultStyle.isItalics = true; } } } return defaultStyle; } /** * Find or create the txBody element and ensure it has required child elements */ getOrCreateTxBody() { let txBody = this.element.getElementsByTagName('p:txBody')[0]; if (!txBody) { txBody = this.document.createElement('p:txBody'); this.element.appendChild(txBody); // Create required bodyPr and lstStyle elements const bodyPr = this.document.createElement('a:bodyPr'); txBody.appendChild(bodyPr); const lstStyle = this.document.createElement('a:lstStyle'); txBody.appendChild(lstStyle); } return txBody; } /** * Remove all existing paragraph elements */ clearExistingParagraphs(txBody) { const existingParagraphs = txBody.getElementsByTagName('a:p'); const length = existingParagraphs.length; for (let i = length - 1; i >= 0; i--) { const paragraph = existingParagraphs[i]; paragraph.parentNode.removeChild(paragraph); } } /** * Create paragraph elements for each MultiTextParagraph */ createParagraphs(txBody, paragraphs, defaultStyle = {}) { paragraphs.forEach((para) => { const p = this.document.createElement('a:p'); txBody.appendChild(p); const pPr = this.document.createElement('a:pPr'); p.appendChild(pPr); if (para.paragraph) { this.applyParagraphProperties(pPr, para.paragraph); } if (para.textRuns && para.textRuns.length > 0) { this.createTextRuns(p, para.textRuns, defaultStyle); } else if (para.text !== undefined) { // Merge default style with provided style const mergedStyle = this.mergeStyles(defaultStyle, para.style); this.createSingleTextRun(p, para.text, mergedStyle); } }); } /** * Merge default style with provided style */ mergeStyles(defaultStyle = {}, customStyle = {}) { return Object.assign(Object.assign({}, defaultStyle), customStyle); } /** * Apply paragraph styling properties */ applyParagraphProperties(pPr, paragraphProps) { // Set bullet level if (paragraphProps.level !== undefined) { pPr.setAttribute('lvl', String(paragraphProps.level)); } // Set bullet configuration this.applyBulletConfiguration(pPr, paragraphProps); // Set alignment if (paragraphProps.alignment !== undefined) { pPr.setAttribute('algn', paragraphProps.alignment); } // Set custom indentation if (paragraphProps.indent !== undefined) { pPr.setAttribute('indent', String(paragraphProps.indent)); } // Set left margin if (paragraphProps.marginLeft !== undefined) { pPr.setAttribute('marL', String(paragraphProps.marginLeft)); } // Apply spacing properties this.applySpacingProperties(pPr, paragraphProps); } /** * Apply bullet configuration to paragraph properties */ applyBulletConfiguration(pPr, paragraphProps) { if (paragraphProps.bullet) { const buChar = this.document.createElement('a:buChar'); buChar.setAttribute('char', '•'); // Default bullet character pPr.appendChild(buChar); } else if (paragraphProps.level === 0 || paragraphProps.bullet === false) { const buNone = this.document.createElement('a:buNone'); pPr.appendChild(buNone); } } /** * Apply spacing properties to paragraph properties */ applySpacingProperties(pPr, paragraphProps) { // Set line spacing if (paragraphProps.lineSpacing !== undefined) { const lnSpc = this.document.createElement('a:lnSpc'); const spcPts = this.document.createElement('a:spcPts'); spcPts.setAttribute('val', String(Math.round(paragraphProps.lineSpacing * 100))); // Convert to 100ths of a point lnSpc.appendChild(spcPts); pPr.appendChild(lnSpc); } // Set space before paragraph if (paragraphProps.spaceBefore !== undefined) { const spcBef = this.document.createElement('a:spcBef'); const spcPts = this.document.createElement('a:spcPts'); spcPts.setAttribute('val', String(Math.round(paragraphProps.spaceBefore * 100))); // Convert to 100ths of a point spcBef.appendChild(spcPts); pPr.appendChild(spcBef); } // Set space after paragraph if (paragraphProps.spaceAfter !== undefined) { const spcAft = this.document.createElement('a:spcAft'); const spcPts = this.document.createElement('a:spcPts'); spcPts.setAttribute('val', String(Math.round(paragraphProps.spaceAfter * 100))); // Convert to 100ths of a point spcAft.appendChild(spcPts); pPr.appendChild(spcAft); } } /** * Create text runs for a paragraph */ createTextRuns(p, textRuns, defaultStyle = {}) { textRuns.forEach((run) => { const mergedStyle = this.mergeStyles(defaultStyle, run.style); // Check if this text run needs a hyperlink if ((mergedStyle === null || mergedStyle === void 0 ? void 0 : mergedStyle.hyperlink) && this.relationElement) { this.createHyperlinkTextRun(p, run.text || '', mergedStyle); } else { this.createRegularTextRun(p, run.text || '', mergedStyle); } }); } /** * Create a single text run with the given text and style */ createSingleTextRun(p, text, style) { const textString = String(text || ''); // Check if this text run needs a hyperlink if ((style === null || style === void 0 ? void 0 : style.hyperlink) && this.relationElement) { this.createHyperlinkTextRun(p, textString, style); } else { this.createRegularTextRun(p, textString, style); } } /** * Create a regular text run without hyperlink */ createRegularTextRun(p, text, style) { const r = this.document.createElement('a:r'); p.appendChild(r); const rPr = this.document.createElement('a:rPr'); r.appendChild(rPr); // Apply text styling (excluding hyperlink) if (style) { const styleWithoutHyperlink = Object.assign({}, style); delete styleWithoutHyperlink.hyperlink; modify_text_helper_1.default.style(styleWithoutHyperlink)(rPr); } this.createTextElement(r, text); } /** * Create a text element with the given content */ createTextElement(r, text) { const t = this.document.createElement('a:t'); r.appendChild(t); // Handle empty strings with xml:space="preserve" if (text === '') { t.setAttribute('xml:space', 'preserve'); } // Set text content const textNode = this.document.createTextNode(text); t.appendChild(textNode); } /** * Create a hyperlinked text run using HyperlinkElement */ createHyperlinkTextRun(p, text, style) { if (!style.hyperlink || !this.relationElement) { // Fallback to regular text run if no hyperlink info or relation element this.createRegularTextRun(p, text, style); return; } const hyperlinkInfo = style.hyperlink; const target = hyperlinkInfo.target; const isInternal = hyperlinkInfo.isInternal; if (!target) { this.createRegularTextRun(p, text, style); return; } // Create relationship data for the hyperlink const relData = this.createRelationshipData(target, isInternal || false); const newRelId = this.addRelationship(this.relationElement, relData); // Create HyperlinkElement to generate the hyperlinked text run const hyperlinkElement = new modify_hyperlink_element_1.default(this.document, newRelId, isInternal || false); // Create the text run with hyperlink const r = hyperlinkElement.createTextRun(text); // Apply additional styling if needed (excluding hyperlink) if (style) { const rPr = r.getElementsByTagName('a:rPr')[0]; if (rPr) { const styleWithoutHyperlink = Object.assign({}, style); delete styleWithoutHyperlink.hyperlink; modify_text_helper_1.default.style(styleWithoutHyperlink)(rPr); } } p.appendChild(r); } /** * Create relationship data for hyperlink (reused from ModifyHyperlinkHelper) */ createRelationshipData(target, isInternal) { if (isInternal) { return { Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', Target: `../slides/${this.formatTarget(target)}`, Id: '', // Will be set later }; } return { Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', Target: target.toString(), TargetMode: 'External', Id: '', // Will be set later }; } formatTarget(target) { // For internal links, ensure the target is properly formatted let formattedTarget = target; if (typeof target === 'number') { formattedTarget = `slide${target}.xml`; } else if (typeof target === 'string' && !target.includes('.xml')) { // If it's a string but doesn't end with .xml, assume it's a slide number formattedTarget = `slide${target}.xml`; } return formattedTarget; } /** * Add relationship to the relation element (reused logic from ModifyHyperlinkHelper) */ addRelationship(relation, relData) { const relNodes = relation.getElementsByTagName('Relationship'); const maxId = xml_helper_1.XmlHelper.getMaxId(relNodes, 'Id', true); const newRelId = `rId${maxId}`; const newRel = relation.ownerDocument.createElement('Relationship'); newRel.setAttribute('Id', newRelId); Object.entries(relData).forEach(([key, value]) => { if (value) newRel.setAttribute(key, value); }); relNodes.item(0).parentNode.appendChild(newRel); return newRelId; } } exports.MultiTextHelper = MultiTextHelper; //# sourceMappingURL=multitext-helper.js.map