From 1fc550127e85a71b65ad1722df63eb42407f1bc1 Mon Sep 17 00:00:00 2001 From: Nathan Woulfe Date: Thu, 2 Mar 2023 14:46:15 +1000 Subject: [PATCH] macro service --- .../libs/macro/macro.service.ts | 151 ++++++++++++++++++ .../libs/macro/rollup.config.js | 4 + 2 files changed, 155 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/macro/macro.service.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/macro/rollup.config.js diff --git a/src/Umbraco.Web.UI.Client/libs/macro/macro.service.ts b/src/Umbraco.Web.UI.Client/libs/macro/macro.service.ts new file mode 100644 index 0000000000..9fc26a52d2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/macro/macro.service.ts @@ -0,0 +1,151 @@ +import { UmbContextToken } from "@umbraco-cms/context-api"; + +export interface MacroSyntaxData { macroAlias: string, macroParamsDictionary: {[key: string]: string}, syntax?: string}; + +export class UmbMacroService { + + /** parses the special macro syntax like + * and returns an object with the macro alias and it's parameters + * */ + parseMacroSyntax(syntax = '') { + + //This regex will match an alias of anything except characters that are quotes or new lines (for legacy reasons, when new macros are created + // their aliases are cleaned an invalid chars are stripped) + const expression = /(<\?UMBRACO_MACRO (?:.+?)?macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i; + const match = expression.exec(syntax); + + if (!match || match.length < 3) { + return null; + } + + const macroAlias = match[2]; + + //this will leave us with just the parameters + const paramsChunk = match[1].trim().replace(new RegExp("UMBRACO_MACRO macroAlias=[\"']" + macroAlias + "[\"']"), "").trim(); + const paramExpression = /(\w+?)=['\"]([\s\S]*?)['\"]/g; + + const returnVal: MacroSyntaxData = { + macroAlias, + macroParamsDictionary: {} + }; + + let paramMatch; + while ((paramMatch = paramExpression.exec(paramsChunk))) { + returnVal.macroParamsDictionary[paramMatch[1]] = paramMatch[2]; + } + + return returnVal; + } + + /** + * generates the syntax for inserting a macro into a rich text editor - this is the very old umbraco style syntax * + * @param {MacroSyntaxData} args an object containing the macro alias and it's parameter values + */ + generateMacroSyntax(args: MacroSyntaxData) { + + let macroString = `'; + + return macroString; + } + + /** + * generates the syntax for inserting a macro into an mvc template * + * @param {object} args an object containing the macro alias and it's parameter values + */ + generateMvcSyntax(args: MacroSyntaxData) { + + let macroString = `@await Umbraco.RenderMacroAsync("${args.macroAlias}"`; + + let hasParams = false; + let paramString = ''; + if (args.macroParamsDictionary) { + + paramString = ', new {'; + + for (const [key, val] of Object.entries(args.macroParamsDictionary)) { + hasParams = true; + + const keyVal = `${key}="${(val ? val : '')}", `; + + paramString += keyVal; + } + + //remove the last , and trailing whitespace + paramString = paramString.trimEnd().replace(/,*$/, ''); + paramString += '}'; + } + + if (hasParams) { + macroString += paramString; + } + + macroString += ')'; + + return macroString; + } + + collectValueData(macro: any, macroParams: any, renderingEngine: any) { + + const macroParamsDictionary: { [key: string]: string} = {}; + const macroAlias = macro.alias; + if (!macroAlias) { + throw "The macro object does not contain an alias"; + } + + let syntax; + + macroParams.forEach((item: any) => { + let val = item.value; + if (item.value !== null && item.value !== undefined && typeof item.value !== 'string') { + try { + val = JSON.parse(val); + } + catch (e) { + // not json + } + } + + //each value needs to be xml escaped!! since the value get's stored as an xml attribute + macroParamsDictionary[item.alias] = encodeURIComponent(val); + }); + + //get the syntax based on the rendering engine + if (renderingEngine && renderingEngine.toLowerCase() === 'mvc') { + syntax = this.generateMvcSyntax({ macroAlias, macroParamsDictionary }); + } + else { + syntax = this.generateMacroSyntax({ macroAlias, macroParamsDictionary }); + } + + return { + macroParamsDictionary, + macroAlias, + syntax, + }; + } +} + +export const UMB_MACRO_SERVICE_CONTEXT_TOKEN = new UmbContextToken( + UmbMacroService.name +); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/libs/macro/rollup.config.js b/src/Umbraco.Web.UI.Client/libs/macro/rollup.config.js new file mode 100644 index 0000000000..945c0afe88 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/macro/rollup.config.js @@ -0,0 +1,4 @@ +import config from '../../utils/rollup.config.js'; +export default { + ...config, +};