120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
import UrlKnife from 'url-knife';
|
|
import {Settings, settings} from "../settings";
|
|
import {renderMarkdownAsBBCode} from "../text/markdown";
|
|
import {escapeBBCode} from "../text/bbcode";
|
|
import {parse as parseBBCode} from "vendor/xbbcode/parser";
|
|
import {TagElement} from "vendor/xbbcode/elements";
|
|
import {regexImage} from "tc-shared/text/bbcode/image";
|
|
|
|
interface UrlKnifeUrl {
|
|
value: {
|
|
url: string,
|
|
},
|
|
area: string,
|
|
index: {
|
|
start: number,
|
|
end: number
|
|
}
|
|
}
|
|
|
|
function bbcodeLinkUrls(message: string, ignore: { start: number, end: number }[]) : string {
|
|
const urls: UrlKnifeUrl[] = UrlKnife.TextArea.extractAllUrls(message, {
|
|
'ip_v4' : true,
|
|
'ip_v6' : false,
|
|
'localhost' : false,
|
|
'intranet' : true
|
|
});
|
|
|
|
/* we want to go through the urls from the back to the front */
|
|
urls.sort((a, b) => b.index.start - a.index.start);
|
|
outerLoop:
|
|
for(const url of urls) {
|
|
if(ignore.findIndex(range => range.start <= url.index.start && range.end >= url.index.end) !== -1) {
|
|
continue;
|
|
}
|
|
|
|
const prefix = message.substr(0, url.index.start);
|
|
const suffix = message.substr(url.index.end);
|
|
const urlPath = message.substring(url.index.start, url.index.end);
|
|
let bbcodeUrl;
|
|
|
|
regexImage.lastIndex = 0;
|
|
if (regexImage.test(urlPath)) {
|
|
for(const suffix of [
|
|
".jpeg", ".jpg",
|
|
".png", ".gif", ".tiff",
|
|
".bmp",
|
|
".webp",
|
|
".svg"
|
|
]) {
|
|
if(urlPath.endsWith(suffix)) {
|
|
/* It's an image. Images will be rendered by the client automatically. */
|
|
continue outerLoop;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
let colonIndex = urlPath.indexOf(":");
|
|
if(colonIndex === -1 || colonIndex + 2 >= urlPath.length || urlPath[colonIndex + 1] !== "/" || urlPath[colonIndex + 2] !== "/") {
|
|
bbcodeUrl = "[url=https://" + urlPath + "]" + urlPath + "[/url]";
|
|
} else {
|
|
bbcodeUrl = "[url]" + urlPath + "[/url]";
|
|
}
|
|
|
|
message = prefix + bbcodeUrl + suffix;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
export function preprocessChatMessageForSend(message: string) : string {
|
|
const parseMarkdown = settings.getValue(Settings.KEY_CHAT_ENABLE_MARKDOWN);
|
|
const escapeBBCodes = !settings.getValue(Settings.KEY_CHAT_ENABLE_BBCODE);
|
|
|
|
if(parseMarkdown) {
|
|
message = renderMarkdownAsBBCode(message, text => escapeBBCodes ? escapeBBCode(text) : text);
|
|
} else if(escapeBBCodes) {
|
|
message = escapeBBCode(message);
|
|
}
|
|
|
|
if(settings.getValue(Settings.KEY_CHAT_TAG_URLS)) {
|
|
const bbcodeElements = parseBBCode(message, {});
|
|
const noParseRanges: { start: number, end: number }[] = [];
|
|
|
|
while(true) {
|
|
const element = bbcodeElements.pop();
|
|
if(!element) {
|
|
break;
|
|
}
|
|
|
|
if(!(element instanceof TagElement)) {
|
|
continue;
|
|
}
|
|
|
|
switch(element.tagType?.tag) {
|
|
case "code":
|
|
case "i-code":
|
|
case "url":
|
|
case "img":
|
|
case "no-parse":
|
|
case "youtube":
|
|
case "quote":
|
|
noParseRanges.push(element.textPosition);
|
|
break;
|
|
|
|
default:
|
|
bbcodeElements.push(...element.content);
|
|
break;
|
|
}
|
|
}
|
|
|
|
message = bbcodeLinkUrls(message, noParseRanges);
|
|
}
|
|
|
|
while(message.endsWith("\n")) {
|
|
message = message.substring(0, message.length - 1);
|
|
}
|
|
|
|
return message;
|
|
} |