yunkong2.node-red/public/selectID.js
2018-12-20 22:06:06 +08:00

2466 lines
111 KiB
JavaScript

/*
Copyright 2014-2017 bluefox <dogafox@gmail.com>
version: 1.0.2 (2017.04.13)
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.
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
noMultiselect: false, // do not make multiselect
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 button
// 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"
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',
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'
},
columns: ['image', 'name', 'type', 'role', 'enum', 'room', 'function', 'value', 'button'],
// 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)
}
+ show(currentId, filter, callback) - all arguments are optional if set by "init"
+ 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
*/
(function ($) {
'use strict';
if ($.fn.selectId) return;
var instance = 0;
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;
}
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 getAllStates(data) {
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 = [];
for (var id in objects) {
if (isRoom && objects[id].type === 'enum' && data.regexEnumRooms.test(id)) data.roomEnums.push(id);
if (isFunc && objects[id].type === 'enum' && data.regexEnumFuncs.test(id)) data.funcEnums.push(id);
if ((isRoom || isFunc) && objects[id].enums) {
for (var e in objects[id].enums) {
if (isRoom && data.regexEnumRooms.test(e)) {
if (data.roomEnums.indexOf(e) === -1) data.roomEnums.push(e);
if (!objects[e]) {
objects[e] = {
_id: e,
common: {
name: objects[id].enums[e],
members: [id]
}
};
} else if (objects[e].common.members.indexOf(id) === -1) {
objects[e].common.members.push(id);
}
} else if (isFunc && data.regexEnumFuncs.test(e)) {
if (data.funcEnums.indexOf(e) === -1) data.funcEnums.push(e);
if (!objects[e]) {
objects[e] = {
_id: e,
common: {
name: objects[id].enums[e],
members: [id]
}
};
} else if (objects[e].common.members.indexOf(id) === -1) {
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);
}
// ignore system objects in expert mode
if (data.expertModeRegEx && !data.expertMode && data.expertModeRegEx.test(id)) continue;
if (!filterId(data, id)) continue;
treeInsert(data, id, data.currentId === id);
if (objects[id].enums) {
for (var e in objects[id].enums) {
if (objects[e] &&
objects[e].common &&
objects[e].common.members &&
objects[e].common.members.indexOf(id) === -1) {
objects[e].common.members.push(id);
}
}
}
}
data.inited = true;
data.roles.sort();
data.types.sort();
data.roomEnums.sort();
data.funcEnums.sort();
data.histories.sort();
}
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('Id ' + id + ' not found');
return;
}
_deleteTree(node, deletedNodes);
}
function findTree(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) {
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});
} catch (err) {
console.error(err);
}
return false;
}
});
}
}
function syncHeader($dlg) {
// read width of data.$tree and set the same width for header
var data = $dlg.data('selectId');
var $header = $('#selectID_header_' + data.instance);
var thDest = $header.find('>colgroup>col'); //if table headers are specified in its semantically correct tag, are obtained
var thSrc = data.$tree.find('>thead>tr>th');
for (var i = 1; i < thSrc.length; i++) {
$(thDest[i]).attr('width', $(thSrc[i]).width());
}
}
function findRoomsForObject(data, id, withParentInfo, rooms) {
rooms = rooms || [];
for (var i = 0; i < data.roomEnums.length; i++) {
if (data.objects[data.roomEnums[i]].common.members.indexOf(id) !== -1 &&
rooms.indexOf(data.objects[data.roomEnums[i]].common.name) === -1) {
if (!withParentInfo) {
rooms.push(data.objects[data.roomEnums[i]].common.name);
} else {
rooms.push({name: data.objects[data.roomEnums[i]].common.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) {
rooms = rooms || [];
for (var i = 0; i < data.roomEnums.length; i++) {
if (data.objects[data.roomEnums[i]].common.members.indexOf(id) !== -1 &&
rooms.indexOf(data.roomEnums[i]) === -1) {
rooms.push(data.roomEnums[i]);
}
}
return rooms;
}
function findFunctionsForObject(data, id, withParentInfo, funcs) {
funcs = funcs || [];
for (var i = 0; i < data.funcEnums.length; i++) {
if (data.objects[data.funcEnums[i]].common.members.indexOf(id) !== -1 &&
funcs.indexOf(data.objects[data.funcEnums[i]].common.name) === -1) {
if (!withParentInfo) {
funcs.push(data.objects[data.funcEnums[i]].common.name);
} else {
funcs.push({name: data.objects[data.funcEnums[i]].common.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) {
funcs = funcs || [];
for (var i = 0; i < data.funcEnums.length; i++) {
if (data.objects[data.funcEnums[i]].common.members.indexOf(id) !== -1 &&
funcs.indexOf(data.funcEnums[i]) === -1) {
funcs.push(data.funcEnums[i]);
}
}
return funcs;
}
function clippyCopy(e) {
var $temp = $('<input>');
//$('body').append($temp);
$(this).append($temp);
$temp.val($(this).parent().data('clippy')).select();
document.execCommand('copy');
$temp.remove();
e.preventDefault();
e.stopPropagation();
}
function clippyShow(e) {
if ($(this).hasClass('clippy')) {
var text = '<button class="clippy-button ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only" ' +
'role="button" title="' + $(this).data('copyToClipboard') + '" ' +
'style="position: absolute; right: 0; top: 0; width: 36px; height: 18px;z-index: 1">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span></button>';
$(this).append(text);
$(this).find('.clippy-button').click(clippyCopy);
}
}
function clippyHide(e) {
$(this).find('.clippy-button').remove();
}
function installColResize(data, $dlg) {
if (data.noColumnResize || !$.fn.colResizable) return;
var data = $dlg.data('selectId');
if (data.$tree.is(':visible')) {
data.$tree.colResizable({
liveDrag: true,
onResize: function (event) {
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 odl 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 onQuickEditField(e) {
var $this = $(this);
var id = $this.data('id');
var attr = $this.data('name');
var data = $this.data('selectId');
var type = $this.data('type');
var clippy = $this.hasClass('clippy');
var options = $this.data('options');
var oldVal = $this.data('old-value');
var states = null;
if (clippy) $this.removeClass('clippy');
$this.unbind('click').removeClass('select-id-quick-edit').css('position', 'relative');
var css = 'cursor: pointer; position: absolute;width: 16px; height: 16px; top: 2px; border-radius: 6px; z-index: 3; background-color: lightgray';
if (type === 'boolean') {
type = 'checkbox';
} else {
type = 'text';
}
var text;
if (attr === 'value') {
states = getStates(data, id);
if (states) {
text = '<select style="width: calc(100% - 50px); z-index: 2">';
for (var t in states) {
if (typeof states[t] !== 'string') continue;
text += '<option value="' + t + '">' + states[t] + '</option>';
}
text += '</select>';
}
} else if (attr === 'room') {
states = findRoomsForObjectAsIds(data, id) || [];
text = '<select style="width: calc(100% - 50px); z-index: 2" multiple="multiple">';
for (var e = 0; e < data.roomEnums.length; e++) {
text += '<option value="' + data.roomEnums[e] + '" ' + (states.indexOf(data.roomEnums[e]) !== -1 ? 'selected' : '') + '>' + data.objects[data.roomEnums[e]].common.name + '</option>';
}
text += '</select>';
} else if (attr === '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++) {
text += '<option value="' + data.funcEnums[e] + '" ' + (states.indexOf(data.funcEnums[e]) !== -1 ? 'selected' : '') + '>' + data.objects[data.funcEnums[e]].common.name + '</option>';
}
text += '</select>';
} else 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) {
text += '<option value="' + t + '">' + states[t] + '</option>';
}
text += '</select>';
} else if (states === false) {
return;
}
}
text = text || '<input style="' + (type !== 'checkbox' ? 'width: 100%;' : '') + ' z-index: 2" type="' + type + '"/>';
var timeout = null;
$this.html(text +
'<div class="ui-icon ui-icon-check select-id-quick-edit-ok" style="' + css + ';right: 22px"></div>' +
'<div class="cancel ui-icon ui-icon-close select-id-quick-edit-cancel" title="' + data.texts.cancel + '" style="' + css + ';right: 2px"></div>');
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') {
$input.autocomplete({
minLength: 0,
source: data.roles
}).on('focus', function () {
$(this).autocomplete('search', '');
});
}
$this.find('.select-id-quick-edit-cancel').click(function (e) {
if (timeout) clearTimeout(timeout);
timeout = null;
e.preventDefault();
e.stopPropagation();
var old = $this.data('old-value');
if (old === undefined) old = '';
$this.html(old).click(onQuickEditField).addClass('select-id-quick-edit');
if (clippy) $this.addClass('clippy');
});
$this.find('.select-id-quick-edit-ok').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: pink">' + _oldText + '</span>';
}
if (clippy) $this.addClass('clippy');
$this.html(_oldText).click(onQuickEditField).addClass('select-id-quick-edit');
}.bind(this), 100);
}).keyup(function (e) {
if (e.which === 13) $(this).trigger('blur');
if (e.which === 27) {
if (clippy) $this.addClass('clippy');
var old = $this.data('old-value');
if (old === undefined) old = '';
$this.html(old).click(onQuickEditField).addClass('select-id-quick-edit');
}
});
if (typeof e === 'object') {
e.preventDefault();
e.stopPropagation();
}
setTimeout(function () {
$input.focus().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 initTreeDialog($dlg) {
var c;
var data = $dlg.data('selectId');
//var noStates = (data.objects && !data.states);
var multiselect = (!data.noDialog && !data.noMultiselect);
// load expert mode flag
if (typeof Storage !== 'undefined' && data.name && data.expertModeRegEx) {
data.expertMode = window.localStorage.getItem(data.name + '-expert');
data.expertMode = (data.expertMode === true || data.expertMode === 'true');
}
// Get all states
getAllStates(data);
if (!data.noDialog && !data.buttonsDlg) {
data.buttonsDlg = [
{
id: data.instance + '-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');
}
},
{
id: data.instance + '-button-cancel',
text: data.texts.cancel,
click: function () {
storeSettings(data);
$(this).dialog('close');
}
}
];
$dlg.dialog({
autoOpen: false,
modal: true,
width: '90%',
close: function () {
storeSettings(data);
},
height: 500,
buttons: data.buttonsDlg
});
if (data.zindex !== null) {
$('div[aria-describedby="' + $dlg.attr('id') + '"]').css({'z-index': data.zindex})
}
}
// Store current filter
var filter = {ID: $('#filter_ID_' + data.instance).val()};
for (var u = 0; u < data.columns.length; u++) {
var name = data.columns[u];
if (typeof name === 'object') name = name.name;
filter[name] = $('#filter_' + name + '_' + data.instance).val();
}
var textRooms;
if (data.columns.indexOf('room') !== -1) {
textRooms = '<select id="filter_room_' + data.instance + '" class="filter_' + data.instance + '" style="padding: 0; width: 150px"><option value="">' + data.texts.all + '</option>';
for (var i = 0; i < data.roomEnums.length; i++) {
textRooms += '<option value="' + data.objects[data.roomEnums[i]].common.name + '">' + data.objects[data.roomEnums[i]].common.name + '</option>';
}
textRooms += '</select>';
} else {
if (data.rooms) delete data.rooms;
if (data.roomsColored) delete data.roomsColored;
}
var textFuncs;
if (data.columns.indexOf('function') !== -1) {
textFuncs = '<select id="filter_function_' + data.instance + '" class="filter_' + data.instance + '" style="padding: 0; width: 150px"><option value="">' + data.texts.all + '</option>';
for (var i = 0; i < data.funcEnums.length; i++) {
textFuncs += '<option value="' + data.objects[data.funcEnums[i]].common.name + '">' + data.objects[data.funcEnums[i]].common.name + '</option>';
}
textFuncs += '</select>';
} else {
if (data.funcs) delete data.funcs;
if (data.funcsColored) delete data.funcsColored;
}
var textRoles;
if (data.columns.indexOf('role') !== -1) {
textRoles = '<select id="filter_role_' + data.instance + '" class="filter_' + data.instance + '" style="padding:0;width:150px"><option value="">' + data.texts.all + '</option>';
for (var j = 0; j < data.roles.length; j++) {
textRoles += '<option value="' + data.roles[j] + '">' + data.roles[j] + '</option>';
}
textRoles += '</select>';
}
var textTypes;
if (data.columns.indexOf('type') !== -1) {
textTypes = '<select id="filter_type_' + data.instance + '" class="filter_' + data.instance + '" style="padding:0;width:150px"><option value="">' + data.texts.all + '</option>';
for (var k = 0; k < data.types.length; k++) {
textTypes += '<option value="' + data.types[k] + '">' + data.types[k] + '</option>';
}
textTypes += '</select>';
}
var text = '<div id="' + data.instance + '-div" style="width:100%; height:100%"><table id="selectID_header_' + data.instance + '" style="width: 100%; padding: 0; height: 50px" cellspacing="0" cellpadding="0">';
text += '<colgroup>';
text += ' <col width="1px"/>';
text += ' <col width="400px"/>';
for (c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'image') {
text += '<col width="' + (data.widths ? data.widths[c] : '20px') + '"/>';
} else if (name === 'name') {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
} else if (name === 'type') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'role') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'room') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'function') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'value') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'button') {
text += '<col width="' + (data.widths ? data.widths[c] : '100px') + '"/>';
} else if (name === 'enum') {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
} else {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
}
}
text += ' <col width="18px"/>'; // TODO calculate width of scroll bar
text += ' </colgroup>';
text += ' <thead>';
text += ' <tr><th></th><th><table style="width: 100%; padding:0" cellspacing="0" cellpadding="0"><tr>';
text += '<td><button id="btn_refresh_' + data.instance + '"></button></td>';
text += '<td><button id="btn_list_' + data.instance + '"></button></td>';
text += '<td><button id="btn_collapse_' + data.instance + '"></button></td>';
text += '<td><button id="btn_expand_' + data.instance + '"></button></td><td class="select-id-custom-buttons"></td>';
if (data.filter && data.filter.type === 'state' && multiselect) {
text += '<td style="padding-left: 10px"><button id="btn_select_all_' + data.instance + '"></button></td>';
text += '<td><button id="btn_unselect_all_' + data.instance + '"></button></td>';
text += '<td><button id="btn_invert_selection_' + data.instance + '"></button></td>';
}
if (data.expertModeRegEx) {
text += '<td style="padding-left: 10px"><button id="btn_expert_' + data.instance + '"></button></td>';
}
if (data.panelButtons) {
text += '<td style="width: 20px">&nbsp;&nbsp;</td>';
for (c = 0; c < data.panelButtons.length; c++) {
text += '<td><button id="btn_custom_' + data.instance + '_' + c + '"></button></td>';
}
}
text += '<td class="ui-widget" style="width: 100%; text-align: center; font-weight: bold; font-size: medium">' + data.texts.id + '</td></tr></table></th>';
for (c = 0; c < data.columns.length; c++) {
var _name = data.columns[c];
if (typeof _name === 'object') _name = name.name;
text += '<th class="ui-widget" style="font-size: medium">' + (data.texts[_name] || '') + '</th>';
}
text += '<th></th></tr>';
text += ' </thead>';
text += ' <tbody>';
text += ' <tr><td></td>';
text += ' <td><table style="width: 100%"><tr><td style="width: 100%"><input style="width: 100%; padding: 0" type="text" id="filter_ID_' + data.instance + '" class="filter_' + data.instance + '"/></td><td style="vertical-align: top;"><button data-id="filter_ID_' + data.instance + '" class="filter_btn_' + data.instance + '"></button></td></tr></table></td>';
for (c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'image') {
text += '<td></td>';
} else if (name === 'name' || name === 'value' || name === 'enum') {
text += '<td><table style="width: 100%"><tr><td style="width: 100%"><input style="width: 100%; padding: 0" type="text" id="filter_' + data.columns[c] + '_' + data.instance + '" class="filter_' + data.instance + '"/></td><td style="vertical-align: top;"><button data-id="filter_' + data.columns[c] + '_' + data.instance + '" class="filter_btn_' + data.instance + '"></button></td></tr></table></td>';
} else if (name === 'type') {
text += '<td>' + textTypes + '</td>';
} else if (name== 'role') {
text += '<td>' + textRoles + '</td>';
} else if (name === 'room') {
text += '<td>' + textRooms + '</td>';
} else if (name === 'function') {
text += '<td>' + textFuncs + '</td>';
} else if (name === 'button') {
text += '<td style="text-align: center">';
if (data.customButtonFilter) {
var t = '<select id="filter_' + name + '_' + data.instance + '" class="filter_' + data.instance + '">';
t += '<option value="">' + data.texts.all + '</option>';
t += '<option value="true">' + data.texts.with + '</option>';
t += '<option value="false">' + data.texts.without + '</option>';
for (var h = 0; h < data.histories.length; h++) {
t += '<option value="' + data.histories[h] + '">' + data.histories[h] + '</option>';
}
t += '</select>';
text += '<table cellpadding="0" cellspacing="0" style="border-spacing: 0 0"><tr><td>' + t + '</td>' + '<td><button id="filter_' + data.columns[c] + '_' + data.instance + '_btn"></button></td></tr></table>'
}
text += '</td>';
} else {
text += '<td></td>';
}
}
text += ' <td></td></tr>';
text += ' </tbody>';
text += ' </table>';
//text += '<div style="width: 100%; height: ' + (data.buttons ? 100 : 85) + '%; padding:0; overflow-y: scroll">';
text += '<div style="width: 100%; height: ' + (data.buttons ? 'calc(100% - 50px)' : 'calc(100% - 50px)') + '; padding:0; overflow-y: scroll">';
text +=' <table id="selectID_' + data.instance + '" style="width: calc(100% - 5px);padding:0;table-layout:fixed; overflow:hidden;white-space:nowrap" cellspacing="0" cellpadding="0">';
text += ' <colgroup>';
text += ' <col width="1px"/>';
text += ' <col ' + (data.firstMinWidth ? ('width="' + data.firstMinWidth + '"') : 'width="400px"') + '/>';
for (c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'image') {
text += '<col width="' + (data.widths ? data.widths[c] : '20px') + '"/>';
} else if (name === 'name') {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
} else if (name === 'type') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'role') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'room') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'function') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'value') {
text += '<col width="' + (data.widths ? data.widths[c] : '150px') + '"/>';
} else if (name === 'button') {
text += '<col width="' + (data.widths ? data.widths[c] : '100px') + '"/>';
} else if (name === 'enum') {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
} else {
text += '<col width="' + (data.widths ? data.widths[c] : '*') + '"/>';
}
}
text += ' </colgroup>';
text += ' <thead>';
text += ' <tr><th></th><th></th>';
for (c = 0; c < data.columns.length; c++) {
text += '<th></th>';
}
text += '</tr>';
text += ' </thead>';
text += ' <tbody>';
text += ' </tbody>';
text += ' </table></div><div id="process_running_' + data.instance + '" style="position: absolute; top: 50%; left: 50%; width: 150px; height: 25px; padding: 12px; background: rgba(30, 30, 30, 0.5); display: none; text-align:center; font-size: 1.2em; color: white; font-weight: bold; border-radius: 5px">' + data.texts.wait + '</div>';
$dlg.html(text);
data.$tree = $('#selectID_' + data.instance);
data.$tree[0]._onChange = data.onSuccess || data.onChange;
var foptions = {
titlesTabbable: true, // Add all node titles to TAB chain
quicksearch: true,
source: data.tree.children,
extensions: ["table", "gridnav", "filter", "themeroller"],
checkbox: multiselect,
table: {
indentation: 20,
nodeColumnIdx: 1
},
gridnav: {
autofocusInput: false,
handleCursorKeys: true
},
filter: {
mode: 'hide',
autoApply: true
},
activate: function (event, data) {
// A node was activated: display its title:
// On change
//var $dlg = $('#' + data.instance + '-dlg');
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
if (_data.objects[newId] && _data.objects[newId].common && _data.objects[newId].common.name) {
$dlg.dialog('option', 'title', _data.texts.selectid + ' - ' + (_data.objects[newId].common.name || ' '));
} else {
$dlg.dialog('option', 'title', _data.texts.selectid + ' - ' + (newId || ' '));
}
// Enable/ disable "Select" button
if (_data.objects[newId]) { // && _data.objects[newId].type === 'state') {
$('#' + _data.instance + '-button-ok').removeClass('ui-state-disabled');
} else {
$('#' + _data.instance + '-button-ok').addClass('ui-state-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) {
$('#' + _data.instance + '-button-ok').removeClass('ui-state-disabled');
} else {
$('#' + _data.instance + '-button-ok').addClass('ui-state-disabled');
}
},
renderColumns: function (event, _data) {
var node = _data.node;
var $tr = $(node.tr);
var $tdList = $tr.find('>td');
var isCommon = data.objects[node.key] && data.objects[node.key].common;
var $firstTD = $tdList.eq(1);
$firstTD.css({'overflow': 'hidden'});
var base = 2;
// hide checkbox if only states should be selected
if (data.filter && data.filter.type === 'state' && (!data.objects[node.key] || data.objects[node.key].type !== 'state')) {
$firstTD.find('.fancytree-checkbox').hide();
}
// special case for javascript scripts
if (data.objects[node.key] && (node.key.match(/^script\.js\./) || node.key.match(/^enum\.[\w\d_-]+$/))) {
if (data.objects[node.key].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) {
$firstTD
.addClass('clippy')
.data('clippy', node.key)
.css({position: 'relative'})
.data('copyToClipboard', data.texts.copyToClipboard || data.texts.copyTpClipboard)
.mouseenter(clippyShow)
.mouseleave(clippyHide);
}
if (data.useNameAsId && data.objects[node.key] && data.objects[node.key].common && data.objects[node.key].common.name) {
$firstTD.find('.fancytree-title').html(data.objects[node.key].common.name);
}
var $elem;
var val;
for (var c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'image') {
var icon = '';
var alt = '';
var _id_ = 'system.adapter.' + node.key;
if (data.objects[_id_] && data.objects[_id_].common && data.objects[_id_].common.icon) {
icon = '/adapter/' + data.objects[_id_].common.name + '/' + data.objects[_id_].common.icon;
} else
if (isCommon) {
if (data.objects[node.key].common.icon) {
var instance;
if (data.objects[node.key].type === 'instance') {
icon = '/adapter/' + data.objects[node.key].common.name + '/' + data.objects[node.key].common.icon;
} else if (node.key.match(/^system\.adapter\./)) {
instance = node.key.split('.', 3);
if (data.objects[node.key].common.icon[0] === '/') {
instance[2] += data.objects[node.key].common.icon;
} else {
instance[2] += '/' + data.objects[node.key].common.icon;
}
icon = '/adapter/' + instance[2];
} else {
instance = node.key.split('.', 2);
if (data.objects[node.key].common.icon[0] === '/') {
instance[0] += data.objects[node.key].common.icon;
} else {
instance[0] += '/' + data.objects[node.key].common.icon;
}
icon = '/adapter/' + instance[0];
}
} else if (data.objects[node.key].type === 'device') {
icon = data.imgPath + 'device.png';
alt = 'device';
} else if (data.objects[node.key].type === 'channel') {
icon = data.imgPath + 'channel.png';
alt = 'channel';
} else if (data.objects[node.key].type === 'state') {
icon = data.imgPath + 'state.png';
alt = 'state';
}
}
if (icon) {
$tdList.eq(base).html('<img width="20px" height="20px" src="' + icon + '" alt="' + alt + '"/>');
} else {
$tdList.eq(base).text('');
}
base++;
} else
if (name === 'name') {
$elem = $tdList.eq(base);
$elem.text(isCommon ? data.objects[node.key].common.name : '').css({overflow: 'hidden', 'white-space': 'nowrap', 'text-overflow': 'ellipsis'}).attr('title', isCommon ? data.objects[node.key].common.name : '');
if (data.quickEdit && data.objects[node.key] && data.quickEdit.indexOf('name') !== -1) {
$elem.data('old-value', isCommon ? data.objects[node.key].common.name : '');
$elem.click(onQuickEditField).data('id', node.key).data('name', 'name').data('selectId', data).addClass('select-id-quick-edit');
}
base++;
} else
if (name === 'type') {
$tdList.eq(base++).text(data.objects[node.key] ? data.objects[node.key].type: '');
} else
if (name === 'role') {
$elem = $tdList.eq(base);
val = isCommon ? data.objects[node.key].common.role : '';
$elem.text(val);
if (data.quickEdit && data.objects[node.key] && data.quickEdit.indexOf('role') !== -1) {
$elem.data('old-value', val);
$elem.click(onQuickEditField).data('id', node.key).data('name', 'role').data('selectId', data).addClass('select-id-quick-edit');
}
base++;
} else
if (name === 'room') {
$elem = $tdList.eq(base);
// Try to find room
if (data.roomsColored) {
if (!data.roomsColored[node.key]) data.roomsColored[node.key] = findRoomsForObject(data, node.key, true);
val = data.roomsColored[node.key].map(function (e) {return e.name;}).join(', ');
if (data.roomsColored[node.key].length && data.roomsColored[node.key][0].origin !== node.key) {
$elem.css({color: 'gray'}).attr('title', data.roomsColored[node.key][0].origin);
} else {
$elem.css({color: 'inherit'}).attr('title', null);
}
} else {
val = '';
}
$elem.text(val);
if (data.quickEdit && data.objects[node.key] && data.quickEdit.indexOf('room') !== -1) {
$elem.data('old-value', val);
$elem.click(onQuickEditField)
.data('id', node.key)
.data('name', 'room')
.data('selectId', data)
.addClass('select-id-quick-edit');
}
base++;
} else
if (name === 'function') {
$elem = $tdList.eq(base);
// 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 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 = '';
}
$elem.text(val);
if (data.quickEdit && data.objects[node.key] && data.quickEdit.indexOf('function') !== -1) {
$elem.data('old-value', val);
$elem.click(onQuickEditField)
.data('id', node.key)
.data('name', 'function')
.data('selectId', data)
.addClass('select-id-quick-edit');
}
base++;
} else
if (name === 'value') {
$elem = $tdList.eq(base);
var common = data.objects[node.key] ? data.objects[node.key].common || {} : {};
if (data.states && (data.states[node.key] || data.states[node.key + '.val'] !== undefined)) {
var $elem = $tdList.eq(base);
var 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'],
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 = JSON.parse(JSON.stringify(state));
}
if (common.role === 'value.time') {
state.val = state.val ? (new Date(state.val)).toString() : 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 && common.unit) state.val += ' ' + common.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 || '');
fullVal += '\x0A' + data.texts.quality + ': ' + quality2text(state.q || 0);
}
$elem.html('<span class="highlight">' + state.val + '</span>')
.attr('title', fullVal)
.css({position: 'relative'});
$elem.css({color: state.ack ? (state.q ? 'orange' : '') : 'red'});
if (!data.noCopyToClipboard && data.objects[node.key] && data.objects[node.key].type === 'state' && common.type !== 'file') {
$elem.data('clippy', state.val)
.addClass('clippy')
.data('copyToClipboard', data.texts.copyToClipboard || data.texts.copyTpClipboard)
.mouseenter(clippyShow)
.mouseleave(clippyHide);
}
} else {
$elem.text('')
.attr('title', '')
.removeClass('clippy');
}
$elem.dblclick(function (e) {
e.preventDefault();
});
if (data.quickEdit &&
data.objects[node.key] &&
data.objects[node.key].type === 'state' &&
data.quickEdit.indexOf('value') !== -1 &&
(data.expertMode || data.objects[node.key].common.write !== false)
) {
if (data.objects[node.key].common.role === 'button' && !data.expertMode) {
$tdList.eq(base).html('<button data-id="' + node.key + '" class="select-button-push"></button>');
} else
if (!data.objects[node.key].common || data.objects[node.key].common.type !== 'file') {
var val = data.states[node.key];
val = val ? val.val : '';
$elem.data('old-value', val).data('type', common.type || typeof val);
$elem.click(onQuickEditField)
.data('id', node.key)
.data('name', 'value')
.data('selectId', data)
.addClass('select-id-quick-edit');
}
$tr.find('.select-button-push[data-id="' + node.key + '"]').button({
text: false,
icons: {
primary: 'ui-icon-arrowthickstop-1-s'
}
}).click(function () {
var id = $(this).data('id');
data.quickEditCallback(id, 'value', true);
}).attr('title', data.texts.push).css({width: 26, height: 20});
}
if (common.type === 'file') {
data.webServer = data.webServer || (window.location.protocol + '//' + window.location.hostname + ':8082');
// link
$elem.html('<a href="' + data.webServer + '/state/' + node.key + '" target="_blank">' + data.webServer + '/state/' + node.key + '</a>')
.attr('title', data.texts.linkToFile);
}
base++;
} else
if (name === 'button') {
// Show buttons
var text;
if (data.buttons) {
if (data.objects[node.key] || data.showButtonsForNotExistingObjects) {
text = '';
if (data.editEnd) {
text += '<button data-id="' + node.key + '" class="select-button-edit"></button>' +
'<button data-id="' + node.key + '" class="select-button-ok"></button>' +
'<button data-id="' + node.key + '" class="select-button-cancel"></button>';
}
for (var j = 0; j < data.buttons.length; j++) {
text += '<button data-id="' + node.key + '" class="select-button-' + j + ' select-button-custom"></button>';
}
$tdList.eq(base).html(text);
for (var p = 0; p < data.buttons.length; p++) {
var btn = $tr.find('.select-button-' + p + '[data-id="' + node.key + '"]').button(data.buttons[p]).click(function () {
var cb = $(this).data('callback');
if (cb) cb.call($(this), $(this).attr('data-id'));
}).data('callback', data.buttons[p].click).attr('title', data.buttons[p].title || '');
if (data.buttons[p].width) btn.css({width: data.buttons[p].width});
if (data.buttons[p].height) btn.css({height: data.buttons[p].height});
if (data.buttons[p].match) data.buttons[p].match.call(btn, node.key);
}
} else {
$tdList.eq(base).text('');
}
} else if (data.editEnd) {
text = '<button data-id="' + node.key + '" class="select-button-edit"></button>' +
'<button data-id="' + node.key + '" class="select-button-ok"></button>' +
'<button data-id="' + node.key + '" class="select-button-cancel"></button>';
}
if (data.editEnd) {
$tr.find('.select-button-edit[data-id="' + node.key + '"]').button({
text: false,
icons: {
primary:'ui-icon-pencil'
}
}).click(function () {
$(this).data('node').editStart();
}).attr('title', data.texts.edit).data('node', node).css({width: 26, height: 20});
$tr.find('.select-button-ok[data-id="' + node.key + '"]').button({
text: false,
icons: {
primary: 'ui-icon-check'
}
}).click(function () {
var node = $(this).data('node');
node.editFinished = true;
node.editEnd(true);
}).attr('title', data.texts.ok).data('node', node).hide().css({width: 26, height: 20});
$tr.find('.select-button-cancel[data-id="' + node.key + '"]').button({
text: false,
icons: {
primary: 'ui-icon-close'
}
}).click(function () {
var node = $(this).data('node');
node.editFinished = true;
node.editEnd(false);
}).attr('title', data.texts.cancel).data('node', node).hide().css({width: 26, height: 20});
}
base++;
} else
if (name === 'enum') {
if (isCommon && data.objects[node.key].common.members && data.objects[node.key].common.members.length > 0) {
if (data.objects[node.key].common.members.length < 4) {
$tdList.eq(base).text('(' + data.objects[node.key].common.members.length + ')' + data.objects[node.key].common.members.join(', '));
} else {
$tdList.eq(base).text(data.objects[node.key].common.members.length);
}
$tdList.eq(base).attr('title', data.objects[node.key].common.members.join('\x0A'));
} else {
$tdList.eq(base).text('');
$tdList.eq(base).attr('title', '');
}
base++;
} else
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 && data.objects[node.key]) {
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.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;
}
}
}
base++;
}
}
},
dblclick: function (event, _data) {
if (data.buttonsDlg && !data.quickEditCallback) {
if (_data && _data.node && !_data.node.folder) {
data.buttonsDlg[0].click();
}
} else if (data.dblclick) {
var tree = data.$tree.fancytree('getTree');
var node = tree.getActiveNode();
if (node) {
data.dblclick(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};
for (var c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'name') {
$tdList.eq(2 + c).html('<input type="text" id="select_edit_' + name + '" value="' + data.objects[_data.node.key].common[name] + '" style="width: 100%"/>');
inputs[name] = $dlg.find('#select_edit_' + 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()};
for (var c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'name') {
editValues[name] = $dlg.find('#select_edit_' + 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, data) {
// Custom event handler that is triggered by keydown-handler and
// context menu:
var refNode;
var tree = $(this).fancytree('getTree');
var node = tree.getActiveNode();
switch (data.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 'copy':
CLIPBOARD = {
mode: data.cmd,
data: node.toDict(function (n) {
delete n.key;
})
};
break;
case 'clear':
CLIPBOARD = null;
break;*/
default:
alert('Unhandled command: ' + data.cmd);
return;
}
}).on('keydown', function (e) {
var c = String.fromCharCode(e.which);
var cmd = null;
if (e.which === 'c' && e.ctrlKey) {
cmd = 'copy';
}else if (e.which === $.ui.keyCode.UP && e.ctrlKey) {
cmd = 'moveUp';
} else if (e.which === $.ui.keyCode.DOWN && e.ctrlKey) {
cmd = 'moveDown';
} else if (e.which === $.ui.keyCode.RIGHT && e.ctrlKey) {
cmd = 'indent';
} else if (e.which === $.ui.keyCode.LEFT && e.ctrlKey) {
cmd = 'outdent';
}
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 = $('#filter_ID_' + data.instance).val().toLowerCase();
if (value) {
data.filterVals.ID = value;
data.filterVals.length++;
}
for (var c = 0; c < data.columns.length; c++) {
var name = data.columns[c];
if (typeof name === 'object') name = name.name;
if (name === 'image') {
//continue;
} else if (name === 'role' || name === 'type' || name === 'room' || name === 'function') {
value = $('#filter_' + name + '_' + data.instance).val();
if (value) {
data.filterVals[name] = value;
data.filterVals.length++;
}
} else {
value = $('#filter_' + name + '_' + data.instance).val();
if (value) {
value = value.toLowerCase();
data.filterVals[name] = value;
data.filterVals.length++;
}
}
}
// if no clear "close" event => store on change
if (data.noDialog) storeSettings(data);
}
var isCommon = null;
for (var f in data.filterVals) {
if (f === 'length') continue;
if (isCommon === null) isCommon = data.objects[node.key] && data.objects[node.key].common;
if (f === 'ID') {
if (node.key.toLowerCase().indexOf(data.filterVals[f]) === -1) return false;
} else
if (f === 'name' || f === 'enum') {
if (!isCommon || data.objects[node.key].common[f] === undefined || data.objects[node.key].common[f].toLowerCase().indexOf(data.filterVals[f]) === -1) return false;
} else
if (f === 'role') {
if (!isCommon || data.objects[node.key].common[f] === undefined || data.objects[node.key].common[f].indexOf(data.filterVals[f]) === -1) return false;
} else
if (f === 'type') {
if (!data.objects[node.key] || data.objects[node.key][f] === undefined || data.objects[node.key][f] !== data.filterVals[f]) return false;
} else
if (f === '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;
} else
if (f === 'button') {
if (data.filterVals[f] === 'true') {
if (!isCommon || !data.objects[node.key].common.custom || data.objects[node.key].common.custom.enabled === false) return false;
} else if (data.filterVals[f] === 'false') {
if (!isCommon || data.objects[node.key].type !== 'state' || data.objects[node.key].common.custom) return false;
} else if (data.filterVals[f]) {
if (!isCommon || !data.objects[node.key].common.custom || !data.objects[node.key].common.custom[data.filterVals[f]]) return false;
}
} else
if (f === 'room') {
if (!data.objects[node.key]) 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;
} else
if (f === 'function') {
if (!data.objects[node.key]) 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;
}
}
return true;
}
$('.filter_' + data.instance).change(function () {
data.filterVals = null;
$('#process_running_' + data.instance).show();
data.$tree.fancytree('getTree').filterNodes(customFilter, false);
$('#process_running_' + data.instance).hide();
}).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);
});
$('.filter_btn_' + data.instance).button({icons: {primary: 'ui-icon-close'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#' + $(this).attr('data-id')).val('').trigger('change');
});
$('#btn_collapse_' + data.instance).button({icons: {primary: 'ui-icon-folder-collapsed'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.$tree.fancytree('getRootNode').visit(function (node) {
if (!data.filterVals.length || node.match || node.subMatch) node.setExpanded(false);
});
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.collapse);
$('#btn_expand_' + data.instance).button({icons: {primary: 'ui-icon-folder-open'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.$tree.fancytree('getRootNode').visit(function (node) {
if (!data.filterVals.length || node.match || node.subMatch)
node.setExpanded(true);
});
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.expand);
$('#btn_list_' + data.instance).button({icons: {primary: 'ui-icon-grip-dotted-horizontal'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
data.list = !data.list;
if (data.list) {
$('#btn_list_' + data.instance).addClass('ui-state-error');
$('#btn_expand_' + data.instance).hide();
$('#btn_collapse_' + data.instance).hide();
$(this).attr('title', data.texts.list);
} else {
$('#btn_list_' + data.instance).removeClass('ui-state-error');
$('#btn_expand_' + data.instance).show();
$('#btn_collapse_' + data.instance).show();
$(this).attr('title', data.texts.tree);
}
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.inited = false;
initTreeDialog(data.$dlg);
$('#process_running_' + data.instance).hide();
}, 200);
}).attr('title', data.texts.tree);
if (data.list) {
$('#btn_list_' + data.instance).addClass('ui-state-error');
$('#btn_expand_' + data.instance).hide();
$('#btn_collapse_' + data.instance).hide();
$('#btn_list_' + data.instance).attr('title', data.texts.list);
}
$('#btn_refresh_' + data.instance).button({icons: {primary: 'ui-icon-refresh'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.inited = false;
initTreeDialog(data.$dlg);
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.refresh);
$('#btn_select_all_' + data.instance).button({icons: {primary: 'ui-icon-circle-check'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.$tree.fancytree('getRootNode').visit(function (node) {
if (!data.filterVals.length || node.match || node.subMatch) {
// hide checkbox if only states should be selected
if (data.objects[node.key] && data.objects[node.key].type === 'state') {
node.setSelected(true);
}
}
});
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.selectAll);
if (data.expertModeRegEx) {
$('#btn_expert_' + data.instance).button({icons: {primary: 'ui-icon-person'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
data.expertMode = !data.expertMode;
if (data.expertMode) {
$('#btn_expert_' + data.instance).addClass('ui-state-error');
} else {
$('#btn_expert_' + data.instance).removeClass('ui-state-error');
}
storeSettings(data, true);
setTimeout(function () {
data.inited = false;
initTreeDialog(data.$dlg);
$('#process_running_' + data.instance).hide();
}, 200);
}).attr('title', data.texts.expertMode);
if (data.expertMode) $('#btn_expert_' + data.instance).addClass('ui-state-error');
}
$('#btn_unselect_all_' + data.instance).button({icons: {primary: 'ui-icon-circle-close'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.$tree.fancytree('getRootNode').visit(function (node) {
node.setSelected(false);
});
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.unselectAll);
$('#btn_invert_selection_' + data.instance).button({icons: {primary: 'ui-icon-transferthick-e-w'}, text: false}).css({width: 18, height: 18}).click(function () {
$('#process_running_' + data.instance).show();
setTimeout(function () {
data.$tree.fancytree('getRootNode').visit(function (node) {
if (!data.filterVals.length || node.match || node.subMatch){
if (data.objects[node.key] && data.objects[node.key].type === 'state') {
node.toggleSelected();
}
}
});
$('#process_running_' + data.instance).hide();
}, 100);
}).attr('title', data.texts.invertSelection);
for (var f in filter) {
try {
if (f) $('#filter_' + f + '_' + data.instance).val(filter[f]).trigger('change');
} catch (err) {
console.error('Cannot apply filter: ' + err)
}
}
if (data.panelButtons) {
for (var z = 0; z < data.panelButtons.length; z++) {
$('#btn_custom_' + data.instance + '_' + z).button(data.panelButtons[z]).css({width: 18, height: 18}).click(data.panelButtons[z].click).attr('title', data.panelButtons[z].title || '');
text += '<td><button id="btn_custom_' + data.instance + '_' + z + '"></button></td>';
}
}
if (data.customButtonFilter) {
$('#filter_button_' + data.instance + '_btn').button(data.customButtonFilter).css({width: 18, height: 18}).click(data.customButtonFilter.callback);
}
showActive($dlg);
loadSettings(data);
installColResize(data, $dlg);
// set preset filters
for (var field in data.filterPresets) {
if (!data.filterPresets[field]) continue;
if (typeof data.filterPresets[field] === 'object') {
$('#filter_' + field + '_' + data.instance).val(data.filterPresets[field][0]).trigger('change');
} else {
$('#filter_' + field + '_' + data.instance).val(data.filterPresets[field]).trigger('change');
}
}
}
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));
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));
}, 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);
for (var field in f) {
if (field === 'length') continue;
if (data.filterPresets[field]) continue;
$('#filter_' + field + '_' + data.instance).val(f[field]).trigger('change');
}
} catch(e) {
console.error('Cannot parse settings: ' + e);
}
} else if (!data.filter) {
// set default filter: state
$('#filter_type_' + data.instance).val('state').trigger('change');
}
}
}
var methods = {
init: function (options) {
// 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,
columns: ['image', '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'
}, 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\\.'),
instance: instance++,
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 () {
if (!$('#select-id-dialog').length) {
$('body').append('<div id="select-id-dialog"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 50px 0;"></span><span>' + (data.texts.noconnection || 'No connection to server') + '</span></div>');
}
$('#select-id-dialog').dialog({
modal: true
});
}, 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;
});
});
});
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 = $('#selectID_' + data.instance);
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) {
$dlg.dialog('option', 'title', data.texts.selectid + ' - ' + (data.currentId || ' '));
if (data.currentId) {
if (data.objects[data.currentId] && data.objects[data.currentId].common && data.objects[data.currentId].common.name) {
$dlg.dialog('option', 'title', data.texts.selectid + ' - ' + (data.objects[data.currentId].common.name || ' '));
} else {
$dlg.dialog('option', 'title', data.texts.selectid + ' - ' + (data.currentId || ' '));
}
} else {
$('#' + data.instance + '-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 = 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 $dlg = $(dlg);
$dlg.data('selectId', null);
$('#' + data.instance + '-div')[0].innerHTML('');
}
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 = 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) {
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;
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 = null;
tree.visit(function (n) {
if (n.key === id) {
node = n;
return false;
}
});
// If new node
if (!node && obj) {
// Filter it
data.objects[id] = obj;
var addedNodes = [];
if (!filterId(data, id)) return;
treeInsert(data, id, false, addedNodes);
for (var i = 0; i < addedNodes.length; i++) {
if (!addedNodes[i].parent.root) {
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) {
// object deleted
delete data.objects[id];
deleteTree(data, id);
if (node) {
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);