Apply media visible hook to inline images.

This commit is contained in:
Half-Shot
2025-04-10 17:21:20 +01:00
parent 3bdd0f4cd1
commit 81b400acfb
3 changed files with 17 additions and 9 deletions

View File

@@ -22,7 +22,7 @@ import { getEmojiFromUnicode } from "@matrix-org/emojibase-bindings";
import SettingsStore from "./settings/SettingsStore";
import { stripHTMLReply, stripPlainReply } from "./utils/Reply";
import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
import { sanitizeHtmlParams, transformTags } from "./Linkify";
import { filterImg, sanitizeHtmlParams, transformTags } from "./Linkify";
import { graphemeSegmenter } from "./utils/strings";
export { Linkify, linkifyAndSanitizeHtml } from "./Linkify";
@@ -294,6 +294,7 @@ export interface EventRenderOpts {
disableBigEmoji?: boolean;
stripReplyFallback?: boolean;
forComposerQuote?: boolean;
mediaIsVisible?: boolean;
}
function analyseEvent(content: IContent, highlights: Optional<string[]>, opts: EventRenderOpts = {}): EventAnalysis {
@@ -301,6 +302,9 @@ function analyseEvent(content: IContent, highlights: Optional<string[]>, opts: E
if (opts.forComposerQuote) {
sanitizeParams = composerSanitizeHtmlParams;
}
if (!opts.mediaIsVisible) {
sanitizeParams.exclusiveFilter = filterImg;
}
try {
const isFormattedBody =

View File

@@ -7,16 +7,14 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type ReactElement } from "react";
import sanitizeHtml, { type IOptions } from "sanitize-html";
import sanitizeHtml, { IFrame, type IOptions } from "sanitize-html";
import { merge } from "lodash";
import _Linkify from "linkify-react";
import { _linkifyString, ELEMENT_URL_PATTERN, options as linkifyMatrixOptions } from "./linkify-matrix";
import SettingsStore from "./settings/SettingsStore";
import { tryTransformPermalinkToLocalHref } from "./utils/permalinks/Permalinks";
import { mediaFromMxc } from "./customisations/Media";
import { PERMITTED_URL_SCHEMES } from "./utils/UrlUtils";
import { MediaPreviewValue } from "./@types/media_preview";
const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
const MEDIA_API_MXC_REGEX = /\/_matrix\/media\/r0\/(?:download|thumbnail)\/(.+?)\/(.+?)(?:[?/]|$)/;
@@ -48,11 +46,9 @@ export const transformTags: NonNullable<IOptions["transformTags"]> = {
// Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag
// because transformTags is used _before_ we filter by allowedSchemesByTag and
// we don't want to allow images with `https?` `src`s.
// We also drop inline images (as if they were not present at all) when the "show
// images" preference is disabled. Future work might expose some UI to reveal them
// like standalone image events have.
// TODO: Is this a private room?
if (!src || SettingsStore.getValue("mediaPreviewConfig").media_previews !== MediaPreviewValue.On) {
// Filtering out images now happens as a exlusive filter so we can conditionally apply this
// based on settings.
if (!src) {
return { tagName, attribs: {} };
}
@@ -200,6 +196,7 @@ export const sanitizeHtmlParams: IOptions = {
nestingLimit: 50,
};
/* Wrapper around linkify-react merging in our default linkify options */
export function Linkify({ as, options, children }: React.ComponentProps<typeof _Linkify>): ReactElement {
return (
@@ -230,3 +227,7 @@ export function linkifyString(str: string, options = linkifyMatrixOptions): stri
export function linkifyAndSanitizeHtml(dirtyHtml: string, options = linkifyMatrixOptions): string {
return sanitizeHtml(linkifyString(dirtyHtml, options), sanitizeHtmlParams);
}
export function filterImg(frame: IFrame): boolean {
return frame.tag === "img";
}

View File

@@ -28,6 +28,7 @@ import {
import MatrixClientContext from "../../../contexts/MatrixClientContext.tsx";
import { useSettingValue } from "../../../hooks/useSettings.ts";
import { filterBoolean } from "../../../utils/arrays.ts";
import { useMediaVisible } from "../../../hooks/useMediaVisible.ts";
/**
* Returns a RegExp pattern for the keyword in the push rule of the given Matrix event, if any
@@ -150,6 +151,7 @@ const EventContentBody = memo(
forwardRef<HTMLElement, Props>(
({ as, mxEvent, stripReply, content, linkify, highlights, includeDir = true, ...options }, ref) => {
const enableBigEmoji = useSettingValue("TextualBody.enableBigEmoji");
const [mediaIsVisible] = useMediaVisible(mxEvent?.getId()!, mxEvent?.getRoomId()!);
const replacer = useReplacer(content, mxEvent, options);
const linkifyOptions = useMemo(
@@ -167,6 +169,7 @@ const EventContentBody = memo(
disableBigEmoji: isEmote || !enableBigEmoji,
// Part of Replies fallback support
stripReplyFallback: stripReply,
mediaIsVisible,
}),
[content, enableBigEmoji, highlights, isEmote, stripReply],
);