|
| 1 | +import escapeRegex from "./escapeRegex.js"; |
| 2 | +// @ts-expect-error |
| 3 | +import encodeXML from "../sap/base/security/encodeXML.js"; |
| 4 | + |
| 5 | +/** |
| 6 | + * Generate markup for a raw string where the first match following StartsWithPerTerm pattern is wrapped with `<b>` tag. |
| 7 | + * StartsWithPerTerm pattern: finds the first word (at start or after whitespace) that starts with the search text. |
| 8 | + * All inputs to this function are considered literal text, and special characters will always be escaped. |
| 9 | + * @param {string} text The text to add highlighting to |
| 10 | + * @param {string} textToHighlight The text which should be highlighted (case-insensitive) |
| 11 | + * @return {string} the markup HTML which contains the first match surrounded with a `<b>` tag. |
| 12 | + */ |
| 13 | +function generateHighlightedMarkupFirstMatch(text: string, textToHighlight: string): string { |
| 14 | + const normalizedText = text || ""; |
| 15 | + |
| 16 | + if (!normalizedText || !textToHighlight) { |
| 17 | + return encodeXML(normalizedText) as string; |
| 18 | + } |
| 19 | + |
| 20 | + const filterValue = textToHighlight.toLowerCase(); |
| 21 | + const lowerText = normalizedText.toLowerCase(); |
| 22 | + const matchLength = textToHighlight.length; |
| 23 | + |
| 24 | + // Find the first word that starts with textToHighlight (StartsWithPerTerm pattern) |
| 25 | + let matchIndex = lowerText.search(new RegExp(`(^|\\s)${escapeRegex(filterValue)}`)); |
| 26 | + if (matchIndex !== -1 && lowerText[matchIndex] === " ") { |
| 27 | + matchIndex++; // Skip the space |
| 28 | + } |
| 29 | + |
| 30 | + // If no match found, return encoded text |
| 31 | + if (matchIndex === -1) { |
| 32 | + return encodeXML(normalizedText) as string; |
| 33 | + } |
| 34 | + |
| 35 | + // Build highlighted markup with only the first match |
| 36 | + const beforeMatch = encodeXML(normalizedText.substring(0, matchIndex)) as string; |
| 37 | + const match = encodeXML(normalizedText.substring(matchIndex, matchIndex + matchLength)) as string; |
| 38 | + const afterMatch = encodeXML(normalizedText.substring(matchIndex + matchLength)) as string; |
| 39 | + |
| 40 | + return `${beforeMatch}<b>${match}</b>${afterMatch}`; |
| 41 | +} |
| 42 | + |
| 43 | +export default generateHighlightedMarkupFirstMatch; |
0 commit comments