Updated previews.
CI / test (3.11) (push) Failing after 24s
CI / test (3.10) (push) Failing after 13s
CI / test (3.12) (push) Failing after 25s
CI / lint (push) Failing after 25s
CI / test (3.9) (push) Failing after 25s
CI / build (push) Failing after 26s
CI / test (3.8) (push) Failing after 35s
CI / test (3.11) (push) Failing after 24s
CI / test (3.10) (push) Failing after 13s
CI / test (3.12) (push) Failing after 25s
CI / lint (push) Failing after 25s
CI / test (3.9) (push) Failing after 25s
CI / build (push) Failing after 26s
CI / test (3.8) (push) Failing after 35s
This commit is contained in:
+60
-1
@@ -100,6 +100,62 @@ function buildAvatarUrl(avatar) {
|
||||
return `/api/proxy-image?url=${encodeURIComponent(`https://avatars.devrant.com/${avatar.i}`)}`;
|
||||
}
|
||||
|
||||
function categorizeLinks(links) {
|
||||
if (!links || !Array.isArray(links)) {
|
||||
return { images: [], youtube: [], other: [] };
|
||||
}
|
||||
const images = [];
|
||||
const youtube = [];
|
||||
const other = [];
|
||||
for (const link of links) {
|
||||
if (!link.url) continue;
|
||||
if (isImageUrl(link.url)) {
|
||||
images.push(link);
|
||||
} else if (isYoutubeUrl(link.url)) {
|
||||
youtube.push(link);
|
||||
} else {
|
||||
other.push(link);
|
||||
}
|
||||
}
|
||||
return { images, youtube, other };
|
||||
}
|
||||
|
||||
function processTextWithLinks(text, links) {
|
||||
if (!text) return '';
|
||||
if (!links || !Array.isArray(links) || links.length === 0) {
|
||||
return escapeHtml(text);
|
||||
}
|
||||
const sortedLinks = [...links].sort((a, b) => b.start - a.start);
|
||||
let result = text;
|
||||
for (const link of sortedLinks) {
|
||||
if (typeof link.start !== 'number' || typeof link.end !== 'number') continue;
|
||||
if (link.start < 0 || link.end > result.length) continue;
|
||||
const before = result.substring(0, link.start);
|
||||
const linkText = result.substring(link.start, link.end);
|
||||
const after = result.substring(link.end);
|
||||
const safeUrl = sanitizeUrl(link.url);
|
||||
if (safeUrl) {
|
||||
const escapedText = escapeHtml(linkText);
|
||||
result = before + `<a href="${safeUrl}" target="_blank" rel="noopener noreferrer" class="inline-link">${escapedText}</a>` + after;
|
||||
}
|
||||
}
|
||||
const parts = result.split(/(<a[^>]*>.*?<\/a>)/g);
|
||||
return parts.map(part => {
|
||||
if (part.startsWith('<a ')) return part;
|
||||
return escapeHtml(part);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
export {
|
||||
extractUrls,
|
||||
isYoutubeUrl,
|
||||
@@ -116,5 +172,8 @@ export {
|
||||
makeAbsoluteUrl,
|
||||
isDevrantImageUrl,
|
||||
buildDevrantImageUrl,
|
||||
buildAvatarUrl
|
||||
buildAvatarUrl,
|
||||
categorizeLinks,
|
||||
processTextWithLinks,
|
||||
escapeHtml
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user