diff --git a/ui/component/claimLink/index.js b/ui/component/claimLink/index.js index 1da8ec075..39bd1e9f9 100644 --- a/ui/component/claimLink/index.js +++ b/ui/component/claimLink/index.js @@ -1,22 +1,32 @@ import { connect } from 'react-redux'; -import { doResolveUri, makeSelectTitleForUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux'; +import { doResolveUri, makeSelectClaimForUri, makeSelectIsUriResolving } from 'lbry-redux'; +import { doSetPlayingUri } from 'redux/actions/content'; import { selectBlackListedOutpoints } from 'lbryinc'; import { selectPlayingUri } from 'redux/selectors/content'; -import { doSetPlayingUri } from 'redux/actions/content'; import ClaimLink from './view'; const select = (state, props) => { + let uri = props.uri; + let claim; + + function getValidClaim(testUri) { + claim = makeSelectClaimForUri(testUri)(state); + if (claim === null) { + getValidClaim(testUri.substring(0, testUri.length - 1)); + } else { + uri = testUri; + } + } + getValidClaim(uri); + return { - uri: props.uri, - claim: makeSelectClaimForUri(props.uri)(state), - title: makeSelectTitleForUri(props.uri)(state), - isResolvingUri: makeSelectIsUriResolving(props.uri)(state), + uri, + claim, + fullUri: props.uri, + isResolvingUri: makeSelectIsUriResolving(uri)(state), blackListedOutpoints: selectBlackListedOutpoints(state), playingUri: selectPlayingUri(state), }; }; -export default connect(select, { - doResolveUri, - doSetPlayingUri, -})(ClaimLink); +export default connect(select, { doResolveUri, doSetPlayingUri })(ClaimLink); diff --git a/ui/component/claimLink/view.jsx b/ui/component/claimLink/view.jsx index f5e7ee69c..aae53873e 100644 --- a/ui/component/claimLink/view.jsx +++ b/ui/component/claimLink/view.jsx @@ -1,14 +1,15 @@ // @flow -import * as React from 'react'; -import classnames from 'classnames'; -import EmbedPlayButton from 'component/embedPlayButton'; -import Button from 'component/button'; -import UriIndicator from 'component/uriIndicator'; import { INLINE_PLAYER_WRAPPER_CLASS } from 'component/fileRenderFloating/view'; import { SIMPLE_SITE } from 'config'; +import * as React from 'react'; +import Button from 'component/button'; +import classnames from 'classnames'; +import EmbedPlayButton from 'component/embedPlayButton'; +import UriIndicator from 'component/uriIndicator'; type Props = { uri: string, + fullUri: string, claim: StreamClaim, children: React.Node, description: ?string, @@ -68,6 +69,7 @@ class ClaimLink extends React.Component { render() { const { uri, + fullUri, claim, children, isResolvingUri, @@ -92,7 +94,10 @@ class ClaimLink extends React.Component { const isChannel = valueType === 'channel'; return isChannel ? ( - + <> + + {fullUri.length > uri.length ? fullUri.substring(uri.length, fullUri.length) : ''} + ) : allowPreview ? (
= 0 - ? commentValue.indexOf(' ', selectedMentionIndex) + modifierIndex >= 0 && (spaceIndex === -1 || modifierIndex < spaceIndex) + ? modifierIndex + : spaceIndex >= 0 && (modifierIndex === -1 || spaceIndex < modifierIndex) + ? spaceIndex : commentValue.length; const channelMention = selectedMentionIndex >= 0 && selectionIndex <= mentionLengthIndex diff --git a/ui/util/remark-lbry.js b/ui/util/remark-lbry.js index 2a2fb1483..fc8bb17e6 100644 --- a/ui/util/remark-lbry.js +++ b/ui/util/remark-lbry.js @@ -3,6 +3,7 @@ import visit from 'unist-util-visit'; const protocol = 'lbry://'; const uriRegex = /(lbry:\/\/)[^\s"]*[^)]/g; +const punctuationMarks = [',', '.', '!', '?', ':', ';', '-', ']', ')', '}']; const mentionToken = '@'; // const mentionTokenCode = 64; // @ @@ -10,9 +11,24 @@ const mentionRegex = /@[^\s()"]*/gm; const invalidRegex = /[-_.+=?!@#$%^&*:;,{}<>\w/\\]/; +function handlePunctuation(value) { + const modifierIndex = + (value.indexOf(':') >= 0 && value.indexOf(':')) || (value.indexOf('#') >= 0 && value.indexOf('#')); + + let punctuationIndex; + punctuationMarks.some((p) => { + if (modifierIndex) { + punctuationIndex = value.indexOf(p, modifierIndex + 1) >= 0 && value.indexOf(p, modifierIndex + 1); + } + return punctuationIndex; + }); + + return punctuationIndex ? value.substring(0, punctuationIndex) : value; +} + // Find channel mention function locateMention(value, fromIndex) { - var index = value.indexOf(mentionToken, fromIndex); + const index = value.indexOf(mentionToken, fromIndex); // Skip invalid mention if (index > 0 && invalidRegex.test(value.charAt(index - 1))) { @@ -45,21 +61,22 @@ const createURI = (text, uri, embed = false) => ({ children: [{ type: 'text', value: text }], }); -const validateURI = (match, eat, self) => { +const validateURI = (match, eat) => { if (match) { try { const text = match[0]; - const uri = parseURI(text); + const newText = handlePunctuation(text); + const uri = parseURI(newText); const isValid = uri && uri.claimName; const isChannel = uri.isChannel && uri.path === uri.claimName; if (isValid) { // Create channel link if (isChannel) { - return eat(text)(createURI(uri.claimName, text, false)); + return eat(newText)(createURI(uri.claimName, newText, false)); } // Create claim link - return eat(text)(createURI(text, text, true)); + return eat(newText)(createURI(newText, newText, true)); } } catch (err) { // Silent errors: console.error(err) @@ -128,7 +145,7 @@ const visitor = (node, index, parent) => { }; // transform -const transform = tree => { +const transform = (tree) => { visit(tree, ['link'], visitor); };