| 77 | } |
| 78 | |
| 79 | export function processTitleString(titleString: string): React.ReactNode[] { |
| 80 | if (titleString == null) { |
| 81 | return null; |
| 82 | } |
| 83 | const tagRegex = /<(\/)?([a-z]+)(?::([#a-z0-9@-]+))?>/g; |
| 84 | let lastIdx = 0; |
| 85 | let match; |
| 86 | const partsStack = [[]]; |
| 87 | while ((match = tagRegex.exec(titleString)) != null) { |
| 88 | const lastPart = partsStack[partsStack.length - 1]; |
| 89 | const before = titleString.substring(lastIdx, match.index); |
| 90 | lastPart.push(before); |
| 91 | lastIdx = match.index + match[0].length; |
| 92 | const [_, isClosing, tagName, tagParam] = match; |
| 93 | if (tagName == "icon" && !isClosing) { |
| 94 | if (tagParam == null) { |
| 95 | continue; |
| 96 | } |
| 97 | const iconClass = util.makeIconClass(tagParam, false); |
| 98 | if (iconClass == null) { |
| 99 | continue; |
| 100 | } |
| 101 | lastPart.push(<i key={match.index} className={iconClass} />); |
| 102 | continue; |
| 103 | } |
| 104 | if (tagName == "c" || tagName == "color") { |
| 105 | if (isClosing) { |
| 106 | if (partsStack.length <= 1) { |
| 107 | continue; |
| 108 | } |
| 109 | partsStack.pop(); |
| 110 | continue; |
| 111 | } |
| 112 | if (tagParam == null) { |
| 113 | continue; |
| 114 | } |
| 115 | if (!tagParam.match(colorRegex)) { |
| 116 | continue; |
| 117 | } |
| 118 | const children = []; |
| 119 | const rtag = React.createElement("span", { key: match.index, style: { color: tagParam } }, children); |
| 120 | lastPart.push(rtag); |
| 121 | partsStack.push(children); |
| 122 | continue; |
| 123 | } |
| 124 | if (tagName == "i" || tagName == "b") { |
| 125 | if (isClosing) { |
| 126 | if (partsStack.length <= 1) { |
| 127 | continue; |
| 128 | } |
| 129 | partsStack.pop(); |
| 130 | continue; |
| 131 | } |
| 132 | const children = []; |
| 133 | const rtag = React.createElement(tagName, { key: match.index }, children); |
| 134 | lastPart.push(rtag); |
| 135 | partsStack.push(children); |
| 136 | continue; |