Skip to content

Commit

Permalink
Merge pull request #37566 from kidroca/kidroca/feat/md-image-syntax
Browse files Browse the repository at this point in the history
Add support for inline image Markdown
  • Loading branch information
marcaaron authored Mar 21, 2024
2 parents 8970d08 + b9ebb19 commit 208aafa
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ const ROUTES = {
},
REPORT_ATTACHMENTS: {
route: 'r/:reportID/attachment',
getRoute: (reportID: string, source: string) => `r/${reportID}/attachment?source=${encodeURI(source)}` as const,
getRoute: (reportID: string, source: string) => `r/${reportID}/attachment?source=${encodeURIComponent(source)}` as const,
},
REPORT_PARTICIPANTS: {
route: 'r/:reportID/participants',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ import CONST from '@src/CONST';
function extractAttachmentsFromReport(parentReportAction, reportActions) {
const actions = [parentReportAction, ...ReportActionsUtils.getSortedReportActions(_.values(reportActions))];
const attachments = [];
// We handle duplicate image sources by considering the first instance as original. Selecting any duplicate
// and navigating back (<) shows the image preceding the first instance, not the selected duplicate's position.
const uniqueSources = new Set();

const htmlParser = new HtmlParser({
onopentag: (name, attribs) => {
if (name === 'video') {
const source = tryResolveUrlFromApiRoot(attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]);
if (uniqueSources.has(source)) {
return;
}

uniqueSources.add(source);
const splittedUrl = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE].split('/');
attachments.unshift({
reportActionID: null,
Expand All @@ -35,7 +44,20 @@ function extractAttachmentsFromReport(parentReportAction, reportActions) {
if (name === 'img' && attribs.src) {
const expensifySource = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE];
const source = tryResolveUrlFromApiRoot(expensifySource || attribs.src);
const fileName = attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || FileUtils.getFileName(`${source}`);
if (uniqueSources.has(source)) {
return;
}

uniqueSources.add(source);
let fileName = attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || FileUtils.getFileName(`${source}`);

// Public image URLs might lack a file extension in the source URL, without an extension our
// AttachmentView fails to recognize them as images and renders fallback content instead.
// We apply this small hack to add an image extension and ensure AttachmentView renders the image.
const fileInfo = FileUtils.splitExtensionFromFileName(fileName);
if (!fileInfo.fileExtension) {
fileName = `${fileInfo.fileName || 'image'}.jpg`;
}

// By iterating actions in chronological order and prepending each attachment
// we ensure correct order of attachments even across actions with multiple attachments.
Expand Down
16 changes: 16 additions & 0 deletions src/components/Attachments/AttachmentView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const defaultProps = {
reportActionID: '',
isHovered: false,
optionalVideoDuration: 0,
fallbackSource: Expensicons.Gallery,
};

function AttachmentView({
Expand Down Expand Up @@ -201,6 +202,21 @@ function AttachmentView({
// We also check for numeric source since this is how static images (used for preview) are represented in RN.
const isImage = typeof source === 'number' || Str.isImage(source);
if (isImage || (file && Str.isImage(file.name))) {
if (imageError) {
// AttachmentViewImage can't handle icon fallbacks, so we need to handle it here
if (typeof fallbackSource === 'number' || _.isFunction(fallbackSource)) {
return (
<Icon
src={fallbackSource}
height={variables.defaultAvatarPreviewSize}
width={variables.defaultAvatarPreviewSize}
additionalStyles={[styles.alignItemsCenter, styles.justifyContentCenter, styles.flex1]}
fill={theme.border}
/>
);
}
}

return (
<AttachmentViewImage
url={imageError ? fallbackSource : source}
Expand Down
3 changes: 1 addition & 2 deletions src/pages/home/report/ReportAttachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ function ReportAttachments({route}: ReportAttachmentsProps) {
const report = ReportUtils.getReport(reportID);

// In native the imported images sources are of type number. Ref: https://reactnative.dev/docs/image#imagesource
const decodedSource = decodeURI(route.params.source);
const source = Number(decodedSource) || decodedSource;
const source = Number(route.params.source) || route.params.source;

const onCarouselAttachmentChange = useCallback(
(attachment: Attachment) => {
Expand Down

0 comments on commit 208aafa

Please sign in to comment.