2020-10-20 19:10:02 +02:00
|
|
|
// @flow
|
2021-04-25 05:27:59 +02:00
|
|
|
import { KNOWN_APP_DOMAINS } from 'config';
|
2020-10-20 19:10:02 +02:00
|
|
|
import * as ICONS from 'constants/icons';
|
|
|
|
import * as React from 'react';
|
2021-10-17 10:36:14 +02:00
|
|
|
import { isURIValid } from 'util/lbryURI';
|
2020-10-20 19:10:02 +02:00
|
|
|
import Button from 'component/button';
|
|
|
|
import ClaimLink from 'component/claimLink';
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
href: string,
|
|
|
|
title?: string,
|
|
|
|
embed?: boolean,
|
2021-03-09 10:33:42 +01:00
|
|
|
allowPreview?: boolean,
|
2020-10-20 19:10:02 +02:00
|
|
|
children: React.Node,
|
|
|
|
parentCommentId?: string,
|
|
|
|
isMarkdownPost?: boolean,
|
2020-10-22 20:16:42 +02:00
|
|
|
simpleLinks?: boolean,
|
2021-12-29 21:04:02 +01:00
|
|
|
myChannelUrls: ?Array<string>,
|
|
|
|
setUserMention?: (boolean) => void,
|
2020-10-20 19:10:02 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
function MarkdownLink(props: Props) {
|
2021-03-09 10:33:42 +01:00
|
|
|
const {
|
|
|
|
children,
|
|
|
|
href,
|
|
|
|
title,
|
|
|
|
embed = false,
|
|
|
|
allowPreview = false,
|
|
|
|
parentCommentId,
|
|
|
|
isMarkdownPost,
|
|
|
|
simpleLinks = false,
|
2021-12-29 21:04:02 +01:00
|
|
|
myChannelUrls,
|
|
|
|
setUserMention,
|
2021-03-09 10:33:42 +01:00
|
|
|
} = props;
|
2020-11-04 20:18:45 +01:00
|
|
|
|
2020-11-19 21:24:58 +01:00
|
|
|
let decodedUri;
|
|
|
|
try {
|
|
|
|
decodedUri = decodeURI(href);
|
|
|
|
} catch (e) {}
|
|
|
|
|
2020-10-22 20:06:28 +02:00
|
|
|
let element = <span>{children}</span>;
|
|
|
|
|
2020-10-20 19:10:02 +02:00
|
|
|
// Regex for url protocol
|
|
|
|
const protocolRegex = new RegExp('^(https?|lbry|mailto)+:', 'i');
|
|
|
|
const protocol = href ? protocolRegex.exec(href) : null;
|
2021-12-30 22:08:34 +01:00
|
|
|
const isMention = href && href.startsWith('lbry://@');
|
2021-12-29 21:04:02 +01:00
|
|
|
const mentionedMyChannel =
|
|
|
|
isMention && (myChannelUrls ? myChannelUrls.some((url) => url.replace('#', ':') === href) : false);
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
if (mentionedMyChannel && setUserMention) setUserMention(true);
|
|
|
|
}, [mentionedMyChannel, setUserMention]);
|
|
|
|
|
|
|
|
if (!href || !decodedUri) return children || null;
|
2020-10-22 20:06:28 +02:00
|
|
|
|
2020-10-23 00:09:17 +02:00
|
|
|
let linkUrlObject;
|
|
|
|
try {
|
|
|
|
linkUrlObject = new URL(decodedUri);
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
let lbryUrlFromLink;
|
2020-12-10 09:25:29 +01:00
|
|
|
if (linkUrlObject && !href.startsWith('mailto:')) {
|
2020-10-22 20:06:28 +02:00
|
|
|
const linkDomain = linkUrlObject.host;
|
|
|
|
const isKnownAppDomainLink = KNOWN_APP_DOMAINS.includes(linkDomain);
|
|
|
|
if (isKnownAppDomainLink) {
|
2020-11-04 20:18:45 +01:00
|
|
|
let linkPathname;
|
|
|
|
try {
|
|
|
|
// This could be anything
|
|
|
|
linkPathname = decodeURIComponent(
|
|
|
|
linkUrlObject.pathname.startsWith('//') ? linkUrlObject.pathname.slice(2) : linkUrlObject.pathname.slice(1)
|
|
|
|
);
|
|
|
|
} catch (e) {}
|
2020-10-23 19:14:12 +02:00
|
|
|
|
2020-11-04 20:18:45 +01:00
|
|
|
const linkPathPlusHash = linkPathname ? `${linkPathname}${linkUrlObject.hash}` : undefined;
|
|
|
|
const possibleLbryUrl = linkPathPlusHash ? `lbry://${linkPathPlusHash.replace(/:/g, '#')}` : undefined;
|
2020-10-23 19:14:12 +02:00
|
|
|
|
2020-11-04 20:18:45 +01:00
|
|
|
const lbryLinkIsValid = possibleLbryUrl && isURIValid(possibleLbryUrl);
|
2021-03-13 15:00:39 +01:00
|
|
|
const isMarkdownLinkWithLabel =
|
|
|
|
children && Array.isArray(children) && React.Children.count(children) === 1 && children.toString() !== href;
|
|
|
|
|
|
|
|
if (lbryLinkIsValid && !isMarkdownLinkWithLabel) {
|
2020-10-22 20:06:28 +02:00
|
|
|
lbryUrlFromLink = possibleLbryUrl;
|
|
|
|
}
|
2020-10-20 19:10:02 +02:00
|
|
|
}
|
2020-10-23 00:09:17 +02:00
|
|
|
}
|
2020-10-20 19:10:02 +02:00
|
|
|
|
2021-03-09 10:33:42 +01:00
|
|
|
// Return timestamp link if it starts with '?t=' (only possible from remark-timestamp).
|
|
|
|
// Return plain text if no valid url.
|
|
|
|
// Return external link if protocol is http or https.
|
|
|
|
// Return local link if protocol is lbry uri.
|
2020-12-15 08:15:02 +01:00
|
|
|
if (href.startsWith('?t=')) {
|
|
|
|
// Video timestamp markers
|
|
|
|
element = (
|
|
|
|
<Button
|
|
|
|
button="link"
|
|
|
|
iconRight={undefined}
|
|
|
|
title={title || decodedUri}
|
|
|
|
label={children}
|
|
|
|
className="button--external-link"
|
|
|
|
onClick={() => {
|
|
|
|
if (window.player) {
|
|
|
|
window.player.currentTime(parseInt(href.substr(3)));
|
|
|
|
window.scrollTo(0, 0);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} else if (!simpleLinks && ((protocol && protocol[0] === 'lbry:' && isURIValid(decodedUri)) || lbryUrlFromLink)) {
|
2021-04-25 05:27:59 +02:00
|
|
|
element = (
|
2020-10-20 19:10:02 +02:00
|
|
|
<ClaimLink
|
|
|
|
uri={lbryUrlFromLink || decodedUri}
|
|
|
|
autoEmbed={embed}
|
|
|
|
parentCommentId={parentCommentId}
|
|
|
|
isMarkdownPost={isMarkdownPost}
|
2021-04-25 05:27:59 +02:00
|
|
|
allowPreview={allowPreview}
|
2020-10-20 19:10:02 +02:00
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</ClaimLink>
|
|
|
|
);
|
2020-10-22 20:16:42 +02:00
|
|
|
} else if (
|
|
|
|
simpleLinks ||
|
|
|
|
(protocol && (protocol[0] === 'http:' || protocol[0] === 'https:' || protocol[0] === 'mailto:'))
|
|
|
|
) {
|
2021-04-25 05:27:59 +02:00
|
|
|
const isLbryLink = href.startsWith('lbry://');
|
|
|
|
|
2020-10-20 19:10:02 +02:00
|
|
|
element = (
|
|
|
|
<Button
|
|
|
|
button="link"
|
2020-10-22 20:30:40 +02:00
|
|
|
iconRight={isLbryLink ? undefined : ICONS.EXTERNAL}
|
2020-10-20 19:10:02 +02:00
|
|
|
title={title || decodedUri}
|
|
|
|
label={children}
|
|
|
|
className="button--external-link"
|
2020-10-22 20:30:40 +02:00
|
|
|
navigate={isLbryLink ? href : undefined}
|
2020-11-04 20:18:45 +01:00
|
|
|
href={isLbryLink ? undefined : href}
|
2020-10-20 19:10:02 +02:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return <>{element}</>;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default MarkdownLink;
|