diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 2f085fe5ed..9dad17f6ac 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -20,9 +20,7 @@ limitations under the License. import React, { ReactNode } from 'react'; import sanitizeHtml from 'sanitize-html'; import cheerio from 'cheerio'; -import * as linkify from 'linkifyjs'; -import _linkifyElement from 'linkifyjs/element'; -import _linkifyString from 'linkifyjs/string'; +import { _linkifyElement, _linkifyString } from './linkify-matrix'; import classNames from 'classnames'; import EMOJIBASE_REGEX from 'emojibase-regex'; import katex from 'katex'; @@ -30,14 +28,12 @@ import { AllHtmlEntities } from 'html-entities'; import { IContent } from 'matrix-js-sdk/src/models/event'; import { IExtendedSanitizeOptions } from './@types/sanitize-html'; -import linkifyMatrix from './linkify-matrix'; import SettingsStore from './settings/SettingsStore'; import { tryTransformPermalinkToLocalHref } from "./utils/permalinks/Permalinks"; import { getEmojiFromUnicode } from "./emoji"; import ReplyChain from "./components/views/elements/ReplyChain"; import { mediaFromMxc } from "./customisations/Media"; - -linkifyMatrix(linkify); +import { ELEMENT_URL_PATTERN, options as linkifyMatrixOptions } from './linkify-matrix'; // Anything outside the basic multilingual plane will be a surrogate pair const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/; @@ -180,7 +176,7 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to attribs.target = '_blank'; // by default const transformed = tryTransformPermalinkToLocalHref(attribs.href); - if (transformed !== attribs.href || attribs.href.match(linkifyMatrix.ELEMENT_URL_PATTERN)) { + if (transformed !== attribs.href || attribs.href.match(ELEMENT_URL_PATTERN)) { attribs.href = transformed; delete attribs.target; } @@ -537,10 +533,10 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts * Linkifies the given string. This is a wrapper around 'linkifyjs/string'. * * @param {string} str string to linkify - * @param {object} [options] Options for linkifyString. Default: linkifyMatrix.options + * @param {object} [options] Options for linkifyString. Default: linkifyMatrixOptions * @returns {string} Linkified string */ -export function linkifyString(str: string, options = linkifyMatrix.options): string { +export function linkifyString(str: string, options = linkifyMatrixOptions): string { return _linkifyString(str, options); } @@ -548,10 +544,10 @@ export function linkifyString(str: string, options = linkifyMatrix.options): str * Linkifies the given DOM element. This is a wrapper around 'linkifyjs/element'. * * @param {object} element DOM element to linkify - * @param {object} [options] Options for linkifyElement. Default: linkifyMatrix.options + * @param {object} [options] Options for linkifyElement. Default: linkifyMatrixOptions * @returns {object} */ -export function linkifyElement(element: HTMLElement, options = linkifyMatrix.options): HTMLElement { +export function linkifyElement(element: HTMLElement, options = linkifyMatrixOptions): HTMLElement { return _linkifyElement(element, options); } @@ -559,10 +555,10 @@ export function linkifyElement(element: HTMLElement, options = linkifyMatrix.opt * Linkify the given string and sanitize the HTML afterwards. * * @param {string} dirtyHtml The HTML string to sanitize and linkify - * @param {object} [options] Options for linkifyString. Default: linkifyMatrix.options + * @param {object} [options] Options for linkifyString. Default: linkifyMatrixOptions * @returns {string} */ -export function linkifyAndSanitizeHtml(dirtyHtml: string, options = linkifyMatrix.options): string { +export function linkifyAndSanitizeHtml(dirtyHtml: string, options = linkifyMatrixOptions): string { return sanitizeHtml(linkifyString(dirtyHtml, options), sanitizeHtmlParams); } diff --git a/src/Markdown.ts b/src/Markdown.ts index 7070919348..b3e5363eb0 100644 --- a/src/Markdown.ts +++ b/src/Markdown.ts @@ -18,7 +18,7 @@ limitations under the License. import * as commonmark from 'commonmark'; import { escape } from "lodash"; import { logger } from 'matrix-js-sdk/src/logger'; -import * as linkify from 'linkifyjs'; +import { linkify } from './linkify-matrix'; const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u']; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 9b423fce82..28e801daf0 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ComponentType, createRef } from 'react'; import { createClient } from "matrix-js-sdk/src/matrix"; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; -import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { sleep, defer, IDeferred, QueryDict } from "matrix-js-sdk/src/utils"; @@ -38,7 +37,6 @@ import Notifier from '../../Notifier'; import Modal from "../../Modal"; import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite'; import * as Rooms from '../../Rooms'; -import linkifyMatrix from "../../linkify-matrix"; import * as Lifecycle from '../../Lifecycle'; // LifecycleStore is not used but does listen to and dispatch actions import '../../stores/LifecycleStore'; @@ -59,7 +57,6 @@ import { storeRoomAliasInCache } from '../../RoomAliasCache'; import ToastStore from "../../stores/ToastStore"; import * as StorageManager from "../../utils/StorageManager"; import type LoggedInViewType from "./LoggedInView"; -import { ViewUserPayload } from "../../dispatcher/payloads/ViewUserPayload"; import { Action } from "../../dispatcher/actions"; import { showToast as showAnalyticsToast, @@ -347,18 +344,6 @@ export default class MatrixChat extends React.PureComponent { // we don't do it as react state as i'm scared about triggering needless react refreshes. this.subTitleStatus = ''; - // this can technically be done anywhere but doing this here keeps all - // the routing url path logic together. - if (this.onAliasClick) { - linkifyMatrix.onAliasClick = this.onAliasClick; - } - if (this.onUserClick) { - linkifyMatrix.onUserClick = this.onUserClick; - } - if (this.onGroupClick) { - linkifyMatrix.onGroupClick = this.onGroupClick; - } - // the first thing to do is to try the token params in the query-string // if the session isn't soft logged out (ie: is a clean session being logged in) if (!Lifecycle.isSoftLogout()) { @@ -1898,28 +1883,6 @@ export default class MatrixChat extends React.PureComponent { } this.setPageSubtitle(); } - - onAliasClick(event: MouseEvent, alias: string) { - event.preventDefault(); - dis.dispatch({ action: Action.ViewRoom, room_alias: alias }); - } - - onUserClick(event: MouseEvent, userId: string) { - event.preventDefault(); - - const member = new RoomMember(null, userId); - if (!member) { return; } - dis.dispatch({ - action: Action.ViewUser, - member: member, - }); - } - - onGroupClick(event: MouseEvent, groupId: string) { - event.preventDefault(); - dis.dispatch({ action: 'view_group', group_id: groupId }); - } - onLogoutClick(event: React.MouseEvent) { dis.dispatch({ action: 'logout', diff --git a/src/linkify-matrix.ts b/src/linkify-matrix.ts index 20f1b1e213..33402889e5 100644 --- a/src/linkify-matrix.ts +++ b/src/linkify-matrix.ts @@ -15,12 +15,19 @@ See the License for the specific language governing permissions and limitations under the License. */ +import * as linkifyjs from 'linkifyjs'; +import linkifyElement from 'linkifyjs/element'; +import linkifyString from 'linkifyjs/string'; +import { RoomMember } from 'matrix-js-sdk/src/models/room-member'; import { baseUrl } from "./utils/permalinks/SpecPermalinkConstructor"; import { parsePermalink, tryTransformEntityToPermalink, tryTransformPermalinkToLocalHref, } from "./utils/permalinks/Permalinks"; +import dis from './dispatcher/dispatcher'; +import { Action } from './dispatcher/actions'; +import { ViewUserPayload } from './dispatcher/payloads/ViewUserPayload'; enum Type { URL = "url", @@ -29,7 +36,20 @@ enum Type { GroupId = "groupid" } -function matrixLinkify(linkify): void { +// Linkifyjs types don't have parser, which really makes this harder. +const linkifyTokens = (linkifyjs as any).scanner.TOKENS; +enum MatrixLinkInitialToken { + POUND = linkifyTokens.POUND, + PLUS = linkifyTokens.PLUS, + AT = linkifyTokens.AT, +} + +/** + * Token should be one of the type of linkify.parser.TOKENS[AT | PLUS | POUND] + * but due to typing issues it's just not a feasible solution. + * This problem kind of gets solved in linkify 3.0 + */ +function parseFreeformMatrixLinks(linkify, token: MatrixLinkInitialToken, type: Type): void { // Text tokens const TT = linkify.scanner.TOKENS; // Multi tokens @@ -37,152 +57,70 @@ function matrixLinkify(linkify): void { const MultiToken = MT.Base; const S_START = linkify.parser.start; - if (TT.UNDERSCORE === undefined) { - throw new Error("linkify-matrix requires linkifyjs 2.1.1: this version is too old."); - } - - const ROOMALIAS = function(value) { + const TOKEN = function(value) { MultiToken.call(this, value); - this.type = 'roomalias'; + this.type = type; this.isLink = true; }; - ROOMALIAS.prototype = new MultiToken(); + TOKEN.prototype = new MultiToken(); - const S_HASH = S_START.jump(TT.POUND); - const S_HASH_NAME = new linkify.parser.State(); - const S_HASH_NAME_COLON = new linkify.parser.State(); - const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State(ROOMALIAS); - const S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State(); - const S_ROOMALIAS = new linkify.parser.State(ROOMALIAS); - const S_ROOMALIAS_COLON = new linkify.parser.State(); - const S_ROOMALIAS_COLON_NUM = new linkify.parser.State(ROOMALIAS); + const S_TOKEN = S_START.jump(token); + const S_TOKEN_NAME = new linkify.parser.State(); + const S_TOKEN_NAME_COLON = new linkify.parser.State(); + const S_TOKEN_NAME_COLON_DOMAIN = new linkify.parser.State(TOKEN); + const S_TOKEN_NAME_COLON_DOMAIN_DOT = new linkify.parser.State(); + const S_MX_LINK = new linkify.parser.State(TOKEN); + const S_MX_LINK_COLON = new linkify.parser.State(); + const S_MX_LINK_COLON_NUM = new linkify.parser.State(TOKEN); - const roomnameTokens = [ + const allowedFreeformTokens = [ TT.DOT, TT.PLUS, TT.NUM, TT.DOMAIN, TT.TLD, TT.UNDERSCORE, - TT.POUND, + token, // because 'localhost' is tokenised to the localhost token, // usernames @localhost:foo.com are otherwise not matched! TT.LOCALHOST, ]; - S_HASH.on(roomnameTokens, S_HASH_NAME); - S_HASH_NAME.on(roomnameTokens, S_HASH_NAME); - S_HASH_NAME.on(TT.DOMAIN, S_HASH_NAME); + S_TOKEN.on(allowedFreeformTokens, S_TOKEN_NAME); + S_TOKEN_NAME.on(allowedFreeformTokens, S_TOKEN_NAME); + S_TOKEN_NAME.on(TT.DOMAIN, S_TOKEN_NAME); - S_HASH_NAME.on(TT.COLON, S_HASH_NAME_COLON); + S_TOKEN_NAME.on(TT.COLON, S_TOKEN_NAME_COLON); - S_HASH_NAME_COLON.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN); - S_HASH_NAME_COLON.on(TT.LOCALHOST, S_ROOMALIAS); // accept #foo:localhost - S_HASH_NAME_COLON.on(TT.TLD, S_ROOMALIAS); // accept #foo:com (mostly for (TLD|DOMAIN)+ mixing) - S_HASH_NAME_COLON_DOMAIN.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT); - S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN); - S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_ROOMALIAS); + S_TOKEN_NAME_COLON.on(TT.DOMAIN, S_TOKEN_NAME_COLON_DOMAIN); + S_TOKEN_NAME_COLON.on(TT.LOCALHOST, S_MX_LINK); // accept #foo:localhost + S_TOKEN_NAME_COLON.on(TT.TLD, S_MX_LINK); // accept #foo:com (mostly for (TLD|DOMAIN)+ mixing) + S_TOKEN_NAME_COLON_DOMAIN.on(TT.DOT, S_TOKEN_NAME_COLON_DOMAIN_DOT); + S_TOKEN_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_TOKEN_NAME_COLON_DOMAIN); + S_TOKEN_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_MX_LINK); - S_ROOMALIAS.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk) - S_ROOMALIAS.on(TT.COLON, S_ROOMALIAS_COLON); // do not accept trailing `:` - S_ROOMALIAS_COLON.on(TT.NUM, S_ROOMALIAS_COLON_NUM); // but do accept :NUM (port specifier) - - const USERID = function(value) { - MultiToken.call(this, value); - this.type = 'userid'; - this.isLink = true; - }; - USERID.prototype = new MultiToken(); - - const S_AT = S_START.jump(TT.AT); - const S_AT_NAME = new linkify.parser.State(); - const S_AT_NAME_COLON = new linkify.parser.State(); - const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State(USERID); - const S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State(); - const S_USERID = new linkify.parser.State(USERID); - const S_USERID_COLON = new linkify.parser.State(); - const S_USERID_COLON_NUM = new linkify.parser.State(USERID); - - const usernameTokens = [ - TT.DOT, - TT.UNDERSCORE, - TT.PLUS, - TT.NUM, - TT.DOMAIN, - TT.TLD, - - // as in roomnameTokens - TT.LOCALHOST, - ]; - - S_AT.on(usernameTokens, S_AT_NAME); - S_AT_NAME.on(usernameTokens, S_AT_NAME); - S_AT_NAME.on(TT.DOMAIN, S_AT_NAME); - - S_AT_NAME.on(TT.COLON, S_AT_NAME_COLON); - - S_AT_NAME_COLON.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN); - S_AT_NAME_COLON.on(TT.LOCALHOST, S_USERID); // accept @foo:localhost - S_AT_NAME_COLON.on(TT.TLD, S_USERID); // accept @foo:com (mostly for (TLD|DOMAIN)+ mixing) - S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT); - S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN); - S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID); - - S_USERID.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk) - S_USERID.on(TT.COLON, S_USERID_COLON); // do not accept trailing `:` - S_USERID_COLON.on(TT.NUM, S_USERID_COLON_NUM); // but do accept :NUM (port specifier) - - const GROUPID = function(value) { - MultiToken.call(this, value); - this.type = 'groupid'; - this.isLink = true; - }; - GROUPID.prototype = new MultiToken(); - - const S_PLUS = S_START.jump(TT.PLUS); - const S_PLUS_NAME = new linkify.parser.State(); - const S_PLUS_NAME_COLON = new linkify.parser.State(); - const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State(GROUPID); - const S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State(); - const S_GROUPID = new linkify.parser.State(GROUPID); - const S_GROUPID_COLON = new linkify.parser.State(); - const S_GROUPID_COLON_NUM = new linkify.parser.State(GROUPID); - - const groupIdTokens = [ - TT.DOT, - TT.UNDERSCORE, - TT.PLUS, - TT.NUM, - TT.DOMAIN, - TT.TLD, - - // as in roomnameTokens - TT.LOCALHOST, - ]; - - S_PLUS.on(groupIdTokens, S_PLUS_NAME); - S_PLUS_NAME.on(groupIdTokens, S_PLUS_NAME); - S_PLUS_NAME.on(TT.DOMAIN, S_PLUS_NAME); - - S_PLUS_NAME.on(TT.COLON, S_PLUS_NAME_COLON); - - S_PLUS_NAME_COLON.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN); - S_PLUS_NAME_COLON.on(TT.LOCALHOST, S_GROUPID); // accept +foo:localhost - S_PLUS_NAME_COLON.on(TT.TLD, S_GROUPID); // accept +foo:com (mostly for (TLD|DOMAIN)+ mixing) - S_PLUS_NAME_COLON_DOMAIN.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT); - S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN); - S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_GROUPID); - - S_GROUPID.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk) - S_GROUPID.on(TT.COLON, S_GROUPID_COLON); // do not accept trailing `:` - S_GROUPID_COLON.on(TT.NUM, S_GROUPID_COLON_NUM); // but do accept :NUM (port specifier) + S_MX_LINK.on(TT.DOT, S_TOKEN_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk) + S_MX_LINK.on(TT.COLON, S_MX_LINK_COLON); // do not accept trailing `:` + S_MX_LINK_COLON.on(TT.NUM, S_MX_LINK_COLON_NUM); // but do accept :NUM (port specifier) } -// stubs, overwritten in MatrixChat's componentDidMount -matrixLinkify.onUserClick = function(e: MouseEvent, userId: string) { e.preventDefault(); }; -matrixLinkify.onAliasClick = function(e: MouseEvent, roomAlias: string) { e.preventDefault(); }; -matrixLinkify.onGroupClick = function(e: MouseEvent, groupId: string) { e.preventDefault(); }; +function onUserClick(event: MouseEvent, userId: string) { + const member = new RoomMember(null, userId); + if (!member) { return; } + dis.dispatch({ + action: Action.ViewUser, + member: member, + }); +} +function onAliasClick(event: MouseEvent, roomAlias: string) { + event.preventDefault(); + dis.dispatch({ action: 'view_room', room_alias: roomAlias }); +} +function onGroupClick(event: MouseEvent, groupId: string) { + event.preventDefault(); + dis.dispatch({ action: 'view_group', group_id: groupId }); +} const escapeRegExp = function(string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); @@ -190,19 +128,19 @@ const escapeRegExp = function(string): string { // Recognise URLs from both our local and official Element deployments. // Anyone else really should be using matrix.to. -matrixLinkify.ELEMENT_URL_PATTERN = +export const ELEMENT_URL_PATTERN = "^(?:https?://)?(?:" + escapeRegExp(window.location.host + window.location.pathname) + "|" + "(?:www\\.)?(?:riot|vector)\\.im/(?:app|beta|staging|develop)/|" + "(?:app|beta|staging|develop)\\.element\\.io/" + ")(#.*)"; -matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?://)?(?:www\\.)?matrix\\.to/#/(([#@!+]).*)"; -matrixLinkify.MATRIXTO_MD_LINK_PATTERN = +export const MATRIXTO_URL_PATTERN = "^(?:https?://)?(?:www\\.)?matrix\\.to/#/(([#@!+]).*)"; +export const MATRIXTO_MD_LINK_PATTERN = '\\[([^\\]]*)\\]\\((?:https?://)?(?:www\\.)?matrix\\.to/#/([#@!+][^\\)]*)\\)'; -matrixLinkify.MATRIXTO_BASE_URL= baseUrl; +export const MATRIXTO_BASE_URL= baseUrl; -matrixLinkify.options = { +export const options = { events: function(href: string, type: Type | string): Partial { switch (type) { case Type.URL: { @@ -213,7 +151,7 @@ matrixLinkify.options = { return { // @ts-ignore see https://linkify.js.org/docs/options.html click: function(e) { - matrixLinkify.onUserClick(e, permalink.userId); + onUserClick(e, permalink.userId); }, }; } @@ -226,21 +164,21 @@ matrixLinkify.options = { return { // @ts-ignore see https://linkify.js.org/docs/options.html click: function(e) { - matrixLinkify.onUserClick(e, href); + onUserClick(e, href); }, }; case Type.RoomAlias: return { // @ts-ignore see https://linkify.js.org/docs/options.html click: function(e) { - matrixLinkify.onAliasClick(e, href); + onAliasClick(e, href); }, }; case Type.GroupId: return { // @ts-ignore see https://linkify.js.org/docs/options.html click: function(e) { - matrixLinkify.onGroupClick(e, href); + onGroupClick(e, href); }, }; } @@ -265,7 +203,7 @@ matrixLinkify.options = { if (type === Type.URL) { try { const transformed = tryTransformPermalinkToLocalHref(href); - if (transformed !== href || decodeURIComponent(href).match(matrixLinkify.ELEMENT_URL_PATTERN)) { + if (transformed !== href || decodeURIComponent(href).match(ELEMENT_URL_PATTERN)) { return null; } else { return '_blank'; @@ -278,4 +216,14 @@ matrixLinkify.options = { }, }; -export default matrixLinkify; +// Run the plugins +// Linkify room aliases +parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.POUND, Type.RoomAlias); +// Linkify group IDs +parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.PLUS, Type.GroupId); +// Linkify user IDs +parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.AT, Type.UserId); + +export const linkify = linkifyjs; +export const _linkifyElement = linkifyElement; +export const _linkifyString = linkifyString; diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index 4c05f42a0d..7627f30ed6 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -25,10 +25,10 @@ import { MatrixClientPeg } from "../../MatrixClientPeg"; import SpecPermalinkConstructor, { baseUrl as matrixtoBaseUrl } from "./SpecPermalinkConstructor"; import PermalinkConstructor, { PermalinkParts } from "./PermalinkConstructor"; import ElementPermalinkConstructor from "./ElementPermalinkConstructor"; -import matrixLinkify from "../../linkify-matrix"; import SdkConfig from "../../SdkConfig"; import { logger } from "matrix-js-sdk/src/logger"; +import { ELEMENT_URL_PATTERN } from "../../linkify-matrix"; // The maximum number of servers to pick when working out which servers // to add to permalinks. The servers are appended as ?via=example.org @@ -348,7 +348,7 @@ export function tryTransformPermalinkToLocalHref(permalink: string): string { } try { - const m = decodeURIComponent(permalink).match(matrixLinkify.ELEMENT_URL_PATTERN); + const m = decodeURIComponent(permalink).match(ELEMENT_URL_PATTERN); if (m) { return m[1]; } @@ -386,7 +386,7 @@ export function getPrimaryPermalinkEntity(permalink: string): string { // If not a permalink, try the vector patterns. if (!permalinkParts) { - const m = permalink.match(matrixLinkify.ELEMENT_URL_PATTERN); + const m = permalink.match(ELEMENT_URL_PATTERN); if (m) { // A bit of a hack, but it gets the job done const handler = new ElementPermalinkConstructor("http://localhost"); diff --git a/test/Markdown-test.ts b/test/Markdown-test.ts index 66d7370556..d5f38dbb9f 100644 --- a/test/Markdown-test.ts +++ b/test/Markdown-test.ts @@ -13,14 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import * as linkifyjs from 'linkifyjs'; -import Markdown from "../src/Markdown"; -import matrixLinkify from '../src/linkify-matrix'; -beforeAll(() => { - // We need to call linkifier plugins before running those tests - matrixLinkify(linkifyjs); -}); +import Markdown from "../src/Markdown"; describe("Markdown parser test", () => { describe("fixing HTML links", () => { diff --git a/test/linkify-matrix-test.ts b/test/linkify-matrix-test.ts index 9ab6e3921e..bedf1664bc 100644 --- a/test/linkify-matrix-test.ts +++ b/test/linkify-matrix-test.ts @@ -13,12 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import * as linkify from "linkifyjs"; -import linkifyMatrix from '../src/linkify-matrix'; - -beforeAll(() => { - linkifyMatrix(linkify); -}); +import { linkify } from '../src/linkify-matrix'; describe('linkify-matrix', () => { describe('roomalias', () => { @@ -74,7 +69,6 @@ describe('linkify-matrix', () => { href: "#foo:bar.com", type: "roomalias", value: "#foo:bar.com", - }])); }); it('accept :NUM (port specifier)', () => { @@ -93,7 +87,6 @@ describe('linkify-matrix', () => { href: "#foo:bar.com", type: "roomalias", value: "#foo:bar.com", - }])); }); it('properly parses room alias with dots in name', () => { @@ -103,7 +96,6 @@ describe('linkify-matrix', () => { href: "#foo.asdf:bar.com", type: "roomalias", value: "#foo.asdf:bar.com", - }])); }); it('does not parse room alias with too many separators', () => {