fix: Use linkifyjs instead, add noreferrer

pull/694/head
Maksim Eltyshev 2 years ago
parent f5f70476e0
commit be1afc7778

@ -10,7 +10,6 @@
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
"dequal": "^2.0.3",
"dompurify": "^3.1.0",
"easymde": "^2.18.0",
"history": "^5.3.0",
"i18next": "^23.7.6",
@ -18,6 +17,8 @@
"initials": "^3.1.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"linkify-react": "^4.1.3",
"linkifyjs": "^4.1.3",
"lodash": "^4.17.21",
"nanoid": "^5.0.3",
"node-sass": "^9.0.0",
@ -7017,11 +7018,6 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/dompurify": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz",
"integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA=="
},
"node_modules/domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
@ -11917,6 +11913,20 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
"node_modules/linkify-react": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.1.3.tgz",
"integrity": "sha512-rhI3zM/fxn5BfRPHfi4r9N7zgac4vOIxub1wHIWXLA5ENTMs+BGaIaFO1D1PhmxgwhIKmJz3H7uCP0Dg5JwSlA==",
"peerDependencies": {
"linkifyjs": "^4.0.0",
"react": ">= 15.0.0"
}
},
"node_modules/linkifyjs": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz",
"integrity": "sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg=="
},
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",

@ -63,7 +63,6 @@
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
"dequal": "^2.0.3",
"dompurify": "^3.1.0",
"easymde": "^2.18.0",
"history": "^5.3.0",
"i18next": "^23.7.6",
@ -71,6 +70,8 @@
"initials": "^3.1.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"linkify-react": "^4.1.3",
"linkifyjs": "^4.1.3",
"lodash": "^4.17.21",
"nanoid": "^5.0.3",
"node-sass": "^9.0.0",

@ -4,6 +4,8 @@ import classNames from 'classnames';
import { Progress } from 'semantic-ui-react';
import { useToggle } from '../../lib/hooks';
import Linkify from '../Linkify';
import styles from './Tasks.module.scss';
const Tasks = React.memo(({ items }) => {
@ -48,7 +50,7 @@ const Tasks = React.memo(({ items }) => {
key={item.id}
className={classNames(styles.task, item.isCompleted && styles.taskCompleted)}
>
{item.name}
<Linkify linkStopPropagation>{item.name}</Linkify>
</li>
))}
</ul>

@ -55,9 +55,10 @@
display: block;
font-size: 12px;
line-height: 14px;
overflow: hidden;
padding-bottom: 6px;
padding-left: 14px;
overflow: hidden;
text-overflow: ellipsis;
&:before {
content: "";

@ -4,11 +4,11 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Draggable } from 'react-beautiful-dnd';
import { Button, Checkbox, Icon } from 'semantic-ui-react';
import { sanitize } from 'dompurify';
import { usePopup } from '../../../lib/popup';
import NameEdit from './NameEdit';
import ActionsStep from './ActionsStep';
import Linkify from '../../Linkify';
import styles from './Item.module.scss';
@ -16,14 +16,11 @@ const Item = React.memo(
({ id, index, name, isCompleted, isPersisted, canEdit, onUpdate, onDelete }) => {
const nameEdit = useRef(null);
const handleClick = useCallback(
(event) => {
if (!event.target.closest('a') && isPersisted && canEdit) {
nameEdit.current.open();
}
},
[isPersisted, canEdit],
);
const handleClick = useCallback(() => {
if (isPersisted && canEdit) {
nameEdit.current.open();
}
}, [isPersisted, canEdit]);
const handleNameUpdate = useCallback(
(newName) => {
@ -44,16 +41,6 @@ const Item = React.memo(
nameEdit.current.open();
}, []);
const parseLinks = (text) => {
const regex = /(http[s]?:\/\/[^\s]+)/g;
return sanitize(text).replace(regex, (match) => {
const url = new URL(match);
return `<a href="${match}" target="_blank">${
url.hostname === window.location.hostname ? url.pathname : match
}</a>`;
});
};
const ActionsPopup = usePopup(ActionsStep);
return (
@ -78,11 +65,9 @@ const Item = React.memo(
className={classNames(styles.text, canEdit && styles.textEditable)}
onClick={handleClick}
>
<span
className={classNames(styles.task, isCompleted && styles.taskCompleted)}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: parseLinks(name) }}
/>
<span className={classNames(styles.task, isCompleted && styles.taskCompleted)}>
<Linkify linkStopPropagation>{name}</Linkify>
</span>
</span>
{isPersisted && canEdit && (
<ActionsPopup onNameEdit={handleNameEdit} onDelete={onDelete}>

@ -0,0 +1,68 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import LinkifyReact from 'linkify-react';
import history from '../history';
const Linkify = React.memo(({ children, linkStopPropagation, ...props }) => {
const handleLinkClick = useCallback(
(event) => {
if (linkStopPropagation) {
event.stopPropagation();
}
if (!event.target.getAttribute('target')) {
event.preventDefault();
history.push(event.target.href);
}
},
[linkStopPropagation],
);
const linkRenderer = useCallback(
({ attributes: { href, ...linkProps }, content }) => {
let url;
try {
url = new URL(href, window.location);
} catch (error) {} // eslint-disable-line no-empty
const isSameSite = !!url && url.origin === window.location.origin;
return (
<a
{...linkProps} // eslint-disable-line react/jsx-props-no-spreading
href={href}
target={isSameSite ? undefined : '_blank'}
rel={isSameSite ? undefined : 'noreferrer'}
onClick={handleLinkClick}
>
{isSameSite ? url.pathname : content}
</a>
);
},
[handleLinkClick],
);
return (
<LinkifyReact
{...props} // eslint-disable-line react/jsx-props-no-spreading
options={{
defaultProtocol: 'https',
render: linkRenderer,
}}
>
{children}
</LinkifyReact>
);
});
Linkify.propTypes = {
children: PropTypes.string.isRequired,
linkStopPropagation: PropTypes.bool,
};
Linkify.defaultProps = {
linkStopPropagation: false,
};
export default Linkify;
Loading…
Cancel
Save