Improved templates
This commit is contained in:
parent
01e9afef1b
commit
a89860815f
@ -85,7 +85,7 @@ The following functions are defined:
|
||||
| `cardTools.moreInfo(entity)` | 0.1 | Brings up the `more-info` dialog for the specified `entity` id |
|
||||
| `cardTools.longPress(element)` | 0.1 | Bind `element` to the long-press handler of lovelace |
|
||||
| `cardTools.hasTemplate(text)` | 0.2 | Check if `text` contains a simple state template |
|
||||
| `cardTools.parseTemplate(text, [error])` | 0.2 | Parse a simple state template and return results |
|
||||
| `cardTools.parseTemplate(text, [data])` | 0.2 | Parse a simple state template and return results |
|
||||
| `cardTools.args(script)` | 0.3 | Returns URL parameters of the script from `resources:` |
|
||||
| `cardTools.localize(key)` | 0.3 | Returns translations of certains strings to the users language |
|
||||
| `cardTools.lovelace`| 0.4 | A reference to a structure containing some information about the users lovelace configuration |
|
||||
@ -220,7 +220,7 @@ Next is one of:
|
||||
|
||||
The function replaces any template found in the supplied string with the requested value, or an error message on failure.
|
||||
|
||||
The optional argument `error` is a string that replaces the default error message.
|
||||
The optional argument `data` can be an object containing extra data for templates. In a template `{key}` will be evaluated to `data[key]`.
|
||||
|
||||
`cardTools.hasTemplate` just checks if a string contains a simple state template.
|
||||
|
||||
@ -286,3 +286,4 @@ The `script` parameter is required if `cardTools.logger` is called from within a
|
||||
- Added `script` parameter to `cardTools.args`
|
||||
|
||||
---
|
||||
<a href="https://www.buymeacoffee.com/uqD6KHCdJ" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/white_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>
|
||||
|
@ -211,23 +211,60 @@ class {
|
||||
return /\[\[\s+.*\s+\]\]/.test(text);
|
||||
}
|
||||
|
||||
static parseTemplateString(str) {
|
||||
static parseTemplateString(str, specialData = {}) {
|
||||
if(typeof(str) !== "string") return text;
|
||||
var RE_entity = /^[a-zA-Z0-9_.]+\.[a-zA-Z0-9_]+$/;
|
||||
var RE_if = /^if\(([^,]*),([^,]*),(.*)\)$/;
|
||||
var RE_expr = /([^=<>!]+)\s*(==|<|>|<=|>=|!=)\s*([^=<>!]+)/
|
||||
const FUNCTION = /^[a-zA-Z0-9_]+\(.*\)$/;
|
||||
const EXPR = /([^=<>!]+)\s*(==|!=|<|>|<=|>=)\s*([^=<>!]+)/;
|
||||
const SPECIAL = /^\{.+\}$/;
|
||||
const STRING = /^"[^"]*"|'[^']*'$/;
|
||||
|
||||
if(typeof(specialData) === "string") specialData = {};
|
||||
specialData = Object.assign({
|
||||
user: this.hass.user.name,
|
||||
browser: this.deviceID,
|
||||
hash: location.hash.substr(1) || ' ',
|
||||
}, specialData);
|
||||
|
||||
const _parse_function = (str) => {
|
||||
let args = [str.substr(0, str.indexOf('(')).trim()]
|
||||
str = str.substr(str.indexOf('(')+1);
|
||||
while(str) {
|
||||
let index = 0;
|
||||
let stack = [];
|
||||
while(str[index]) {
|
||||
if(",)".includes(str[index]) && !stack.length) break;
|
||||
if(str[index] == '(') stack.push(')');
|
||||
if(stack[stack.length - 1] === str[index]) stack.pop();
|
||||
else if(`"'`.includes(str[index])) stack.push(str[index]);
|
||||
index = index + 1;
|
||||
}
|
||||
args.push(str.substr(0, index).trim());
|
||||
str = str.substr(index+1);
|
||||
}
|
||||
return args;
|
||||
};
|
||||
|
||||
const _parse_special = (str) => {
|
||||
str = str.substr(1, str.length - 2);
|
||||
return specialData[str] || `{${str}}`;
|
||||
};
|
||||
|
||||
const _parse_entity = (str) => {
|
||||
str = str.trim();
|
||||
const parts = str.split(".");
|
||||
let v = this.hass().states[`${parts.shift()}.${parts.shift()}`];
|
||||
if(!parts.length) return v['state'];
|
||||
parts.forEach(item => v=v[item]);
|
||||
str = str.split(".");
|
||||
let v;
|
||||
if(str[0].match(SPECIAL)) {
|
||||
v = _parse_special(str.shift());
|
||||
v = this.hass().states[v] || v;
|
||||
} else {
|
||||
v = this.hass().states[`${str.shift()}.${str.shift()}`];
|
||||
if(!str.length) return v['state'];
|
||||
}
|
||||
str.forEach(item => v=v[item]);
|
||||
return v;
|
||||
}
|
||||
|
||||
const _parse_expr = (str) => {
|
||||
str = RE_expr.exec(str);
|
||||
const _eval_expr = (str) => {
|
||||
str = EXPR.exec(str);
|
||||
if(str === null) return false;
|
||||
const lhs = this.parseTemplateString(str[1]);
|
||||
const rhs = this.parseTemplateString(str[3]);
|
||||
@ -239,38 +276,35 @@ class {
|
||||
return eval(expr);
|
||||
}
|
||||
|
||||
const _parse_if = (str) => {
|
||||
str = RE_if.exec(str);
|
||||
if(_parse_expr(str[1]))
|
||||
return this.parseTemplateString(str[2]);
|
||||
return this.parseTemplateString(str[3]);
|
||||
const _eval_function = (args) => {
|
||||
if(args[0] === "if") {
|
||||
if(_eval_expr(args[1]))
|
||||
return this.parseTemplateString(args[2]);
|
||||
return this.parseTemplateString(args[3]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
str = str.trim();
|
||||
if(str.match(RE_if))
|
||||
return _parse_if(str);
|
||||
if(str.match(RE_entity))
|
||||
if(str.match(STRING))
|
||||
return str.substr(1, str.length - 2);
|
||||
if(str.match(SPECIAL))
|
||||
return _parse_special(str);
|
||||
if(str.match(FUNCTION))
|
||||
return _eval_function(_parse_function(str));
|
||||
if(str.includes("."))
|
||||
return _parse_entity(str);
|
||||
if(str.match(/^".*"$/) || str.match(/^'.*'$/))
|
||||
return str.substr(1, str.length-2);
|
||||
if(str.match(/{user}/))
|
||||
return this.hass().user.name;
|
||||
if(str.match(/{browser}/))
|
||||
return this.deviceID();
|
||||
if(str.match(/{hash}/))
|
||||
return location.hash.substr(1);
|
||||
return str;
|
||||
} catch (err) {
|
||||
return `[[ Template matching failed ${str} ]]`;
|
||||
return `[[ Template matching failed: ${str} ]]`;
|
||||
}
|
||||
}
|
||||
|
||||
static parseTemplate(text, error) {
|
||||
static parseTemplate(text, data = {}) {
|
||||
if(typeof(text) !== "string") return text;
|
||||
// Note: .*? is javascript regex syntax for NON-greedy matching
|
||||
var RE_template = /\[\[\s(.*?)\s\]\]/g;
|
||||
text = text.replace(RE_template, (str, p1, offset, s) => this.parseTemplateString(p1));
|
||||
text = text.replace(RE_template, (str, p1, offset, s) => this.parseTemplateString(p1, data));
|
||||
return text;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user