81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
|
import React, { useEffect, useRef } from 'react';
|
||
|
import { useHistory } from 'react-router-dom';
|
||
|
|
||
|
import type { Announcement as AnnouncementEntity, Mention as MentionEntity } from 'soapbox/types/entities';
|
||
|
|
||
|
interface IAnnouncementContent {
|
||
|
announcement: AnnouncementEntity;
|
||
|
}
|
||
|
|
||
|
const AnnouncementContent: React.FC<IAnnouncementContent> = ({ announcement }) => {
|
||
|
const history = useHistory();
|
||
|
|
||
|
const node = useRef<HTMLDivElement>(null);
|
||
|
|
||
|
useEffect(() => {
|
||
|
updateLinks();
|
||
|
});
|
||
|
|
||
|
const onMentionClick = (mention: MentionEntity, e: MouseEvent) => {
|
||
|
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||
|
e.preventDefault();
|
||
|
e.stopPropagation();
|
||
|
history.push(`/@${mention.acct}`);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const onHashtagClick = (hashtag: string, e: MouseEvent) => {
|
||
|
hashtag = hashtag.replace(/^#/, '').toLowerCase();
|
||
|
|
||
|
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||
|
e.preventDefault();
|
||
|
e.stopPropagation();
|
||
|
history.push(`/tags/${hashtag}`);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** For regular links, just stop propogation */
|
||
|
const onLinkClick = (e: MouseEvent) => {
|
||
|
e.stopPropagation();
|
||
|
};
|
||
|
|
||
|
const updateLinks = () => {
|
||
|
if (!node.current) return;
|
||
|
|
||
|
const links = node.current.querySelectorAll('a');
|
||
|
|
||
|
links.forEach(link => {
|
||
|
// Skip already processed
|
||
|
if (link.classList.contains('status-link')) return;
|
||
|
|
||
|
// Add attributes
|
||
|
link.classList.add('status-link');
|
||
|
link.setAttribute('rel', 'nofollow noopener');
|
||
|
link.setAttribute('target', '_blank');
|
||
|
|
||
|
const mention = announcement.mentions.find(mention => link.href === `${mention.url}`);
|
||
|
|
||
|
// Add event listeners on mentions and hashtags
|
||
|
if (mention) {
|
||
|
link.addEventListener('click', onMentionClick.bind(link, mention), false);
|
||
|
link.setAttribute('title', mention.acct);
|
||
|
} else if (link.textContent?.charAt(0) === '#' || (link.previousSibling?.textContent?.charAt(link.previousSibling.textContent.length - 1) === '#')) {
|
||
|
link.addEventListener('click', onHashtagClick.bind(link, link.text), false);
|
||
|
} else {
|
||
|
link.setAttribute('title', link.href);
|
||
|
link.addEventListener('click', onLinkClick.bind(link), false);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
return (
|
||
|
<div
|
||
|
className='translate text-sm'
|
||
|
ref={node}
|
||
|
dangerouslySetInnerHTML={{ __html: announcement.contentHtml }}
|
||
|
/>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default AnnouncementContent;
|