nas/app/javascript/mastodon/selectors/contexts.ts
2025-04-28 13:38:40 +00:00

94 lines
2.2 KiB
TypeScript

import { createAppSelector } from 'mastodon/store';
export const getAncestorsIds = createAppSelector(
[(_, id: string) => id, (state) => state.contexts.inReplyTos],
(statusId, inReplyTos) => {
const ancestorsIds: string[] = [];
let currentId: string | undefined = statusId;
while (currentId && !ancestorsIds.includes(currentId)) {
ancestorsIds.unshift(currentId);
currentId = inReplyTos[currentId];
}
return ancestorsIds;
},
);
export const getDescendantsIds = createAppSelector(
[
(_, id: string) => id,
(state) => state.contexts.replies,
(state) => state.statuses,
],
(statusId, contextReplies, statuses) => {
const descendantsIds: string[] = [];
const visitIds = [statusId];
while (visitIds.length > 0) {
const id = visitIds.pop();
if (!id) {
break;
}
const replies = contextReplies[id];
if (statusId !== id) {
descendantsIds.push(id);
}
if (replies) {
replies.reverse().forEach((replyId) => {
if (
!visitIds.includes(replyId) &&
!descendantsIds.includes(replyId) &&
statusId !== replyId
) {
visitIds.push(replyId);
}
});
}
}
let insertAt = descendantsIds.findIndex((id) => {
const status = statuses.get(id);
if (!status) {
return false;
}
const inReplyToAccountId = status.get('in_reply_to_account_id') as
| string
| null;
const accountId = status.get('account') as string;
return inReplyToAccountId !== accountId;
});
if (insertAt !== -1) {
descendantsIds.forEach((id, idx) => {
const status = statuses.get(id);
if (!status) {
return;
}
const inReplyToAccountId = status.get('in_reply_to_account_id') as
| string
| null;
const accountId = status.get('account') as string;
if (idx > insertAt && inReplyToAccountId === accountId) {
descendantsIds.splice(idx, 1);
descendantsIds.splice(insertAt, 0, id);
insertAt += 1;
}
});
}
return descendantsIds;
},
);