4045 lines
171 KiB
JavaScript
4045 lines
171 KiB
JavaScript
/* global jQuery */
|
||
/* global document */
|
||
/* jshint -W097 */
|
||
/* jshint strict: false */
|
||
/*
|
||
MIT, Copyright 2014-2018 bluefox <dogafox@gmail.com>, soef <soef@gmx.net>
|
||
|
||
version: 1.1.6 (2018.08.03)
|
||
|
||
To use this dialog as standalone in yunkong2 environment include:
|
||
<link type="text/css" rel="stylesheet" href="lib/css/redmond/jquery-ui.min.css">
|
||
<link rel="stylesheet" type="text/css" href="lib/css/fancytree/ui.fancytree.min.css"/>
|
||
|
||
<script type="text/javascript" src="lib/js/jquery-1.11.1.min.js"></script>
|
||
<script type="text/javascript" src="lib/js/jquery-ui-1.10.3.full.min.js"></script>
|
||
<script type="text/javascript" src="lib/js/jquery.fancytree-all.min.js"></script>
|
||
<script type="text/javascript" src="js/translate.js"></script>
|
||
<script type="text/javascript" src="js/words.js"></script><!--this file must be after translate.js -->
|
||
|
||
<script type="text/javascript" src="js/selectID.js"></script>
|
||
|
||
<script src="lib/js/socket.io.js"></script>
|
||
<script src="/_socket/info.js"></script>
|
||
|
||
To use as part, just
|
||
<link rel="stylesheet" type="text/css" href="lib/css/fancytree/ui.fancytree.min.css"/>
|
||
<script type="text/javascript" src="lib/js/jquery.fancytree-all.min.js"></script>
|
||
<script type="text/javascript" src="js/selectID.js"></script>
|
||
|
||
Interface:
|
||
+ init(options) - init select ID dialog. Following options are supported
|
||
{
|
||
currentId: '', // Current ID or empty if nothing preselected
|
||
objects: null, // All objects that should be shown. It can be empty if connCfg used.
|
||
getObjects: null, // null or function to read all objects anew on refresh (because of subscripitons): funsubscriptionsjects) {}
|
||
states: null, // All states of objects. It can be empty if connCfg used. If objects are set and no states, states will no be shown.
|
||
filter: null, // filter
|
||
imgPath: 'lib/css/fancytree/', // Path to images device.png, channel.png and state.png
|
||
connCfg: null, // configuration for dialog, ti read objects itself: {socketUrl: socketUrl, socketSession: socketSession}
|
||
onSuccess: null, // callback function to be called if user press "Select". Can be overwritten in "show" - function (newId, oldId, newObj)
|
||
onChange: null, // called every time the new object selected - function (newId, oldId, newObj)
|
||
noDialog: false, // do not make dialog
|
||
stats: false, // show objects statistics
|
||
noMultiselect: false, // do not make multiselect
|
||
useValues: false, // show button to toggle objects<=>values
|
||
buttons: null, // array with buttons, that should be shown in last column
|
||
// if array is not empty it can has following fields
|
||
// [{
|
||
// text: false, // same as jquery button
|
||
// icons: { // same as jquery bdata.columnsutton
|
||
// primary: 'ui-icon-gear'
|
||
// },
|
||
// click: function (id) {
|
||
// // do on click
|
||
// },
|
||
// match: function (id) {
|
||
// // you have here object "this" pointing to $('button')
|
||
// },
|
||
// width: 26, // same as jquery button
|
||
// height: 20 // same as jquery button
|
||
// }],
|
||
panelButtons: null, // array with buttons, that should be shown at the top of dialog (near expand all)
|
||
list: false, // tree view or list view
|
||
name: null, // name of the dialog to store filter settings
|
||
noCopyToClipboard: false, // do not show button for copy to clipboard
|
||
root: null, // root node, e.g. "script.js"
|
||
useNameAsId: false, // use name of object as ID
|
||
noColumnResize: false, // do not allow column resize
|
||
firstMinWidth: null, // width if ID column, default 400
|
||
showButtonsForNotExistingObjects: false,
|
||
webServer: null, // link to webserver, by default ":8082"
|
||
filterPresets: null, // Object with predefined filters, eg {role: 'level.dimmer'} or {type: 'state'}
|
||
roleExactly: false, // If the role must be equal or just content the filter value
|
||
sortConfig: {
|
||
statesFirst: true, // Show states before folders
|
||
ignoreSortOrder: false // Ignore standard sort order of fancytree
|
||
},
|
||
texts: {
|
||
select: 'Select',
|
||
cancel: 'Cancel',
|
||
all: 'All',
|
||
id: 'ID',
|
||
name: 'Name',
|
||
role: 'Role',
|
||
type: 'Type',
|
||
room: 'Room',
|
||
'function': 'Function',
|
||
enum: 'Members',
|
||
value: 'Value',
|
||
selectid: 'Select ID',
|
||
from: 'From',
|
||
user: 'user',
|
||
lc: 'Last changed',
|
||
ts: 'Time stamp',
|
||
ack: 'Acknowledged',
|
||
expand: 'Expand all nodes',
|
||
collapse: 'Collapse all nodes',
|
||
refresh: 'Rebuild tree',
|
||
edit: 'Edit',
|
||
ok: 'Ok',
|
||
push: 'Trigger event'
|
||
wait: 'Processing...',
|
||
list: 'Show list view',
|
||
tree: 'Show tree view',
|
||
selectAll: 'Select all',
|
||
unselectAll: 'Unselect all',
|
||
invertSelection: 'Invert selection',
|
||
copyToClipboard: 'Copy to clipboard',
|
||
expertMode: 'Toggle expert mode',
|
||
button: 'Settings',
|
||
noData: 'No data',
|
||
Objects: 'Objects',
|
||
States: 'States',
|
||
toggleValues: 'Toggle states view'
|
||
},
|
||
columns: ['image', 'name', 'type', 'role', 'enum', 'room', 'function', 'value', 'button', 'value.val', 'value.ts', 'value.lc', 'value.from', 'value.q'],
|
||
// some elements of columns could be an object {name: field, data: function (id, name){}, title: function (id, name) {}}
|
||
widths: null, // array with width for every column
|
||
editEnd: null, // function (id, newValues) for edit lines (only id and name can be edited)
|
||
editStart: null, // function (id, $inputs) called after edit start to correct input fields (inputs are jquery objects),
|
||
zindex: null, // z-index of dialog or table
|
||
customButtonFilter: null, // if in the filter over the buttons some specific button must be shown. It has type like {icons:{primary: 'ui-icon-close'}, text: false, callback: function ()}
|
||
expertModeRegEx: null // list of regex with objects, that will be shown only in expert mode, like /^system\.|^yunkong2\.|^_|^[\w-]+$|^enum\.|^[\w-]+\.admin/
|
||
quickEdit: null, // list of fields with edit on click. Elements can be just names from standard list or objects like:
|
||
// {name: 'field', options: {a1: 'a111_Text', a2: 'a22_Text'}}, options can be a function (id, name), that give back such an object
|
||
quickEditCallback: null, // function (id, attr, newValue, oldValue),
|
||
readyCallback: null // called when objects and states are read from server (only if connCfg is not null). function (err, objects, states)
|
||
expandedCallback: null, // called when some node was expanded. function (id, childrenCount, statesCount)
|
||
collapsedCallback: null, // called when some node was expanded. function (id, childrenCount, statesCount)
|
||
}
|
||
+ show(currentId, filter, callback) - all arguments are optional if set by "init". Callback is like function (newId, oldId) {}. If multiselect, so the arguments are arrays.
|
||
+ clear() - clear object tree to read and build anew (used only if objects set by "init")
|
||
+ getInfo(id) - get information about ID
|
||
+ getTreeInfo(id) - get {id, parent, children, object}
|
||
+ state(id, val) - update states in tree
|
||
+ object(id, obj) - update object info in tree
|
||
+ reinit() - draw tree anew
|
||
|
||
|
||
filter is like:
|
||
common: {
|
||
history: true
|
||
}
|
||
or
|
||
type: "state"
|
||
*/
|
||
|
||
var addAll2FilterCombobox = false;
|
||
|
||
function tdp(x, decimals) {
|
||
// TODO support of US format too
|
||
return isNaN(x) ? '' : x.toFixed(decimals || 0).replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
||
}
|
||
|
||
function removeImageFromSettings(data) {
|
||
if (!data || !data.columns) return;
|
||
var idx = data.columns.indexOf('image');
|
||
if (idx >= 0) data.columns.splice(idx, 1);
|
||
}
|
||
|
||
var lineIndent = '5px';
|
||
|
||
function span(txt, attr) {
|
||
//if (txt === undefined) txt = '';
|
||
//return txt;
|
||
|
||
var style = 'padding-left: ' + lineIndent + ';';
|
||
if (attr) style += attr;
|
||
return '<span style="' + style + '">' + txt + '</span>';
|
||
}
|
||
|
||
function filterChanged(e) {
|
||
var $e = $(e);
|
||
var val = $e.val();
|
||
var td = $e.parent();
|
||
if (val) {
|
||
td.addClass('filter-active');
|
||
} else {
|
||
td.removeClass('filter-active');
|
||
}
|
||
}
|
||
|
||
(function ($) {
|
||
'use strict';
|
||
|
||
if ($.fn.selectId) return;
|
||
|
||
var isMaterial;
|
||
|
||
function getNameObj(obj, id) {
|
||
if (obj && obj.common) {
|
||
return getName(obj.common.name || (id || '').split('.').pop());
|
||
} else {
|
||
return (id || '').split('.').pop();
|
||
}
|
||
}
|
||
|
||
function formatDate(dateObj) {
|
||
//return dateObj.getFullYear() + '-' +
|
||
// ('0' + (dateObj.getMonth() + 1).toString(10)).slice(-2) + '-' +
|
||
// ('0' + (dateObj.getDate()).toString(10)).slice(-2) + ' ' +
|
||
// ('0' + (dateObj.getHours()).toString(10)).slice(-2) + ':' +
|
||
// ('0' + (dateObj.getMinutes()).toString(10)).slice(-2) + ':' +
|
||
// ('0' + (dateObj.getSeconds()).toString(10)).slice(-2);
|
||
// Following implementation is 5 times faster
|
||
if (!dateObj) return '';
|
||
|
||
var text = dateObj.getFullYear();
|
||
var v = dateObj.getMonth() + 1;
|
||
if (v < 10) {
|
||
text += '-0' + v;
|
||
} else {
|
||
text += '-' + v;
|
||
}
|
||
|
||
v = dateObj.getDate();
|
||
if (v < 10) {
|
||
text += '-0' + v;
|
||
} else {
|
||
text += '-' + v;
|
||
}
|
||
|
||
v = dateObj.getHours();
|
||
if (v < 10) {
|
||
text += ' 0' + v;
|
||
} else {
|
||
text += ' ' + v;
|
||
}
|
||
v = dateObj.getMinutes();
|
||
if (v < 10) {
|
||
text += ':0' + v;
|
||
} else {
|
||
text += ':' + v;
|
||
}
|
||
|
||
v = dateObj.getSeconds();
|
||
if (v < 10) {
|
||
text += ':0' + v;
|
||
} else {
|
||
text += ':' + v;
|
||
}
|
||
|
||
v = dateObj.getMilliseconds();
|
||
if (v < 10) {
|
||
text += '.00' + v;
|
||
} else if (v < 100) {
|
||
text += '.0' + v;
|
||
} else {
|
||
text += '.' + v;
|
||
}
|
||
|
||
return text;
|
||
}
|
||
|
||
function filterId(data, id) {
|
||
if (data.rootExp) {
|
||
if (!data.rootExp.test(id)) return false;
|
||
}
|
||
// ignore system objects in expert mode
|
||
if (data.expertModeRegEx && !data.expertMode && data.expertModeRegEx.test(id)) {
|
||
return false;
|
||
}
|
||
|
||
// ignore exeprt objects in expert mode
|
||
if (!data.expertMode && data.objects[id] && data.objects[id].common && data.objects[id].common.expert) {
|
||
return;
|
||
}
|
||
|
||
if (data.filter) {
|
||
if (data.filter.type && data.filter.type !== data.objects[id].type) return false;
|
||
|
||
if (data.filter.common && data.filter.common.custom) {
|
||
if (!data.objects[id].common) return false;
|
||
// todo: remove history sometime 09.2016
|
||
var custom = data.objects[id].common.custom || data.objects[id].common.history;
|
||
|
||
if (!custom) return false;
|
||
if (data.filter.common.custom === true) {
|
||
return true;
|
||
} else {
|
||
if (!custom[data.filter.common.custom]) return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function getExpandeds(data) {
|
||
if (!data.$tree) return null;
|
||
var expandeds = {};
|
||
(function getIt(nodes) {
|
||
if (!Array.isArray(nodes.children)) return;
|
||
for (var i = 0, len = nodes.children.length; i < len; i++) {
|
||
var node = nodes.children[i];
|
||
if (node.expanded) {
|
||
expandeds[node.key] = true;
|
||
}
|
||
getIt(node);
|
||
}
|
||
})(data.$tree.fancytree('getRootNode'));
|
||
return expandeds;
|
||
}
|
||
|
||
function restoreExpandeds(data, expandeds) {
|
||
if (!expandeds || !data.$tree) return;
|
||
(function setIt(nodes) {
|
||
if (!Array.isArray(nodes.children)) return;
|
||
for (var i = 0, len = nodes.children.length; i < len; i++) {
|
||
var node = nodes.children[i];
|
||
if (expandeds[node.key]) {
|
||
try {
|
||
node.setExpanded();
|
||
} catch (e) {
|
||
console.log('Cannot expand: ' + e);
|
||
}
|
||
//node.setActive();
|
||
}
|
||
setIt(node);
|
||
}
|
||
})(data.$tree.fancytree('getRootNode'));
|
||
expandeds = null;
|
||
}
|
||
|
||
function sortTree(data) {
|
||
var objects = data.objects;
|
||
var checkStatesFirst;
|
||
switch (data.sortConfig.statesFirst) {
|
||
case undefined: checkStatesFirst = function () { return 0 }; break;
|
||
case true: checkStatesFirst = function (child1, child2) { return ((~~child2.folder) - (~~child1.folder))}; break;
|
||
case false: checkStatesFirst = function (child1, child2) { return ((~~child1.folder) - (~~child2.folder))}; break;
|
||
}
|
||
|
||
// function compAdapterAndInstance(c1, c2) {
|
||
// var s1 = c1.key.substr(0, c1.key.lastIndexOf('.'));
|
||
// var s2 = c2.key.substr(0, c2.key.lastIndexOf('.'));
|
||
//
|
||
// if (s1 > s2) return 1;
|
||
// if (s1 < s2) return -1;
|
||
// return 0;
|
||
// }
|
||
|
||
function sortByName(child1, child2) {
|
||
var ret = checkStatesFirst(child1, child2);
|
||
if (ret) return ret;
|
||
|
||
var o1 = objects[child1.key], o2 = objects[child2.key];
|
||
if (o1 && o2) {
|
||
var c1 = o1.common, c2 = o2.common;
|
||
if (c1 && c2) {
|
||
|
||
// var s1 = child1.key.substr(0, child1.key.lastIndexOf('.')); // faster than regexp.
|
||
// var s2 = child2.key.substr(0, child2.key.lastIndexOf('.'));
|
||
// if (s1 > s2) return 1;
|
||
// if (s1 < s2) return -1;
|
||
|
||
if (!data.sortConfig.ignoreSortOrder && c1.sortOrder && c2.sortOrder) {
|
||
if (c1.sortOrder > c2.sortOrder) return 1;
|
||
if (c1.sortOrder < c2.sortOrder) return -1;
|
||
return 0;
|
||
}
|
||
var name1;
|
||
var name2;
|
||
if (c1.name) {
|
||
name1 = c1.name;
|
||
if (typeof name1 === 'object') {
|
||
name1 = (name1[systemLang] || name1.en).toLowerCase();
|
||
} else {
|
||
name1 = name1.toLowerCase();
|
||
}
|
||
} else {
|
||
name1 = child1.key;
|
||
}
|
||
if (c2.name) {
|
||
name2 = c2.name;
|
||
if (typeof name2 === 'object') {
|
||
name2 = (name2[systemLang] || name2.en).toLowerCase();
|
||
} else {
|
||
name2 = name2.toLowerCase();
|
||
}
|
||
} else {
|
||
name2 = child1.key;
|
||
}
|
||
if (name1 > name2) return 1;
|
||
if (name1 < name2) return -1;
|
||
}
|
||
}
|
||
if (child1.key > child2.key) return 1;
|
||
if (child1.key < child2.key) return -1;
|
||
return 0;
|
||
}
|
||
|
||
function sortByKey(child1, child2) {
|
||
var ret = checkStatesFirst(child1, child2);
|
||
if (ret) return ret;
|
||
if (!data.sortConfig.ignoreSortOrder) {
|
||
var o1 = objects[child1.key], o2 = objects[child2.key];
|
||
if (o1 && o2) {
|
||
var c1 = o1.common, c2 = o2.common;
|
||
if (c1 && c2 && c1.sortOrder && c2.sortOrder) {
|
||
// var s1 = child1.key.substr(0, child1.key.lastIndexOf('.')); // faster than regexp.
|
||
// var s2 = child2.key.substr(0, child2.key.lastIndexOf('.'));
|
||
// if (s1 > s2) return 1;
|
||
// if (s1 < s2) return -1;
|
||
|
||
if (c1.sortOrder > c2.sortOrder) return 1;
|
||
if (c1.sortOrder < c2.sortOrder) return -1;
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
if (child1.key > child2.key) return 1;
|
||
if (child1.key < child2.key) return -1;
|
||
return 0;
|
||
}
|
||
|
||
var sortFunc = data.sort ? sortByName : sortByKey;
|
||
var sfunc = sortByKey; // sort the root always by key
|
||
return (function sort(tree) {
|
||
if (!tree || !tree.children) return;
|
||
try {
|
||
tree.sortChildren(sfunc);
|
||
} catch (e) {
|
||
console.log(e);
|
||
}
|
||
sfunc = sortFunc;
|
||
for (var i=tree.children.length-1; i>=0; i--) {
|
||
sort(tree.children[i]);
|
||
}
|
||
})(data.$tree.fancytree('getRootNode'));
|
||
|
||
// var sortFunc = data.sort ? sortByName : sortByKey;
|
||
// var root = data.$tree.fancytree('getRootNode');
|
||
// root.sortChildren(sortByKey, false);
|
||
// return (function sort(tree) {
|
||
// if (!tree) return;
|
||
// for (var i=tree.children.length-1; i>=0; i--) {
|
||
// var child = tree.children[i];
|
||
// if (!child) return;
|
||
// child.sortChildren(sortFunc);
|
||
// sort(child.children);
|
||
// }
|
||
// })(root.children);
|
||
|
||
|
||
//data.$tree.fancytree('getRootNode').sortChildren(data.sort ? sortByName : sortByKey, true);
|
||
//var tree = data.$tree.fancytree('getTree');
|
||
//var node = tree.getActiveNode();
|
||
}
|
||
|
||
function getAllStates(data) {
|
||
var stats = data.stats ? {objs: 0, states: 0} : null;
|
||
var objects = data.objects;
|
||
var isType = data.columns.indexOf('type') !== -1;
|
||
var isRoom = data.columns.indexOf('room') !== -1;
|
||
var isFunc = data.columns.indexOf('function') !== -1;
|
||
var isRole = data.columns.indexOf('role') !== -1;
|
||
var isHist = data.columns.indexOf('button') !== -1;
|
||
|
||
data.tree = {title: '', children: [], count: 0, root: true};
|
||
data.roomEnums = [];
|
||
data.funcEnums = [];
|
||
data.ids = [];
|
||
|
||
for (var id in objects) {
|
||
if (!objects.hasOwnProperty(id)) continue;
|
||
if (!id) {
|
||
console.error('Invalid empty ID found! Please fix it');
|
||
continue;
|
||
}
|
||
stats && stats.objs++;
|
||
|
||
if (objects[id].type === 'state') {
|
||
stats && stats.states++;
|
||
} else if (data.valuesActive) {
|
||
continue;
|
||
}
|
||
|
||
if (isRoom) {
|
||
if (objects[id].type === 'enum' && data.regexEnumRooms.test(id) && data.roomEnums.indexOf(id) === -1) data.roomEnums.push(id);
|
||
if (objects[id].enums) {
|
||
for (var e in objects[id].enums) {
|
||
if (data.regexEnumRooms.test(e) && data.roomEnums.indexOf(e) === -1) {
|
||
data.roomEnums.push(e);
|
||
}
|
||
data.objects[e] = data.objects[e] || {
|
||
_id: e,
|
||
common: {
|
||
name: objects[id].enums[e],
|
||
members: [id]
|
||
}
|
||
};
|
||
data.objects[e].common.members = data.objects[e].common.members || [];
|
||
if (data.objects[e].common.members.indexOf(id) === -1) {
|
||
data.objects[e].common.members.push(id);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (isFunc) {
|
||
if (objects[id].type === 'enum' && data.regexEnumFuncs.test(id) && data.funcEnums.indexOf(id) === -1) {
|
||
data.funcEnums.push(id);
|
||
}
|
||
if (objects[id].enums) {
|
||
for (var e in objects[id].enums) {
|
||
if (data.regexEnumFuncs.test(e) && data.funcEnums.indexOf(e) === -1) {
|
||
data.funcEnums.push(e);
|
||
}
|
||
data.objects[e] = data.objects[e] || {
|
||
_id: e,
|
||
common: {
|
||
name: objects[id].enums[e],
|
||
members: [id]
|
||
}
|
||
};
|
||
data.objects[e].common.members = data.objects[e].common.members || [];
|
||
if (data.objects[e].common.members.indexOf(id) === -1) {
|
||
data.objects[e].common.members.push(id);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (isType && objects[id].type && data.types.indexOf(objects[id].type) === -1) data.types.push(objects[id].type);
|
||
|
||
if (isRole && objects[id].common && objects[id].common.role) {
|
||
try {
|
||
var parts = objects[id].common.role.split('.');
|
||
var role = '';
|
||
for (var u = 0; u < parts.length; u++) {
|
||
role += (role ? '.' : '') + parts[u];
|
||
if (data.roles.indexOf(role) === -1) data.roles.push(role);
|
||
}
|
||
} catch (e) {
|
||
console.error('Cannot parse role "' + objects[id].common.role + '" by ' + id);
|
||
}
|
||
}
|
||
if (isHist && objects[id].type === 'instance' && (objects[id].common.type === 'storage' || objects[id].common.supportCustoms)) {
|
||
var h = id.substring('system.adapter.'.length);
|
||
if (data.histories.indexOf(h) === -1) {
|
||
data.histories.push(h);
|
||
}
|
||
}
|
||
|
||
if (!filterId(data, id)) continue;
|
||
|
||
treeInsert(data, id, data.currentId === id);
|
||
|
||
if (objects[id].enums) {
|
||
for (var ee in objects[id].enums) {
|
||
if (objects[id].enums.hasOwnProperty(ee) &&
|
||
objects[ee] &&
|
||
objects[ee].common &&
|
||
objects[ee].common.members &&
|
||
objects[ee].common.members.indexOf(id) === -1) {
|
||
objects[ee].common.members.push(id);
|
||
}
|
||
}
|
||
}
|
||
|
||
// fill counters
|
||
if (data.expertMode) {
|
||
data.ids.push(id);
|
||
}
|
||
}
|
||
data.inited = true;
|
||
data.roles.sort();
|
||
data.types.sort();
|
||
data.roomEnums.sort();
|
||
data.funcEnums.sort();
|
||
data.histories.sort();
|
||
data.ids.sort();
|
||
if (stats) {
|
||
data.stats = stats;
|
||
}
|
||
}
|
||
|
||
function treeSplit(data, id) {
|
||
if (!id) return null;
|
||
if (data.root) {
|
||
id = id.substring(data.root.length);
|
||
}
|
||
|
||
var parts = id.split('.');
|
||
if (data.regexSystemAdapter.test(id)) {
|
||
if (parts.length > 3) {
|
||
parts[0] = 'system.adapter.' + parts[2] + '.' + parts[3];
|
||
parts.splice(1, 3);
|
||
} else {
|
||
parts[0] = 'system.adapter.' + parts[2];
|
||
parts.splice(1, 2);
|
||
}
|
||
} else if (data.regexSystemHost.test(id)) {
|
||
parts[0] = 'system.host.' + parts[2];
|
||
parts.splice(1, 2);
|
||
} else if (parts.length > 1 && !data.root) {
|
||
parts[0] = parts[0] + '.' + parts[1];
|
||
parts.splice(1, 1);
|
||
}
|
||
|
||
/*if (optimized) {
|
||
parts = treeOptimizePath(parts);
|
||
}*/
|
||
|
||
return parts;
|
||
}
|
||
|
||
function _deleteTree(node, deletedNodes) {
|
||
if (node.parent) {
|
||
if (deletedNodes && node.id) {
|
||
deletedNodes.push(node);
|
||
}
|
||
var p = node.parent;
|
||
if (p.children.length <= 1) {
|
||
_deleteTree(node.parent);
|
||
} else {
|
||
for (var z = 0; z < p.children.length; z++) {
|
||
if (node.key === p.children[z].key) {
|
||
p.children.splice(z, 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
//error
|
||
}
|
||
}
|
||
|
||
function deleteTree(data, id, deletedNodes) {
|
||
var node = findTree(data, id);
|
||
if (!node) {
|
||
console.log('deleteTree: Id ' + id + ' not found');
|
||
return;
|
||
}
|
||
_deleteTree(node, deletedNodes);
|
||
}
|
||
|
||
function findTree(data, id) {
|
||
return (function find(tree) {
|
||
if (!tree.children) return;
|
||
for (var i = tree.children.length - 1; i >= 0; i--) {
|
||
var child = tree.children[i];
|
||
if (id === child.key) return child;
|
||
if (id.startsWith(child.key + '.')) {
|
||
//if (id === child.key) return child;
|
||
return find(child);
|
||
}
|
||
}
|
||
return null;
|
||
})(data.tree);
|
||
}
|
||
|
||
// function xfindTree(data, id) {
|
||
// return _findTree(data.tree, treeSplit(data, id, false), 0);
|
||
// }
|
||
// function _findTree(tree, parts, index) {
|
||
// var num = -1;
|
||
// for (var j = 0; j < tree.children.length; j++) {
|
||
// if (tree.children[j].title === parts[index]) {
|
||
// num = j;
|
||
// break;
|
||
// }
|
||
// //if (tree.children[j].title > parts[index]) break;
|
||
// }
|
||
//
|
||
// if (num === -1) return null;
|
||
//
|
||
// if (parts.length - 1 === index) {
|
||
// return tree.children[num];
|
||
// } else {
|
||
// return _findTree(tree.children[num], parts, index + 1);
|
||
// }
|
||
// }
|
||
|
||
/*
|
||
function treeInsert(data, id, isExpanded, addedNodes) {
|
||
var idArr = data.list ? [id] : treeSplit(data, id);
|
||
if (!idArr) return console.error('Empty object ID!');
|
||
|
||
(function insert(tree, idx) {
|
||
for ( ; idx < idArr.length; idx += 1) {
|
||
for (var i = tree.children.length - 1; i >= 0; i--) {
|
||
var child = tree.children[i];
|
||
if (id === child.key) return child;
|
||
if (id.startsWith (child.key + '.')) {
|
||
//if (id === child.key) return child;
|
||
child.expanded = child.expanded || isExpanded;
|
||
return insert (child, idx + 1);
|
||
}
|
||
}
|
||
tree.folder = true;
|
||
tree.expanded = isExpanded;
|
||
|
||
var obj = {
|
||
key: (data.root || '') + idArr.slice (0, idx + 1).join ('.'),
|
||
children: [],
|
||
title: idArr[idx],
|
||
folder: false,
|
||
expanded: false,
|
||
parent: tree
|
||
};
|
||
//data.objects[obj.key].node = obj;
|
||
tree.children.push (obj);
|
||
if (addedNodes) {
|
||
addedNodes.push (obj);
|
||
}
|
||
tree = obj;
|
||
}
|
||
tree.id = id;
|
||
})(data.tree, 0);
|
||
} */
|
||
|
||
function treeInsert(data, id, isExpanded, addedNodes) {
|
||
return _treeInsert(data.tree, data.list ? [id] : treeSplit(data, id, false), id, 0, isExpanded, addedNodes, data);
|
||
}
|
||
function _treeInsert(tree, parts, id, index, isExpanded, addedNodes, data) {
|
||
index = index || 0;
|
||
|
||
if (!parts) {
|
||
console.error('Empty object ID!');
|
||
return;
|
||
}
|
||
|
||
var num = -1;
|
||
var j;
|
||
for (j = 0; j < tree.children.length; j++) {
|
||
if (tree.children[j].title === parts[index]) {
|
||
num = j;
|
||
break;
|
||
}
|
||
//if (tree.children[j].title > parts[index]) break;
|
||
}
|
||
|
||
if (num === -1) {
|
||
tree.folder = true;
|
||
tree.expanded = isExpanded;
|
||
|
||
var fullName = '';
|
||
for (var i = 0; i <= index; i++) {
|
||
fullName += ((fullName) ? '.' : '') + parts[i];
|
||
}
|
||
var obj = {
|
||
key: (data.root || '') + fullName,
|
||
children: [],
|
||
title: parts[index],
|
||
folder: false,
|
||
expanded: false,
|
||
parent: tree
|
||
};
|
||
if (j === tree.children.length) {
|
||
num = tree.children.length;
|
||
tree.children.push(obj);
|
||
} else {
|
||
num = j;
|
||
tree.children.splice(num, 0, obj);
|
||
}
|
||
if (addedNodes) {
|
||
addedNodes.push(tree.children[num]);
|
||
}
|
||
}
|
||
if (parts.length - 1 === index) {
|
||
tree.children[num].id = id;
|
||
} else {
|
||
tree.children[num].expanded = tree.children[num].expanded || isExpanded;
|
||
_treeInsert(tree.children[num], parts, id, index + 1, isExpanded, addedNodes, data);
|
||
}
|
||
}
|
||
|
||
function showActive($dlg, scrollIntoView) {
|
||
var data = $dlg.data('selectId');
|
||
// Select current element
|
||
if (data.selectedID) {
|
||
data.$tree.fancytree('getTree').visit(function (node) {
|
||
if (node.key === data.selectedID) {
|
||
try {
|
||
node.setActive();
|
||
node.makeVisible({scrollIntoView: scrollIntoView || false});
|
||
//$(node).find('table.fancytree-ext-table tbody tr td') //xxx
|
||
} catch (err) {
|
||
console.error(err);
|
||
}
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
function syncHeader($dlg) {
|
||
var data = $dlg.data('selectId');
|
||
if (!data) return;
|
||
var $header = $dlg.find('.main-header-table');
|
||
var thDest = $header.find('>tbody>tr>th'); //if table headers are specified in its semantically correct tag, are obtained
|
||
var thSrc = data.$tree.find('>tbody>tr>td');
|
||
|
||
var x, o;
|
||
for (var i = 0; i < thDest.length - 1; i++) {
|
||
if ((x = $(thSrc[i]).width())) {
|
||
$(thDest[i]).attr('width', x);
|
||
if ((o = $(thSrc[i + 1]).offset().left)) {
|
||
if ((o -= $(thDest[i + 1]).offset().left)) {
|
||
$(thDest[i]).attr('width', x + o);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function getName(name) {
|
||
if (name && typeof name === 'object') {
|
||
return name[systemLang] || name.en;
|
||
} else {
|
||
return name || '';
|
||
}
|
||
}
|
||
|
||
function findRoomsForObject(data, id, withParentInfo, rooms) {
|
||
if (!id) {
|
||
return [];
|
||
}
|
||
rooms = rooms || [];
|
||
for (var i = 0; i < data.roomEnums.length; i++) {
|
||
var common = data.objects[data.roomEnums[i]] && data.objects[data.roomEnums[i]].common;
|
||
var name = getName(common.name);
|
||
|
||
if (common.members && common.members.indexOf(id) !== -1 && rooms.indexOf(name) === -1) {
|
||
if (!withParentInfo) {
|
||
rooms.push(name);
|
||
} else {
|
||
rooms.push({name: name, origin: id});
|
||
}
|
||
}
|
||
}
|
||
var parts = id.split('.');
|
||
parts.pop();
|
||
id = parts.join('.');
|
||
if (data.objects[id]) findRoomsForObject(data, id, withParentInfo, rooms);
|
||
|
||
return rooms;
|
||
}
|
||
|
||
function findRoomsForObjectAsIds(data, id, rooms) {
|
||
if (!id) {
|
||
return [];
|
||
}
|
||
rooms = rooms || [];
|
||
for (var i = 0; i < data.roomEnums.length; i++) {
|
||
var common = data.objects[data.roomEnums[i]] && data.objects[data.roomEnums[i]].common;
|
||
if (common && common.members && common.members.indexOf(id) !== -1 &&
|
||
rooms.indexOf(data.roomEnums[i]) === -1) {
|
||
rooms.push(data.roomEnums[i]);
|
||
}
|
||
}
|
||
return rooms;
|
||
}
|
||
|
||
function findFunctionsForObject(data, id, withParentInfo, funcs) {
|
||
if (!id) {
|
||
return [];
|
||
}
|
||
funcs = funcs || [];
|
||
for (var i = 0; i < data.funcEnums.length; i++) {
|
||
var common = data.objects[data.funcEnums[i]] && data.objects[data.funcEnums[i]].common;
|
||
var name = getName(common.name);
|
||
if (common && common.members && common.members.indexOf(id) !== -1 && funcs.indexOf(name) === -1) {
|
||
if (!withParentInfo) {
|
||
funcs.push(name);
|
||
} else {
|
||
funcs.push({name: name, origin: id});
|
||
}
|
||
}
|
||
}
|
||
var parts = id.split('.');
|
||
parts.pop();
|
||
id = parts.join('.');
|
||
if (data.objects[id]) findFunctionsForObject(data, id, withParentInfo, funcs);
|
||
|
||
return funcs;
|
||
}
|
||
|
||
function findFunctionsForObjectAsIds(data, id, funcs) {
|
||
if (!id) {
|
||
return [];
|
||
}
|
||
funcs = funcs || [];
|
||
for (var i = 0; i < data.funcEnums.length; i++) {
|
||
var common = data.objects[data.funcEnums[i]] && data.objects[data.funcEnums[i]].common;
|
||
if (common && common.members && common.members.indexOf(id) !== -1 &&
|
||
funcs.indexOf(data.funcEnums[i]) === -1) {
|
||
funcs.push(data.funcEnums[i]);
|
||
}
|
||
}
|
||
|
||
return funcs;
|
||
}
|
||
|
||
function clippyCopy(e) {
|
||
var $input = $('<input>');
|
||
$(this).append($input);
|
||
$input.val($(this).parent().data('clippy'));
|
||
$input.trigger('select');
|
||
document.execCommand('copy');
|
||
$input.remove();
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
}
|
||
|
||
function editValueDialog() {
|
||
var data = $(this).data('data');
|
||
var $parent = $(this).parent();
|
||
var value = $parent.data('clippy');
|
||
var id = $parent.data('id');
|
||
var $dlg = $('#dialog-value-edit');
|
||
if (typeof M !== 'undefined' && $dlg.length) {
|
||
$dlg.find('textarea').val(value);
|
||
$dlg.find('input[type="checkbox"]').prop('checked', false);
|
||
|
||
// workaround for materialize checkbox problem
|
||
$dlg.find('input[type="checkbox"]+span').off('click').on('click', function () {
|
||
var $input = $(this).prev();
|
||
if (!$input.prop('disabled')) {
|
||
$input.prop('checked', !$input.prop('checked')).trigger('change');
|
||
}
|
||
});
|
||
|
||
$dlg.find('.btn-set').off('click').on('click', function () {
|
||
var val = $dlg.find('textarea').val();
|
||
var ack = $dlg.find('input[type="checkbox"]').prop('checked');
|
||
if (val !== value || ack) {
|
||
data.quickEditCallback(id, 'value', val, value, ack);
|
||
value = '<span style="color: darkviolet; width: 100%;">' + value + '</span>';
|
||
$parent.html(value);
|
||
}
|
||
$dlg.modal('close');
|
||
});
|
||
$dlg.modal().modal('open');
|
||
} else {
|
||
$('<div style="position: absolute;left: 5px; top: 5px; right: 5px; bottom: 5px; border: 1px solid #CCC;">' +
|
||
'<textarea style="margin: 0; border: 0;background: white; width: 100%; height: calc(100% - 50px); resize: none;" ></textarea><br>' +
|
||
'<input type="checkbox" /><span>' + _('ack') + '</span></div>')
|
||
.dialog({
|
||
autoOpen: true,
|
||
modal: true,
|
||
title: data.texts.edit,
|
||
width: '50%',
|
||
height: 200,
|
||
open: function (event) {
|
||
$(this).find('textarea').val(value);
|
||
$(this).find('input[type="checkbox"]').prop('checked', false);
|
||
$(event.target).parent().find('.ui-dialog-titlebar-close .ui-button-text').html('');
|
||
},
|
||
buttons: [
|
||
{
|
||
text: data.texts.select,
|
||
click: function () {
|
||
var val = $(this).find('textarea').val();
|
||
var ack = $(this).find('input[type="checkbox"]').prop('checked');
|
||
if (val !== value || ack) {
|
||
data.quickEditCallback(id, 'value', val, value, ack);
|
||
value = '<span style="color: darkviolet; width: 100%;">' + value + '</span>';
|
||
$parent.html(value);
|
||
}
|
||
$(this).dialog('close').dialog('destroy').remove();
|
||
}
|
||
},
|
||
{
|
||
text: data.texts.cancel,
|
||
click: function () {
|
||
$(this).dialog('close').dialog('destroy').remove();
|
||
}
|
||
}
|
||
]
|
||
});
|
||
}
|
||
}
|
||
|
||
function editEnumsDialog() {
|
||
var data = $(this).data('data');
|
||
var $parent = $(this).parent();
|
||
var id = $parent.data('id');
|
||
var oldVal = $parent.data('old-value');
|
||
var $dlg = $('#dialog-enum-edit');
|
||
var attr = $parent.data('name');
|
||
if (typeof M !== 'undefined' && $dlg.length) {
|
||
var funcs = [];
|
||
var text = '';
|
||
$dlg.find('.name').html(getNameObj(data.objects[id], id));
|
||
var enums = attr === 'function' ? data.funcEnums : data.roomEnums;
|
||
for (var i = 0; i < enums.length; i++) {
|
||
var common = data.objects[enums[i]] && data.objects[enums[i]].common;
|
||
var name = getName(common.name);
|
||
if (funcs.indexOf(name) === -1) {
|
||
funcs.push(name);
|
||
var checked = common && common.members && common.members.indexOf(id) !== -1;
|
||
text +=
|
||
'<li class="collection-item">' +
|
||
getSelectIdIcon(data, data.objects[enums[i]]) +
|
||
' <span class="title">' + name + '<span class="dialog-enum-list-id">' + enums[i] + '</span></span>' +
|
||
' ' +
|
||
' <label class="secondary-content">' +
|
||
' <input class="filled-in" type="checkbox" ' + (checked ? 'checked' : '') + ' data-id="' + enums[i] + '" data-name="' + name + '"/>' +
|
||
' <span></span>' +
|
||
' </label>' +
|
||
'</li>';
|
||
}
|
||
}
|
||
|
||
$dlg.find('.collection').html(text);
|
||
|
||
// workaround for materialize checkbox problem
|
||
$dlg.find('input[type="checkbox"]').off('click').on('click', function () {
|
||
var $input = $(this).prev();
|
||
if (!$input.prop('disabled')) {
|
||
$input.prop('checked', !$input.prop('checked')).trigger('change');
|
||
}
|
||
});
|
||
|
||
$dlg.find('.btn-set').off('click').on('click', function () {
|
||
var checks = $dlg.find('input[type="checkbox"]');
|
||
var val = [];
|
||
var names = [];
|
||
checks.each(function () {
|
||
if ($(this).prop('checked')) {
|
||
val.push($(this).data('id'));
|
||
names.push($(this).data('name'))
|
||
}
|
||
});
|
||
|
||
if (JSON.stringify(oldVal) !== JSON.stringify(val)) {
|
||
data.quickEditCallback(id, attr, val, oldVal);
|
||
var value = '<span style="color: darkviolet; width: 100%;">' + names.join(', ') + '</span>';
|
||
$parent.html(value);
|
||
}
|
||
$dlg.modal('close');
|
||
});
|
||
$dlg.modal().modal('open');
|
||
} else {
|
||
// todo
|
||
}
|
||
}
|
||
function getSelectIdIcon(data, obj, key) {
|
||
var icon = '';
|
||
var alt = '';
|
||
var _id_ = 'system.adapter.' + key;
|
||
if (key && data.objects[_id_] && data.objects[_id_].common && data.objects[_id_].common.icon) {
|
||
// if not BASE64
|
||
if (!data.objects[_id_].common.icon.match(/^data:image\//)) {
|
||
if (data.objects[_id_].common.icon.indexOf('.') !== -1) {
|
||
icon = '/adapter/' + data.objects[_id_].common.name + '/' + data.objects[_id_].common.icon;
|
||
} else {
|
||
return '<i class="material-icons iob-list-icon">' + data.objects[_id_].common.icon + '</i>';
|
||
}
|
||
} else {
|
||
icon = data.objects[_id_].common.icon;
|
||
}
|
||
} else
|
||
if (obj && obj.common) {
|
||
if (obj.common.icon) {
|
||
if (!obj.common.icon.match(/^data:image\//)) {
|
||
if (obj.common.icon.indexOf('.') !== -1) {
|
||
var instance;
|
||
if (obj.type === 'instance') {
|
||
icon = '/adapter/' + obj.common.name + '/' + obj.common.icon;
|
||
} else if (key && key.match(/^system\.adapter\./)) {
|
||
instance = key.split('.', 3);
|
||
if (obj.common.icon[0] === '/') {
|
||
instance[2] += obj.common.icon;
|
||
} else {
|
||
instance[2] += '/' + obj.common.icon;
|
||
}
|
||
icon = '/adapter/' + instance[2];
|
||
} else {
|
||
instance = key.split('.', 2);
|
||
if (obj.common.icon[0] === '/') {
|
||
instance[0] += obj.common.icon;
|
||
} else {
|
||
instance[0] += '/' + obj.common.icon;
|
||
}
|
||
icon = '/adapter/' + instance[0];
|
||
}
|
||
} else {
|
||
return '<i class="material-icons iob-list-icon">' + obj.common.icon + '</i>';
|
||
}
|
||
} else {
|
||
// base 64 image
|
||
icon = obj.common.icon;
|
||
}
|
||
} else if (obj.type === 'device') {
|
||
icon = data.imgPath + 'device.png';
|
||
alt = 'device';
|
||
} else if (obj.type === 'channel') {
|
||
icon = data.imgPath + 'channel.png';
|
||
alt = 'channel';
|
||
} else if (obj.type === 'state') {
|
||
icon = data.imgPath + 'state.png';
|
||
alt = 'state';
|
||
}
|
||
}
|
||
|
||
if (icon) {
|
||
return '<img class="iob-list-icon" src="' + icon + '" alt="' + alt + '"/>';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
|
||
function clippyShow(e) {
|
||
var text;
|
||
var data;
|
||
if ($(this).hasClass('clippy') && !$(this).find('.clippy-button').length) {
|
||
data = data || $(this).data('data');
|
||
text = '<button class="clippy-button ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only td-button m" ' +
|
||
'role="button" title="' + data.texts.copyToClipboard + '">';
|
||
if (typeof M !== 'undefined') {
|
||
text += '<i class="material-icons tiny">content_copy</i>'
|
||
} else {
|
||
text += '<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>'
|
||
}
|
||
text += '</button>';
|
||
|
||
$(this).append(text);
|
||
var $clippy = $(this).find('.clippy-button');
|
||
$clippy.on('click', clippyCopy);
|
||
}
|
||
|
||
if ($(this).hasClass('edit-dialog') && !$(this).find('.edit-dialog-button').length) {
|
||
data = data || $(this).data('data');
|
||
text = '<button class="edit-dialog-button ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only td-button m" ' +
|
||
'role="button" title="' + (data.texts.editDialog || '') + '">';
|
||
if (typeof M !== 'undefined') {
|
||
text += '<i class="material-icons tiny">edit</i>'
|
||
} else {
|
||
text += '<span class="ui-button-icon-primary ui-icon ui-icon-pencil"></span>';
|
||
}
|
||
text += '</button>';
|
||
$(this).append(text);
|
||
var name = $(this).data('name');
|
||
if (name === 'function' || name === 'room') {
|
||
$(this).find('.edit-dialog-button').on('click', editEnumsDialog).data('data', data);
|
||
} else {
|
||
$(this).find('.edit-dialog-button').on('click', editValueDialog).data('data', data);
|
||
}
|
||
}
|
||
}
|
||
|
||
function clippyHide(e) {
|
||
$(this).find('.clippy-button').remove();
|
||
$(this).find('.edit-dialog-button').remove();
|
||
}
|
||
|
||
function installColResize(data, $dlg) {
|
||
if (data.noColumnResize || !$.fn.colResizable) return;
|
||
|
||
if (data.$tree.is(':visible')) {
|
||
data.$tree.colResizable({
|
||
liveDrag: true,
|
||
//resizeMode: 'flex',
|
||
resizeMode: 'fit',
|
||
minWidth: 50,
|
||
|
||
partialRefresh: true,
|
||
marginLeft: 5,
|
||
postbackSafe: true,
|
||
|
||
onResize: function (/* event */) {
|
||
syncHeader($dlg);
|
||
}
|
||
});
|
||
syncHeader($dlg);
|
||
} else {
|
||
setTimeout(function () {
|
||
installColResize(data, $dlg);
|
||
}, 400)
|
||
}
|
||
}
|
||
|
||
function getStates(data, id) {
|
||
var states;
|
||
if (data.objects[id] &&
|
||
data.objects[id].common &&
|
||
data.objects[id].common.states) {
|
||
states = data.objects[id].common.states;
|
||
}
|
||
if (states) {
|
||
if (typeof states === 'string' && states[0] === '{') {
|
||
try {
|
||
states = JSON.parse(states);
|
||
} catch (ex) {
|
||
console.error('Cannot parse states: ' + states);
|
||
states = null;
|
||
}
|
||
} else
|
||
// if old format val1:text1;val2:text2
|
||
if (typeof states === 'string') {
|
||
var parts = states.split(';');
|
||
states = {};
|
||
for (var p = 0; p < parts.length; p++) {
|
||
var s = parts[p].split(':');
|
||
states[s[0]] = s[1];
|
||
}
|
||
}
|
||
}
|
||
return states;
|
||
}
|
||
|
||
function setFilterVal(data, field, val) {
|
||
if (!field) return;
|
||
data.$dlg.find('.filter[data-index="' + field + '"]').val(val).trigger('change');
|
||
}
|
||
|
||
function onQuickEditField(event) {
|
||
var $this = $(this);
|
||
var id = $this.data('id');
|
||
var attr = $this.data('name');
|
||
var data = $this.data('selectId');
|
||
var type = $this.data('type');
|
||
var innerHTML = this.innerHTML;
|
||
var $parentTR = $(event.currentTarget).parent();
|
||
// actually $parentTR === $thisParent, but I dont know
|
||
var $thisParent = $this.parent();
|
||
var clippy = $thisParent.hasClass('clippy');
|
||
var editDialog = $thisParent.hasClass('edit-dialog');
|
||
var options = $this.data('options');
|
||
var oldVal = $this.data('old-value');
|
||
var states = null;
|
||
//var activeNode = $(this).fancytree('getTree').getActiveNode();
|
||
|
||
if (clippy) {
|
||
$thisParent.removeClass('clippy');
|
||
$thisParent.find('.clippy-button').remove(); // delete clippy buttons because they overlay the edit field
|
||
}
|
||
if (editDialog) {
|
||
$thisParent.removeClass('edit-dialog');
|
||
$thisParent.find('.edit-dialog-button').remove(); // delete edit buttons because they overlay the edit field
|
||
}
|
||
$thisParent.css({overflow: 'visible'});
|
||
$this.css({overflow: 'visible'});
|
||
$this.closest('td').css({overflow: 'visible'});
|
||
$this.off('click').removeClass('select-id-quick-edit').css('position', 'relative');
|
||
|
||
type = type === 'boolean' ? 'checkbox' : 'text';
|
||
var text;
|
||
var editType = type;
|
||
data.editing = true; // ignore pressing of DEL button
|
||
|
||
switch (attr) {
|
||
case 'value':
|
||
states = getStates(data, id);
|
||
if (states) {
|
||
text = '<select style="width: calc(100% - 50px); z-index: 2">';
|
||
for (var s in states) {
|
||
if (!states.hasOwnProperty(s) || typeof states[s] !== 'string') continue;
|
||
text += '<option value="' + s + '">' + states[s] + '</option>';
|
||
}
|
||
text += '</select>';
|
||
editType = 'select';
|
||
}
|
||
break;
|
||
case 'room':
|
||
states = findRoomsForObjectAsIds (data, id) || [];
|
||
text = '<select style="width: calc(100% - 50px); z-index: 2" multiple="multiple">';
|
||
for (var ee = 0; ee < data.roomEnums.length; ee++) {
|
||
var room = data.objects[data.roomEnums[ee]];
|
||
var rName;
|
||
if (room && room.common && room.common.name) {
|
||
rName = getName(room.common.name);
|
||
} else {
|
||
rName = data.roomEnums[ee].split('.').pop();
|
||
}
|
||
|
||
text += '<option value="' + data.roomEnums[ee] + '" ' + (states.indexOf(data.roomEnums[ee]) !== -1 ? 'selected' : '') + '>' + rName + '</option>';
|
||
}
|
||
text += '</select>';
|
||
editType = 'select';
|
||
break;
|
||
case 'function':
|
||
states = findFunctionsForObjectAsIds (data, id) || [];
|
||
text = '<select style="width: calc(100% - 50px); z-index: 2" multiple="multiple">';
|
||
for (var e = 0; e < data.funcEnums.length; e++) {
|
||
var func = data.objects[data.funcEnums[e]];
|
||
var fName;
|
||
if (func && func.common && func.common.name) {
|
||
fName = getName(func.common.name);
|
||
} else {
|
||
fName = data.funcEnums[e].split('.').pop();
|
||
}
|
||
text += '<option value="' + data.funcEnums[e] + '" ' + (states.indexOf(data.funcEnums[e]) !== -1 ? 'selected' : '') + '>' + fName + '</option>';
|
||
}
|
||
text += '</select>';
|
||
editType = 'select';
|
||
break;
|
||
default: if (options) {
|
||
if (typeof options === 'function') {
|
||
states = options(id, attr);
|
||
} else {
|
||
states = options;
|
||
}
|
||
if (states) {
|
||
text = '<select style="width: calc(100% - 50px); z-index: 2">';
|
||
for (var t in states) {
|
||
if (states.hasOwnProperty(t)) {
|
||
text += '<option value="' + t + '">' + states[t] + '</option>';
|
||
}
|
||
}
|
||
text += '</select>';
|
||
editType = 'select';
|
||
} else if (states === false) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
text = text || '<input style="z-index: 2" type="' + type + '"' + (type !== 'checkbox' ? 'class="objects-inline-edit"' : '') + '/>';
|
||
|
||
var timeout = null;
|
||
|
||
if (attr === 'room' || attr === 'function' || attr === 'role') {
|
||
editType = 'select';
|
||
}
|
||
|
||
var oldLeftPadding = $this.css('padding-left');
|
||
var oldWidth = $this.css('width');
|
||
var isTitleEdit = $this.is('.objects-name-coll-title');
|
||
|
||
$this.html(text +
|
||
'<div class="select-id-quick-edit-buttons m ' + editType + '">' +
|
||
' <div class="ui-icon ui-icon-check select-id-quick-edit-ok"></div>' +
|
||
' <div class="cancel ui-icon ui-icon-close select-id-quick-edit-cancel" title="' + data.texts.cancel + '"></div>' +
|
||
'</div>');
|
||
|
||
$this.css({'padding-left': 2, width: isTitleEdit ? 'calc(100% - 28px)' : '100%'});
|
||
|
||
var $input = (attr === 'function' || attr === 'room' || states) ? $this.find('select') : $this.find('input');
|
||
|
||
if (attr === 'room' || attr === 'function') {
|
||
$input.multiselect({
|
||
autoOpen: true,
|
||
close: function () {
|
||
$input.trigger('blur');
|
||
}
|
||
});
|
||
} else if (attr === 'role') {
|
||
// remove jquery UI - todo
|
||
$input.autocomplete({
|
||
minLength: 0,
|
||
source: data.roles
|
||
}).on('focus', function () {
|
||
$(this).autocomplete('search', '');
|
||
});
|
||
}
|
||
|
||
if (editType === 'select') {
|
||
if ($input.width() > $this.width() - 34) {
|
||
var x = Math.max($input.width() - ($this.width() - 34), 34);
|
||
$input.css({'padding-right': x});
|
||
}
|
||
}
|
||
function editDone(ot) {
|
||
if (ot === undefined) ot = innerHTML;
|
||
innerHTML = null;
|
||
if (clippy) {
|
||
$thisParent.addClass('clippy');
|
||
}
|
||
if (editDialog) {
|
||
$thisParent.addClass('edit-dialog');
|
||
}
|
||
$thisParent.css({overflow: 'hidden'});
|
||
$this.css({overflow: 'hidden'});
|
||
$this.closest('td').css({overflow: 'hidden'});
|
||
$this.css({'padding-left': oldLeftPadding, width: oldWidth ? oldWidth: null});
|
||
$this.html(ot).off('click').on('click', onQuickEditField).addClass('select-id-quick-edit');
|
||
//if (activeNode && activeNode.length) activeNode.setActive();
|
||
setTimeout(function () {
|
||
//$(event.currentTarget).parent().trigger('click'); // re-select the line so we can continue using the keyboard
|
||
$parentTR.trigger('click'); // re-select the line so we can continue using the keyboard
|
||
}, 50);
|
||
|
||
data.editing = false;
|
||
|
||
//var $parentTR = $(event.currentTarget).parent();
|
||
$parentTR.focus().trigger('select');
|
||
}
|
||
|
||
function handleCancel(e) {
|
||
if (timeout) {
|
||
clearTimeout(timeout);
|
||
timeout = null;
|
||
}
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
editDone();
|
||
}
|
||
|
||
$this
|
||
.find('.select-id-quick-edit-cancel')
|
||
.on('click', handleCancel).on('mousedown', function (e) {
|
||
handleCancel(e);
|
||
});
|
||
|
||
$this
|
||
.find('.select-id-quick-edit-ok')
|
||
.on('click', function () {
|
||
var _$input = (attr === 'function' || attr === 'room' || states) ? $this.find('select') : $this.find('input');
|
||
_$input.trigger('blur');
|
||
});
|
||
|
||
if (type === 'checkbox') {
|
||
$input.prop('checked', oldVal);
|
||
} else {
|
||
if (attr !== 'room' && attr !== 'function') {
|
||
$input.val(oldVal);
|
||
}
|
||
}
|
||
|
||
$input.blur(function () {
|
||
if (timeout) clearTimeout(timeout);
|
||
timeout = setTimeout(function () {
|
||
var _oldText = $this.data('old-value');
|
||
var val = $(this).attr('type') === 'checkbox' ? $(this).prop('checked') : $(this).val();
|
||
if ((attr === 'room' || attr === 'function') && !val) {
|
||
val = [];
|
||
}
|
||
|
||
if (attr === 'value' || JSON.stringify(val) !== JSON.stringify(_oldText)) {
|
||
data.quickEditCallback(id, attr, val, _oldText);
|
||
_oldText = '<span style="color: rgb(192, 0, 1); width: 100%;">' + _oldText + '</span>';
|
||
}
|
||
editDone(_oldText);
|
||
}.bind(this), 100);
|
||
}).keyup(function (e) {
|
||
if (e.which === 13) $(this).trigger('blur');
|
||
if (e.which === 27) {
|
||
handleCancel(e);
|
||
}
|
||
});
|
||
|
||
if (typeof event === 'object') {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
}
|
||
|
||
setTimeout(function () {
|
||
$input.focus().trigger('select');
|
||
}, 100);
|
||
}
|
||
|
||
function quality2text(q) {
|
||
if (!q) return 'ok';
|
||
var custom = q & 0xFFFF0000;
|
||
var text = '';
|
||
if (q & 0x40) text += 'device';
|
||
if (q & 0x80) text += 'sensor';
|
||
if (q & 0x01) text += ' bad';
|
||
if (q & 0x02) text += ' not connected';
|
||
if (q & 0x04) text += ' error';
|
||
|
||
return text + (custom ? '|0x' + (custom >> 16).toString(16).toUpperCase() : '') + ' [0x' + q.toString(16).toUpperCase() + ']';
|
||
}
|
||
|
||
function forEachColumn (data, cb) {
|
||
for (var c = 0; c < data.columns.length; c++) {
|
||
var name = data.columns[c];
|
||
if (typeof name === 'object') {
|
||
if (name.hasOwnProperty('name')) {
|
||
name = name.name;
|
||
} else if (name.hasOwnProperty('en')) {
|
||
name = name[systemLang] || name.en;
|
||
}
|
||
}
|
||
cb (name, c);
|
||
}
|
||
}
|
||
|
||
function initTreeDialog($dlg) {
|
||
var c;
|
||
$dlg.addClass('dialog-select-object-ids');
|
||
if ($dlg.attr('id') !== 'dialog-select-member' && $dlg.attr('id') !== 'dialog-select-members') {
|
||
$dlg.css({height: '100%', width: '100%'});
|
||
} else {
|
||
$dlg.css({height: 'calc(100% - 110px)', width: 'calc(100% - 20px)'});
|
||
}
|
||
var data = $dlg.data('selectId');
|
||
if (!data) return;
|
||
|
||
//var noStates = (data.objects && !data.states);
|
||
var multiselect = (!data.noDialog && !data.noMultiselect);
|
||
|
||
// load expert mode flag
|
||
if (typeof Storage !== 'undefined') {
|
||
if (data.name) {
|
||
if (data.expertModeRegEx) {
|
||
data.expertMode = window.localStorage.getItem(data.name + '-expert');
|
||
data.expertMode = (data.expertMode === true || data.expertMode === 'true');
|
||
}
|
||
data.sort = window.localStorage.getItem(data.name + '-sort');
|
||
data.sort = (data.sort === true || data.sort === 'true');
|
||
|
||
if (data.useValues) {
|
||
data.valuesActive = window.localStorage.getItem(data.name + '-values');
|
||
data.valuesActive = (data.valuesActive === true || data.valuesActive === 'true');
|
||
}
|
||
}
|
||
}
|
||
// switch columns
|
||
if (data.useValues && data.valuesActive) {
|
||
data._columns = data._columns || data.columns;
|
||
data.columns = data.useValues === true ? ['ID', 'name', 'value.from', 'value.q', 'value.ts', 'value.lc', 'value.val', 'button'] : data.useValues;
|
||
} else if (data._columns) {
|
||
data.columns = data._columns;
|
||
}
|
||
|
||
if (data.columns && data.columns[0] !== 'ID') {
|
||
data.columns.unshift('ID');
|
||
if (data.widths) data.widths.unshift('200px');
|
||
}
|
||
|
||
removeImageFromSettings(data);
|
||
|
||
// Get all states
|
||
var expandeds = getExpandeds(data);
|
||
getAllStates(data);
|
||
|
||
if (!data.noDialog && !data.buttonsDlg) {
|
||
if (typeof M !== 'undefined') {
|
||
data.buttonsDlg = true;
|
||
// following structure is expected
|
||
// <div id="dialog-select-member" class="modal modal-fixed-footer">
|
||
// <div class="modal-content">
|
||
// <div class="row">
|
||
// <div class="col s12 title"></div>
|
||
// </div>
|
||
// <div class="row">
|
||
// <div class="col s12 dialog-content">
|
||
// </div>
|
||
// </div>
|
||
// </div>
|
||
// <div class="modal-footer">
|
||
// <a class="modal-action modal-close waves-effect waves-green btn btn-set" ><i class="large material-icons">check</i><span class="translate">Ok</span></a>
|
||
// <a class="modal-action modal-close waves-effect waves-green btn btn-close"><i class="large material-icons">close</i><span class="translate">Cancel</span></a>
|
||
// </div>
|
||
// </div>
|
||
$dlg.find('.btn-set').off('click').on('click', function () {
|
||
var _data = $dlg.data('selectId');
|
||
if (_data && _data.onSuccess) _data.onSuccess(_data.selectedID, _data.currentId, _data.objects[_data.selectedID]);
|
||
_data.currentId = _data.selectedID;
|
||
storeSettings(_data);
|
||
});
|
||
$dlg.find('.btn-close').off('click').on('click', function () {
|
||
var _data = $dlg.data('selectId');
|
||
storeSettings(_data);
|
||
});
|
||
$dlg.modal({
|
||
dismissible: false
|
||
});
|
||
} else {
|
||
data.buttonsDlg = [
|
||
{
|
||
id: 'button-ok',
|
||
text: data.texts.select,
|
||
click: function () {
|
||
var _data = $dlg.data('selectId');
|
||
if (_data && _data.onSuccess) _data.onSuccess(_data.selectedID, _data.currentId, _data.objects[_data.selectedID]);
|
||
_data.currentId = _data.selectedID;
|
||
storeSettings(_data);
|
||
$dlg.dialog('close');
|
||
}
|
||
},
|
||
{
|
||
text: data.texts.cancel,
|
||
click: function () {
|
||
var _data = $dlg.data('selectId');
|
||
storeSettings(_data);
|
||
$(this).dialog('close');
|
||
}
|
||
}
|
||
];
|
||
|
||
$dlg.dialog ({
|
||
autoOpen: false,
|
||
modal: true,
|
||
resizable: false,
|
||
width: '90%',
|
||
open: function (event) {
|
||
$(event.target).parent().find('.ui-dialog-titlebar-close .ui-button-text').html('');
|
||
},
|
||
close: function () {
|
||
storeSettings (data);
|
||
},
|
||
buttons: data.buttonsDlg
|
||
});
|
||
if (data.zindex !== null) {
|
||
$('div[aria-describedby="' + $dlg.attr('id') + '"]').css({'z-index': data.zindex})
|
||
}
|
||
}
|
||
}
|
||
|
||
var filter = {};
|
||
forEachColumn(data, function (name) {
|
||
filter[name] = $dlg.find('.filter[data-index="' + name + '"]').val();
|
||
});
|
||
|
||
function getComboBoxEnums(kind) {
|
||
var i, ret = [];
|
||
switch (kind) {
|
||
case 'room':
|
||
for (i = 0; i < data.roomEnums.length; i++) {
|
||
ret.push(getNameObj(data.objects[data.roomEnums[i]], data.roomEnums[i]));
|
||
}
|
||
// if (data.rooms) delete data.rooms;
|
||
// if (data.roomsColored) delete data.roomsColored;
|
||
return ret;
|
||
case 'function':
|
||
for (i = 0; i < data.funcEnums.length; i++) {
|
||
ret.push(getNameObj(data.objects[data.funcEnums[i]], data.funcEnums[i]));
|
||
}
|
||
// if (data.funcs) delete data.funcs;
|
||
// if (data.funcsColored) delete data.funcsColored;
|
||
return ret;
|
||
case 'role':
|
||
for (var j = 0; j < data.roles.length; j++) {
|
||
ret.push(data.roles[j]);
|
||
}
|
||
return ret;
|
||
case 'type':
|
||
for (var k = 0; k < data.types.length; k++) {
|
||
ret.push(data.types[k]);
|
||
}
|
||
return ret;
|
||
case 'button':
|
||
ret.push([data.texts.all, '']);
|
||
ret.push([data.texts.with, 'true']);
|
||
ret.push([data.texts.without, 'false']);
|
||
for (var h = 0; h < data.histories.length; h++) {
|
||
ret.push(data.histories[h]);
|
||
}
|
||
return ret;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
// toolbar buttons
|
||
var tds =
|
||
'<button class="ui-button-icon-only panel-button btn-refresh"></button>\n' +
|
||
'<button class="panel-button btn-list"></button>\n' +
|
||
'<button class="panel-button btn-collapse"></button>\n' +
|
||
'<button class="panel-button btn-expand"></button>\n' +
|
||
'<div class="select-id-custom-buttons"></div>\n';
|
||
|
||
if (data.useValues) {
|
||
tds += '<button class="panel-button btn-values"></button>\n';
|
||
}
|
||
|
||
if (data.filter && data.filter.type === 'state' && multiselect) {
|
||
tds +=
|
||
'<div class="iob-toolbar-sep"></div>\n' +
|
||
'<button class="panel-button btn-select-all"></button>\n' +
|
||
'<button class="panel-button btn-unselect-all"></button>\n' +
|
||
'<button class="panel-button btn-invert-selection"></button>\n';
|
||
}
|
||
if (data.expertModeRegEx) {
|
||
tds += '<div class="iob-toolbar-sep"></div><button class="panel-button btn-expert"></button>';
|
||
}
|
||
tds += '<button class="panel-button btn-sort"></button>';
|
||
|
||
if (data.panelButtons) {
|
||
tds += '<div class="iob-toolbar-sep"></div>\n';
|
||
for (c = 0; c < data.panelButtons.length; c++) {
|
||
tds += '<button class="panel-button btn-custom-' + c + '"></button>\n';
|
||
}
|
||
}
|
||
|
||
if (data.useHistory) {
|
||
tds += '<button class="panel-button btn-history"></button>\n';
|
||
}
|
||
if (typeof data.stats === 'object') {
|
||
tds += '<div class="objects-info">' +
|
||
'<span class="objects-title">' + data.texts['Objects'] + ': </span>' +
|
||
'<span class="objects-val-objs">' + data.stats.objs + '</span>, ' +
|
||
'<span class="objects-title">' + data.texts['States'] + ': </span>' +
|
||
'<span class="objects-val-states">' + data.stats.states + '</span></div>';
|
||
}
|
||
|
||
var height = '100%';
|
||
if (!data.noDialog && !isMaterial) {
|
||
height = Math.round(window.innerHeight * 0.6) + 'px';
|
||
}
|
||
|
||
var text =
|
||
'<div class="dialog-select-container' + (isMaterial ? ' material' : ' old-style') + '" style="width: 100%; height: ' + height + '">\n' +
|
||
' <div class="main-toolbar-table m">' + tds + '</div>\n' +
|
||
' <table class="main-header-table">\n'
|
||
;
|
||
|
||
function textFilterText(filterNo, placeholder) {
|
||
if (placeholder === undefined) {
|
||
placeholder = data.texts[filterNo.toLowerCase()] || '';
|
||
}
|
||
return '<input data-index="' + filterNo + '" placeholder="' + placeholder + '" class="filter">' +
|
||
'<button data-index="' + filterNo + '" class="filter-btn"></button>\n';
|
||
}
|
||
|
||
function textCombobox(filterNo, placeholder) {
|
||
var txt = '';
|
||
if (data.columns.indexOf(filterNo) !== -1) {
|
||
if (placeholder === undefined) placeholder = data.texts[filterNo.toLowerCase()] || '';
|
||
var cbEntries = getComboBoxEnums(filterNo);
|
||
var cbText = '<select data-index="' + filterNo + '" class="filter">';
|
||
|
||
var add = function (a, b) {
|
||
if (Array.isArray(a)) {
|
||
b = a[0];
|
||
a = a[1]
|
||
} else if (b === undefined) {
|
||
b = a;
|
||
}
|
||
cbText += '<option value="' + a + '">' + b + '</option>';
|
||
};
|
||
if (typeof addAll2FilterCombobox !== 'undefined' && addAll2FilterCombobox) {
|
||
add('', placeholder + ' (' + data.texts.all + ')');
|
||
} else {
|
||
add('', placeholder);
|
||
}
|
||
for (var i = 0, len = cbEntries.length; i < len; i++) {
|
||
add (cbEntries[i]);
|
||
}
|
||
cbText += '</select>';
|
||
|
||
txt = cbText + '<button data-index="' + filterNo + '" class="filter-btn"></button>\n';
|
||
} else {
|
||
if (filterNo === 'room') {
|
||
if (data.rooms) delete data.rooms;
|
||
if (data.roomsColored) delete data.roomsColored;
|
||
} else if (filterNo === 'function') {
|
||
if (data.funcs) delete data.funcs;
|
||
if (data.funcsColored) delete data.funcsColored;
|
||
}
|
||
}
|
||
return txt;
|
||
}
|
||
|
||
function detectStates(node, patterns) {
|
||
if (node && node.children) {
|
||
var hasStates = false;
|
||
var someExpanded = false;
|
||
for (var c = 0; c < node.children.length; c++) {
|
||
if (!node.children[c].expanded) {
|
||
if (data.objects[node.children[c].data.id] && data.objects[node.children[c].data.id].type === 'state') {
|
||
hasStates = true;
|
||
break;
|
||
}
|
||
} else {
|
||
someExpanded = true;
|
||
}
|
||
}
|
||
if (hasStates) {
|
||
patterns.push(node.data.id || node.key);
|
||
} else if (someExpanded) {
|
||
for (var cc = 0; cc < node.children.length; cc++) {
|
||
if (node.children[cc].expanded) {
|
||
detectStates(node.children[cc], patterns);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
text += ' <tbody>\n';
|
||
text += ' <tr>\n'; //<td></td>';
|
||
|
||
forEachColumn(data, function (name) {
|
||
text += '<th>';
|
||
// we may not search by value
|
||
if (name === 'ID' || name === 'name' || name === 'enum') {
|
||
text += textFilterText(name);
|
||
} else if (name === 'type' || name === 'role' || name === 'room' || name === 'function') {
|
||
text += textCombobox(name);
|
||
} else if (name === 'button') {
|
||
if (data.customButtonFilter) {
|
||
text += textCombobox(name);
|
||
} else {
|
||
//if (name === 'buttons' || name === 'button') {
|
||
text += '<span style="padding-left: ' + lineIndent + '"></span>';
|
||
// } else {
|
||
// text += '<table class="main-header-input-table"><tbody><tr><td style="padding-left: ' + lineIndent + '">' + _(name) + '</td></tr></tbody></table>';
|
||
// }
|
||
}
|
||
} else {
|
||
text += '<span style="padding-left: ' + lineIndent + '">' + _(name) + '</span>';
|
||
}
|
||
text += '</th>';
|
||
});
|
||
|
||
text += ' </tr>\n';
|
||
text += ' </tbody>\n';
|
||
text += ' </table>\n';
|
||
|
||
text += '<div class="' + (data.buttons ? 'grid-main-wh-div' : 'grid-main-wob-div') + '">\n';
|
||
text += ' <table class="iob-list-font objects-list-table" cellspacing="0" cellpadding="0">\n';
|
||
text += ' <colgroup>\n';
|
||
|
||
var thead = '<thead class="grid-objects-head"><tr>\n';
|
||
|
||
var widths = {
|
||
ID: data.firstMinWidth ? data.firstMinWidth : '20%',
|
||
name: '20%',
|
||
type: '6%',
|
||
role: '10%',
|
||
room: '10%',
|
||
'function': '10%',
|
||
value: '10%',
|
||
button: '9%',
|
||
enum: '2%',
|
||
'value.val': '10%',
|
||
'value.ts': '15%',
|
||
'value.lc': '15%',
|
||
'value.from': '10%',
|
||
'value.q': '10%',
|
||
'value.ack': '2%',
|
||
};
|
||
|
||
forEachColumn(data, function (name, i) {
|
||
var w = data.widths ? data.widths[i] : widths[name] || '2%';
|
||
text += '<col width="' + w + '"/>';
|
||
thead += '<th style="width: ' + w + ';"></th>';
|
||
});
|
||
|
||
text += ' </colgroup>\n';
|
||
text += thead + '</tr>\n</thead>\n';
|
||
|
||
text += ' <tbody>\n';
|
||
text += ' </tbody>\n';
|
||
text += ' </table>\n</div>\n';
|
||
if (isMaterial) {
|
||
text += '<div class="objects-list-running loader"><svg class="spinner" width="100%" height="100%" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">\n' +
|
||
' <circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>\n' +
|
||
'</svg></div>\n'
|
||
} else {
|
||
text += '<div class="objects-list-running" style="display: none;">' + data.texts.wait + '</div>\n';
|
||
}
|
||
text += '</div>\n'
|
||
;
|
||
|
||
function addClippyToElement($elem, key, objectId) {
|
||
if (!data.noCopyToClipboard) {
|
||
var name = $elem.data('name');
|
||
if (name === 'function' || name === 'room') {
|
||
$elem.addClass('edit-enum edit-dialog');
|
||
} else {
|
||
$elem.addClass('clippy' + (objectId ? ' edit-dialog' : ''));
|
||
}
|
||
|
||
if (key !== undefined) {
|
||
$elem.data('clippy', key);
|
||
}
|
||
|
||
if (objectId) {
|
||
$elem.data('id', objectId);
|
||
}
|
||
|
||
$elem.css({position: 'relative'})
|
||
.data('data', data)
|
||
.mouseenter(clippyShow)
|
||
.mouseleave(clippyHide);
|
||
}
|
||
}
|
||
|
||
if (typeof M !== 'undefined' && (!data.noDialog || data.buttonsDlg)) {
|
||
var $content = $dlg.find('.dialog-content');
|
||
if (!$content.length) {
|
||
$dlg.html('<div class="modal-content">\n' +
|
||
' <div class="row">\n' +
|
||
' <div class="col s12 title"></div>\n' +
|
||
' </div>\n' +
|
||
' <div class="row">\n' +
|
||
' <div class="col s12 dialog-content">\n' +
|
||
' </div>\n' +
|
||
' </div>\n' +
|
||
' </div>\n' +
|
||
' <div class="modal-footer">\n' +
|
||
' <a class="modal-action modal-close waves-effect waves-green btn btn-set" ><i class="large material-icons">check</i><span class="translate">Select</span></a>\n' +
|
||
' <a class="modal-action modal-close waves-effect waves-green btn btn-close"><i class="large material-icons">close</i><span class="translate">Cancel</span></a>\n' +
|
||
' </div>');
|
||
$content = $dlg.find('.dialog-content');
|
||
if (!$dlg.closest('.m').length) {
|
||
var $body = $('body');
|
||
$body.append('<div class="m material-dialogs"></div>');
|
||
$dlg.appendTo($body.find('.material-dialogs'));
|
||
}
|
||
}
|
||
|
||
$content.html(text)
|
||
} else {
|
||
$dlg.html(text);
|
||
}
|
||
|
||
data.$tree = $dlg.find('.objects-list-table');
|
||
if (!data.$tree.length) {
|
||
|
||
}
|
||
data.$tree[0]._onChange = data.onSuccess || data.onChange;
|
||
|
||
var foptions = {
|
||
titlesTabbable: true, // Add all node titles to TAB chain
|
||
quicksearch: true,
|
||
///////////////////////////
|
||
|
||
//autoScroll: true,
|
||
|
||
///////////////////////////////////////////
|
||
|
||
source: data.tree.children,
|
||
extensions: ['table', 'gridnav', 'filter', 'themeroller'],
|
||
strings: {
|
||
noData: data.texts.noData
|
||
},
|
||
themeroller: {
|
||
addClass: '', // no rounded corners
|
||
selectedClass: 'iob-state-active'
|
||
},
|
||
|
||
checkbox: multiselect,
|
||
table: {
|
||
//indentation: 20,
|
||
indentation: 9,
|
||
nodeColumnIdx: 0
|
||
},
|
||
gridnav: {
|
||
autofocusInput: false,
|
||
handleCursorKeys: true
|
||
},
|
||
filter: {
|
||
mode: 'hide',
|
||
autoApply: true,
|
||
counter: false
|
||
},
|
||
|
||
// keydown: function (event, data){
|
||
// var KC = $.ui.keyCode;
|
||
//
|
||
// if( $(event.originalEvent.target).is(':input') ){
|
||
//
|
||
// // When inside an input, let the control handle the keys
|
||
// data.result = 'preventNav';
|
||
//
|
||
// // But do the tree navigation on Ctrl + NAV_KEY
|
||
// switch( event.which ){
|
||
// case KC.LEFT:
|
||
// case KC.RIGHT:
|
||
// case KC.BACKSPACE:
|
||
// case KC.SPACE:
|
||
// if( e.shiftKey ){
|
||
// data.node.navigate(event.which);
|
||
// }
|
||
// }
|
||
// }
|
||
// },
|
||
|
||
|
||
activate: function (event, data) {
|
||
// A node was activated: display its title:
|
||
// On change
|
||
if (!multiselect) {
|
||
var _data = $dlg.data('selectId');
|
||
var newId = data.node.key;
|
||
|
||
if (_data.onChange) _data.onChange(newId, _data.selectedID, _data.objects[newId]);
|
||
|
||
_data.selectedID = newId;
|
||
if (!_data.noDialog) {
|
||
// Set title of dialog box
|
||
var title = _data.texts.selectid + ' - ' + getNameObj(_data.objects[newId], newId);
|
||
if (typeof M !== 'undefined') {
|
||
$dlg.find('.title').text(title);
|
||
} else {
|
||
$dlg.dialog('option', 'title', title);
|
||
}
|
||
|
||
// Enable/ disable 'Select' button
|
||
if (_data.objects[newId]) { // && _data.objects[newId].type === 'state') {
|
||
$dlg.find('#button-ok').removeClass('ui-state-disabled');
|
||
$dlg.find('.btn-set').removeClass('disabled');
|
||
} else {
|
||
$dlg.find('#button-ok').addClass('ui-state-disabled');
|
||
$dlg.find('.btn-set').addClass('disabled');
|
||
}
|
||
|
||
}
|
||
}
|
||
},
|
||
select: function (event, data) {
|
||
var _data = $dlg.data('selectId');
|
||
var newIds = [];
|
||
var selectedNodes = data.tree.getSelectedNodes();
|
||
for (var i = 0; i < selectedNodes.length; i++) {
|
||
newIds.push(selectedNodes[i].key);
|
||
}
|
||
|
||
if (_data.onChange) {
|
||
_data.onChange(newIds, _data.selectedID);
|
||
}
|
||
|
||
_data.selectedID = newIds;
|
||
|
||
// Enable/ disable 'Select' button
|
||
if (newIds.length > 0) {
|
||
$dlg.find('#button-ok').removeClass('ui-state-disabled');
|
||
$dlg.find('.btn-set').removeClass('disabled');
|
||
} else {
|
||
$dlg.find('#button-ok').addClass('ui-state-disabled');
|
||
$dlg.find('.btn-set').addClass('disabled');
|
||
}
|
||
},
|
||
renderColumns: function (event, _data) {
|
||
var node = _data.node;
|
||
var key = node.key;
|
||
var obj = data.objects[key];
|
||
|
||
var $tr = $(node.tr);
|
||
var $tdList = $tr.find('>td');
|
||
|
||
var isCommon = obj && obj.common;
|
||
var $firstTD = $tdList.eq(0);
|
||
$firstTD.css({'overflow': 'hidden'});
|
||
var cnt = countChildren(key, data);
|
||
|
||
if (isCommon && obj.type) {
|
||
$tr.addClass('fancytree-type-' + obj.type + (data.draggable && data.draggable.indexOf(obj.type) !== -1 ? ' fancytree-type-draggable' : ' fancytree-type-not-draggable'));
|
||
if (data.draggable && data.draggable.indexOf(obj.type) === -1) {
|
||
$tr.attr('data-nodrag', 'true');
|
||
}
|
||
} else {
|
||
$tr.attr('data-nodrag', 'true');
|
||
}
|
||
$tr.attr('data-id', key);
|
||
|
||
// Show number of all children as small grey number
|
||
var $cnt = $firstTD.find('.select-id-cnt');
|
||
// If node has some children
|
||
if (cnt) {
|
||
if ($cnt.length) {
|
||
// modify it if span yet exists
|
||
$cnt.text('#' + cnt);
|
||
} else {
|
||
// create new span
|
||
$firstTD.append('<span class="select-id-cnt">#' + cnt + '</span>');
|
||
}
|
||
} else {
|
||
// remove this span, because object may be was updated
|
||
$cnt.remove();
|
||
}
|
||
|
||
var base = 0;
|
||
|
||
// hide checkbox if only states should be selected
|
||
if (data.filter && data.filter.type === 'state' && (!obj || obj.type !== 'state')) {
|
||
$firstTD.find('.fancytree-checkbox').hide();
|
||
}
|
||
|
||
// special case for javascript scripts
|
||
if (obj && (key.match(/^script\.js\./) || key.match(/^enum\.[\w\d_-]+$/))) {
|
||
if (obj.type !== 'script') {
|
||
// force folder icon and change color
|
||
if (node.key !== 'script.js.global') {
|
||
$firstTD.find('.fancytree-title').css({'font-weight': 'bold', color: '#000080'});
|
||
} else {
|
||
$firstTD.find('.fancytree-title').css({'font-weight': 'bold', color: '#078a0c'});
|
||
}
|
||
$firstTD.addClass('fancytree-force-folder');
|
||
}
|
||
}
|
||
|
||
if (!data.noCopyToClipboard) {
|
||
addClippyToElement($firstTD, node.key);
|
||
}
|
||
|
||
if (data.useNameAsId) {
|
||
$firstTD.find('.fancytree-title').html(getNameObj(obj, key));
|
||
}
|
||
|
||
var $elem;
|
||
var val;
|
||
for (var c = 0; c < data.columns.length; c++) {
|
||
var name = data.columns[c];
|
||
$elem = $tdList.eq(base);
|
||
|
||
var setText = function (txt) {
|
||
$elem.html(span(txt));
|
||
};
|
||
|
||
if (typeof name === 'object') {
|
||
if (name.hasOwnProperty('name')) {
|
||
name = name.name;
|
||
} else {
|
||
name = name[systemLang] || name.en;
|
||
}
|
||
}
|
||
|
||
switch (name) {
|
||
case 'id':
|
||
case 'ID':
|
||
break;
|
||
|
||
case 'name':
|
||
var icon = getSelectIdIcon(data, obj, key);
|
||
var t = isCommon ? getName(obj.common.name || '') : '';
|
||
|
||
$elem.html('<span style="padding-left: ' + (icon ? lineIndent : 0) + '; height: 100%; width: 100%">' +
|
||
(icon ? '<span class="objects-name-coll-icon" style="vertical-align: middle">' + icon + '</span>' : '') +
|
||
'<div class="objects-name-coll-title iob-ellipsis" style="border:0;">' + t + '</div>' +
|
||
'</span>');
|
||
|
||
|
||
var $e = $elem.find('.objects-name-coll-title');
|
||
if (!t) $e.css({'vertical-align': 'middle'});
|
||
|
||
$e.attr('title', t);
|
||
// why here was the obj commented ??
|
||
if (data.quickEdit && obj && data.quickEdit.indexOf('name') !== -1) {
|
||
$e.data('old-value', t);
|
||
$e.on('click', onQuickEditField).data('id', node.key).data('name', 'name').data('selectId', data).addClass('select-id-quick-edit');
|
||
}
|
||
break;
|
||
|
||
case 'type':
|
||
setText(obj ? obj.type || '' : '');
|
||
break;
|
||
|
||
case 'role':
|
||
val = isCommon ? obj.common.role || '' : '';
|
||
setText(val);
|
||
|
||
if (data.quickEdit && obj && data.quickEdit.indexOf('role') !== -1) {
|
||
$elem.data('old-value', val);
|
||
$elem.on('click', onQuickEditField).data('id', node.key).data('name', 'role').data('selectId', data).addClass('select-id-quick-edit');
|
||
}
|
||
break;
|
||
|
||
case 'room':
|
||
// Try to find room
|
||
if (data.roomsColored) {
|
||
var room = data.roomsColored[node.key];
|
||
if (!room) room = data.roomsColored[node.key] = findRoomsForObject(data, node.key, true);
|
||
val = room.map(function (e) {
|
||
return getName(e.name);
|
||
}).join(', ');
|
||
|
||
if (room.length && room[0].origin !== node.key) {
|
||
$elem.css({color: 'gray'}).attr('title', room[0].origin);
|
||
} else {
|
||
$elem.css({color: 'inherit'}).attr('title', null);
|
||
}
|
||
} else {
|
||
val = '';
|
||
}
|
||
setText(val);
|
||
|
||
if (data.quickEdit && obj && data.quickEdit.indexOf('room') !== -1) {
|
||
$elem
|
||
.data('old-value', val)
|
||
.data('id', node.key)
|
||
.data('name', 'room')
|
||
.data('selectId', data);
|
||
addClippyToElement($elem, val, obj && data.quickEditCallback ? key : undefined);
|
||
}
|
||
break;
|
||
|
||
case 'function':
|
||
// Try to find function
|
||
if (data.funcsColored) {
|
||
if (!data.funcsColored[node.key]) data.funcsColored[node.key] = findFunctionsForObject(data, node.key, true);
|
||
val = data.funcsColored[node.key].map(function (e) {
|
||
return getName(e.name);
|
||
}).join (', ');
|
||
if (data.funcsColored[node.key].length && data.funcsColored[node.key][0].origin !== node.key) {
|
||
$elem.css({color: 'gray'}).attr('title', data.funcsColored[node.key][0].origin);
|
||
} else {
|
||
$elem.css({color: 'inherit'}).attr('title', null);
|
||
}
|
||
} else {
|
||
val = '';
|
||
}
|
||
setText(val);
|
||
|
||
if (data.quickEdit && obj && data.quickEdit.indexOf('function') !== -1) {
|
||
$elem
|
||
.data('old-value', val)
|
||
.data('id', node.key)
|
||
.data('name', 'function')
|
||
.data('selectId', data);
|
||
addClippyToElement($elem, val, obj && data.quickEditCallback ? key : undefined);
|
||
}
|
||
break;
|
||
|
||
case 'value.ts':
|
||
if (data.states && obj && obj.type === 'state') {
|
||
var state = data.states[node.key];
|
||
state = state || {ts: data.states[node.key + '.ts']};
|
||
var val = state.ts;
|
||
|
||
if (val === undefined) {
|
||
val = ' ';
|
||
} else {
|
||
val = val ? formatDate(new Date(val)) : '';
|
||
}
|
||
|
||
$elem.html('<span class="highlight select-value">' + val + '</span>');
|
||
} else {
|
||
$elem.text('');
|
||
}
|
||
break;
|
||
|
||
case 'value.lc':
|
||
if (data.states && obj && obj.type === 'state') {
|
||
var state = data.states[node.key] || {};
|
||
state = state || {lc: data.states[node.key + '.lc']};
|
||
var val = state.lc;
|
||
|
||
if (val === undefined) {
|
||
val = ' ';
|
||
} else {
|
||
val = val ? formatDate(new Date(val)) : '';
|
||
}
|
||
|
||
$elem.html('<span class="highlight select-value">' + val + '</span>');
|
||
} else {
|
||
$elem.text('');
|
||
}
|
||
break;
|
||
|
||
case 'value.from':
|
||
if (data.states && obj && obj.type === 'state') {
|
||
var state = data.states[node.key] || {};
|
||
state = state || {from: data.states[node.key + '.from'], user: data.states[node.key + '.user']};
|
||
var val = state.from;
|
||
|
||
|
||
if (val === undefined) {
|
||
val = ' ';
|
||
} else {
|
||
val = val ? val.replace(/^system\.adapter\.|^system\./, '') : '';
|
||
}
|
||
if (state.user) {
|
||
val += '/' + state.user.replace('system.user.', '');
|
||
}
|
||
$elem.html('<span class="highlight select-value">' + val + '</span>');
|
||
} else {
|
||
$elem.text('');
|
||
}
|
||
break;
|
||
|
||
case 'value.q':
|
||
if (data.states && obj && obj.type === 'state') {
|
||
var state = data.states[node.key] || {};
|
||
state = state || {q: data.states[node.key + '.q']};
|
||
var q = state.q;
|
||
var val = q;
|
||
|
||
if (val === undefined) {
|
||
val = ' ';
|
||
} else {
|
||
val = quality2text(val);
|
||
}
|
||
$elem.html('<span class="highlight select-value" style="' + (q ? 'orange' : '') + '">' + val + '</span>');
|
||
} else {
|
||
$elem.text('');
|
||
}
|
||
break;
|
||
|
||
case 'value.val':
|
||
if (data.states && obj && obj.type === 'state') {
|
||
var state = data.states[node.key] || {};
|
||
if (!state) {
|
||
state = {
|
||
val: data.states[node.key + '.val'],
|
||
ack: (data.states[node.key + '.ack'] === undefined) ? '' : data.states[node.key + '.ack']
|
||
};
|
||
}
|
||
var val = state.val;
|
||
var ack = state.ack;
|
||
|
||
var states = getStates(data, node.key);
|
||
|
||
if (isCommon && isCommon.role && isCommon.role.match(/^value\.time|^date/)) {
|
||
val = val ? (new Date(val)).toString() : val;
|
||
}
|
||
if (states && states[val] !== undefined) {
|
||
val = states[val] + '(' + val + ')';
|
||
}
|
||
|
||
if (val === undefined) {
|
||
val = ' ';
|
||
} else
|
||
if (val === null || val === '') {
|
||
val = ' ';
|
||
}
|
||
if (typeof val === 'string' && val !== '$nbsp;') {
|
||
val = val.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
}
|
||
|
||
$elem.html('<span class="highlight select-value" style="' + (ack ? '' : '#c00000') + '">' + val + '</span>');
|
||
|
||
if (obj && obj.type === 'state' && isCommon && isCommon.type !== 'file') {
|
||
addClippyToElement($elem, state.val === undefined || state.val === null ? '' : state.val.toString(),
|
||
obj && data.quickEditCallback &&
|
||
obj.type === 'state' &&
|
||
(data.expertMode || isCommon.write !== false) ? key : undefined);
|
||
}
|
||
} else {
|
||
$elem.text('')
|
||
.removeClass('clippy');
|
||
}
|
||
$elem.dblclick (function (e) {
|
||
e.preventDefault ();
|
||
});
|
||
|
||
if (data.quickEdit &&
|
||
isCommon &&
|
||
obj.type === 'state' &&
|
||
data.quickEdit.indexOf('value') !== -1 &&
|
||
(data.expertMode || isCommon.write !== false)
|
||
) {
|
||
if (isCommon.role && isCommon.role.match(/^button/) && !data.expertMode) {
|
||
$elem.html('<button data-id="' + node.key + '" class="select-button-push"></button>');
|
||
} else if (!isCommon || isCommon.type !== 'file') {
|
||
var val_ = data.states[node.key];
|
||
val_ = val_ ? val_.val : '';
|
||
var $span_ = $elem.find('span');
|
||
$span_.data('old-value', val_).data('type', isCommon.type || typeof val_);
|
||
|
||
$span_.on('click', onQuickEditField)
|
||
.data('id', node.key)
|
||
.data('name', 'value')
|
||
.data('selectId', data)
|
||
.addClass('select-id-quick-edit');
|
||
}
|
||
|
||
var $btnPush = $tr.find('.select-button-push[data-id="' + node.key + '"]');
|
||
$btnPush.on('click', function () {
|
||
var id = $(this).data('id');
|
||
data.quickEditCallback(id, 'value', true);
|
||
}).attr('title', data.texts.push);
|
||
|
||
if (!isMaterial) {
|
||
$btnPush.button({
|
||
text: false,
|
||
icons: {
|
||
primary: 'ui-icon-arrowthickstop-1-s'
|
||
}
|
||
});
|
||
} else {
|
||
$btnPush.prepend('<i class="material-icons">room_service</i>')
|
||
}
|
||
}
|
||
|
||
if (isCommon && isCommon.type === 'file') {
|
||
data.webServer = data.webServer || (window.location.protocol + '//' + window.location.hostname + ':8082');
|
||
|
||
// link
|
||
$elem.html('<a href="' + data.webServer + '/state/' + encodeURIComponent(node.key) + '" target="_blank">' + data.webServer + '/state/' + node.key + '</a>')
|
||
.attr('title', data.texts.linkToFile);
|
||
}
|
||
break;
|
||
|
||
case 'value':
|
||
var state;
|
||
if (data.states && obj && obj.type === 'state') {
|
||
state = data.states[node.key];
|
||
|
||
var states = getStates(data, node.key);
|
||
if (!state) {
|
||
state = {
|
||
val: data.states[node.key + '.val'],
|
||
ts: data.states[node.key + '.ts'],
|
||
lc: data.states[node.key + '.lc'],
|
||
from: data.states[node.key + '.from'],
|
||
user: data.states[node.key + '.user'],
|
||
ack: (data.states[node.key + '.ack'] === undefined) ? '' : data.states[node.key + '.ack'],
|
||
q: (data.states[node.key + '.q'] === undefined) ? 0 : data.states[node.key + '.q']
|
||
};
|
||
} else {
|
||
state = Object.assign({}, state);
|
||
}
|
||
|
||
if (isCommon && isCommon.role && isCommon.role.match(/^value\.time|^date/)) {
|
||
state.val = state.val ? (new Date(state.val)).toString() : state.val;
|
||
}
|
||
|
||
var originalVal = state.val;
|
||
|
||
if (states && states[state.val] !== undefined) {
|
||
state.val = states[state.val] + '(' + state.val + ')';
|
||
}
|
||
|
||
var fullVal;
|
||
if (state.val === undefined) {
|
||
state.val = ' ';
|
||
} else {
|
||
// if less 2000.01.01 00:00:00
|
||
if (state.ts < 946681200000) state.ts *= 1000;
|
||
if (state.lc < 946681200000) state.lc *= 1000;
|
||
|
||
if (isCommon && isCommon.unit) state.val += ' ' + isCommon.unit;
|
||
fullVal = data.texts.value + ': ' + state.val;
|
||
fullVal += '\x0A' + data.texts.ack + ': ' + state.ack;
|
||
fullVal += '\x0A' + data.texts.ts + ': ' + (state.ts ? formatDate(new Date(state.ts)) : '');
|
||
fullVal += '\x0A' + data.texts.lc + ': ' + (state.lc ? formatDate(new Date(state.lc)) : '');
|
||
fullVal += '\x0A' + data.texts.from + ': ' + (state.from || '');
|
||
if (state.user) fullVal += '\x0A' + data.texts.user + ': ' + (state.user || '');
|
||
fullVal += '\x0A' + data.texts.quality + ': ' + quality2text(state.q || 0);
|
||
}
|
||
if (state.val === null || state.val === '') {
|
||
state.val = ' ';
|
||
}
|
||
if (typeof state.val === 'string' && state.val !== ' ') {
|
||
state.val = state.val.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
}
|
||
|
||
$elem.html('<span class="highlight select-value">' + state.val + '</span>')
|
||
.attr('title', fullVal);
|
||
|
||
var $span = $elem.find('span');
|
||
$span.css({color: state.ack ? (state.q ? 'orange' : '') : '#c00000'});
|
||
|
||
if (obj && obj.type === 'state' && isCommon && isCommon.type !== 'file') {
|
||
addClippyToElement($elem, originalVal === undefined || originalVal === null ? '' : originalVal.toString(),
|
||
obj && data.quickEditCallback &&
|
||
obj.type === 'state' &&
|
||
(data.expertMode || isCommon.write !== false) ? key : undefined);
|
||
}
|
||
} else {
|
||
$elem
|
||
.text('')
|
||
.attr('title', '')
|
||
.removeClass('clippy');
|
||
}
|
||
$elem.dblclick (function (e) {
|
||
e.preventDefault ();
|
||
});
|
||
|
||
if (data.quickEdit &&
|
||
isCommon &&
|
||
obj.type === 'state' &&
|
||
data.quickEdit.indexOf('value') !== -1 &&
|
||
(data.expertMode || isCommon.write !== false)
|
||
) {
|
||
if (isCommon.role && isCommon.role.match(/^button/) && !data.expertMode) {
|
||
$elem.html('<button data-id="' + node.key + '" class="select-button-push"></button>');
|
||
} else if (!isCommon || isCommon.type !== 'file') {
|
||
var val_ = data.states[node.key];
|
||
val_ = val_ ? val_.val : '';
|
||
var $span_ = $elem.find('span');
|
||
$span_.data('old-value', val_).data('type', isCommon.type || typeof val_);
|
||
|
||
$span_.on('click', onQuickEditField)
|
||
.data('id', node.key)
|
||
.data('name', 'value')
|
||
.data('selectId', data)
|
||
.addClass('select-id-quick-edit');
|
||
}
|
||
|
||
var $btnPush = $tr.find('.select-button-push[data-id="' + node.key + '"]');
|
||
$btnPush.on('click', function () {
|
||
var id = $(this).data('id');
|
||
data.quickEditCallback(id, 'value', true);
|
||
}).attr('title', data.texts.push);
|
||
|
||
if (!isMaterial) {
|
||
$btnPush.button({
|
||
text: false,
|
||
icons: {
|
||
primary: 'ui-icon-arrowthickstop-1-s'
|
||
}
|
||
});
|
||
} else {
|
||
$btnPush.prepend('<i class="material-icons">room_service</i>')
|
||
}
|
||
}
|
||
|
||
if (isCommon && isCommon.type === 'file') {
|
||
data.webServer = data.webServer || (window.location.protocol + '//' + window.location.hostname + ':8082');
|
||
|
||
// link
|
||
$elem.html('<a href="' + data.webServer + '/state/' + encodeURIComponent(node.key) + '" target="_blank">' + data.webServer + '/state/' + node.key + '</a>')
|
||
.attr('title', data.texts.linkToFile);
|
||
}
|
||
break;
|
||
|
||
case 'button':
|
||
// Show buttons
|
||
var text;
|
||
if (data.buttons) {
|
||
if (obj || data.showButtonsForNotExistingObjects) {
|
||
text = '';
|
||
if (data.editEnd) {
|
||
text += '' +
|
||
'<button data-id="' + node.key + '" class="m select-button-edit"></button>' +
|
||
'<button data-id="' + node.key + '" class="m select-button-ok"></button>' +
|
||
'<button data-id="' + node.key + '" class="m select-button-cancel"></button>';
|
||
}
|
||
|
||
for (var j = 0; j < data.buttons.length; j++) {
|
||
text += '<button data-id="' + node.key + '" class="m select-button-' + j + ' select-button-custom td-button"></button>';
|
||
}
|
||
|
||
setText(text);
|
||
|
||
for (var p = 0; p < data.buttons.length; p++) {
|
||
var $btn = $tr.find('.select-button-' + p + '[data-id="' + node.key + '"]');
|
||
|
||
if ($btn.length === 0) continue;
|
||
|
||
$btn
|
||
.on('click', function () {
|
||
var cb = $(this).data('callback');
|
||
if (cb) cb.call($(this), $(this).data('id'));
|
||
})
|
||
.data('callback', data.buttons[p].click)
|
||
.attr('title', data.buttons[p].title || '');
|
||
|
||
if (data.buttons[p].match) data.buttons[p].match.call($btn, node.key);
|
||
if (!isMaterial) {
|
||
// if (data.buttons[p].width) $btn.css({width: data.buttons[p].width});
|
||
// if (data.buttons[p].height) $btn.css({height: data.buttons[p].height});
|
||
$btn.button(data.buttons[p]);
|
||
} else {
|
||
$btn.addClass('custom-obj-btn').prepend('<i class="material-icons">' + data.buttons[p]['material-icon'] + '</i>');
|
||
}
|
||
}
|
||
} else {
|
||
$elem.text('');
|
||
}
|
||
} else if (data.editEnd) {
|
||
text = '<button data-id="' + node.key + '" class="m select-button-edit"></button>' +
|
||
'<button data-id="' + node.key + '" class="m select-button-ok"></button>' +
|
||
'<button data-id="' + node.key + '" class="m select-button-cancel"></button>';
|
||
}
|
||
|
||
if (data.editEnd) {
|
||
var $btnEdit = $tr.find('.select-button-edit[data-id="' + node.key + '"]');
|
||
$btnEdit
|
||
.on('click', function () {
|
||
$(this).data('node').editStart();
|
||
})
|
||
.attr('title', data.texts.edit)
|
||
.data('node', node);
|
||
|
||
if (!isMaterial) {
|
||
$btnEdit.button({
|
||
text: false,
|
||
icons: {
|
||
primary: 'ui-icon-pencil'
|
||
}
|
||
});
|
||
} else {
|
||
$btnEdit.prepend('<i class="material-icons">edit</i>');
|
||
}
|
||
|
||
$btnEdit = $tr.find('.select-button-ok[data-id="' + node.key + '"]');
|
||
$btnEdit.on('click', function () {
|
||
var node = $(this).data('node');
|
||
node.editFinished = true;
|
||
node.editEnd (true);
|
||
}).attr('title', data.texts.ok).data('node', node).hide();
|
||
|
||
if (!isMaterial) {
|
||
$btnEdit.button({
|
||
text: false,
|
||
icons: {
|
||
primary: 'ui-icon-check'
|
||
}
|
||
});
|
||
} else {
|
||
$btnEdit.prepend('<i class="material-icons">done</i>');
|
||
}
|
||
|
||
$btnEdit = $tr.find('.select-button-cancel[data-id="' + node.key + '"]');
|
||
$btnEdit.on('click', function () {
|
||
var node = $(this).data('node');
|
||
node.editFinished = true;
|
||
node.editEnd (false);
|
||
}).attr('title', data.texts.cancel).data('node', node).hide();
|
||
|
||
if (!isMaterial) {
|
||
$btnEdit.button({
|
||
text: false,
|
||
icons: {
|
||
primary: 'ui-icon-close'
|
||
}
|
||
});
|
||
} else {
|
||
$btnEdit.prepend('<i class="material-icons">close</i>');
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 'enum':
|
||
if (isCommon && obj.common.members && obj.common.members.length > 0) {
|
||
var te;
|
||
if (obj.common.members.length < 4) {
|
||
te = '#' + obj.common.members.length + ' ' + obj.common.members.join (', ');
|
||
} else {
|
||
te = '#' + obj.common.members.length;
|
||
}
|
||
$elem.html('<div class="iob-ellipsis">' + te + '</div>');
|
||
$elem.attr('title', obj.common.members.join ('\x0A'));
|
||
} else {
|
||
$elem.text('');
|
||
$elem.attr('title', '');
|
||
}
|
||
break;
|
||
|
||
default:
|
||
if (typeof data.columns[c].data === 'function') {
|
||
//$elem = $tdList.eq(base);
|
||
var val = data.columns[c].data(node.key, data.columns[c].name);
|
||
var title = '';
|
||
if (data.columns[c].title) {
|
||
title = data.columns[c].title(node.key, data.columns[c].name);
|
||
}
|
||
$elem.html(val).attr('title', title);
|
||
if (data.quickEdit && obj) {
|
||
for (var q = 0; q < data.quickEdit.length; q++) {
|
||
if (data.quickEdit[q] === data.columns[c].name ||
|
||
data.quickEdit[q].name === data.columns[c].name) {
|
||
$elem.data('old-value', val).data('type', typeof val);
|
||
|
||
$elem.on('click', onQuickEditField)
|
||
.data('id', node.key)
|
||
.data('name', data.columns[c].name)
|
||
.data('selectId', data)
|
||
.data('options', data.quickEdit[q].options)
|
||
.addClass('select-id-quick-edit');
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
///
|
||
base++;
|
||
///
|
||
}
|
||
},
|
||
dblclick: function (event, _data) {
|
||
if (data.buttonsDlg && !data.quickEditCallback) {
|
||
if (_data && _data.node && !_data.node.folder) {
|
||
if (typeof M !== 'undefined') {
|
||
$dlg.find('.btn-set').trigger('click');
|
||
$dlg.modal('close');
|
||
} else {
|
||
$('#button-ok').trigger('click');
|
||
}
|
||
}
|
||
} else if (data.dblclick) {
|
||
var tree = data.$tree.fancytree('getTree');
|
||
|
||
var node = tree.getActiveNode();
|
||
if (node) {
|
||
data.dblclick(node.key);
|
||
}
|
||
}
|
||
},
|
||
beforeExpand: function (event, _data) {
|
||
if (data.expandedCallback) {
|
||
if (_data && _data.node) {
|
||
// if will be expanded
|
||
if (!_data.node.expanded) {
|
||
var childrenCount = 0;
|
||
var hasStates = false;
|
||
var patterns = [];
|
||
if (_data.node.children) {
|
||
childrenCount = _data.node.children.length;
|
||
detectStates(_data.node, patterns);
|
||
if (patterns.length) hasStates = true;
|
||
}
|
||
|
||
if (!patterns.length) {
|
||
patterns.push(_data.node.key);
|
||
}
|
||
|
||
data.expandedCallback(patterns, childrenCount, hasStates);
|
||
|
||
} else {
|
||
data.collapsedCallback(_data.node.key);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
collapse: function (event, _data) {
|
||
/*if (data.collapsedCallback) {
|
||
if (_data && _data.node) {
|
||
data.collapsedCallback(_data.node.key);
|
||
}
|
||
}*/
|
||
}
|
||
};
|
||
|
||
if (data.editEnd) {
|
||
foptions.extensions.push('edit');
|
||
foptions.edit = {
|
||
triggerStart: ['f2', 'dblclick', 'shift+click', 'mac+enter'],
|
||
triggerStop: ['esc'],
|
||
beforeEdit: function (event, _data) {
|
||
// Return false to prevent edit mode
|
||
if (!data.objects[_data.node.key]) return false;
|
||
},
|
||
edit: function (event, _data) {
|
||
$dlg.find('.select-button-edit[data-id="' + _data.node.key + '"]').hide();
|
||
$dlg.find('.select-button-cancel[data-id="' + _data.node.key + '"]').show();
|
||
$dlg.find('.select-button-ok[data-id="' + _data.node.key + '"]').show();
|
||
$dlg.find('.select-button-custom[data-id="' + _data.node.key + '"]').hide();
|
||
|
||
var node = _data.node;
|
||
var $tdList = $(node.tr).find('>td');
|
||
// Editor was opened (available as data.input)
|
||
var inputs = {id: _data.input};
|
||
|
||
forEachColumn(data, function (name, c) {
|
||
if (name === 'name') {
|
||
inputs[name] = $('<input type="text" data-name="' + name + '" class="select-edit" value="' + data.objects[_data.node.key].common[name] + '" style="width: 100%"/>');
|
||
$tdList.eq(c).html(inputs[name]);
|
||
}
|
||
});
|
||
|
||
for (var i in inputs) {
|
||
inputs[i].keyup(function (e) {
|
||
var node;
|
||
if (e.which === 13) {
|
||
// end edit
|
||
node = $(this).data('node');
|
||
node.editFinished = true;
|
||
node.editEnd(true);
|
||
} else if (e.which === 27) {
|
||
// end edit
|
||
node = $(this).data('node');
|
||
node.editFinished = true;
|
||
node.editEnd(false);
|
||
}
|
||
}).data('node', node);
|
||
}
|
||
|
||
if (data.editStart) data.editStart(_data.node.key, inputs);
|
||
node.editFinished = false;
|
||
},
|
||
beforeClose: function (event, _data) {
|
||
// Return false to prevent cancel/save (data.input is available)
|
||
return _data.node.editFinished;
|
||
},
|
||
save: function (event, _data) {
|
||
var editValues = {id: _data.input.val()};
|
||
|
||
forEachColumn (data, function (name) {
|
||
if (name === 'name') {
|
||
editValues[name] = $dlg.find('.select-edit[data-name="' + name + '"]').val();
|
||
}
|
||
});
|
||
|
||
// Save data.input.val() or return false to keep editor open
|
||
if (data.editEnd) data.editEnd(_data.node.key, editValues);
|
||
_data.node.render(true);
|
||
|
||
// We return true, so ext-edit will set the current user input
|
||
// as title
|
||
return true;
|
||
},
|
||
close: function (event, _data) {
|
||
$dlg.find('.select-button-edit[data-id="' + _data.node.key + '"]').show();
|
||
$dlg.find('.select-button-cancel[data-id="' + _data.node.key + '"]').hide();
|
||
$dlg.find('.select-button-ok[data-id="' + _data.node.key + '"]').hide();
|
||
$dlg.find('.select-button-custom[data-id="' + _data.node.key + '"]').show();
|
||
if (_data.node.editFinished !== undefined) delete _data.node.editFinished;
|
||
// Editor was removed
|
||
if (data.save) {
|
||
// Since we started an async request, mark the node as preliminary
|
||
$(data.node.span).addClass('pending');
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
data.$tree.fancytree(foptions).on('nodeCommand', function (event, bData) {
|
||
// Custom event handler that is triggered by keydown-handler and
|
||
// context menu:
|
||
var refNode;
|
||
var tree = $(this).fancytree('getTree');
|
||
var node = tree.getActiveNode();
|
||
|
||
switch (bData.cmd) {
|
||
case 'moveUp':
|
||
node.moveTo(node.getPrevSibling(), 'before');
|
||
node.setActive();
|
||
break;
|
||
case 'moveDown':
|
||
node.moveTo(node.getNextSibling(), 'after');
|
||
node.setActive();
|
||
break;
|
||
case 'indent':
|
||
refNode = node.getPrevSibling();
|
||
node.moveTo(refNode, 'child');
|
||
refNode.setExpanded();
|
||
node.setActive();
|
||
break;
|
||
case 'outdent':
|
||
node.moveTo(node.getParent(), 'after');
|
||
node.setActive();
|
||
break;
|
||
case 'delete':
|
||
var button = $(node.tr).find('.select-button-1');
|
||
if (button && button.length) {
|
||
button.trigger('click');
|
||
}
|
||
break;
|
||
case 'rename':
|
||
var e = $(node.tr).find('.objects-name-coll-title');
|
||
if (e && e.length) {
|
||
e.trigger('click');
|
||
}
|
||
break;
|
||
|
||
/*case 'copy':
|
||
CLIPBOARD = {
|
||
mode: data.cmd,
|
||
data: node.toDict(function (n) {
|
||
delete n.key;
|
||
})
|
||
};
|
||
break;
|
||
case 'clear':
|
||
CLIPBOARD = null;
|
||
break;*/
|
||
default:
|
||
alert('Unhandled command: ' + bData.cmd);
|
||
return;
|
||
}
|
||
|
||
}).on('keydown', function (e) {
|
||
if (data.editing) {
|
||
return;
|
||
}
|
||
var cmd = null;
|
||
if (e.ctrlKey) {
|
||
switch (e.which) {
|
||
case 'c':
|
||
cmd = 'copy';
|
||
break;
|
||
case $.ui.keyCode.UP:
|
||
cmd = 'moveUp';
|
||
break;
|
||
case $.ui.keyCode.DOWN:
|
||
cmd = 'moveDown';
|
||
break;
|
||
case $.ui.keyCode.RIGHT:
|
||
cmd = 'indent';
|
||
break;
|
||
case $.ui.keyCode.LEFT:
|
||
cmd = 'outdent';
|
||
break;
|
||
}
|
||
} else {
|
||
switch (e.which) {
|
||
case $.ui.keyCode.DELETE:
|
||
cmd = 'delete';
|
||
break;
|
||
case 113: // F2
|
||
cmd = 'rename';
|
||
break;
|
||
}
|
||
}
|
||
if (cmd) {
|
||
$(this).trigger('nodeCommand', {cmd: cmd});
|
||
return false;
|
||
}
|
||
});
|
||
|
||
function customFilter(node) {
|
||
if (node.parent && node.parent.match) return true;
|
||
|
||
// Read all filter settings
|
||
if (data.filterVals === null) {
|
||
data.filterVals = {length: 0};
|
||
var value_;
|
||
|
||
forEachColumn (data, function (name) {
|
||
//if (name === 'image') return;
|
||
value_ = $dlg.find('.filter[data-index="' + name + '"]').val();
|
||
if (name !== 'role' && name !== 'type' && name !== 'room' && name !== 'function' && value_) {
|
||
value_ = value_.toLowerCase();
|
||
}
|
||
if (value_) {
|
||
data.filterVals[name] = value_;
|
||
data.filterVals.length++;
|
||
}
|
||
});
|
||
|
||
// if no clear "close" event => store on change
|
||
if (data.noDialog) storeSettings(data);
|
||
}
|
||
|
||
var obj = data.objects[node.key];
|
||
var isCommon = obj && obj.common;
|
||
var value;
|
||
|
||
for (var f in data.filterVals) {
|
||
//if (f === 'length') continue;
|
||
//if (isCommon === null) isCommon = obj && obj.common;
|
||
if (!data.filterVals.hasOwnProperty(f)) continue;
|
||
|
||
switch (f) {
|
||
case 'length':
|
||
continue;
|
||
case 'ID':
|
||
if (node.key.toLowerCase ().indexOf(data.filterVals[f]) === -1) return false;
|
||
break;
|
||
case 'name':
|
||
case 'enum':
|
||
if (!isCommon || obj.common[f] === undefined) return false;
|
||
value = obj.common[f];
|
||
if (typeof value === 'object') {
|
||
value = value[systemLang] || value.en || '';
|
||
}
|
||
if ((value || '').toLowerCase().indexOf(data.filterVals[f]) === -1) {
|
||
return false;
|
||
}
|
||
break;
|
||
case 'role':
|
||
if (data.roleExactly) {
|
||
if (!isCommon || obj.common[f] === undefined || obj.common[f] !== data.filterVals[f]) return false;
|
||
} else {
|
||
if (!isCommon || obj.common[f] === undefined || obj.common[f].indexOf(data.filterVals[f]) === -1) return false;
|
||
}
|
||
break;
|
||
case 'type':
|
||
if (!obj || obj[f] === undefined || obj[f] !== data.filterVals[f]) return false;
|
||
break;
|
||
/*case 'value':
|
||
if (!data.states[node.key] || data.states[node.key].val === undefined || data.states[node.key].val === null || data.states[node.key].val.toString ().toLowerCase ().indexOf(data.filterVals[f]) === -1) return false;
|
||
break;*/
|
||
case 'button':
|
||
if (data.filterVals[f] === 'true') {
|
||
if (!isCommon || !obj.common.custom || obj.common.custom.enabled === false) return false;
|
||
} else if (data.filterVals[f] === 'false') {
|
||
if (!isCommon || obj.type !== 'state' || obj.common.custom) return false;
|
||
} else if (data.filterVals[f]) {
|
||
if (!isCommon || !obj.common.custom || !obj.common.custom[data.filterVals[f]]) return false;
|
||
}
|
||
break;
|
||
case 'room':
|
||
if (!obj || !data.rooms) return false;
|
||
|
||
// Try to find room
|
||
if (!data.rooms[node.key]) data.rooms[node.key] = findRoomsForObject(data, node.key);
|
||
if (data.rooms[node.key].indexOf(data.filterVals[f]) === -1) return false;
|
||
break;
|
||
case 'function':
|
||
if (!obj || !data.funcs) return false;
|
||
|
||
// Try to find functions
|
||
if (!data.funcs[node.key]) data.funcs[node.key] = findFunctionsForObject(data, node.key);
|
||
if (data.funcs[node.key].indexOf(data.filterVals[f]) === -1) return false;
|
||
break;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
restoreExpandeds(data, expandeds);
|
||
var resizeTimer;
|
||
$(window).on('resize', function (/* x, y */) {
|
||
if (resizeTimer) clearTimeout(resizeTimer);
|
||
resizeTimer = setTimeout(function () {
|
||
syncHeader($dlg);
|
||
}, 100);
|
||
});
|
||
$dlg.trigger('resize');
|
||
|
||
var changeTimer;
|
||
|
||
$dlg.find('.filter').change(function (event) {
|
||
data.filterVals = null;
|
||
if (changeTimer) clearTimeout(changeTimer);
|
||
//changeTimer = setTimeout(function () {
|
||
if (event && event.target) {
|
||
filterChanged(event.target);
|
||
}
|
||
|
||
var $ee = $dlg.find('.objects-list-running');
|
||
$ee.show();
|
||
data.$tree.fancytree('getTree').filterNodes(customFilter, false);
|
||
$ee.hide();
|
||
//}, 0);
|
||
}).keyup(function () {
|
||
var tree = data.$tree[0];
|
||
if (tree._timer) tree._timer = clearTimeout(tree._timer);
|
||
|
||
var that = this;
|
||
tree._timer = setTimeout(function () {
|
||
$(that).trigger('change');
|
||
}, 200);
|
||
});
|
||
|
||
var $btn = $dlg.find('.filter-btn');
|
||
|
||
$btn.on('click', function () {
|
||
$dlg.find('.filter[data-index="' + $(this).data('index') + '"]').val('').trigger('change'); //filter buttons action
|
||
});
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-close'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">close</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-collapse');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.$tree.fancytree('getRootNode').visit(function (node) {
|
||
if (!data.filterVals.length || node.match || node.subMatchCount) {
|
||
node.setExpanded(false);
|
||
}
|
||
});
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.collapse);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-folder-collapsed'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">folder</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-expand');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.$tree.fancytree('getRootNode').visit(function (node) {
|
||
if (!data.filterVals.length || node.match || node.subMatchCount) {
|
||
node.setExpanded(true);
|
||
}
|
||
});
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.expand);
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-folder-open'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">folder_open</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-list');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
data.list = !data.list;
|
||
if (data.list) {
|
||
$dlg.find('.btn-list').addClass('ui-state-error red lighten-3');
|
||
$dlg.find('.btn-collapse').hide();
|
||
$(this).attr('title', data.texts.list);
|
||
} else {
|
||
$dlg.find('.btn-list').removeClass('ui-state-error red lighten-3');
|
||
$dlg.find('.btn-expand').show();
|
||
$dlg.find('.btn-collapse').show();
|
||
$(this).attr('title', data.texts.tree);
|
||
}
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.inited = false;
|
||
initTreeDialog(data.$dlg);
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 200);
|
||
}).attr('title', data.texts.tree);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-grip-dotted-horizontal'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">format_list_bulleted</i>');
|
||
}
|
||
|
||
if (data.list) {
|
||
$dlg.find('.btn-list')
|
||
.addClass('ui-state-error red lighten-3')
|
||
.attr('title', data.texts.list);
|
||
$dlg.find('.btn-expand').hide();
|
||
$dlg.find('.btn-collapse').hide();
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-refresh');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.inited = false;
|
||
// request all objects anew on refresh
|
||
if (data.getObjects) {
|
||
data.getObjects(function (err, objs) {
|
||
data.objects = objs;
|
||
initTreeDialog(data.$dlg, false);
|
||
$dlg.find('.objects-list-running').hide();
|
||
});
|
||
} else {
|
||
initTreeDialog(data.$dlg, false);
|
||
$dlg.find('.objects-list-running').hide();
|
||
}
|
||
}, 100);
|
||
}).attr('title', data.texts.refresh);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-refresh'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">refresh</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-sort');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
|
||
data.sort = !data.sort;
|
||
if (data.sort) {
|
||
$dlg.find('.btn-sort').addClass('ui-state-error red lighten-3');
|
||
} else {
|
||
$dlg.find('.btn-sort').removeClass('ui-state-error red lighten-3');
|
||
}
|
||
storeSettings(data, true);
|
||
|
||
setTimeout(function () {
|
||
data.inited = false;
|
||
sortTree(data);
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.sort);
|
||
if (data.sort) $dlg.find('.btn-sort').addClass('ui-state-error red lighten-3');
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-bookmark'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">sort_by_alpha</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-history');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
|
||
setTimeout(function () {
|
||
data.customButtonFilter.callback();
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 1);
|
||
}).attr('title', data.texts.history);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-gear'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">build</i>');
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-select-all');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.$tree.fancytree('getRootNode').visit(function (node) {
|
||
if (!data.filterVals.length || node.match || node.subMatchCount) {
|
||
// hide checkbox if only states should be selected
|
||
if (data.objects[node.key] && data.objects[node.key].type === 'state') {
|
||
node.setSelected(true);
|
||
}
|
||
}
|
||
});
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.selectAll);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-circle-check'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">playlist_add_check</i>');
|
||
}
|
||
|
||
if (data.expertModeRegEx) {
|
||
$btn = $dlg.find('.btn-expert');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
|
||
data.expertMode = !data.expertMode;
|
||
if (data.expertMode) {
|
||
$dlg.find('.btn-expert').addClass('ui-state-error red lighten-3');
|
||
} else {
|
||
$dlg.find('.btn-expert').removeClass('ui-state-error red lighten-3');
|
||
}
|
||
storeSettings(data, true);
|
||
|
||
setTimeout(function () {
|
||
data.inited = false;
|
||
initTreeDialog(data.$dlg);
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 200);
|
||
}).attr('title', data.texts.expertMode);
|
||
|
||
if (data.expertMode) $dlg.find('.btn-expert').addClass('ui-state-error red lighten-3');
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-person'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">assignment_ind</i>');
|
||
}
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-unselectall');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.$tree.fancytree('getRootNode').visit(function (node) {
|
||
node.setSelected(false);
|
||
});
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.unselectAll);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-circle-close'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">cancel</i>');// todo
|
||
}
|
||
|
||
$btn = $dlg.find('.btn-invert-selection');
|
||
$btn.on('click', function () {
|
||
$dlg.find('.objects-list-running').show();
|
||
setTimeout(function () {
|
||
data.$tree.fancytree('getRootNode').visit(function (node) {
|
||
if (!data.filterVals.length || node.match || node.subMatchCount){
|
||
if (data.objects[node.key] && data.objects[node.key].type === 'state') {
|
||
node.toggleSelected();
|
||
}
|
||
}
|
||
});
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
}).attr('title', data.texts.invertSelection);
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-transferthick-e-w'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">invert_colors</i>'); // todo
|
||
}
|
||
|
||
if (data.useValues) {
|
||
$btn = $dlg.find('.btn-values');
|
||
$btn.on('click', function () {
|
||
data.valuesActive = !data.valuesActive;
|
||
updateValuesButton(data);
|
||
window.localStorage && window.localStorage.setItem(data.name + '-values', data.valuesActive ? 'true' : 'false');
|
||
|
||
$dlg.find('.objects-list-running').show();
|
||
|
||
setTimeout(function () {
|
||
data.inited = false;
|
||
initTreeDialog(data.$dlg);
|
||
$dlg.find('.objects-list-running').hide();
|
||
}, 100);
|
||
|
||
}).attr('title', data.texts.toggleValues);
|
||
updateValuesButton(data);
|
||
}
|
||
|
||
if (!isMaterial) {
|
||
$btn.button({icons: {primary: 'ui-icon-tag'}, text: false});
|
||
} else {
|
||
$btn.prepend('<i class="material-icons">looks_one</i>');
|
||
}
|
||
|
||
for (var f in filter) {
|
||
try {
|
||
if (f) setFilterVal(data, f, filter[f]);
|
||
} catch (err) {
|
||
console.error('Cannot apply filter: ' + err)
|
||
}
|
||
}
|
||
|
||
if (data.panelButtons) {
|
||
for (var z = 0; z < data.panelButtons.length; z++) {
|
||
$btn = $dlg.find('.btn-custom-' + z);
|
||
$btn.attr('title', data.panelButtons[z].title || '');
|
||
|
||
$btn.on('click', data.panelButtons[z].click);
|
||
if (!isMaterial) {
|
||
$btn.button(data.panelButtons[z]);
|
||
} else {
|
||
$btn.addClass('custom-toolbar-btn').prepend('<i class="material-icons">' + data.panelButtons[z]['material-icon'] + '</i>');
|
||
}
|
||
}
|
||
}
|
||
|
||
/*if (data.useHistory) {
|
||
$dlg.find('.filter_button_' + data.instance + '_btn')
|
||
.button(data.customButtonFilter)
|
||
.on('click', data.customButtonFilter.callback);
|
||
}*/
|
||
|
||
showActive($dlg);
|
||
installColResize(data, $dlg);
|
||
loadSettings(data);
|
||
if ($dlg.attr('id') !== 'dialog-select-member' && $dlg.attr('id') !== 'dialog-select-members') {
|
||
setTimeout(function () {
|
||
$dlg.css({height: '100%'}); //xxx
|
||
}, 500);
|
||
} else if ($dlg.attr('id') === 'dialog-select-members') {
|
||
//$dlg.find('div:first-child').css({height: 'calc(100% - 50px)'});
|
||
}
|
||
|
||
// set preset filters
|
||
for (var field in data.filterPresets) {
|
||
if (!data.filterPresets.hasOwnProperty(field) || !data.filterPresets[field]) continue;
|
||
if (typeof data.filterPresets[field] === 'object') {
|
||
setFilterVal(data, field, data.filterPresets[field][0]);
|
||
} else {
|
||
setFilterVal(data, field, data.filterPresets[field]);
|
||
}
|
||
}
|
||
sortTree(data);
|
||
}
|
||
|
||
function storeSettings(data, force) {
|
||
if (typeof Storage === 'undefined' || !data.name) return;
|
||
|
||
if (data.timer) clearTimeout(data.timer);
|
||
|
||
if (force) {
|
||
window.localStorage.setItem(data.name + '-filter', JSON.stringify(data.filterVals));
|
||
window.localStorage.setItem(data.name + '-expert', JSON.stringify(data.expertMode));
|
||
window.localStorage.setItem(data.name + '-sort', JSON.stringify(data.sort));
|
||
window.localStorage.setItem(data.name + '-values', data.valuesActive ? 'true' : 'false');
|
||
data.timer = null;
|
||
} else {
|
||
data.timer = setTimeout(function () {
|
||
window.localStorage.setItem(data.name + '-filter', JSON.stringify(data.filterVals));
|
||
window.localStorage.setItem(data.name + '-expert', JSON.stringify(data.expertMode));
|
||
window.localStorage.setItem(data.name + '-sort', JSON.stringify(data.sort));
|
||
window.localStorage.setItem(data.name + '-values', data.valuesActive ? 'true' : 'false');
|
||
}, 500);
|
||
}
|
||
}
|
||
|
||
function loadSettings(data) {
|
||
if (typeof Storage !== 'undefined' && data.name) {
|
||
var f = window.localStorage.getItem(data.name + '-filter');
|
||
if (f) {
|
||
try{
|
||
f = JSON.parse(f);
|
||
removeImageFromSettings(f);
|
||
//setTimeout(function () {
|
||
for (var field in f) {
|
||
if (!f.hasOwnProperty(field) || field === 'length') continue;
|
||
if (data.filterPresets[field]) continue;
|
||
setFilterVal(data, field, f[field]);
|
||
}
|
||
//}, 0);
|
||
} catch (e) {
|
||
console.error('Cannot parse settings: ' + e);
|
||
}
|
||
} else if (!data.filter) {
|
||
// set default filter: state
|
||
setFilterVal(data, 'type', 'state');
|
||
}
|
||
}
|
||
}
|
||
|
||
function updateValuesButton(data) {
|
||
if (data.valuesActive) {
|
||
data.$dlg.find('.btn-values').addClass('ui-state-error red lighten-3');
|
||
} else {
|
||
data.$dlg.find('.btn-values').removeClass('ui-state-error red lighten-3');
|
||
}
|
||
}
|
||
|
||
function countChildren(id, data) {
|
||
var pos = data.ids.indexOf(id);
|
||
var len = data.ids.length;
|
||
var cnt = 0;
|
||
if (id.indexOf('.') === -1 || (
|
||
data.objects[id] && (data.objects[id].type === 'state' || data.objects[id].type === 'adapter'))) {
|
||
return cnt;
|
||
}
|
||
if (pos === -1) {
|
||
pos = 0;
|
||
while (pos < len && data.ids[pos] < id) {
|
||
pos++;
|
||
}
|
||
pos--;
|
||
}
|
||
if (pos !== -1) {
|
||
pos++;
|
||
while (pos < len && data.ids[pos].startsWith(id + '.')) {
|
||
pos++;
|
||
cnt++;
|
||
}
|
||
}
|
||
return cnt;
|
||
}
|
||
|
||
function updateStats(data) {
|
||
data.$dlg.find('.objects-info .objects-val-objs').html('<span class="highlight">' + data.stats.objs + '</span>');
|
||
data.$dlg.find('.objects-info .objects-val-states').html('<span class="highlight">' + data.stats.states + '</span>');
|
||
}
|
||
|
||
function recalcChildrenCounters(node, data) {
|
||
var id = node.key;
|
||
var $tr = $(node.tr);
|
||
var $firstTD = $tr.find('>td').eq(0);
|
||
var cnt = countChildren(id, data);
|
||
if (cnt) {
|
||
var $cnt = $firstTD.find('.select-id-cnt');
|
||
if ($cnt.length) {
|
||
$cnt.text('#' + cnt);
|
||
} else {
|
||
//$firstTD.append('<span class="select-id-cnt" style="position: absolute; top: 6px; right: 1px; font-size: smaller; color: lightslategray">#' + cnt + '</span>');
|
||
$firstTD.append('<span class="select-id-cnt">#' + cnt + '</span>');
|
||
}
|
||
} else {
|
||
$firstTD.find('.select-id-cnt').remove();
|
||
}
|
||
if (node.children && node.children.length) {
|
||
for (var c = 0; c < node.children.length; c++) {
|
||
recalcChildrenCounters(node.children[c], data);
|
||
}
|
||
}
|
||
}
|
||
|
||
var methods = {
|
||
init: function (options) {
|
||
isMaterial = typeof M !== 'undefined'; // is material UI
|
||
// done, just to show possible settings, this is not required
|
||
var settings = $.extend({
|
||
currentId: '',
|
||
objects: null,
|
||
states: null,
|
||
filter: null,
|
||
imgPath: 'lib/css/fancytree/',
|
||
connCfg: null,
|
||
onSuccess: null,
|
||
onChange: null,
|
||
zindex: null,
|
||
list: false,
|
||
name: null,
|
||
sortConfig: {
|
||
statesFirst: true,
|
||
ignoreSortOrder: false
|
||
},
|
||
//columns: ['image', 'name', 'type', 'role', 'enum', 'room', 'function', 'value', 'button']
|
||
columns: ['name', 'type', 'role', 'enum', 'room', 'function', 'value', 'button']
|
||
}, options);
|
||
|
||
settings.texts = settings.texts || {};
|
||
settings.texts = $.extend({
|
||
select: 'Select',
|
||
cancel: 'Cancel',
|
||
all: 'All',
|
||
id: 'ID',
|
||
name: 'Name',
|
||
role: 'Role',
|
||
type: 'Type',
|
||
room: 'Room',
|
||
'function': 'Function',
|
||
enum: 'Members',
|
||
value: 'Value',
|
||
selectid: 'Select ID',
|
||
from: 'From',
|
||
quality: 'Quality',
|
||
lc: 'Last changed',
|
||
ts: 'Time stamp',
|
||
ack: 'Acknowledged',
|
||
expand: 'Expand all nodes',
|
||
collapse: 'Collapse all nodes',
|
||
refresh: 'Rebuild tree',
|
||
edit: 'Edit',
|
||
ok: 'Ok',
|
||
push: 'Trigger event',
|
||
wait: 'Processing...',
|
||
list: 'Show list view',
|
||
tree: 'Show tree view',
|
||
selectAll: 'Select all',
|
||
unselectAll: 'Unselect all',
|
||
invertSelection: 'Invert selection',
|
||
copyToClipboard: 'Copy to clipboard',
|
||
expertMode: 'Toggle expert mode',
|
||
button: 'Settings',
|
||
noData: 'No data',
|
||
Objects: 'Objects',
|
||
States: 'States',
|
||
toggleValues: 'Toggle states view'
|
||
}, settings.texts);
|
||
|
||
var that = this;
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
// Init data
|
||
if (!data) {
|
||
data = {
|
||
tree: {title: '', children: [], count: 0, root: true},
|
||
roomEnums: [],
|
||
rooms: {},
|
||
roomsColored: {},
|
||
funcEnums: [],
|
||
funcs: {},
|
||
funcsColored: {},
|
||
roles: [],
|
||
histories: [],
|
||
types: [],
|
||
regexSystemAdapter: new RegExp('^system\\.adapter\\.'),
|
||
regexSystemHost: new RegExp('^system\\.host\\.'),
|
||
regexEnumRooms: new RegExp('^enum\\.rooms\\.'),
|
||
regexEnumFuncs: new RegExp('^enum\\.functions\\.'),
|
||
inited: false,
|
||
filterPresets: {}
|
||
};
|
||
$dlg.data('selectId', data);
|
||
}
|
||
if (data.inited) {
|
||
// Re-init tree if filter or selectedID changed
|
||
if ((data.filter && !settings.filter && settings.filter !== undefined) ||
|
||
(!data.filter && settings.filter) ||
|
||
(data.filter && settings.filter && JSON.stringify(data.filter) !== JSON.stringify(settings.filter))) {
|
||
data.inited = false;
|
||
}
|
||
if (data.inited && settings.currentId !== undefined && (data.currentId !== settings.currentId)) {
|
||
// Deactivate current line
|
||
var tree = data.$tree.fancytree('getTree');
|
||
tree.visit(function (node) {
|
||
if (node.key === data.currentId) {
|
||
node.setActive(false);
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
data = $.extend(data, settings);
|
||
|
||
data.rootExp = data.root ? new RegExp('^' + data.root.replace('.', '\\.')) : null;
|
||
|
||
data.selectedID = data.currentId;
|
||
|
||
// make a copy of filter
|
||
data.filter = JSON.parse(JSON.stringify(data.filter));
|
||
|
||
if (!data.objects && data.connCfg) {
|
||
// Read objects and states
|
||
data.socketURL = '';
|
||
data.socketSESSION = '';
|
||
if (typeof data.connCfg.socketUrl !== 'undefined') {
|
||
data.socketURL = data.connCfg.socketUrl;
|
||
if (data.socketURL && data.socketURL[0] === ':') {
|
||
data.socketURL = location.protocol + '//' + location.hostname + data.socketURL;
|
||
}
|
||
data.socketSESSION = data.connCfg.socketSession;
|
||
data.socketUPGRADE = data.connCfg.upgrade;
|
||
data.socketRememberUpgrade = data.connCfg.rememberUpgrade;
|
||
data.socketTransports = data.connCfg.transports;
|
||
}
|
||
|
||
var connectTimeout = setTimeout(function () {
|
||
// noinspection JSJQueryEfficiency
|
||
var $dlg = $('#select-id-dialog');
|
||
if (!$dlg.length) {
|
||
$('body').append('<div id="select-id-dialog"><span class="ui-icon ui-icon-alert"></span><span>' + (data.texts.noconnection || 'No connection to server') + '</span></div>');
|
||
$dlg = $('#select-id-dialog');
|
||
}
|
||
|
||
if (typeof M !== 'undefined') {
|
||
$dlg.modal();
|
||
} else {
|
||
$dlg.dialog({
|
||
modal: true,
|
||
open: function (event) {
|
||
$(event.target).parent().find('.ui-dialog-titlebar-close .ui-button-text').html('');
|
||
}
|
||
});
|
||
}
|
||
}, 5000);
|
||
|
||
data.socket = io.connect(data.socketURL, {
|
||
query: 'key=' + data.socketSESSION,
|
||
'reconnection limit': 10000,
|
||
'max reconnection attempts': Infinity,
|
||
upgrade: data.socketUPGRADE,
|
||
rememberUpgrade: data.socketRememberUpgrade,
|
||
transports: data.socketTransports
|
||
});
|
||
|
||
data.socket.on('connect', function () {
|
||
if (connectTimeout) clearTimeout(connectTimeout);
|
||
this.emit('name', data.connCfg.socketName || 'selectId');
|
||
this.emit('getObjects', function (err, res) {
|
||
data.objects = res;
|
||
data.socket.emit('getStates', function (err, res) {
|
||
data.states = res;
|
||
if (data.readyCallback) {
|
||
data.readyCallback(err, data.objects, data.states);
|
||
}
|
||
});
|
||
});
|
||
});
|
||
data.socket.on('stateChange', function (id, obj) {
|
||
that.selectId('state', id, obj);
|
||
});
|
||
data.socket.on('objectChange', function (id, obj) {
|
||
that.selectId('object', id, obj);
|
||
});
|
||
}
|
||
|
||
$dlg.data('selectId', data);
|
||
}
|
||
|
||
return this;
|
||
},
|
||
show: function (currentId, filter, onSuccess) {
|
||
if (typeof filter === 'function') {
|
||
onSuccess = filter;
|
||
filter = undefined;
|
||
}
|
||
if (typeof currentId === 'function') {
|
||
onSuccess = currentId;
|
||
currentId = undefined;
|
||
}
|
||
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data) continue;
|
||
if (data.inited) {
|
||
// Re-init tree if filter or selectedID changed
|
||
if ((data.filter && !filter && filter !== undefined) ||
|
||
(!data.filter && filter) ||
|
||
(data.filter && filter && JSON.stringify(data.filter) !== JSON.stringify(filter))) {
|
||
data.inited = false;
|
||
}
|
||
|
||
if (data.inited && currentId !== undefined && (data.currentId !== currentId)) {
|
||
// Deactivate current line
|
||
var tree_ = data.$tree.fancytree('getTree');
|
||
tree_.visit(function (node) {
|
||
if (node.key === data.currentId) {
|
||
node.setActive(false);
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
if (currentId !== undefined) data.currentId = currentId;
|
||
if (filter !== undefined) data.filter = JSON.parse(JSON.stringify(filter));
|
||
if (onSuccess !== undefined) {
|
||
data.onSuccess = onSuccess;
|
||
data.$tree = $dlg.find('.objects-list-table');
|
||
if (data.$tree[0]) data.$tree[0]._onSuccess = data.onSuccess;
|
||
}
|
||
data.selectedID = data.currentId;
|
||
|
||
if (!data.inited || !data.noDialog) {
|
||
data.$dlg = $dlg;
|
||
initTreeDialog($dlg);
|
||
} else {
|
||
if (data.selectedID) {
|
||
var tree__ = data.$tree.fancytree('getTree');
|
||
tree__.visit(function (node) {
|
||
if (node.key === data.selectedID) {
|
||
node.setActive();
|
||
node.makeVisible({scrollIntoView: false});
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
if (!data.noDialog) {
|
||
if (typeof M !== 'undefined') {
|
||
if (data.currentId) {
|
||
$dlg.find('.title').text(data.texts.selectid + ' - ' + getNameObj(data.objects[data.currentId], data.currentId));
|
||
$dlg.find('.btn-set').removeClass('disabled');
|
||
} else {
|
||
$dlg.find('.title').text(data.texts.selectid);
|
||
$dlg.find('.btn-set').addClass('disabled');
|
||
}
|
||
$dlg.show().modal('open');
|
||
} else {
|
||
if (data.currentId) {
|
||
$dlg.dialog('option', 'title', data.texts.selectid + ' - ' + getNameObj(data.objects[data.currentId], data.currentId));
|
||
$dlg.find('#button-ok').removeClass('ui-state-disabled');
|
||
} else {
|
||
$dlg.dialog('option', 'title', data.texts.selectid);
|
||
$dlg.find('#button-ok').addClass('ui-state-disabled');
|
||
}
|
||
$dlg.dialog('open');
|
||
}
|
||
showActive($dlg, true);
|
||
} else {
|
||
$dlg.show();
|
||
showActive($dlg, true);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
},
|
||
hide: function () {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (data && !data.noDialog) {
|
||
$dlg.dialog('hide');
|
||
} else {
|
||
$dlg.hide();
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
clear: function () {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
// Init data
|
||
if (data) {
|
||
data.tree = {title: '', children: [], count: 0, root: true};
|
||
data.rooms = {};
|
||
data.roomEnums = [];
|
||
data.funcs = {};
|
||
data.funcEnums = [];
|
||
data.roles = [];
|
||
data.types = [];
|
||
data.histories = [];
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
getInfo: function (id) {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (data && data.objects) {
|
||
return data.objects[id];
|
||
}
|
||
}
|
||
return null;
|
||
},
|
||
getTreeInfo: function (id) {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data || !data.$tree) continue;
|
||
|
||
var tree = data.$tree.fancytree('getTree');
|
||
var node = tree && tree.getNodeByKey(id);
|
||
// var node = null;
|
||
// tree.visit(function (n) {
|
||
// if (n.key === id) {
|
||
// node = n;
|
||
// return false;
|
||
// }
|
||
// });
|
||
var result = {
|
||
id: id,
|
||
parent: (node && node.parent && node.parent.parent) ? node.parent.key : null,
|
||
children: null,
|
||
obj: data.objects ? data.objects[id] : null
|
||
};
|
||
if (node && node.children) {
|
||
result.children = [];
|
||
for (var t = 0; t < node.children.length; t++) {
|
||
result.children.push(node.children[t].key);
|
||
}
|
||
if (!result.children.length) delete result.children;
|
||
|
||
}
|
||
return result;
|
||
}
|
||
return null;
|
||
},
|
||
destroy: function () {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var $dlg = $(this[i]);
|
||
var data = $dlg.data('selectId');
|
||
if (data) {
|
||
$dlg.data('selectId', null);
|
||
$dlg.find('.dialog-select-container').remove();
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
reinit: function () {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (data) {
|
||
data.inited = false;
|
||
initTreeDialog(data.$dlg);
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
// update states
|
||
state: function (id, state) {
|
||
for (var i = 0; i < this.length; i++) {
|
||
var dlg = this[i];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data || !data.states || !data.$tree) continue;
|
||
/*if (data.states[id] &&
|
||
state &&
|
||
data.states[id].val === state.val &&
|
||
data.states[id].ack === state.ack &&
|
||
data.states[id].q === state.q &&
|
||
data.states[id].from === state.from &&
|
||
data.states[id].ts === state.ts
|
||
) return;*/
|
||
|
||
data.states[id] = state;
|
||
var tree = data.$tree.fancytree('getTree');
|
||
var node = tree.getNodeByKey(id);
|
||
// var node = null;
|
||
// tree.visit(function (n) {
|
||
// if (n.key === id) {
|
||
// node = n;
|
||
// return false;
|
||
// }
|
||
// });
|
||
if (node) node.render(true);
|
||
}
|
||
return this;
|
||
},
|
||
// update objects
|
||
object: function (id, obj, action) {
|
||
for (var k = 0, len = this.length; k < len; k++) {
|
||
var dlg = this[k];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data || !data.$tree || !data.objects) continue;
|
||
|
||
if (id.match(/^enum\.rooms/)) {
|
||
data.rooms = {};
|
||
data.roomsColored = {};
|
||
}
|
||
if (id.match(/^enum\.functions/)) {
|
||
data.funcs = {};
|
||
data.funcsColored = {};
|
||
}
|
||
|
||
var tree = data.$tree.fancytree('getTree');
|
||
var node = tree.getNodeByKey(id);
|
||
// var node = null;
|
||
// tree.visit(function (n) {
|
||
// if (n.key === id) {
|
||
// node = n;
|
||
// return false;
|
||
// }
|
||
// });
|
||
|
||
// If new node
|
||
if (!node && obj) {
|
||
// Filter it
|
||
if (typeof data.stats === 'object' && action === 'add') {
|
||
data.stats.objs++;
|
||
if (obj.type === 'state') {
|
||
data.stats.states++;
|
||
}
|
||
updateStats(data);
|
||
}
|
||
|
||
data.objects[id] = obj;
|
||
var addedNodes = [];
|
||
|
||
if (!filterId(data, id)) {
|
||
return;
|
||
}
|
||
// add ID to IDS;
|
||
if (data.ids.length) {
|
||
var p = 0;
|
||
while (data.ids[p] < id) {
|
||
p++;
|
||
}
|
||
data.ids.splice(p, 0, id);
|
||
}
|
||
treeInsert(data, id, false, addedNodes);
|
||
|
||
for (var i = 0; i < addedNodes.length; i++) {
|
||
if (!addedNodes[i].parent.root) {
|
||
node = tree.getNodeByKey(addedNodes[i].parent.key);
|
||
// tree.visit(function (n) {
|
||
// if (n.key === addedNodes[i].parent.key) {
|
||
// node = n;
|
||
// return false;
|
||
// }
|
||
// });
|
||
|
||
} else {
|
||
node = data.$tree.fancytree('getRootNode');
|
||
}
|
||
// if no children
|
||
if (!node.children || !node.children.length) {
|
||
// add
|
||
node.addChildren(addedNodes[i]);
|
||
node.folder = true;
|
||
node.expanded = false;
|
||
node.render(true);
|
||
node.children[0].match = true;
|
||
} else {
|
||
var c;
|
||
for (c = 0; c < node.children.length; c++) {
|
||
if (node.children[c].key > addedNodes[i].key) break;
|
||
}
|
||
// if some found greater than new one
|
||
if (c !== node.children.length) {
|
||
node.addChildren(addedNodes[i], node.children[c]);
|
||
node.children[c].match = true;
|
||
node.render(true);
|
||
} else {
|
||
// just add
|
||
node.addChildren(addedNodes[i]);
|
||
node.children[node.children.length - 1].match = true;
|
||
node.render(true);
|
||
}
|
||
}
|
||
}
|
||
} else if (!obj) {
|
||
if (typeof data.stats === 'object' && action === 'delete') {
|
||
data.stats.objs--;
|
||
if (data.objects[id] && data.objects[id].type === 'state') {
|
||
data.stats.states--;
|
||
}
|
||
updateStats(data);
|
||
}
|
||
|
||
// object deleted
|
||
delete data.objects[id];
|
||
deleteTree(data, id);
|
||
|
||
if (data.ids.length) {
|
||
var pos = data.ids.indexOf(id);
|
||
if (pos !== -1) {
|
||
data.ids.splice(pos, 1);
|
||
}
|
||
}
|
||
|
||
if (node) {
|
||
var prev = node.getPrevSibling();
|
||
var parent = node.parent;
|
||
node.removeChildren();
|
||
node.remove();
|
||
prev && prev.setActive();
|
||
|
||
while (parent && (!parent.children || !parent.children.length)) {
|
||
var _parent = parent.parent;
|
||
parent.remove();
|
||
if (_parent) {
|
||
_parent.setActive();
|
||
}
|
||
parent = _parent;
|
||
}
|
||
|
||
// recalculate numbers of all children
|
||
if (data.ids.length) {
|
||
recalcChildrenCounters(parent, data);
|
||
}
|
||
// if (node.children && node.children.length) {
|
||
// if (node.children.length === 1) {
|
||
// node.folder = false;
|
||
// node.expanded = false;
|
||
// }
|
||
// node.render(true);
|
||
// } else {
|
||
// if (node.parent && node.parent.children.length === 1) {
|
||
// node.parent.folder = false;
|
||
// node.parent.expanded = false;
|
||
// node.parent.render(true);
|
||
// }
|
||
// node.remove();
|
||
// }
|
||
}
|
||
} else {
|
||
// object updated
|
||
if (node) {
|
||
node.render(true);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
},
|
||
option: function (name, value) {
|
||
for (var k = 0; k < this.length; k++) {
|
||
var dlg = this[k];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data) continue;
|
||
|
||
if (data[name] !== undefined) {
|
||
data[name] = value;
|
||
} else {
|
||
console.error('Unknown options for selectID: ' + name);
|
||
}
|
||
}
|
||
},
|
||
objectAll: function (id, obj) {
|
||
$('.select-id-dialog-marker').selectId('object', id, obj);
|
||
},
|
||
stateAll: function (id, state) {
|
||
$('.select-id-dialog-marker').selectId('state', id, state);
|
||
},
|
||
getFilteredIds: function () {
|
||
for (var k = 0; k < this.length; k++) {
|
||
var dlg = this[k];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
if (!data || !data.$tree || !data.objects) continue;
|
||
|
||
var tree = data.$tree.fancytree('getTree');
|
||
var nodes = [];
|
||
tree.visit(function (n) {
|
||
if (n.match) {
|
||
nodes.push(n.key);
|
||
}
|
||
});
|
||
return nodes;
|
||
}
|
||
return null;
|
||
},
|
||
getActual: function () {
|
||
//for (var k = 0; k < this.length; k++) {
|
||
//
|
||
//}
|
||
var dlg = this[0];
|
||
var $dlg = $(dlg);
|
||
var data = $dlg.data('selectId');
|
||
return data ? data.selectedID : null;
|
||
}
|
||
};
|
||
|
||
$.fn.selectId = function (method) {
|
||
if (methods[method]) {
|
||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||
} else if (typeof method === 'object' || !method) {
|
||
return methods.init.apply(this, arguments);
|
||
} else {
|
||
$.error('Method "' + method + '" not found in jQuery.selectId');
|
||
}
|
||
};
|
||
})(jQuery);
|