Files
yunkong2.js-controller/lib/www/js/visUtils.js
2018-09-17 20:32:19 +08:00

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;
}