Simple approach, may be extended/enhanced in the future.
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
|||||||
import config from '../config'
|
import config from '../config'
|
||||||
import { intersperse } from '../utils'
|
import { intersperse } from '../utils'
|
||||||
import AlbumExternalLinks from './AlbumExternalLinks'
|
import AlbumExternalLinks from './AlbumExternalLinks'
|
||||||
|
import AnchorMe from '../common/AnchorMe'
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
(theme) => ({
|
(theme) => ({
|
||||||
@@ -116,7 +117,7 @@ const AlbumComment = ({ record }) => {
|
|||||||
const formatted = useMemo(() => {
|
const formatted = useMemo(() => {
|
||||||
return lines.map((line, idx) => (
|
return lines.map((line, idx) => (
|
||||||
<span key={record.id + '-comment-' + idx}>
|
<span key={record.id + '-comment-' + idx}>
|
||||||
<span dangerouslySetInnerHTML={{ __html: line }} />
|
<AnchorMe text={line} />
|
||||||
<br />
|
<br />
|
||||||
</span>
|
</span>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import React, { useCallback, useMemo } from 'react'
|
||||||
|
import { Link } from '@material-ui/core'
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
(theme) => ({
|
||||||
|
link: {
|
||||||
|
textDecoration: 'none',
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ name: 'RaLink' }
|
||||||
|
)
|
||||||
|
|
||||||
|
const AnchorMe = ({ text, ...rest }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
const linkify = useCallback((text) => {
|
||||||
|
const urlRegex =
|
||||||
|
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/gi
|
||||||
|
return [...text.matchAll(urlRegex)]
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const parse = useCallback(() => {
|
||||||
|
const matches = linkify(text)
|
||||||
|
if (matches.length === 0) return text
|
||||||
|
|
||||||
|
const elements = []
|
||||||
|
let lastIndex = 0
|
||||||
|
matches.forEach((match, index) => {
|
||||||
|
// Push text located before matched string
|
||||||
|
if (match.index > lastIndex) {
|
||||||
|
elements.push(text.substring(lastIndex, match.index))
|
||||||
|
}
|
||||||
|
|
||||||
|
const href = match[0]
|
||||||
|
// Push Link component
|
||||||
|
elements.push(
|
||||||
|
<Link
|
||||||
|
{...rest}
|
||||||
|
target="_blank"
|
||||||
|
className={classes.link}
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
key={index}
|
||||||
|
href={href}
|
||||||
|
>
|
||||||
|
{href}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
|
||||||
|
lastIndex = match.index + href.length
|
||||||
|
})
|
||||||
|
|
||||||
|
// Push remaining text
|
||||||
|
if (text.length > lastIndex) {
|
||||||
|
elements.push(
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: text.substring(lastIndex) }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements.length === 1 ? elements[0] : elements
|
||||||
|
}, [linkify, text, rest, classes.link])
|
||||||
|
|
||||||
|
const parsedText = useMemo(() => parse(), [parse])
|
||||||
|
|
||||||
|
return <>{parsedText}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
AnchorMe.propTypes = {
|
||||||
|
text: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(AnchorMe)
|
||||||
Reference in New Issue
Block a user