diff --git a/__tests__/ExpensiMark-HTML-test.js b/__tests__/ExpensiMark-HTML-test.js
index 1417cc5a..488088d4 100644
--- a/__tests__/ExpensiMark-HTML-test.js
+++ b/__tests__/ExpensiMark-HTML-test.js
@@ -2102,7 +2102,7 @@ describe('Video markdown conversion to html tag', () => {
const resultString = '';
expect(parser.replace(testString, {
extras: {
- videoAttributeCache: {
+ mediaAttributeCache: {
'https://example.com/video.mp4': 'data-expensify-height="100" data-expensify-width="100"'
}
}
diff --git a/__tests__/ExpensiMark-Markdown-test.js b/__tests__/ExpensiMark-Markdown-test.js
index 1ebfd21a..9199ca7d 100644
--- a/__tests__/ExpensiMark-Markdown-test.js
+++ b/__tests__/ExpensiMark-Markdown-test.js
@@ -867,6 +867,18 @@ describe('Image tag conversion to markdown', () => {
const resultString = '![```code```](https://example.com/image.png)';
expect(parser.htmlToMarkdown(testString)).toBe(resultString);
});
+
+ test('Cache extra attributes for img', () => {
+ const cacheMediaAttributes = jest.fn();
+ const testString = '';
+ const resultString = '![altText](https://example.com/image.png)';
+ const extras = {
+ cacheMediaAttributes,
+ };
+ expect(parser.htmlToMarkdown(testString, extras)).toBe(resultString);
+ expect(cacheMediaAttributes).toHaveBeenCalledWith("https://example.com/image.png", 'data-expensify-width="100" data-expensify-height="500" data-name="newName" data-expensify-source="expensify-source"')
+ });
+
});
describe('Video tag conversion to markdown', () => {
@@ -883,14 +895,14 @@ describe('Video tag conversion to markdown', () => {
})
test('While convert video, cache some extra attributes from the video tag', () => {
- const cacheVideoAttributes = jest.fn();
+ const cacheMediaAttributes = jest.fn();
const testString = '';
const resultString = '![video](https://example.com/video.mp4)';
const extras = {
- cacheVideoAttributes,
+ cacheMediaAttributes,
};
expect(parser.htmlToMarkdown(testString, extras)).toBe(resultString);
- expect(cacheVideoAttributes).toHaveBeenCalledWith("https://example.com/video.mp4", ' data-expensify-width="100" data-expensify-height="500" data-expensify-thumbnail-url="https://image.com/img.jpg"')
+ expect(cacheMediaAttributes).toHaveBeenCalledWith("https://example.com/video.mp4", ' data-expensify-width="100" data-expensify-height="500" data-expensify-thumbnail-url="https://image.com/img.jpg"')
})
})
diff --git a/lib/ExpensiMark.ts b/lib/ExpensiMark.ts
index 0a17a763..b125b578 100644
--- a/lib/ExpensiMark.ts
+++ b/lib/ExpensiMark.ts
@@ -9,8 +9,8 @@ import * as Utils from './utils';
type Extras = {
reportIDToName?: Record;
accountIDToName?: Record;
- cacheVideoAttributes?: (vidSource: string, attrs: string) => void;
- videoAttributeCache?: Record;
+ cacheMediaAttributes?: (mediaSource: string, attrs: string) => void;
+ mediaAttributeCache?: Record;
};
const EXTRAS_DEFAULT = {};
@@ -171,11 +171,11 @@ export default class ExpensiMark {
* @return Returns the HTML video tag
*/
replacement: (extras, _match, videoName, videoSource) => {
- const extraAttrs = extras && extras.videoAttributeCache && extras.videoAttributeCache[videoSource];
+ const extraAttrs = extras && extras.mediaAttributeCache && extras.mediaAttributeCache[videoSource];
return ``;
},
rawInputReplacement: (extras, _match, videoName, videoSource) => {
- const extraAttrs = extras && extras.videoAttributeCache && extras.videoAttributeCache[videoSource];
+ const extraAttrs = extras && extras.mediaAttributeCache && extras.mediaAttributeCache[videoSource];
return ``;
},
},
@@ -658,13 +658,37 @@ export default class ExpensiMark {
{
name: 'image',
- regex: /<]*src\s*=\s*(['"])(.*?)\1(?:[^><]*alt\s*=\s*(['"])(.*?)\3)?[^><]*>*(?![^<][\s\S]*?(<\/pre>|<\/code>))/gi,
- replacement: (_extras, _match, _g1, g2, _g3, g4) => {
- if (g4) {
- return `![${g4}](${g2})`;
+ regex: /<]*src\s*=\s*(['"])(.*?)\1(.*?)>(?![^<][\s\S]*?(<\/pre>|<\/code>))/gi,
+ /**
+ * @param extras - The extras object
+ * @param match - The full match
+ * @param _g1 - The first capture group (the quote)
+ * @param imgSource - The second capture group - src attribute value
+ * @param imgAttrs - The third capture group - any attributes after src
+ * @returns The markdown image tag
+ */
+ replacement: (extras, _match, _g1, imgSource, imgAttrs) => {
+ // Extract alt attribute from imgAttrs
+ let altText = '';
+ const altRegex = /alt\s*=\s*(['"])(.*?)\1/i;
+ const altMatch = imgAttrs.match(altRegex);
+ let attributes = '';
+ if (altMatch) {
+ altText = altMatch[2];
+ // Remove the alt attribute from imgAttrs
+ attributes = imgAttrs.replace(altRegex, '');
}
-
- return `!(${g2})`;
+ // Remove trailing slash and extra whitespace
+ attributes = attributes.replace(/\s*\/\s*$/, '').trim();
+ // Cache attributes without alt and trailing slash
+ if (imgAttrs && extras && extras.cacheMediaAttributes && typeof extras.cacheMediaAttributes === 'function') {
+ extras.cacheMediaAttributes(imgSource, attributes);
+ }
+ // Return the markdown image tag
+ if (altText) {
+ return `![${altText}](${imgSource})`;
+ }
+ return `!(${imgSource})`;
},
},
@@ -681,8 +705,8 @@ export default class ExpensiMark {
* @returns The markdown video tag
*/
replacement: (extras, _match, _g1, videoSource, videoAttrs, videoName) => {
- if (videoAttrs && extras && extras.cacheVideoAttributes && typeof extras.cacheVideoAttributes === 'function') {
- extras.cacheVideoAttributes(videoSource, videoAttrs);
+ if (videoAttrs && extras && extras.cacheMediaAttributes && typeof extras.cacheMediaAttributes === 'function') {
+ extras.cacheMediaAttributes(videoSource, videoAttrs);
}
if (videoName) {
return `![${videoName}](${videoSource})`;