mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix: include manual post-number quotes in reply backlinks
Backlink map generation now merges protocol-level quotedCids with parsed >>number references from reply content. Manual quotes are resolved through numberToCid from usePostNumberStore and deduplicated using Set. Centralized QUOTE_NUMBER_REGEX in url-utils to keep markdown conversion and backlink detection aligned.
This commit is contained in:
@@ -8,7 +8,7 @@ import styles from '../../views/post/post.module.css';
|
||||
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isValidURL, QUOTE_NUMBER_REGEX } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { formatUserIDForDisplay } from '../../lib/utils/string-utils';
|
||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||
@@ -620,6 +620,7 @@ const PostDesktop = ({
|
||||
|
||||
const { replies, hasMore, loadMore } = useReplies({ comment: post, flat: true, accountComments: { newerThan: Infinity } });
|
||||
const registerComments = usePostNumberStore((s) => s.registerComments);
|
||||
const numberToCid = usePostNumberStore((s) => s.numberToCid);
|
||||
const prevCidsRef = useRef<string>('');
|
||||
useEffect(() => {
|
||||
const all = post ? [post, ...(replies || [])] : replies || [];
|
||||
@@ -653,17 +654,32 @@ const PostDesktop = ({
|
||||
const quotedByMap = useMemo(() => {
|
||||
const map = new Map<string, Comment[]>();
|
||||
for (const reply of filteredReplies) {
|
||||
const quotedCids = reply.quotedCids;
|
||||
if (quotedCids?.length) {
|
||||
for (const quotedCid of quotedCids) {
|
||||
const arr = map.get(quotedCid);
|
||||
if (arr) arr.push(reply);
|
||||
else map.set(quotedCid, [reply]);
|
||||
const cidSet = new Set<string>();
|
||||
|
||||
if (reply.quotedCids?.length) {
|
||||
for (const quotedCid of reply.quotedCids) {
|
||||
cidSet.add(quotedCid);
|
||||
}
|
||||
}
|
||||
|
||||
if (reply.content) {
|
||||
for (const match of reply.content.matchAll(QUOTE_NUMBER_REGEX)) {
|
||||
const postNumber = parseInt(match[1], 10);
|
||||
const quotedCid = numberToCid[postNumber];
|
||||
if (quotedCid) {
|
||||
cidSet.add(quotedCid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const quotedCid of cidSet) {
|
||||
const arr = map.get(quotedCid);
|
||||
if (arr) arr.push(reply);
|
||||
else map.set(quotedCid, [reply]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}, [filteredReplies]);
|
||||
}, [filteredReplies, numberToCid]);
|
||||
|
||||
// Virtuoso scroll position management for infinite replies
|
||||
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { shouldShowSnow } from '../../lib/snow';
|
||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { QUOTE_NUMBER_REGEX } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { formatUserIDForDisplay } from '../../lib/utils/string-utils';
|
||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||
@@ -465,6 +466,7 @@ const PostMobile = ({
|
||||
const linksCount = useCountLinksInReplies(post);
|
||||
const { replies, hasMore, loadMore } = useReplies({ comment: post, accountComments: { newerThan: Infinity } });
|
||||
const registerComments = usePostNumberStore((s) => s.registerComments);
|
||||
const numberToCid = usePostNumberStore((s) => s.numberToCid);
|
||||
const prevCidsRef = useRef<string>('');
|
||||
useEffect(() => {
|
||||
const all = post ? [post, ...(replies || [])] : replies || [];
|
||||
@@ -491,17 +493,32 @@ const PostMobile = ({
|
||||
const quotedByMap = useMemo(() => {
|
||||
const map = new Map<string, Comment[]>();
|
||||
for (const reply of filteredReplies) {
|
||||
const quotedCids = reply.quotedCids;
|
||||
if (quotedCids?.length) {
|
||||
for (const quotedCid of quotedCids) {
|
||||
const arr = map.get(quotedCid);
|
||||
if (arr) arr.push(reply);
|
||||
else map.set(quotedCid, [reply]);
|
||||
const cidSet = new Set<string>();
|
||||
|
||||
if (reply.quotedCids?.length) {
|
||||
for (const quotedCid of reply.quotedCids) {
|
||||
cidSet.add(quotedCid);
|
||||
}
|
||||
}
|
||||
|
||||
if (reply.content) {
|
||||
for (const match of reply.content.matchAll(QUOTE_NUMBER_REGEX)) {
|
||||
const postNumber = parseInt(match[1], 10);
|
||||
const quotedCid = numberToCid[postNumber];
|
||||
if (quotedCid) {
|
||||
cidSet.add(quotedCid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const quotedCid of cidSet) {
|
||||
const arr = map.get(quotedCid);
|
||||
if (arr) arr.push(reply);
|
||||
else map.set(quotedCid, [reply]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}, [filteredReplies]);
|
||||
}, [filteredReplies, numberToCid]);
|
||||
|
||||
// Virtuoso scroll position management for infinite replies
|
||||
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { copyToClipboard } from './clipboard-utils';
|
||||
|
||||
export const QUOTE_NUMBER_REGEX = /(?<![>/\w])>>(\d+)/g;
|
||||
|
||||
export const getHostname = (url: string) => {
|
||||
try {
|
||||
return new URL(url).hostname.replace(/^www\./, '');
|
||||
@@ -183,8 +185,7 @@ export const isValidCrossboardPattern = (pattern: string): boolean => {
|
||||
// Transform >>{number} post number patterns to markdown links with special anchor
|
||||
const preprocessPostNumberPatterns = (content: string): string => {
|
||||
// Match >> followed by digits, avoid overlap with greentext (>>>), cross-board (>>>/), URLs, CID-like patterns
|
||||
const pattern = /(?<![>/\w])>>(\d+)(?![\d/])/g;
|
||||
return content.replace(pattern, (_, num) => `[>>${num}](#q-${num})`);
|
||||
return content.replace(QUOTE_NUMBER_REGEX, (_, num) => `[>>${num}](#q-${num})`);
|
||||
};
|
||||
|
||||
// Preprocess content to convert plain text 5chan cross-board patterns to markdown links
|
||||
|
||||
Reference in New Issue
Block a user