Handle punctuation after mention

This commit is contained in:
saltrafael 2021-09-30 16:17:31 -03:00
parent 23a5aa2751
commit 7c35299207
No known key found for this signature in database
GPG key ID: 85B63D36CBFAB1E5
4 changed files with 60 additions and 24 deletions

View file

@ -1,22 +1,32 @@
import { connect } from 'react-redux'; 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 { selectBlackListedOutpoints } from 'lbryinc';
import { selectPlayingUri } from 'redux/selectors/content'; import { selectPlayingUri } from 'redux/selectors/content';
import { doSetPlayingUri } from 'redux/actions/content';
import ClaimLink from './view'; import ClaimLink from './view';
const select = (state, props) => { 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 { return {
uri: props.uri, uri,
claim: makeSelectClaimForUri(props.uri)(state), claim,
title: makeSelectTitleForUri(props.uri)(state), fullUri: props.uri,
isResolvingUri: makeSelectIsUriResolving(props.uri)(state), isResolvingUri: makeSelectIsUriResolving(uri)(state),
blackListedOutpoints: selectBlackListedOutpoints(state), blackListedOutpoints: selectBlackListedOutpoints(state),
playingUri: selectPlayingUri(state), playingUri: selectPlayingUri(state),
}; };
}; };
export default connect(select, { export default connect(select, { doResolveUri, doSetPlayingUri })(ClaimLink);
doResolveUri,
doSetPlayingUri,
})(ClaimLink);

View file

@ -1,14 +1,15 @@
// @flow // @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 { INLINE_PLAYER_WRAPPER_CLASS } from 'component/fileRenderFloating/view';
import { SIMPLE_SITE } from 'config'; 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 = { type Props = {
uri: string, uri: string,
fullUri: string,
claim: StreamClaim, claim: StreamClaim,
children: React.Node, children: React.Node,
description: ?string, description: ?string,
@ -68,6 +69,7 @@ class ClaimLink extends React.Component<Props> {
render() { render() {
const { const {
uri, uri,
fullUri,
claim, claim,
children, children,
isResolvingUri, isResolvingUri,
@ -92,7 +94,10 @@ class ClaimLink extends React.Component<Props> {
const isChannel = valueType === 'channel'; const isChannel = valueType === 'channel';
return isChannel ? ( return isChannel ? (
<>
<UriIndicator uri={uri} link /> <UriIndicator uri={uri} link />
<span>{fullUri.length > uri.length ? fullUri.substring(uri.length, fullUri.length) : ''}</span>
</>
) : allowPreview ? ( ) : allowPreview ? (
<div className={classnames('claim-link')}> <div className={classnames('claim-link')}>
<div <div

View file

@ -111,9 +111,13 @@ export function CommentCreate(props: Props) {
commentValue.indexOf('@', selectionIndex) === selectionIndex commentValue.indexOf('@', selectionIndex) === selectionIndex
? commentValue.indexOf('@', selectionIndex) ? commentValue.indexOf('@', selectionIndex)
: commentValue.lastIndexOf('@', selectionIndex); : commentValue.lastIndexOf('@', selectionIndex);
const modifierIndex = commentValue.indexOf(':', selectedMentionIndex);
const spaceIndex = commentValue.indexOf(' ', selectedMentionIndex);
const mentionLengthIndex = const mentionLengthIndex =
commentValue.indexOf(' ', selectedMentionIndex) >= 0 modifierIndex >= 0 && (spaceIndex === -1 || modifierIndex < spaceIndex)
? commentValue.indexOf(' ', selectedMentionIndex) ? modifierIndex
: spaceIndex >= 0 && (modifierIndex === -1 || spaceIndex < modifierIndex)
? spaceIndex
: commentValue.length; : commentValue.length;
const channelMention = const channelMention =
selectedMentionIndex >= 0 && selectionIndex <= mentionLengthIndex selectedMentionIndex >= 0 && selectionIndex <= mentionLengthIndex

View file

@ -3,6 +3,7 @@ import visit from 'unist-util-visit';
const protocol = 'lbry://'; const protocol = 'lbry://';
const uriRegex = /(lbry:\/\/)[^\s"]*[^)]/g; const uriRegex = /(lbry:\/\/)[^\s"]*[^)]/g;
const punctuationMarks = [',', '.', '!', '?', ':', ';', '-', ']', ')', '}'];
const mentionToken = '@'; const mentionToken = '@';
// const mentionTokenCode = 64; // @ // const mentionTokenCode = 64; // @
@ -10,9 +11,24 @@ const mentionRegex = /@[^\s()"]*/gm;
const invalidRegex = /[-_.+=?!@#$%^&*:;,{}<>\w/\\]/; 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 // Find channel mention
function locateMention(value, fromIndex) { function locateMention(value, fromIndex) {
var index = value.indexOf(mentionToken, fromIndex); const index = value.indexOf(mentionToken, fromIndex);
// Skip invalid mention // Skip invalid mention
if (index > 0 && invalidRegex.test(value.charAt(index - 1))) { if (index > 0 && invalidRegex.test(value.charAt(index - 1))) {
@ -45,21 +61,22 @@ const createURI = (text, uri, embed = false) => ({
children: [{ type: 'text', value: text }], children: [{ type: 'text', value: text }],
}); });
const validateURI = (match, eat, self) => { const validateURI = (match, eat) => {
if (match) { if (match) {
try { try {
const text = match[0]; const text = match[0];
const uri = parseURI(text); const newText = handlePunctuation(text);
const uri = parseURI(newText);
const isValid = uri && uri.claimName; const isValid = uri && uri.claimName;
const isChannel = uri.isChannel && uri.path === uri.claimName; const isChannel = uri.isChannel && uri.path === uri.claimName;
if (isValid) { if (isValid) {
// Create channel link // Create channel link
if (isChannel) { if (isChannel) {
return eat(text)(createURI(uri.claimName, text, false)); return eat(newText)(createURI(uri.claimName, newText, false));
} }
// Create claim link // Create claim link
return eat(text)(createURI(text, text, true)); return eat(newText)(createURI(newText, newText, true));
} }
} catch (err) { } catch (err) {
// Silent errors: console.error(err) // Silent errors: console.error(err)
@ -128,7 +145,7 @@ const visitor = (node, index, parent) => {
}; };
// transform // transform
const transform = tree => { const transform = (tree) => {
visit(tree, ['link'], visitor); visit(tree, ['link'], visitor);
}; };