mirror of
https://github.com/vector-im/element-web.git
synced 2026-03-28 00:31:16 +01:00
* Port over linkifyJS to shared-components. * Drop rubbish * update lock * quickfix test * drop group id * Modernize tests * Remove stories that aren't in use. * Complete working version * Add copyright * tidy up * update lock * Update snaps * update snap * undo change * remove unused * More test updates * fix typo * fix margin on preview * move margin block * snapupdate * prettier * cleanup a test mistake * Fixup sonar issues * Don't expose linkifyjs to applications, just provide helper functions. * Add story for documentation. * remove $ * Use a const * typo * cleanup var name * remove console line * Changes checkpoint * Convert to context * Revert unrelated change. * more cleanup * Add a test to cover ignoring incoming data elements * Make tests happy * Update tests for LinkedText * Underlines! * fix lock * remove unused linkify packages * import move * Remove mod to remove underline * undo * fix snap * another snapshot fix * Tidy up based on review. * fix story * Pass in args
92 lines
3.2 KiB
TypeScript
92 lines
3.2 KiB
TypeScript
/*
|
|
* Copyright 2026 Element Creations Ltd.
|
|
* Copyright 2024 New Vector Ltd.
|
|
* Copyright 2023 The Matrix.org Foundation C.I.C.
|
|
* Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { type IContent, type IEventRelation, type MatrixEvent, THREAD_RELATION_TYPE } from "matrix-js-sdk/src/matrix";
|
|
import sanitizeHtml from "sanitize-html";
|
|
import { PERMITTED_URL_SCHEMES } from "@element-hq/web-shared-components";
|
|
|
|
export function getParentEventId(ev?: MatrixEvent): string | undefined {
|
|
if (!ev || ev.isRedacted()) return;
|
|
if (ev.replyEventId) {
|
|
return ev.replyEventId;
|
|
}
|
|
}
|
|
|
|
// Part of Replies fallback support
|
|
export function stripPlainReply(body: string): string {
|
|
// Removes lines beginning with `> ` until you reach one that doesn't.
|
|
const lines = body.split("\n");
|
|
while (lines.length && lines[0].startsWith("> ")) lines.shift();
|
|
// Reply fallback has a blank line after it, so remove it to prevent leading newline
|
|
if (lines[0] === "") lines.shift();
|
|
return lines.join("\n");
|
|
}
|
|
|
|
// Part of Replies fallback support - MUST NOT BE RENDERED DIRECTLY - UNSAFE HTML
|
|
export function stripHTMLReply(html: string): string {
|
|
// Sanitize the original HTML for inclusion in <mx-reply>. We allow
|
|
// any HTML, since the original sender could use special tags that we
|
|
// don't recognize, but want to pass along to any recipients who do
|
|
// recognize them -- recipients should be sanitizing before displaying
|
|
// anyways. However, we sanitize to 1) remove any mx-reply, so that we
|
|
// don't generate a nested mx-reply, and 2) make sure that the HTML is
|
|
// properly formatted (e.g. tags are closed where necessary)
|
|
return sanitizeHtml(html, {
|
|
allowedTags: false, // false means allow everything
|
|
allowedAttributes: false,
|
|
allowVulnerableTags: true, // silence xss warning, we won't be rendering directly this, so it is safe to do
|
|
// we somehow can't allow all schemes, so we allow all that we
|
|
// know of and mxc (for img tags)
|
|
allowedSchemes: [...PERMITTED_URL_SCHEMES, "mxc"],
|
|
exclusiveFilter: (frame) => frame.tag === "mx-reply",
|
|
});
|
|
}
|
|
|
|
export function makeReplyMixIn(ev?: MatrixEvent): IEventRelation {
|
|
if (!ev) return {};
|
|
|
|
const mixin: IEventRelation = {
|
|
"m.in_reply_to": {
|
|
event_id: ev.getId(),
|
|
},
|
|
};
|
|
|
|
if (ev.threadRootId) {
|
|
mixin.is_falling_back = false;
|
|
}
|
|
|
|
return mixin;
|
|
}
|
|
|
|
export function shouldDisplayReply(event: MatrixEvent): boolean {
|
|
if (event.isRedacted()) {
|
|
return false;
|
|
}
|
|
|
|
const inReplyTo = event.getWireContent()?.["m.relates_to"]?.["m.in_reply_to"];
|
|
if (!inReplyTo) {
|
|
return false;
|
|
}
|
|
|
|
const relation = event.getRelation();
|
|
if (relation?.rel_type === THREAD_RELATION_TYPE.name && relation?.is_falling_back) {
|
|
return false;
|
|
}
|
|
|
|
return !!inReplyTo.event_id;
|
|
}
|
|
|
|
export function addReplyToMessageContent(content: IContent, replyToEvent: MatrixEvent): void {
|
|
content["m.relates_to"] = {
|
|
...(content["m.relates_to"] || {}),
|
|
...makeReplyMixIn(replyToEvent),
|
|
};
|
|
}
|