diff --git a/src/main/resources/lib/enonic/react4xp/DataFetcher.ts b/src/main/resources/lib/enonic/react4xp/DataFetcher.ts index 357f675e..07d31a98 100644 --- a/src/main/resources/lib/enonic/react4xp/DataFetcher.ts +++ b/src/main/resources/lib/enonic/react4xp/DataFetcher.ts @@ -51,7 +51,7 @@ import { import { getCachedPageComponentFromContentType } from '/lib/enonic/react4xp/pageTemplate/getCachedPageComponentFromContentType'; import { getCachedPageComponentFromPageTemplateContentId } from '/lib/enonic/react4xp/pageTemplate/getCachedPageComponentFromPageTemplateContentId'; -import {replaceMacroComments} from './replaceMacroComments'; +import { dataFromProcessedHtml } from '/lib/enonic/react4xp/dataFromProcessedHtml'; export type FragmentContent< @@ -515,7 +515,7 @@ export class DataFetcher { const processedHtml = processHtml({ value: html }); - const data = replaceMacroComments(processedHtml); + const data = dataFromProcessedHtml(processedHtml); setIn(processedComponent, path, data); } } // for @@ -545,7 +545,7 @@ export class DataFetcher { }); const renderableTextComponent: RenderableTextComponent = JSON.parse(JSON.stringify(component)); renderableTextComponent.props = { - data: replaceMacroComments(processedHtml), + data: dataFromProcessedHtml(processedHtml), mode }; return renderableTextComponent; @@ -586,7 +586,7 @@ export class DataFetcher { const processedHtml = processHtml({ value: html }); - const data = replaceMacroComments(processedHtml); + const data = dataFromProcessedHtml(processedHtml); setIn(processedLayoutOrPageComponent, path, data); } } // for diff --git a/src/main/resources/lib/enonic/react4xp/dataFromProcessedHtml.ts b/src/main/resources/lib/enonic/react4xp/dataFromProcessedHtml.ts new file mode 100644 index 00000000..4dfcc074 --- /dev/null +++ b/src/main/resources/lib/enonic/react4xp/dataFromProcessedHtml.ts @@ -0,0 +1,115 @@ +import type { + ImageContent, + ImageData, + MacroData, + RichTextData +} from '@enonic/react-components'; +import {get as getContentByKey} from '/lib/xp/content'; + + +export function dataFromProcessedHtml(processedHtml: string): RichTextData { + const rv: RichTextData = { + processedHtml, + macros: [], + images: [], + links: [], + }; + let index = 0; + rv.processedHtml = processedHtml + .replace( + /
()<\/p>/gm, + '$1' + ) + .replace( + /
()<\/pre>/gm, + '$1' + ) + .replace( + //gm, + (_origHtmlMacroComment, attributesString) => { + // Replacer is executed once per match (macro comment) + index++; + const ref = index.toString(); + let name: string = ''; + const macro: Partial= { + config: {}, + ref, + }; + const replacedAttributes = attributesString.replace( + /([^=]+)="([^"]*)"\s*/g, + (_kv, key, value) => { + // Replacer is executed once per match (attribute key/value) + if (key === '_name') { + name = value; + macro.name = name; + macro.descriptor = `whatever:${name}`; + return `data-macro-name="${value}" data-macro-ref="${ref}"`; + } + if (key === '_document') { + return ''; + } + if (key === '_body') { + key = 'body'; + } + if (macro.config && name) { + if (!macro.config[name]) { + macro.config[name] = {}; + } + macro.config[name][key] = value; + } + return ''; + } + ) + const replacedMacro = ` `; + if (rv.macros) { + rv.macros.push(macro as MacroData); + } + return replacedMacro; + } // single macro replacer + ); + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match + // If the g flag is used, all results matching the complete regular expression will be returned, but capturing groups are not included. + rv.processedHtml = rv.processedHtml.replace(//gm, + (_origImgString, imgAttributesString) => { + // Replacer is executed once per match (img element) + index++; + const ref = index.toString(); + + const srcMatches = imgAttributesString.match(/src="((?:.*?\n?)*?)"/m); + if (!srcMatches) { + throw new Error(`No src attribute found in imgAttributesString:${imgAttributesString}!`); + } + const [_fullSrc, src] = srcMatches; + // (log||console).debug('src:%s', src); + + const idMatches = src.match(/_\/image\/([0-9a-f-]+)/); + // (log||console).debug('idMatches:%s', idMatches); + + if (!idMatches) { + throw new Error(`No image id found in src:${src}!`); + } + const [_fullId, imageContentId] = idMatches; + // (log||console).debug('imageContentId:%s', imageContentId); + + const imageContent: ImageContent = getContentByKey({ key: imageContentId }); + if (!imageContent) { + throw new Error(`No image content found for id:${imageContentId}!`); + } + // (log||console).debug('imageContent:%s', imageContent); + + const image = { + image: imageContent, + ref, + // style: null // TODO + }; + rv.images.push(image as ImageData); + const replacedImage = ``; + // (log||console).debug('replacedImage:%s', replacedImage); + return replacedImage; + }); + + // NOTE content-links seems to work fine without any special handling + + return rv; +} diff --git a/src/main/resources/lib/enonic/react4xp/replaceMacroComments.ts b/src/main/resources/lib/enonic/react4xp/replaceMacroComments.ts deleted file mode 100644 index cea78da4..00000000 --- a/src/main/resources/lib/enonic/react4xp/replaceMacroComments.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { - MacroData, - RichTextData -} from '@enonic/react-components'; - -export function replaceMacroComments(processedHtml: string): RichTextData { - const rv: RichTextData = { - processedHtml, - macros: [] - }; - let index = 0; - rv.processedHtml = processedHtml - .replace( - / ()<\/p>/gm, - '$1' - ) - .replace( - /
()<\/pre>/gm, - '$1' - ) - .replace( - //gm, - (_origHtmlMacroComment, attributesString) => { - // Replacer is executed once per match (macro comment) - index++; - const ref = index.toString(); - let name: string = ''; - const macro: Partial= { - config: {}, - ref, - }; - const replacedAttributes = attributesString.replace( - /([^=]+)="([^"]*)"\s*/g, - (_kv, key, value) => { - // Replacer is executed once per match (attribute key/value) - if (key === '_name') { - name = value; - macro.name = name; - macro.descriptor = `whatever:${name}`; - return `data-macro-name="${value}" data-macro-ref="${ref}"`; - } - if (key === '_document') { - return ''; - } - if (key === '_body') { - key = 'body'; - } - if (macro.config && name) { - if (!macro.config[name]) { - macro.config[name] = {}; - } - macro.config[name][key] = value; - } - return ''; - } - ) - const replacedMacro = ` `; - if (rv.macros) { - rv.macros.push(macro as MacroData); - } - return replacedMacro; - } // single macro replacer - ); - return rv; -}