diff --git a/src/utils/permalinks/ElementPermalinkConstructor.js b/src/utils/permalinks/ElementPermalinkConstructor.js
index 29f2602304..da7f5797ea 100644
--- a/src/utils/permalinks/ElementPermalinkConstructor.js
+++ b/src/utils/permalinks/ElementPermalinkConstructor.js
@@ -75,15 +75,28 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor {
throw new Error("Does not appear to be a permalink");
}
- const parts = fullUrl.substring(`${this._elementUrl}/#/`.length).split("/");
- return ElementPermalinkConstructor.parseLinkParts(parts);
+ const parts = fullUrl.substring(`${this._elementUrl}/#/`.length);
+ return ElementPermalinkConstructor.parseAppRoute(parts);
}
- static parseLinkParts(parts: string[]): PermalinkParts {
+ /**
+ * Parses an app route (`(user|room|group)/identifer`) to a Matrix entity
+ * (room, user, group).
+ * @param {string} route The app route
+ * @returns {PermalinkParts}
+ */
+ static parseAppRoute(route: string): PermalinkParts {
+ const parts = route.split("/");
+
if (parts.length < 2) { // we're expecting an entity and an ID of some kind at least
throw new Error("URL is missing parts");
}
+ // Split optional query out of last part
+ const [lastPartMaybeWithQuery] = parts.splice(-1, 1);
+ const [lastPart, query = ""] = lastPartMaybeWithQuery.split("?");
+ parts.push(lastPart);
+
const entityType = parts[0];
const entity = parts[1];
if (entityType === 'user') {
@@ -93,20 +106,9 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor {
// Probably a group, no further parsing needed.
return PermalinkParts.forGroup(entity);
} else if (entityType === 'room') {
- if (parts.length === 2) {
- return PermalinkParts.forRoom(entity, []);
- }
-
- // rejoin the rest because v3 events can have slashes (annoyingly)
- const eventIdAndQuery = parts.length > 2 ? parts.slice(2).join('/') : "";
- const secondaryParts = eventIdAndQuery.split("?");
-
- const eventId = secondaryParts[0];
- const query = secondaryParts.length > 1 ? secondaryParts[1] : "";
-
- // TODO: Verify Element works with via args
- const via = query.split("via=").filter(p => !!p);
-
+ // Rejoin the rest because v3 events can have slashes (annoyingly)
+ const eventId = parts.length > 2 ? parts.slice(2).join('/') : "";
+ const via = query.split(/&?via=/).filter(p => !!p);
return PermalinkParts.forEvent(entity, eventId, via);
} else {
throw new Error("Unknown entity type in permalink");
diff --git a/src/utils/permalinks/Permalinks.js b/src/utils/permalinks/Permalinks.js
index 9851bc3cb3..086abc669d 100644
--- a/src/utils/permalinks/Permalinks.js
+++ b/src/utils/permalinks/Permalinks.js
@@ -414,8 +414,8 @@ export function parsePermalink(fullUrl: string): PermalinkParts {
*/
export function parseAppLocalLink(localLink: string): PermalinkParts {
try {
- const segments = localLink.replace("#/", "").split("/");
- return ElementPermalinkConstructor.parseLinkParts(segments);
+ const segments = localLink.replace("#/", "");
+ return ElementPermalinkConstructor.parseAppRoute(segments);
} catch (e) {
// Ignore failures
}
diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js
index 461af19658..d5b80b6756 100644
--- a/test/components/views/messages/TextualBody-test.js
+++ b/test/components/views/messages/TextualBody-test.js
@@ -242,6 +242,38 @@ describe("", () => {
'rel="noreferrer noopener">event link with text',
);
});
+
+ it("pills appear for room links with vias", () => {
+ const ev = mkEvent({
+ type: "m.room.message",
+ room: "room_id",
+ user: "sender",
+ content: {
+ body:
+ "A [room link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com" +
+ "?via=example.com&via=bob.com) with vias",
+ msgtype: "m.text",
+ format: "org.matrix.custom.html",
+ formatted_body:
+ "A room link with vias",
+ },
+ event: true,
+ });
+
+ const wrapper = mount();
+ expect(wrapper.text()).toBe("A !ZxbRYPQXDXKGmDnJNg:example.com with vias");
+ const content = wrapper.find(".mx_EventTile_body");
+ expect(content.html()).toBe(
+ '' +
+ 'A
' +
+ '!ZxbRYPQXDXKGmDnJNg:example.com with vias',
+ );
+ });
});
it("renders url previews correctly", () => {
diff --git a/test/test-utils.js b/test/test-utils.js
index c8e623b1d9..839e1d6cd8 100644
--- a/test/test-utils.js
+++ b/test/test-utils.js
@@ -243,6 +243,7 @@ export function mkStubRoom(roomId = null) {
on: jest.fn(),
removeListener: jest.fn(),
getDMInviter: jest.fn(),
+ getAvatarUrl: () => 'mxc://avatar.url/room.png',
};
}