Handle punctuation after mention
This commit is contained in:
parent
23a5aa2751
commit
7c35299207
4 changed files with 60 additions and 24 deletions
|
@ -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);
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue