singerla / pptx-automizer

A template based pptx generator for Node.js
MIT License
68 stars 12 forks source link

[Question] Getting element's text. #83

Closed dloaizarico closed 9 months ago

dloaizarico commented 11 months ago

Hi.

First of all, thanks a lot for the library, I think it's really good.

I wonder if you guys know a way of getting the current text of an element?

For example:

This is a callback fnt for editing existing slides:

const updateSlide = async (slide) => { const elements = await slide.getAllTextElementIds(); elements.forEach((element, index) => { console.log(index); if (index === 4) { slide.modifyElement(element, [ModifyTextHelper.setText("My content")]); } }); };

I need to get the element text and compare if it's equal to something, I will need to update that text, at the moment, I am only able to edit existing elements but I can't find a way to validate which of the elements in the slide is the one that I need to update.

Unfortunately, I cannot use replace because my original files do not have the {{}}

Thanks a lot.

MP70 commented 11 months ago

You can do this, although won't work if the "find" text is spread across elements. Best to edit your pres to include a tag if possible

        await slide.modifyElement(
          elementId,
          modify.replaceText(replacements, {
            openingTag: "",
            closingTag: "",
          }),

Otherwise you'll need to do it manually like

      const textElements = element.getElementsByTagName('a:r');

etc.

singerla commented 11 months ago

Hi! I was playing around a bit. Just like @MP70 proposed, you would need to extract elements. element.getElementsByTagName('a:r') will be retrieve formatting and language settings as well, eleXml.getElementsByTagName('a:t') returns only text.

const automizer = new Automizer({
    templateDir: `${__dirname}/../__tests__/pptx-templates`,
    outputDir: `${__dirname}/../__tests__/pptx-output`,
    removeExistingSlides: true,
  });

  // This is taken from pptx-automizer examples
  let pres = automizer
    .loadRoot(`RootTemplate.pptx`)
    .load(`TextReplace.pptx`, 'TextReplace');

  // Create your own modifier:
  const parseTextNodesCallback = (eleXml: XmlElement) => {
    const textElements = eleXml.getElementsByTagName('a:t');
    const textStrings: string[] = [];
    XmlHelper.modifyCollection(textElements, (textXml) => {
      textStrings.push(textXml.firstChild.textContent);
      // You can apply changes to xml here, too.
    });
    // The output can be segmented
    console.log(textStrings);
  };

  pres.addSlide('TextReplace', 1, async (slide) => {
    const textElements = await slide.getAllTextElementIds();
    textElements.forEach((elementName) => {
      slide.modifyElement(elementName, [
        XmlHelper.dump, // Let's take a look inside the mess
        parseTextNodesCallback, // apply the custom modifier callback
      ]);
    });
  });

  pres.write(`myOutputPresentation.pptx`).then((summary) => {
    console.log(summary);
  });

It will result to something like:

[
  'This',
  ' is test',
  ' ',
  'content',
  '. It will be completely replaced by ',
  'setText',
  '.'
]

I guess this will be a useful little modifier!

Please notice also #82 to see the caveats.

MP70 commented 11 months ago

Sorry! Yes, I modify styling in mine too - I didn't rob enough lines to show text only. Incase it's useful;

      const textElements = element.getElementsByTagName('a:r');
      Array.from(textElements).forEach(textElement => {
        const textContentElements = textElement.getElementsByTagName('a:t');
        const attrsElements = textElement.getElementsByTagName('a:rPr');