diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 3c8d100be3..2c6e2a1830 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -176,8 +176,9 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to attribs.target = '_blank'; // by default const transformed = tryTransformPermalinkToLocalHref(attribs.href); // only used to check if it is a link that can be handled locally - if (transformed !== attribs.href || // it could be converted so handle locally symbols e.g. @user:server.tdl, matrix: and matrix.to - attribs.href.match(ELEMENT_URL_PATTERN) // for https:vector|riot... + if ( + transformed !== attribs.href || // it could be converted so handle locally symbols e.g. @user:server.tdl, matrix: and matrix.to + attribs.href.match(ELEMENT_URL_PATTERN) // for https links to Element domains ) { delete attribs.target; } diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx index 8ae5a785dd..91feace2eb 100644 --- a/src/components/views/messages/TextualBody.tsx +++ b/src/components/views/messages/TextualBody.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { createRef, SyntheticEvent } from 'react'; +import React, { createRef, SyntheticEvent, MouseEvent } from 'react'; import ReactDOM from 'react-dom'; import highlight from 'highlight.js'; import { MsgType } from "matrix-js-sdk/src/@types/event"; @@ -31,7 +31,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import ReplyChain from "../elements/ReplyChain"; import { pillifyLinks, unmountPills } from '../../../utils/pillify'; import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; -import { isPermalinkHost } from "../../../utils/permalinks/Permalinks"; +import { isPermalinkHost, tryTransformPermalinkToLocalHref } from "../../../utils/permalinks/Permalinks"; import { copyPlaintext } from "../../../utils/strings"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import { replaceableComponent } from "../../../utils/replaceableComponent"; @@ -47,6 +47,7 @@ import LinkPreviewGroup from '../rooms/LinkPreviewGroup'; import { IBodyProps } from "./IBodyProps"; import RoomContext from "../../../contexts/RoomContext"; import AccessibleButton from '../elements/AccessibleButton'; +import { options as linkifyOpts } from "../../../linkify-matrix"; const MAX_HIGHLIGHT_LENGTH = 4096; @@ -418,6 +419,23 @@ export default class TextualBody extends React.Component { }); }; + /** + * This acts as a fallback in-app navigation handler for any body links that + * were ignored as part of linkification because they were already links + * to start with (e.g. pills, links in the content). + */ + private onBodyLinkClick = (e: MouseEvent): void => { + const target = e.target as Element; + if (target.nodeName !== "A" || target.classList.contains(linkifyOpts.className)) return; + const { href } = target as HTMLLinkElement; + const localHref = tryTransformPermalinkToLocalHref(href); + if (localHref !== href) { + // it could be converted to a localHref -> therefore handle locally + e.preventDefault(); + window.location.hash = localHref; + } + }; + public getEventTileOps = () => ({ isWidgetHidden: () => { return this.state.widgetHidden; @@ -606,7 +624,9 @@ export default class TextualBody extends React.Component { if (isEmote) { return ( -
+
{ } if (isNotice) { return ( -
+
{ body } { widgets }
); } return ( -
+
{ body } { widgets }
diff --git a/src/linkify-matrix.ts b/src/linkify-matrix.ts index 0b21ac1543..dbbece9033 100644 --- a/src/linkify-matrix.ts +++ b/src/linkify-matrix.ts @@ -21,7 +21,6 @@ import linkifyString from '@matrix-org/linkify-string'; import { RoomMember } from 'matrix-js-sdk/src/models/room-member'; import { registerCustomProtocol, registerPlugin } from '@matrix-org/linkifyjs'; -//linkifyjs/src/core/fsm import { baseUrl } from "./utils/permalinks/MatrixToPermalinkConstructor"; import { parsePermalink, @@ -227,8 +226,9 @@ export const options = { if (type === Type.URL) { try { const transformed = tryTransformPermalinkToLocalHref(href); - if (transformed !== href || // if it could be converted to handle locally for matrix symbols e.g. @user:server.tdl and matrix.to - decodeURIComponent(href).match(ELEMENT_URL_PATTERN) // for https:vector|riot... + if ( + transformed !== href || // if it could be converted to handle locally for matrix symbols e.g. @user:server.tdl and matrix.to + decodeURIComponent(href).match(ELEMENT_URL_PATTERN) // for https links to Element domains ) { return null; } else { diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index c79e8af826..ed4844c3ac 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -328,7 +328,7 @@ export function tryTransformEntityToPermalink(entity: string): string { if (!entity) return null; // Check to see if it is a bare entity for starters - {if (entity[0] === '#' || entity[0] === '!') return makeRoomPermalink(entity);} + if (entity[0] === '#' || entity[0] === '!') return makeRoomPermalink(entity); if (entity[0] === '@') return makeUserPermalink(entity); if (entity[0] === '+') return makeGroupPermalink(entity);