Files
docx-js/src/patcher/paragraph-token-replacer.ts

65 lines
2.3 KiB
TypeScript
Raw Normal View History

2023-02-23 19:43:19 +00:00
import { Element } from "xml-js";
2023-02-24 01:05:43 +00:00
import { createTextElementContents } from "./util";
2023-02-23 19:43:19 +00:00
import { IRenderedParagraphNode } from "./run-renderer";
enum ReplaceMode {
START,
MIDDLE,
END,
}
export const replaceTokenInParagraphElement = ({
paragraphElement,
renderedParagraph,
originalText,
replacementText,
}: {
readonly paragraphElement: Element;
readonly renderedParagraph: IRenderedParagraphNode;
readonly originalText: string;
readonly replacementText: string;
}): Element => {
const startIndex = renderedParagraph.text.indexOf(originalText);
const endIndex = startIndex + originalText.length - 1;
let replaceMode = ReplaceMode.START;
for (const run of renderedParagraph.runs) {
for (const { text, index, start, end } of run.parts) {
switch (replaceMode) {
case ReplaceMode.START:
if (startIndex >= start) {
const partToReplace = run.text.substring(Math.max(startIndex, start), Math.min(endIndex, end) + 1);
// We use a token to split the text if the replacement is within the same run
// If not, we just add text to the middle of the run later
const firstPart = text.replace(partToReplace, replacementText);
patchTextElement(paragraphElement.elements![run.index].elements![index], firstPart);
replaceMode = ReplaceMode.MIDDLE;
continue;
}
break;
case ReplaceMode.MIDDLE:
if (endIndex <= end) {
const lastPart = text.substring(endIndex - start + 1);
patchTextElement(paragraphElement.elements![run.index].elements![index], lastPart);
replaceMode = ReplaceMode.END;
} else {
patchTextElement(paragraphElement.elements![run.index].elements![index], "");
}
break;
default:
}
}
}
return paragraphElement;
};
const patchTextElement = (element: Element, text: string): Element => {
// eslint-disable-next-line functional/immutable-data
2023-02-24 01:05:43 +00:00
element.elements = createTextElementContents(text);
2023-02-23 19:43:19 +00:00
return element;
};