From da13cf57942cfc13f8c1e15de150e8d3adf1b322 Mon Sep 17 00:00:00 2001 From: Devasia Joseph Date: Tue, 7 Jul 2026 19:08:56 +0530 Subject: [PATCH] fix: contract jsinput html_file asset URLs to /static/ on save (LP-704) --- .../TinyMceWidget/hooks.test.js | 29 +++++++++++++++++++ .../sharedComponents/TinyMceWidget/hooks.ts | 9 ++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/editors/sharedComponents/TinyMceWidget/hooks.test.js b/src/editors/sharedComponents/TinyMceWidget/hooks.test.js index 1eb2ed787b..ff02b2b758 100644 --- a/src/editors/sharedComponents/TinyMceWidget/hooks.test.js +++ b/src/editors/sharedComponents/TinyMceWidget/hooks.test.js @@ -227,6 +227,35 @@ describe('TinyMceEditor hooks', () => { const content = module.setAssetToStaticUrl({ editorValue, lmsEndpointUrl }); expect(content).toEqual(' testing link'); }); + it('returns content with updated jsinput html_file links', () => { + const editorValue = ``; + const lmsEndpointUrl = getConfig().LMS_BASE_URL; + const content = module.setAssetToStaticUrl({ editorValue, lmsEndpointUrl }); + expect(content).toEqual(''); + }); + it('returns content with updated jsinput html_file links when URL is absolute', () => { + const lmsEndpointUrl = getConfig().LMS_BASE_URL; + const editorValue = ``; + const content = module.setAssetToStaticUrl({ editorValue, lmsEndpointUrl }); + expect(content).toEqual(''); + }); + it('returns content with updated jsinput html_file links using encoded quotes', () => { + const editorValue = ``; + const lmsEndpointUrl = getConfig().LMS_BASE_URL; + const content = module.setAssetToStaticUrl({ editorValue, lmsEndpointUrl }); + expect(content).toEqual(''); + }); + it('does not strip the literal text "undefined" when lmsEndpointUrl is not provided', () => { + const editorValue = `

value may be undefined

`; + const content = module.setAssetToStaticUrl({ editorValue }); + expect(content).toEqual('

value may be undefined

'); + }); + it('returns content with updated href links using encoded quotes', () => { + const editorValue = `testing link`; + const lmsEndpointUrl = getConfig().LMS_BASE_URL; + const content = module.setAssetToStaticUrl({ editorValue, lmsEndpointUrl }); + expect(content).toEqual('testing link'); + }); }); describe('editorConfig', () => { diff --git a/src/editors/sharedComponents/TinyMceWidget/hooks.ts b/src/editors/sharedComponents/TinyMceWidget/hooks.ts index 9439bad51d..a80099bca0 100644 --- a/src/editors/sharedComponents/TinyMceWidget/hooks.ts +++ b/src/editors/sharedComponents/TinyMceWidget/hooks.ts @@ -510,10 +510,13 @@ export const setAssetToStaticUrl = ({ editorValue, lmsEndpointUrl }) => { // TODO: should probably move this to when the assets are being looped through in the off chance that // some of the text in the editor contains the lmsEndpointUrl - const regExLmsEndpointUrl = RegExp(lmsEndpointUrl, 'g'); - let content = editorValue.replace(regExLmsEndpointUrl, ''); + let content = editorValue; + if (lmsEndpointUrl) { + const escapedLmsEndpointUrl = lmsEndpointUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + content = content.replace(RegExp(escapedLmsEndpointUrl, 'g'), ''); + } - const assetSrcs = typeof content === 'string' ? content.split(/(src="|src="|href="|href=")/g) : []; + const assetSrcs = typeof content === 'string' ? content.split(/(src="|src="|href="|href="|html_file="|html_file=")/g) : []; assetSrcs.filter(src => src.startsWith('/asset')).forEach(src => { const nameFromEditorSrc = parseAssetName(src); const portableUrl = getStaticUrl({ displayName: nameFromEditorSrc });