fix: bugs with some static asset paths in TinyMCE editors (#2702)

* fix: only convert assets static file path

* fix: direct static file is fixed

* fix: setting newContent now load the content in html as well
This commit is contained in:
Muhammad Arslan
2025-12-11 22:19:40 +05:00
committed by GitHub
parent 67a5694ca3
commit a596bf5d38
2 changed files with 28 additions and 6 deletions

View File

@@ -213,6 +213,15 @@ describe('TinyMceEditor hooks', () => {
const actual = module.replaceStaticWithAsset({ initialContent: content, learningContextId });
expect(actual).toBeFalsy();
});
it('does not convert static URLs with subdirectories but converts direct static files', () => {
const contentWithSubdirectory = '<img src="/static/images/placeholder-faculty.png"/><img src="/static/example.jpg"/>';
const expected = `<img src="/static/images/placeholder-faculty.png"/><img src="/${baseAssetUrl}@example.jpg"/>`;
const actual = module.replaceStaticWithAsset({
initialContent: contentWithSubdirectory,
learningContextId,
});
expect(actual).toEqual(expected);
});
});
describe('setAssetToStaticUrl', () => {
it('returns content with updated img links', () => {

View File

@@ -121,10 +121,17 @@ export const replaceStaticWithAsset = ({
let staticFullUrl;
const isStatic = src.startsWith('/static/');
const assetSrc = src.substring(0, src.indexOf('"'));
// Check if this is a direct /static/filename.ext pattern (should be converted)
// vs /static/images/filename.ext pattern (should NOT be converted)
// /static/images/ are direct links to images stored in static, not course assets
// we have dummy images there for course content that should not be converted to assets
const isDirectStaticFile = (isStatic || assetSrc.startsWith('/asset')) && !assetSrc.substring(8).includes('images/');
const staticName = assetSrc.substring(8);
const assetName = parseAssetName(src);
const displayName = isStatic ? staticName : assetName;
const isCorrectAssetFormat = assetSrc.startsWith('/asset') && assetSrc.match(/\/asset-v1:\S+[+]\S+[@]\S+[+]\S+[@]/g)?.length >= 1;
const isCorrectAssetFormat = assetSrc.match(/\/asset-v1:\S+[+]\S+[@]\S+[+]\S+[@]/g)?.length >= 1;
// assets in expandable text areas do not support relative urls so all assets must have the lms
// endpoint prepended to the relative url
@@ -133,16 +140,16 @@ export const replaceStaticWithAsset = ({
// set the base URL to an endpoint serving the draft version of an asset by
// its path.
/* istanbul ignore next */
if (isStatic) {
if (isStatic && isDirectStaticFile) {
staticFullUrl = assetSrc.substring(1);
}
} else if (editorType === 'expandable') {
if (isCorrectAssetFormat) {
staticFullUrl = `${lmsEndpointUrl}${assetSrc}`;
} else {
} else if (isDirectStaticFile) {
staticFullUrl = `${lmsEndpointUrl}${getRelativeUrl({ courseId: learningContextId, displayName })}`;
}
} else if (!isCorrectAssetFormat) {
} else if (!isCorrectAssetFormat && isDirectStaticFile) {
staticFullUrl = getRelativeUrl({ courseId: learningContextId, displayName });
}
if (staticFullUrl) {
@@ -365,12 +372,18 @@ export const setupCustomBehavior = ({
editor.on('ExecCommand', /* istanbul ignore next */ (e) => {
if (editorType === 'text' && e.command === 'mceFocus') {
const initialContent = editor.getContent();
// @ts-ignore Some parameters like 'lmsEndpointUrl' were missing here. Fix me?
const newContent = replaceStaticWithAsset({
initialContent,
editorType,
lmsEndpointUrl,
learningContextId,
});
if (newContent) { editor.setContent(newContent); }
if (newContent) {
// Use setTimeout to ensure the update happens after current execution
setTimeout(() => {
editor.setContent(newContent);
}, 0);
}
}
if (e.command === 'RemoveFormat') {
editor.formatter.remove('blockquote');