diff --git a/README.md b/README.md index 24529ce..31524f4 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ variables: # {{ states('sensor.time') }} ``` -## Defining global functions in variables +### Defining global functions in variables If you find yourself having to rewrite the same logic in multiple locations, you can define global methods inside Config Template Card's variables, which can be called anywhere within the scope of the card: @@ -185,7 +185,7 @@ type: 'custom:config-template-card' name: '${ setTempMessage("House: ", currentTemp) }' ```` -## Dashboard wide variables +### Dashboard wide variables If you need to use the same variable in multiple cards, then instead of defining it in each card's `variables` you can do that once for the entire dashboard. @@ -202,7 +202,13 @@ Both arrays and objects are supported, just like in card's local variables. It i ### Note: All templates must be enclosed by `${}`, except when defining variables. -[Troubleshooting](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins) +`${}` is optional in variable definitions (variables will be parsed as templates even without `${}`). + +Values that begin with `$!` will not be parsed for templates. `$!` will be stripped from the beginning of the value, but any `${}` sequences within the value will be left as-is. + +## Troubleshooting + +[General HA Plugin Troubleshooting](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins) ## Developers diff --git a/src/config-template-card.ts b/src/config-template-card.ts index fb915cc..714ef4d 100644 --- a/src/config-template-card.ts +++ b/src/config-template-card.ts @@ -53,9 +53,9 @@ export class ConfigTemplateCard extends LitElement { } private _initialize(): void { - if (this.hass === undefined) return; - if (this._config === undefined) return; - if (this._helpers === undefined) return; + if (this.hass === undefined) { return }; + if (this._config === undefined) { return }; + if (this._helpers === undefined) { return }; this._initialized = true; globalThis._ctcVarMgr = this._varMgr; // Used by _evalWithVars() } @@ -210,14 +210,14 @@ export class ConfigTemplateCard extends LitElement { } for (let v of structuredClone(arrayVars)) { - if (isString(v) && !v.includes('${')) { v = this._evalWithVars(v); } + if (isString(v)) { v = this._evaluateTemplate(v, true); } else { v = this._evaluateStructure(v); } vars.push(v); } for (const varName in structuredClone(namedVars)) { let v = namedVars[varName]; - if (isString(v) && !v.includes('${')) { v = this._evalWithVars(v); } + if (isString(v)) { v = this._evaluateTemplate(v, true); } else { v = this._evaluateStructure(v); } vars[varName] = v; this._varMgr._evalInitVars += `var ${varName} = vars['${varName}'];\n`; @@ -237,23 +237,36 @@ export class ConfigTemplateCard extends LitElement { const value = entry[1]; struct[key] = this._evaluateStructure(value); }); - } else if (isString(struct) && struct.includes('${')) { + } else if (isString(struct)) { return this._evaluateTemplate(struct); } return struct; } - private _evaluateTemplate(template: string): any { + private _evaluateTemplate(template: string, withoutDelim = false): any { + if (template.startsWith('$!')) { + return template.substring(2, template.length); + } + if (template.startsWith('${') && template.endsWith('}')) { // The entire property is a template, return eval's result directly // to preserve types other than string (eg. numbers) return this._evalWithVars(template.substring(2, template.length - 1)); } - /\${[^}]+}/.exec(template)?.forEach(m => { - const repl = this._evalWithVars(m.substring(2, m.length - 1)).toString() as string; - template = template.replace(m, repl); - }); + const matches = /\${[^}]+}/.exec(template); + if (matches) { + matches.forEach(m => { + const repl = this._evalWithVars(m.substring(2, m.length - 1)).toString() as string; + template = template.replace(m, repl); + }); + return template; + } + + if (withoutDelim) { + return this._evalWithVars(template); + } + return template; }