537 lines
25 KiB
JavaScript
537 lines
25 KiB
JavaScript
function getWidgetGroup(views, view, widget) {
|
|
var widgets = views[view].widgets;
|
|
var members;
|
|
for (var w in widgets) {
|
|
if (!widgets.hasOwnProperty(w)) continue;
|
|
members = views[view].widgets[w].data.members;
|
|
if (members && members.indexOf(widget) !== -1) {
|
|
return w;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function extractBinding(format) {
|
|
var oid = format.match(/{(.+?)}/g);
|
|
var result = null;
|
|
if (oid) {
|
|
if (oid.length > 50) {
|
|
console.warn('Too many bindings in one widget: ' + oid.length + '[max = 50]');
|
|
}
|
|
for (var p = 0; p < oid.length && p < 50; p++) {
|
|
var _oid = oid[p].substring(1, oid[p].length - 1);
|
|
if (_oid[0] === '{') continue;
|
|
// If first symbol '"' => it is JSON
|
|
if (_oid && _oid[0] === '"') continue;
|
|
var parts = _oid.split(';');
|
|
result = result || [];
|
|
var systemOid = parts[0].trim();
|
|
var visOid = systemOid;
|
|
|
|
var test1 = visOid.substring(visOid.length - 4);
|
|
var test2 = visOid.substring(visOid.length - 3);
|
|
|
|
if (visOid && test1 !== '.val' && test2 !== '.ts' && test2 !== '.lc' && test1 !== '.ack') {
|
|
visOid = visOid + '.val';
|
|
}
|
|
|
|
var isSeconds = (test2 === '.ts' || test2 === '.lc');
|
|
|
|
test1 = systemOid.substring(systemOid.length - 4);
|
|
test2 = systemOid.substring(systemOid.length - 3);
|
|
|
|
if (test1 === '.val' || test1 === '.ack') {
|
|
systemOid = systemOid.substring(0, systemOid.length - 4);
|
|
} else if (test2 === '.lc' || test2 === '.ts') {
|
|
systemOid = systemOid.substring(0, systemOid.length - 3);
|
|
}
|
|
var operations = null;
|
|
var isEval = visOid.match(/[\d\w_.]+:[-\d\w_.]+/) || (!visOid.length && parts.length > 0);//(visOid.indexOf(':') !== -1) && (visOid.indexOf('::') === -1);
|
|
|
|
if (isEval) {
|
|
var xx = visOid.split(':', 2);
|
|
var yy = systemOid.split(':', 2);
|
|
visOid = xx[1];
|
|
systemOid = yy[1];
|
|
operations = operations || [];
|
|
operations.push({
|
|
op: 'eval',
|
|
arg: [{
|
|
name: xx[0],
|
|
visOid: visOid,
|
|
systemOid: systemOid
|
|
}]
|
|
});
|
|
}
|
|
|
|
for (var u = 1; u < parts.length; u++) {
|
|
// eval construction
|
|
if (isEval) {
|
|
if (parts[u].trim().match(/^[\d\w_.]+:[-.\d\w_]+$/)) {//parts[u].indexOf(':') !== -1 && parts[u].indexOf('::') === -1) {
|
|
var _systemOid = parts[u].trim();
|
|
var _visOid = _systemOid;
|
|
|
|
test1 = _visOid.substring(_visOid.length - 4);
|
|
test2 = _visOid.substring(_visOid.length - 3);
|
|
|
|
if (test1 !== '.val' && test2 !== '.ts' && test2 !== '.lc' && test1 !== '.ack') {
|
|
_visOid = _visOid + '.val';
|
|
}
|
|
|
|
test1 = systemOid.substring(_systemOid.length - 4);
|
|
test2 = systemOid.substring(_systemOid.length - 3);
|
|
|
|
if (test1 === '.val' || test1 === '.ack') {
|
|
_systemOid = _systemOid.substring(0, _systemOid.length - 4);
|
|
} else if (test2 === '.lc' || test2 === '.ts') {
|
|
_systemOid = _systemOid.substring(0, _systemOid.length - 3);
|
|
}
|
|
var x1 = _visOid.split(':', 2);
|
|
var y1 = _systemOid.split(':', 2);
|
|
|
|
operations[0].arg.push({
|
|
name: x1[0],
|
|
visOid: x1[1],
|
|
systemOid: y1[1]
|
|
});
|
|
} else {
|
|
parts[u] = parts[u].replace(/::/g, ':');
|
|
if (operations[0].formula) {
|
|
var n = JSON.parse(JSON.stringify(operations[0]));
|
|
n.formula = parts[u];
|
|
operations.push(n);
|
|
} else {
|
|
operations[0].formula = parts[u];
|
|
}
|
|
}
|
|
} else {
|
|
var parse = parts[u].match(/([\w\s\/+*-]+)(\(.+\))?/);
|
|
if (parse && parse[1]) {
|
|
parse[1] = parse[1].trim();
|
|
// operators requires parameter
|
|
if (parse[1] === '*' ||
|
|
parse[1] === '+' ||
|
|
parse[1] === '-' ||
|
|
parse[1] === '/' ||
|
|
parse[1] === '%' ||
|
|
parse[1] === 'min' ||
|
|
parse[1] === 'max') {
|
|
if (parse[2] === undefined) {
|
|
console.log('Invalid format of format string: ' + format);
|
|
parse[2] = null;
|
|
} else {
|
|
parse[2] = (parse[2] || '').trim().replace(',', '.');
|
|
parse[2] = parse[2].substring(1, parse[2].length - 1);
|
|
parse[2] = parseFloat(parse[2].trim());
|
|
|
|
if (parse[2].toString() === 'NaN') {
|
|
console.log('Invalid format of format string: ' + format);
|
|
parse[2] = null;
|
|
} else {
|
|
operations = operations || [];
|
|
operations.push({op: parse[1], arg: parse[2]});
|
|
}
|
|
}
|
|
} else
|
|
// date formatting
|
|
if (parse[1] === 'date') {
|
|
operations = operations || [];
|
|
parse[2] = (parse[2] || '').trim();
|
|
parse[2] = parse[2].substring(1, parse[2].length - 1);
|
|
operations.push({op: parse[1], arg: parse[2]});
|
|
} else
|
|
// returns array[value]. e.g.: {id.ack;array(ack is false,ack is true)}
|
|
if (parse[1] === 'array') {
|
|
operations = operations || [];
|
|
param = (parse[2] || '').trim();
|
|
param = param.substring(1, param.length - 1);
|
|
param = param.split(',');
|
|
if (Array.isArray(param)) {
|
|
operations.push ({op: parse[1], arg: param}); //xxx
|
|
}
|
|
} else
|
|
// value formatting
|
|
if (parse[1] === 'value') {
|
|
operations = operations || [];
|
|
var param = (parse[2] === undefined) ? '(2)' : (parse[2] || '');
|
|
param = param.trim();
|
|
param = param.substring(1, param.length - 1);
|
|
operations.push({op: parse[1], arg: param});
|
|
} else
|
|
// operators have optional parameter
|
|
if (parse[1] === 'pow' || parse[1] === 'round' || parse[1] === 'random') {
|
|
if (parse[2] === undefined) {
|
|
operations = operations || [];
|
|
operations.push({op: parse[1]});
|
|
} else {
|
|
parse[2] = (parse[2] || '').trim().replace(',', '.');
|
|
parse[2] = parse[2].substring(1, parse[2].length - 1);
|
|
parse[2] = parseFloat(parse[2].trim());
|
|
|
|
if (parse[2].toString() === 'NaN') {
|
|
console.log('Invalid format of format string: ' + format);
|
|
parse[2] = null;
|
|
} else {
|
|
operations = operations || [];
|
|
operations.push({op: parse[1], arg: parse[2]});
|
|
}
|
|
}
|
|
} else
|
|
// operators without parameter
|
|
{
|
|
operations = operations || [];
|
|
operations.push({op: parse[1]});
|
|
}
|
|
} else {
|
|
console.log('Invalid format ' + format);
|
|
}
|
|
}
|
|
}
|
|
|
|
result.push({
|
|
visOid: visOid,
|
|
systemOid: systemOid,
|
|
token: oid[p],
|
|
operations: operations ? operations : undefined,
|
|
format: format,
|
|
isSeconds: isSeconds
|
|
});
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getUsedObjectIDs(views, isByViews) {
|
|
if (!views) {
|
|
console.log('Check why views are not yet loaded!');
|
|
return null;
|
|
}
|
|
|
|
var _views = isByViews ? {} : null;
|
|
var IDs = [];
|
|
var visibility = {};
|
|
var bindings = {};
|
|
var lastChanges = {};
|
|
var signals = {};
|
|
|
|
var view;
|
|
var id;
|
|
var sidd;
|
|
for (view in views) {
|
|
if (!views.hasOwnProperty(view)) continue;
|
|
|
|
if (view === '___settings') continue;
|
|
|
|
if (_views) _views[view] = [];
|
|
|
|
for (id in views[view].widgets) {
|
|
if (!views[view].widgets.hasOwnProperty(id)) continue;
|
|
// Check all attributes
|
|
var data = views[view].widgets[id].data;
|
|
var style = views[view].widgets[id].style;
|
|
|
|
// fix error in naming
|
|
if (views[view].widgets[id].groupped) {
|
|
views[view].widgets[id].grouped = true;
|
|
delete views[view].widgets[id].groupped;
|
|
}
|
|
|
|
// rename hqWidgets => hqwidgets
|
|
if (views[view].widgets[id].widgetSet === 'hqWidgets') {
|
|
views[view].widgets[id].widgetSet = 'hqwidgets';
|
|
}
|
|
|
|
// rename RGraph => rgraph
|
|
if (views[view].widgets[id].widgetSet === 'RGraph') {
|
|
views[view].widgets[id].widgetSet = 'rgraph';
|
|
}
|
|
|
|
// rename timeAndWeather => timeandweather
|
|
if (views[view].widgets[id].widgetSet === 'timeAndWeather') {
|
|
views[view].widgets[id].widgetSet = 'timeandweather';
|
|
}
|
|
|
|
// convert "Show on Value" to HTML
|
|
if (views[view].widgets[id].tpl === 'tplShowValue') {
|
|
views[view].widgets[id].tpl = 'tplHtml';
|
|
views[view].widgets[id].data['visibility-oid'] = views[view].widgets[id].data.oid;
|
|
views[view].widgets[id].data['visibility-val'] = views[view].widgets[id].data.value;
|
|
delete views[view].widgets[id].data.oid;
|
|
delete views[view].widgets[id].data.value;
|
|
}
|
|
|
|
// convert "Hide on >0/True" to HTML
|
|
if (views[view].widgets[id].tpl === 'tplHideTrue') {
|
|
views[view].widgets[id].tpl = 'tplHtml';
|
|
views[view].widgets[id].data['visibility-cond'] = '!=';
|
|
views[view].widgets[id].data['visibility-oid'] = views[view].widgets[id].data.oid;
|
|
views[view].widgets[id].data['visibility-val'] = true;
|
|
delete views[view].widgets[id].data.oid;
|
|
}
|
|
|
|
// convert "Hide on 0/False" to HTML
|
|
if (views[view].widgets[id].tpl === 'tplHide') {
|
|
views[view].widgets[id].tpl = 'tplHtml';
|
|
views[view].widgets[id].data['visibility-cond'] = '!=';
|
|
views[view].widgets[id].data['visibility-oid'] = views[view].widgets[id].data.oid;
|
|
views[view].widgets[id].data['visibility-val'] = false;
|
|
delete views[view].widgets[id].data.oid;
|
|
}
|
|
|
|
// convert "Door/Window sensor" to HTML
|
|
if (views[view].widgets[id].tpl === 'tplHmWindow') {
|
|
views[view].widgets[id].tpl = 'tplValueBool';
|
|
views[view].widgets[id].data.html_false = views[view].widgets[id].data.html_closed;
|
|
views[view].widgets[id].data.html_true = views[view].widgets[id].data.html_open;
|
|
delete views[view].widgets[id].data.html_closed;
|
|
delete views[view].widgets[id].data.html_open;
|
|
}
|
|
|
|
// convert "Door/Window sensor" to HTML
|
|
if (views[view].widgets[id].tpl === 'tplHmWindowRotary') {
|
|
views[view].widgets[id].tpl = 'tplValueListHtml8';
|
|
views[view].widgets[id].data.count = 2;
|
|
views[view].widgets[id].data.value0 = views[view].widgets[id].data.html_closed;
|
|
views[view].widgets[id].data.value1 = views[view].widgets[id].data.html_open;
|
|
views[view].widgets[id].data.value2 = views[view].widgets[id].data.html_tilt;
|
|
delete views[view].widgets[id].data.html_closed;
|
|
delete views[view].widgets[id].data.html_open;
|
|
delete views[view].widgets[id].data.html_tilt;
|
|
}
|
|
|
|
// convert "tplBulbOnOff" to tplBulbOnOffCtrl
|
|
if (views[view].widgets[id].tpl === 'tplBulbOnOff') {
|
|
views[view].widgets[id].tpl = 'tplBulbOnOffCtrl';
|
|
views[view].widgets[id].data.readOnly = true;
|
|
}
|
|
|
|
// convert "tplValueFloatBarVertical" to tplValueFloatBar
|
|
if (views[view].widgets[id].tpl === 'tplValueFloatBarVertical') {
|
|
views[view].widgets[id].tpl = 'tplValueFloatBar';
|
|
views[view].widgets[id].data.orientation = 'vertical';
|
|
}
|
|
|
|
for (var attr in data) {
|
|
if (!data.hasOwnProperty(attr) || !attr) continue;
|
|
/* TODO DO do not forget remove it after a while. Required for import from DashUI */
|
|
if (attr === 'state_id') {
|
|
data.state_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'state_oid';
|
|
} else
|
|
if (attr === 'number_id') {
|
|
data.number_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'number_oid';
|
|
} else
|
|
if (attr === 'toggle_id') {
|
|
data.toggle_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'toggle_oid';
|
|
} else
|
|
if (attr === 'set_id') {
|
|
data.set_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'set_oid';
|
|
} else
|
|
if (attr === 'temp_id') {
|
|
data.temp_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'temp_oid';
|
|
} else
|
|
if (attr === 'drive_id') {
|
|
data.drive_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'drive_oid';
|
|
} else
|
|
if (attr === 'content_id') {
|
|
data.content_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'content_oid';
|
|
} else
|
|
if (attr === 'dialog_id') {
|
|
data.dialog_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'dialog_oid';
|
|
} else
|
|
if (attr === 'max_value_id') {
|
|
data.max_value_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'max_value_oid';
|
|
} else
|
|
if (attr === 'dialog_id') {
|
|
data.dialog_oid = data[attr];
|
|
delete data[attr];
|
|
attr = 'dialog_oid';
|
|
} else
|
|
if (attr === 'weoid') {
|
|
data.woeid = data[attr];
|
|
delete data[attr];
|
|
attr = 'woeid';
|
|
}
|
|
|
|
if (typeof data[attr] === 'string') {
|
|
var m;
|
|
var oids = extractBinding(data[attr]);
|
|
if (oids) {
|
|
for (var t = 0; t < oids.length; t++) {
|
|
var ssid = oids[t].systemOid;
|
|
if (ssid) {
|
|
if (IDs.indexOf(ssid) === -1) IDs.push(ssid);
|
|
if (_views && _views[view].indexOf(ssid) === -1) _views[view].push(ssid);
|
|
if (!bindings[ssid]) bindings[ssid] = [];
|
|
oids[t].type = 'data';
|
|
oids[t].attr = attr;
|
|
oids[t].view = view;
|
|
oids[t].widget = id;
|
|
|
|
bindings[ssid].push(oids[t]);
|
|
}
|
|
|
|
if (oids[t].operations && oids[t].operations[0].arg instanceof Array) {
|
|
for (var ww = 0; ww < oids[t].operations[0].arg.length; ww++) {
|
|
ssid = oids[t].operations[0].arg[ww].systemOid;
|
|
if (!ssid) continue;
|
|
if (IDs.indexOf(ssid) === -1) IDs.push(ssid);
|
|
if (_views && _views[view].indexOf(ssid) === -1) _views[view].push(ssid);
|
|
if (!bindings[ssid]) bindings[ssid] = [];
|
|
bindings[ssid].push(oids[t]);
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
if (attr !== 'oidTrueValue' && attr !== 'oidFalseValue' && ((attr.match(/oid\d{0,2}$/) || attr.match(/^oid/) || attr.match(/^signals-oid-/) || attr === 'lc-oid') && data[attr])) {
|
|
if (data[attr] && data[attr] !== 'nothing_selected') {
|
|
if (IDs.indexOf(data[attr]) === -1) IDs.push(data[attr]);
|
|
if (_views && _views[view].indexOf(data[attr]) === -1) _views[view].push(data[attr]);
|
|
}
|
|
|
|
// Visibility binding
|
|
if (attr === 'visibility-oid' && data['visibility-oid']) {
|
|
var vid = data['visibility-oid'];
|
|
if (vid.match(/^groupAttr(\d+)$/)) {
|
|
var vgroup = getWidgetGroup(views, view, id);
|
|
if (vgroup) vid = views[view].widgets[vgroup].data[vid];
|
|
}
|
|
|
|
if (!visibility[vid]) visibility[vid] = [];
|
|
visibility[vid].push({view: view, widget: id});
|
|
}
|
|
|
|
// Signal binding
|
|
if (attr.match(/^signals-oid-/) && data[attr]) {
|
|
var sid = data[attr];
|
|
if (sid.match(/^groupAttr(\d+)$/)) {
|
|
var group = getWidgetGroup(views, view, id);
|
|
if (group) sid = views[view].widgets[group].data[sid];
|
|
}
|
|
|
|
if (!signals[sid]) signals[sid] = [];
|
|
signals[sid].push({
|
|
view: view,
|
|
widget: id,
|
|
index: parseInt(attr.substring('signals-oid-'.length), 10)
|
|
});
|
|
}
|
|
if (attr === 'lc-oid') {
|
|
var lcsid = data[attr];
|
|
if (lcsid.match(/^groupAttr(\d+)$/)) {
|
|
var ggroup = getWidgetGroup(views, view, id);
|
|
if (ggroup) lcsid = views[view].widgets[ggroup].data[lcsid];
|
|
}
|
|
|
|
if (!lastChanges[lcsid]) lastChanges[lcsid] = [];
|
|
lastChanges[lcsid].push({
|
|
view: view,
|
|
widget: id
|
|
});
|
|
}
|
|
} else
|
|
if ((m = attr.match(/^attrType(\d+)$/)) && data[attr] === 'id') {
|
|
var _id = 'groupAttr' + m[1];
|
|
if (data[_id]) {
|
|
if (IDs.indexOf(data[_id]) === -1) IDs.push(data[_id]);
|
|
if (_views && _views[view].indexOf(data[_id]) === -1) _views[view].push(data[_id]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// build bindings for styles
|
|
if (style) {
|
|
for (var cssAttr in style) {
|
|
if (!style.hasOwnProperty(cssAttr) || !cssAttr) continue;
|
|
if (typeof style[cssAttr] === 'string') {
|
|
var objIDs = extractBinding(style[cssAttr]);
|
|
if (objIDs) {
|
|
for (var tt = 0; tt < objIDs.length; tt++) {
|
|
sidd = objIDs[tt].systemOid;
|
|
if (sidd) {
|
|
if (IDs.indexOf(sidd) === -1) IDs.push(sidd);
|
|
if (_views && _views[view].indexOf(sidd) === -1) _views[view].push(sidd);
|
|
if (!bindings[sidd]) bindings[sidd] = [];
|
|
|
|
objIDs[tt].type = 'style';
|
|
objIDs[tt].attr = cssAttr;
|
|
objIDs[tt].view = view;
|
|
objIDs[tt].widget = id;
|
|
|
|
bindings[sidd].push(objIDs[tt]);
|
|
}
|
|
|
|
if (objIDs[tt].operations && objIDs[tt].operations[0].arg instanceof Array) {
|
|
for (var w = 0; w < objIDs[tt].operations[0].arg.length; w++) {
|
|
sidd = objIDs[tt].operations[0].arg[w].systemOid;
|
|
if (!sidd) continue;
|
|
if (IDs.indexOf(sidd) === -1) IDs.push(sidd);
|
|
if (_views && _views[view].indexOf(sidd) === -1) _views[view].push(sidd);
|
|
if (!bindings[sidd]) bindings[sidd] = [];
|
|
bindings[sidd].push(objIDs[tt]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_views) {
|
|
var changed;
|
|
do {
|
|
changed = false;
|
|
// Check containers
|
|
for (view in views) {
|
|
if (!views.hasOwnProperty(view)) continue;
|
|
|
|
if (view === '___settings') continue;
|
|
|
|
for (id in views[view].widgets) {
|
|
if (!views[view].widgets.hasOwnProperty(id)) continue;
|
|
|
|
// Add all OIDs from this view to parent
|
|
if (views[view].widgets[id].tpl === 'tplContainerView' && views[view].widgets[id].data.contains_view) {
|
|
var ids = _views[views[view].widgets[id].data.contains_view];
|
|
if (ids) {
|
|
for (var a = 0; a < ids.length; a++) {
|
|
if (ids[a] && _views[view].indexOf(ids[a]) === -1) {
|
|
_views[view].push(ids[a]);
|
|
changed = true;
|
|
}
|
|
}
|
|
} else {
|
|
console.warn('View does not exist: "' + views[view].widgets[id].data.contains_view + '"');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (changed);
|
|
}
|
|
|
|
return {IDs: IDs, byViews: _views, visibility: visibility, bindings: bindings, lastChanges: lastChanges, signals: signals};
|
|
}
|
|
|
|
if (module && module.parent) {
|
|
module.exports.getUsedObjectIDs = getUsedObjectIDs;
|
|
} |