gitbrent / PptxGenJS

Create PowerPoint presentations with a powerful, concise JavaScript API.
https://gitbrent.github.io/PptxGenJS/
MIT License
2.84k stars 625 forks source link

[FEATURE] Make `addText` remove unsupported Unicode characters #1240

Open AndreasNasman opened 1 year ago

AndreasNasman commented 1 year ago

We appreciate your feedback - to help the team understand your needs please complete the following template to ensure we have the details to help.

Submission Guidelines

Issue Category

Product Versions

Desired Behavior

It would be great if slide.addText removed or replaced unsupported Unicode characters in Powerpoint. This functionality could be enabled by default or a separate option to enable it could be implemented. A warning that unsupported Unicode characters were found in the added text would also be helpful.

For example, adding text containing a line tabulation character results in a broken PPT document.

import PptxGenJS from 'pptxgenjs';

const presentation = new PptxGenJS();
const slide = presentation.addSlide();

// Adding text containing a line tabulation character (\v) produces a broken PPT document.
slide.addText('Hello\vWorld!');
slide.addText([{ text: 'Hello\vWorld!' }]);

presentation.writeFile({ fileName: 'Sample Presentation.pptx' });
AndreasNasman commented 1 year ago

We encountered this problem at the company I work at and we made a temporary solution overwriting the behavior of addText:

function sanitizeText(text?: string) {
  if (!text) {
    return '';
  }

  // Vertical tabs has to be removed as Powerpoint cannot handle them.
  return text.replaceAll('\v', '');
}

// eslint-disable-next-line @typescript-eslint/unbound-method
const { addSlide: originalAddSlide } = PptxGenJS.prototype;
PptxGenJS.prototype.addSlide = function (arg: unknown) {
  const slide = originalAddSlide.apply(
    this,
    arg as Parameters<PptxGenJS['addSlide']>
  );

  const originalAddText = slide.addText.bind(slide);
  slide.addText = function (...args) {
    const text = args[0];
    let sanitizedText: typeof text = '';

    if (Array.isArray(text)) {
      sanitizedText = text.map((textProp) => ({
        ...textProp,
        text: sanitizeText(textProp.text),
      }));
    } else if (typeof text === 'string') {
      sanitizedText = sanitizeText(text);
    }

    args[0] = sanitizedText;
    return originalAddText(...args);
  };

  return slide;
};